diff options
author | marha <marha@users.sourceforge.net> | 2009-10-08 13:15:52 +0000 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2009-10-08 13:15:52 +0000 |
commit | a0c4815433ccd57322f4f7703ca35e9ccfa59250 (patch) | |
tree | f5213802ec12adb86ec3136001c1c29fe5343700 /mesalib/src/mesa/shader | |
parent | c73dc01b6de45612b24dc2dd34fba24d81ebf46c (diff) | |
download | vcxsrv-a0c4815433ccd57322f4f7703ca35e9ccfa59250.tar.gz vcxsrv-a0c4815433ccd57322f4f7703ca35e9ccfa59250.tar.bz2 vcxsrv-a0c4815433ccd57322f4f7703ca35e9ccfa59250.zip |
Added MesaLib-7.6
Diffstat (limited to 'mesalib/src/mesa/shader')
125 files changed, 70804 insertions, 0 deletions
diff --git a/mesalib/src/mesa/shader/Makefile b/mesalib/src/mesa/shader/Makefile new file mode 100644 index 000000000..400a543bd --- /dev/null +++ b/mesalib/src/mesa/shader/Makefile @@ -0,0 +1,7 @@ +all: program_parse.tab.c lex.yy.c + +program_parse.tab.c program_parse.tab.h: program_parse.y + bison -v -d $< + +lex.yy.c: program_lexer.l + flex --never-interactive $< diff --git a/mesalib/src/mesa/shader/arbprogparse.c b/mesalib/src/mesa/shader/arbprogparse.c new file mode 100644 index 000000000..05ee4f563 --- /dev/null +++ b/mesalib/src/mesa/shader/arbprogparse.c @@ -0,0 +1,212 @@ +/* + * 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/macros.h" +#include "main/mtypes.h" +#include "shader/grammar/grammar_mesa.h" +#include "arbprogparse.h" +#include "program.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; + } + + /* 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; + 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->UsesKill = state.fragment.UsesKill; + + if (program->FogOption) + program->Base.InputsRead |= FRAG_BIT_FOGC; + + if (program->Base.Instructions) + _mesa_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 + _mesa_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; + } + + /* 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->IsPositionInvariant = (state.option.PositionInvariant) + ? GL_TRUE : GL_FALSE; + + if (program->Base.Instructions) + _mesa_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 + _mesa_printf("____________Vertex program %u __________\n", program->Base.Id); + _mesa_print_program(&program->Base); +#endif +} diff --git a/mesalib/src/mesa/shader/arbprogparse.h b/mesalib/src/mesa/shader/arbprogparse.h new file mode 100644 index 000000000..980d39fb9 --- /dev/null +++ b/mesalib/src/mesa/shader/arbprogparse.h @@ -0,0 +1,41 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef ARBPROGPARSE_H +#define ARBPROGPARSE_H + +#include "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 diff --git a/mesalib/src/mesa/shader/arbprogram.c b/mesalib/src/mesa/shader/arbprogram.c new file mode 100644 index 000000000..4d8cff070 --- /dev/null +++ b/mesalib/src/mesa/shader/arbprogram.c @@ -0,0 +1,1042 @@ +/* + * Mesa 3-D graphics library + * Version: 7.0 + * + * 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 arbprogram.c + * ARB_vertex/fragment_program state management functions. + * \author Brian Paul + */ + + +#include "main/glheader.h" +#include "main/context.h" +#include "main/hash.h" +#include "main/imports.h" +#include "main/macros.h" +#include "main/mtypes.h" +#include "arbprogram.h" +#include "arbprogparse.h" +#include "program.h" + + + +/** + * Mixing ARB and NV vertex/fragment programs can be tricky. + * Note: GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV + * but, GL_FRAGMENT_PROGRAM_ARB != GL_FRAGMENT_PROGRAM_NV + * The two different fragment program targets are supposed to be compatible + * to some extent (see GL_ARB_fragment_program spec). + * This function does the compatibility check. + */ +static GLboolean +compatible_program_targets(GLenum t1, GLenum t2) +{ + if (t1 == t2) + return GL_TRUE; + if (t1 == GL_FRAGMENT_PROGRAM_ARB && t2 == GL_FRAGMENT_PROGRAM_NV) + return GL_TRUE; + if (t1 == GL_FRAGMENT_PROGRAM_NV && t2 == GL_FRAGMENT_PROGRAM_ARB) + return GL_TRUE; + return GL_FALSE; +} + + +/** + * Bind a program (make it current) + * \note Called from the GL API dispatcher by both glBindProgramNV + * and glBindProgramARB. + */ +void GLAPIENTRY +_mesa_BindProgram(GLenum target, GLuint id) +{ + struct gl_program *curProg, *newProg; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* Error-check target and get curProg */ + if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */ + (ctx->Extensions.NV_vertex_program || + ctx->Extensions.ARB_vertex_program)) { + curProg = &ctx->VertexProgram.Current->Base; + } + else if ((target == GL_FRAGMENT_PROGRAM_NV + && ctx->Extensions.NV_fragment_program) || + (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program)) { + curProg = &ctx->FragmentProgram.Current->Base; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)"); + return; + } + + /* + * Get pointer to new program to bind. + * NOTE: binding to a non-existant program is not an error. + * That's supposed to be caught in glBegin. + */ + if (id == 0) { + /* Bind a default program */ + newProg = NULL; + if (target == GL_VERTEX_PROGRAM_ARB) /* == GL_VERTEX_PROGRAM_NV */ + newProg = &ctx->Shared->DefaultVertexProgram->Base; + else + newProg = &ctx->Shared->DefaultFragmentProgram->Base; + } + else { + /* Bind a user program */ + newProg = _mesa_lookup_program(ctx, id); + if (!newProg || newProg == &_mesa_DummyProgram) { + /* allocate a new program now */ + newProg = ctx->Driver.NewProgram(ctx, target, id); + if (!newProg) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB"); + return; + } + _mesa_HashInsert(ctx->Shared->Programs, id, newProg); + } + else if (!compatible_program_targets(newProg->Target, target)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindProgramNV/ARB(target mismatch)"); + return; + } + } + + /** All error checking is complete now **/ + + if (curProg->Id == id) { + /* binding same program - no change */ + return; + } + + /* signal new program (and its new constants) */ + FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + + /* bind newProg */ + if (target == GL_VERTEX_PROGRAM_ARB) { /* == GL_VERTEX_PROGRAM_NV */ + _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, + (struct gl_vertex_program *) newProg); + } + else if (target == GL_FRAGMENT_PROGRAM_NV || + target == GL_FRAGMENT_PROGRAM_ARB) { + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, + (struct gl_fragment_program *) newProg); + } + + /* Never null pointers */ + ASSERT(ctx->VertexProgram.Current); + ASSERT(ctx->FragmentProgram.Current); + + if (ctx->Driver.BindProgram) + ctx->Driver.BindProgram(ctx, target, newProg); +} + + +/** + * Delete a list of programs. + * \note Not compiled into display lists. + * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB. + */ +void GLAPIENTRY +_mesa_DeletePrograms(GLsizei n, const GLuint *ids) +{ + GLint i; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (n < 0) { + _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" ); + return; + } + + for (i = 0; i < n; i++) { + if (ids[i] != 0) { + struct gl_program *prog = _mesa_lookup_program(ctx, ids[i]); + if (prog == &_mesa_DummyProgram) { + _mesa_HashRemove(ctx->Shared->Programs, ids[i]); + } + else if (prog) { + /* Unbind program if necessary */ + if (prog->Target == GL_VERTEX_PROGRAM_ARB || /* == GL_VERTEX_PROGRAM_NV */ + prog->Target == GL_VERTEX_STATE_PROGRAM_NV) { + if (ctx->VertexProgram.Current && + ctx->VertexProgram.Current->Base.Id == ids[i]) { + /* unbind this currently bound program */ + _mesa_BindProgram(prog->Target, 0); + } + } + else if (prog->Target == GL_FRAGMENT_PROGRAM_NV || + prog->Target == GL_FRAGMENT_PROGRAM_ARB) { + if (ctx->FragmentProgram.Current && + ctx->FragmentProgram.Current->Base.Id == ids[i]) { + /* unbind this currently bound program */ + _mesa_BindProgram(prog->Target, 0); + } + } + else { + _mesa_problem(ctx, "bad target in glDeleteProgramsNV"); + return; + } + /* The ID is immediately available for re-use now */ + _mesa_HashRemove(ctx->Shared->Programs, ids[i]); + _mesa_reference_program(ctx, &prog, NULL); + } + } + } +} + + +/** + * Generate a list of new program identifiers. + * \note Not compiled into display lists. + * \note Called by both glGenProgramsNV and glGenProgramsARB. + */ +void GLAPIENTRY +_mesa_GenPrograms(GLsizei n, GLuint *ids) +{ + GLuint first; + GLuint i; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms"); + return; + } + + if (!ids) + return; + + first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n); + + /* Insert pointer to dummy program as placeholder */ + for (i = 0; i < (GLuint) n; i++) { + _mesa_HashInsert(ctx->Shared->Programs, first + i, &_mesa_DummyProgram); + } + + /* Return the program names */ + for (i = 0; i < (GLuint) n; i++) { + ids[i] = first + i; + } +} + + +void GLAPIENTRY +_mesa_EnableVertexAttribArrayARB(GLuint index) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= ctx->Const.VertexProgram.MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glEnableVertexAttribArrayARB(index)"); + return; + } + + ASSERT(index < Elements(ctx->Array.ArrayObj->VertexAttrib)); + + FLUSH_VERTICES(ctx, _NEW_ARRAY); + ctx->Array.ArrayObj->VertexAttrib[index].Enabled = GL_TRUE; + ctx->Array.ArrayObj->_Enabled |= _NEW_ARRAY_ATTRIB(index); + ctx->Array.NewState |= _NEW_ARRAY_ATTRIB(index); +} + + +void GLAPIENTRY +_mesa_DisableVertexAttribArrayARB(GLuint index) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= ctx->Const.VertexProgram.MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glEnableVertexAttribArrayARB(index)"); + return; + } + + ASSERT(index < Elements(ctx->Array.ArrayObj->VertexAttrib)); + + FLUSH_VERTICES(ctx, _NEW_ARRAY); + ctx->Array.ArrayObj->VertexAttrib[index].Enabled = GL_FALSE; + ctx->Array.ArrayObj->_Enabled &= ~_NEW_ARRAY_ATTRIB(index); + ctx->Array.NewState |= _NEW_ARRAY_ATTRIB(index); +} + + +void GLAPIENTRY +_mesa_GetVertexAttribdvARB(GLuint index, GLenum pname, GLdouble *params) +{ + GLfloat fparams[4]; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + _mesa_GetVertexAttribfvARB(index, pname, fparams); + if (ctx->ErrorValue == GL_NO_ERROR) { + if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) { + COPY_4V(params, fparams); + } + else { + params[0] = fparams[0]; + } + } +} + + +/** + * Return info for a generic vertex attribute array (no alias with + * legacy vertex attributes (pos, normal, color, etc)). + */ +void GLAPIENTRY +_mesa_GetVertexAttribfvARB(GLuint index, GLenum pname, GLfloat *params) +{ + const struct gl_client_array *array; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= MAX_VERTEX_GENERIC_ATTRIBS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribfvARB(index)"); + return; + } + + ASSERT(index < Elements(ctx->Array.ArrayObj->VertexAttrib)); + + array = &ctx->Array.ArrayObj->VertexAttrib[index]; + + switch (pname) { + case GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB: + params[0] = (GLfloat) array->Enabled; + break; + case GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB: + params[0] = (GLfloat) array->Size; + break; + case GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB: + params[0] = (GLfloat) array->Stride; + break; + case GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB: + params[0] = (GLfloat) array->Type; + break; + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB: + params[0] = array->Normalized; + break; + case GL_CURRENT_VERTEX_ATTRIB_ARB: + if (index == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetVertexAttribfvARB(index==0)"); + return; + } + FLUSH_CURRENT(ctx, 0); + COPY_4V(params, ctx->Current.Attrib[VERT_ATTRIB_GENERIC0 + index]); + break; + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB: + params[0] = (GLfloat) array->BufferObj->Name; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribfvARB(pname)"); + return; + } +} + + +void GLAPIENTRY +_mesa_GetVertexAttribivARB(GLuint index, GLenum pname, GLint *params) +{ + GLfloat fparams[4]; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + _mesa_GetVertexAttribfvARB(index, pname, fparams); + if (ctx->ErrorValue == GL_NO_ERROR) { + if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) { + COPY_4V_CAST(params, fparams, GLint); /* float to int */ + } + else { + params[0] = (GLint) fparams[0]; + } + } +} + + +void GLAPIENTRY +_mesa_GetVertexAttribPointervARB(GLuint index, GLenum pname, GLvoid **pointer) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= ctx->Const.VertexProgram.MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerARB(index)"); + return; + } + + if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerARB(pname)"); + return; + } + + ASSERT(index < Elements(ctx->Array.ArrayObj->VertexAttrib)); + + *pointer = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[index].Ptr; +} + + +/** + * Determine if id names a vertex or fragment program. + * \note Not compiled into display lists. + * \note Called from both glIsProgramNV and glIsProgramARB. + * \param id is the program identifier + * \return GL_TRUE if id is a program, else GL_FALSE. + */ +GLboolean GLAPIENTRY +_mesa_IsProgramARB(GLuint id) +{ + struct gl_program *prog = NULL; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + + if (id == 0) + return GL_FALSE; + + prog = _mesa_lookup_program(ctx, id); + if (prog && (prog != &_mesa_DummyProgram)) + return GL_TRUE; + else + return GL_FALSE; +} + + +void GLAPIENTRY +_mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len, + const GLvoid *string) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + if (format != GL_PROGRAM_FORMAT_ASCII_ARB) { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(format)"); + return; + } + + if (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program) { + struct gl_vertex_program *prog = ctx->VertexProgram.Current; + _mesa_parse_arb_vertex_program(ctx, target, string, len, prog); + + if (ctx->Program.ErrorPos == -1 && ctx->Driver.ProgramStringNotify) + ctx->Driver.ProgramStringNotify( ctx, target, &prog->Base ); + } + else if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + struct gl_fragment_program *prog = ctx->FragmentProgram.Current; + _mesa_parse_arb_fragment_program(ctx, target, string, len, prog); + + if (ctx->Program.ErrorPos == -1 && ctx->Driver.ProgramStringNotify) + ctx->Driver.ProgramStringNotify( ctx, target, &prog->Base ); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(target)"); + return; + } +} + + +/** + * Set a program env parameter register. + * \note Called from the GL API dispatcher. + * Note, this function is also used by the GL_NV_vertex_program extension + * (alias to ProgramParameterdNV) + */ +void GLAPIENTRY +_mesa_ProgramEnvParameter4dARB(GLenum target, GLuint index, + GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) x, (GLfloat) y, + (GLfloat) z, (GLfloat) w); +} + + +/** + * Set a program env parameter register. + * \note Called from the GL API dispatcher. + * Note, this function is also used by the GL_NV_vertex_program extension + * (alias to ProgramParameterdvNV) + */ +void GLAPIENTRY +_mesa_ProgramEnvParameter4dvARB(GLenum target, GLuint index, + const GLdouble *params) +{ + _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) params[0], + (GLfloat) params[1], (GLfloat) params[2], + (GLfloat) params[3]); +} + + +/** + * Set a program env parameter register. + * \note Called from the GL API dispatcher. + * Note, this function is also used by the GL_NV_vertex_program extension + * (alias to ProgramParameterfNV) + */ +void GLAPIENTRY +_mesa_ProgramEnvParameter4fARB(GLenum target, GLuint index, + GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + if (index >= ctx->Const.FragmentProgram.MaxEnvParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter(index)"); + return; + } + ASSIGN_4V(ctx->FragmentProgram.Parameters[index], x, y, z, w); + } + else if (target == GL_VERTEX_PROGRAM_ARB /* == GL_VERTEX_PROGRAM_NV */ + && (ctx->Extensions.ARB_vertex_program || ctx->Extensions.NV_vertex_program)) { + if (index >= ctx->Const.VertexProgram.MaxEnvParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter(index)"); + return; + } + ASSIGN_4V(ctx->VertexProgram.Parameters[index], x, y, z, w); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameter(target)"); + return; + } +} + +/** + * Set a program env parameter register. + * \note Called from the GL API dispatcher. + * Note, this function is also used by the GL_NV_vertex_program extension + * (alias to ProgramParameterfvNV) + */ +void GLAPIENTRY +_mesa_ProgramEnvParameter4fvARB(GLenum target, GLuint index, + const GLfloat *params) +{ + _mesa_ProgramEnvParameter4fARB(target, index, params[0], params[1], + params[2], params[3]); +} + + +void GLAPIENTRY +_mesa_ProgramEnvParameters4fvEXT(GLenum target, GLuint index, GLsizei count, + const GLfloat *params) +{ + GET_CURRENT_CONTEXT(ctx); + GLint i; + GLfloat * dest; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + if (count <= 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(count)"); + } + + if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + if ((index + count) > ctx->Const.FragmentProgram.MaxEnvParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)"); + return; + } + dest = ctx->FragmentProgram.Parameters[index]; + } + else if (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program) { + if ((index + count) > ctx->Const.VertexProgram.MaxEnvParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)"); + return; + } + dest = ctx->VertexProgram.Parameters[index]; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameters4fv(target)"); + return; + } + + for ( i = 0 ; i < count ; i++ ) { + COPY_4V(dest, params); + params += 4; + dest += 4; + } +} + + +void GLAPIENTRY +_mesa_GetProgramEnvParameterdvARB(GLenum target, GLuint index, + GLdouble *params) +{ + GET_CURRENT_CONTEXT(ctx); + GLfloat fparams[4]; + + _mesa_GetProgramEnvParameterfvARB(target, index, fparams); + if (ctx->ErrorValue == GL_NO_ERROR) { + params[0] = fparams[0]; + params[1] = fparams[1]; + params[2] = fparams[2]; + params[3] = fparams[3]; + } +} + + +void GLAPIENTRY +_mesa_GetProgramEnvParameterfvARB(GLenum target, GLuint index, + GLfloat *params) +{ + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + if (index >= ctx->Const.FragmentProgram.MaxEnvParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramEnvParameter(index)"); + return; + } + COPY_4V(params, ctx->FragmentProgram.Parameters[index]); + } + else if (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program) { + if (index >= ctx->Const.VertexProgram.MaxEnvParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramEnvParameter(index)"); + return; + } + COPY_4V(params, ctx->VertexProgram.Parameters[index]); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramEnvParameter(target)"); + return; + } +} + + +/** + * Note, this function is also used by the GL_NV_fragment_program extension. + */ +void GLAPIENTRY +_mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index, + GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_program *prog; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + if ((target == GL_FRAGMENT_PROGRAM_NV + && ctx->Extensions.NV_fragment_program) || + (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program)) { + if (index >= ctx->Const.FragmentProgram.MaxLocalParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB"); + return; + } + prog = &(ctx->FragmentProgram.Current->Base); + } + else if (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program) { + if (index >= ctx->Const.VertexProgram.MaxLocalParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB"); + return; + } + prog = &(ctx->VertexProgram.Current->Base); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameterARB"); + return; + } + + ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS); + prog->LocalParams[index][0] = x; + prog->LocalParams[index][1] = y; + prog->LocalParams[index][2] = z; + prog->LocalParams[index][3] = w; +} + + +/** + * Note, this function is also used by the GL_NV_fragment_program extension. + */ +void GLAPIENTRY +_mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index, + const GLfloat *params) +{ + _mesa_ProgramLocalParameter4fARB(target, index, params[0], params[1], + params[2], params[3]); +} + + +void GLAPIENTRY +_mesa_ProgramLocalParameters4fvEXT(GLenum target, GLuint index, GLsizei count, + const GLfloat *params) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_program *prog; + GLint i; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + if (count <= 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fv(count)"); + } + + if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + if ((index + count) > ctx->Const.FragmentProgram.MaxLocalParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fvEXT(index + count)"); + return; + } + prog = &(ctx->FragmentProgram.Current->Base); + } + else if (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program) { + if ((index + count) > ctx->Const.VertexProgram.MaxLocalParams) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fvEXT(index + count)"); + return; + } + prog = &(ctx->VertexProgram.Current->Base); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameters4fvEXT(target)"); + return; + } + + for (i = 0; i < count; i++) { + ASSERT((index + i) < MAX_PROGRAM_LOCAL_PARAMS); + COPY_4V(prog->LocalParams[index + i], params); + params += 4; + } +} + + +/** + * Note, this function is also used by the GL_NV_fragment_program extension. + */ +void GLAPIENTRY +_mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index, + GLdouble x, GLdouble y, + GLdouble z, GLdouble w) +{ + _mesa_ProgramLocalParameter4fARB(target, index, (GLfloat) x, (GLfloat) y, + (GLfloat) z, (GLfloat) w); +} + + +/** + * Note, this function is also used by the GL_NV_fragment_program extension. + */ +void GLAPIENTRY +_mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index, + const GLdouble *params) +{ + _mesa_ProgramLocalParameter4fARB(target, index, + (GLfloat) params[0], (GLfloat) params[1], + (GLfloat) params[2], (GLfloat) params[3]); +} + + +/** + * Note, this function is also used by the GL_NV_fragment_program extension. + */ +void GLAPIENTRY +_mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index, + GLfloat *params) +{ + const struct gl_program *prog; + GLuint maxParams; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program) { + prog = &(ctx->VertexProgram.Current->Base); + maxParams = ctx->Const.VertexProgram.MaxLocalParams; + } + else if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + prog = &(ctx->FragmentProgram.Current->Base); + maxParams = ctx->Const.FragmentProgram.MaxLocalParams; + } + else if (target == GL_FRAGMENT_PROGRAM_NV + && ctx->Extensions.NV_fragment_program) { + prog = &(ctx->FragmentProgram.Current->Base); + maxParams = MAX_NV_FRAGMENT_PROGRAM_PARAMS; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetProgramLocalParameterARB(target)"); + return; + } + + if (index >= maxParams) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetProgramLocalParameterARB(index)"); + return; + } + + ASSERT(prog); + ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS); + COPY_4V(params, prog->LocalParams[index]); +} + + +/** + * Note, this function is also used by the GL_NV_fragment_program extension. + */ +void GLAPIENTRY +_mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index, + GLdouble *params) +{ + GET_CURRENT_CONTEXT(ctx); + GLfloat floatParams[4]; + ASSIGN_4V(floatParams, 0.0F, 0.0F, 0.0F, 0.0F); + _mesa_GetProgramLocalParameterfvARB(target, index, floatParams); + if (ctx->ErrorValue == GL_NO_ERROR) { + COPY_4V(params, floatParams); + } +} + + +void GLAPIENTRY +_mesa_GetProgramivARB(GLenum target, GLenum pname, GLint *params) +{ + const struct gl_program_constants *limits; + struct gl_program *prog; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_ARB + && ctx->Extensions.ARB_vertex_program) { + prog = &(ctx->VertexProgram.Current->Base); + limits = &ctx->Const.VertexProgram; + } + else if (target == GL_FRAGMENT_PROGRAM_ARB + && ctx->Extensions.ARB_fragment_program) { + prog = &(ctx->FragmentProgram.Current->Base); + limits = &ctx->Const.FragmentProgram; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)"); + return; + } + + ASSERT(prog); + ASSERT(limits); + + /* Queries supported for both vertex and fragment programs */ + switch (pname) { + case GL_PROGRAM_LENGTH_ARB: + *params + = prog->String ? (GLint) _mesa_strlen((char *) prog->String) : 0; + return; + case GL_PROGRAM_FORMAT_ARB: + *params = prog->Format; + return; + case GL_PROGRAM_BINDING_ARB: + *params = prog->Id; + return; + case GL_PROGRAM_INSTRUCTIONS_ARB: + *params = prog->NumInstructions; + return; + case GL_MAX_PROGRAM_INSTRUCTIONS_ARB: + *params = limits->MaxInstructions; + return; + case GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB: + *params = prog->NumNativeInstructions; + return; + case GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB: + *params = limits->MaxNativeInstructions; + return; + case GL_PROGRAM_TEMPORARIES_ARB: + *params = prog->NumTemporaries; + return; + case GL_MAX_PROGRAM_TEMPORARIES_ARB: + *params = limits->MaxTemps; + return; + case GL_PROGRAM_NATIVE_TEMPORARIES_ARB: + *params = prog->NumNativeTemporaries; + return; + case GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB: + *params = limits->MaxNativeTemps; + return; + case GL_PROGRAM_PARAMETERS_ARB: + *params = prog->NumParameters; + return; + case GL_MAX_PROGRAM_PARAMETERS_ARB: + *params = limits->MaxParameters; + return; + case GL_PROGRAM_NATIVE_PARAMETERS_ARB: + *params = prog->NumNativeParameters; + return; + case GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB: + *params = limits->MaxNativeParameters; + return; + case GL_PROGRAM_ATTRIBS_ARB: + *params = prog->NumAttributes; + return; + case GL_MAX_PROGRAM_ATTRIBS_ARB: + *params = limits->MaxAttribs; + return; + case GL_PROGRAM_NATIVE_ATTRIBS_ARB: + *params = prog->NumNativeAttributes; + return; + case GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB: + *params = limits->MaxNativeAttribs; + return; + case GL_PROGRAM_ADDRESS_REGISTERS_ARB: + *params = prog->NumAddressRegs; + return; + case GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB: + *params = limits->MaxAddressRegs; + return; + case GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB: + *params = prog->NumNativeAddressRegs; + return; + case GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB: + *params = limits->MaxNativeAddressRegs; + return; + case GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB: + *params = limits->MaxLocalParams; + return; + case GL_MAX_PROGRAM_ENV_PARAMETERS_ARB: + *params = limits->MaxEnvParams; + return; + case GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB: + /* + * XXX we may not really need a driver callback here. + * If the number of native instructions, registers, etc. used + * are all below the maximums, we could return true. + * The spec says that even if this query returns true, there's + * no guarantee that the program will run in hardware. + */ + if (prog->Id == 0) { + /* default/null program */ + *params = GL_FALSE; + } + else if (ctx->Driver.IsProgramNative) { + /* ask the driver */ + *params = ctx->Driver.IsProgramNative( ctx, target, prog ); + } + else { + /* probably running in software */ + *params = GL_TRUE; + } + return; + default: + /* continue with fragment-program only queries below */ + break; + } + + /* + * The following apply to fragment programs only (at this time) + */ + if (target == GL_FRAGMENT_PROGRAM_ARB) { + const struct gl_fragment_program *fp = ctx->FragmentProgram.Current; + switch (pname) { + case GL_PROGRAM_ALU_INSTRUCTIONS_ARB: + *params = fp->Base.NumNativeAluInstructions; + return; + case GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB: + *params = fp->Base.NumAluInstructions; + return; + case GL_PROGRAM_TEX_INSTRUCTIONS_ARB: + *params = fp->Base.NumTexInstructions; + return; + case GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB: + *params = fp->Base.NumNativeTexInstructions; + return; + case GL_PROGRAM_TEX_INDIRECTIONS_ARB: + *params = fp->Base.NumTexIndirections; + return; + case GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB: + *params = fp->Base.NumNativeTexIndirections; + return; + case GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB: + *params = limits->MaxAluInstructions; + return; + case GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB: + *params = limits->MaxNativeAluInstructions; + return; + case GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB: + *params = limits->MaxTexInstructions; + return; + case GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB: + *params = limits->MaxNativeTexInstructions; + return; + case GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB: + *params = limits->MaxTexIndirections; + return; + case GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB: + *params = limits->MaxNativeTexIndirections; + return; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)"); + return; + } + } else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)"); + return; + } +} + + +void GLAPIENTRY +_mesa_GetProgramStringARB(GLenum target, GLenum pname, GLvoid *string) +{ + const struct gl_program *prog; + char *dst = (char *) string; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_ARB) { + prog = &(ctx->VertexProgram.Current->Base); + } + else if (target == GL_FRAGMENT_PROGRAM_ARB) { + prog = &(ctx->FragmentProgram.Current->Base); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(target)"); + return; + } + + ASSERT(prog); + + if (pname != GL_PROGRAM_STRING_ARB) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(pname)"); + return; + } + + if (prog->String) + _mesa_memcpy(dst, prog->String, _mesa_strlen((char *) prog->String)); + else + *dst = '\0'; +} diff --git a/mesalib/src/mesa/shader/arbprogram.h b/mesalib/src/mesa/shader/arbprogram.h new file mode 100644 index 000000000..6fe76267b --- /dev/null +++ b/mesalib/src/mesa/shader/arbprogram.h @@ -0,0 +1,152 @@ +/* + * 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. + */ + + +#ifndef ARBPROGRAM_H +#define ARBPROGRAM_H + + +extern void GLAPIENTRY +_mesa_BindProgram(GLenum target, GLuint id); + +extern void GLAPIENTRY +_mesa_DeletePrograms(GLsizei n, const GLuint *ids); + +extern void GLAPIENTRY +_mesa_GenPrograms(GLsizei n, GLuint *ids); + + +extern void GLAPIENTRY +_mesa_EnableVertexAttribArrayARB(GLuint index); + + +extern void GLAPIENTRY +_mesa_DisableVertexAttribArrayARB(GLuint index); + + +extern void GLAPIENTRY +_mesa_GetVertexAttribdvARB(GLuint index, GLenum pname, GLdouble *params); + + +extern void GLAPIENTRY +_mesa_GetVertexAttribfvARB(GLuint index, GLenum pname, GLfloat *params); + + +extern void GLAPIENTRY +_mesa_GetVertexAttribivARB(GLuint index, GLenum pname, GLint *params); + + +extern void GLAPIENTRY +_mesa_GetVertexAttribPointervARB(GLuint index, GLenum pname, GLvoid **pointer); + + +extern GLboolean GLAPIENTRY +_mesa_IsProgramARB(GLuint id); + + +extern void GLAPIENTRY +_mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len, + const GLvoid *string); + + +extern void GLAPIENTRY +_mesa_ProgramEnvParameter4dARB(GLenum target, GLuint index, + GLdouble x, GLdouble y, GLdouble z, GLdouble w); + + +extern void GLAPIENTRY +_mesa_ProgramEnvParameter4dvARB(GLenum target, GLuint index, + const GLdouble *params); + + +extern void GLAPIENTRY +_mesa_ProgramEnvParameter4fARB(GLenum target, GLuint index, + GLfloat x, GLfloat y, GLfloat z, GLfloat w); + + +extern void GLAPIENTRY +_mesa_ProgramEnvParameter4fvARB(GLenum target, GLuint index, + const GLfloat *params); + + +extern void GLAPIENTRY +_mesa_ProgramEnvParameters4fvEXT(GLenum target, GLuint index, GLsizei count, + const GLfloat *params); + + +extern void GLAPIENTRY +_mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index, + GLdouble x, GLdouble y, + GLdouble z, GLdouble w); + + +extern void GLAPIENTRY +_mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index, + const GLdouble *params); + + +extern void GLAPIENTRY +_mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index, + GLfloat x, GLfloat y, GLfloat z, GLfloat w); + + +extern void GLAPIENTRY +_mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index, + const GLfloat *params); + + +extern void GLAPIENTRY +_mesa_ProgramLocalParameters4fvEXT(GLenum target, GLuint index, GLsizei count, + const GLfloat *params); + + +extern void GLAPIENTRY +_mesa_GetProgramEnvParameterdvARB(GLenum target, GLuint index, + GLdouble *params); + + +extern void GLAPIENTRY +_mesa_GetProgramEnvParameterfvARB(GLenum target, GLuint index, + GLfloat *params); + + +extern void GLAPIENTRY +_mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index, + GLdouble *params); + + +extern void GLAPIENTRY +_mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index, + GLfloat *params); + + +extern void GLAPIENTRY +_mesa_GetProgramivARB(GLenum target, GLenum pname, GLint *params); + + +extern void GLAPIENTRY +_mesa_GetProgramStringARB(GLenum target, GLenum pname, GLvoid *string); + + +#endif diff --git a/mesalib/src/mesa/shader/atifragshader.c b/mesalib/src/mesa/shader/atifragshader.c new file mode 100644 index 000000000..ac087d415 --- /dev/null +++ b/mesalib/src/mesa/shader/atifragshader.c @@ -0,0 +1,759 @@ +/** + * \file atifragshader.c + * \author David Airlie + * Copyright (C) 2004 David Airlie All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * DAVID AIRLIE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "main/glheader.h" +#include "main/context.h" +#include "main/hash.h" +#include "main/imports.h" +#include "main/macros.h" +#include "main/enums.h" +#include "main/mtypes.h" +#include "atifragshader.h" + +#define MESA_DEBUG_ATI_FS 0 + +static struct ati_fragment_shader DummyShader; + + +/** + * Allocate and initialize a new ATI fragment shader object. + */ +struct ati_fragment_shader * +_mesa_new_ati_fragment_shader(GLcontext *ctx, GLuint id) +{ + struct ati_fragment_shader *s = CALLOC_STRUCT(ati_fragment_shader); + (void) ctx; + if (s) { + s->Id = id; + s->RefCount = 1; + } + return s; +} + + +/** + * Delete the given ati fragment shader + */ +void +_mesa_delete_ati_fragment_shader(GLcontext *ctx, struct ati_fragment_shader *s) +{ + GLuint i; + for (i = 0; i < MAX_NUM_PASSES_ATI; i++) { + if (s->Instructions[i]) + _mesa_free(s->Instructions[i]); + if (s->SetupInst[i]) + _mesa_free(s->SetupInst[i]); + } + _mesa_free(s); +} + + + +static void +new_arith_inst(struct ati_fragment_shader *prog) +{ +/* set "default" instruction as not all may get defined. + there is no specified way to express a nop with ati fragment shaders we use + GL_NONE as the op enum and just set some params to 0 - so nothing to do here */ + prog->numArithInstr[prog->cur_pass >> 1]++; +} + +static void +new_tex_inst(struct ati_fragment_shader *prog) +{ +} + +static void match_pair_inst(struct ati_fragment_shader *curProg, GLuint optype) +{ + if (optype == curProg->last_optype) { + curProg->last_optype = 1; + } +} + +#if MESA_DEBUG_ATI_FS +static char * +create_dst_mod_str(GLuint mod) +{ + static char ret_str[1024]; + + _mesa_memset(ret_str, 0, 1024); + if (mod & GL_2X_BIT_ATI) + _mesa_strncat(ret_str, "|2X", 1024); + + if (mod & GL_4X_BIT_ATI) + _mesa_strncat(ret_str, "|4X", 1024); + + if (mod & GL_8X_BIT_ATI) + _mesa_strncat(ret_str, "|8X", 1024); + if (mod & GL_HALF_BIT_ATI) + _mesa_strncat(ret_str, "|HA", 1024); + if (mod & GL_QUARTER_BIT_ATI) + _mesa_strncat(ret_str, "|QU", 1024); + if (mod & GL_EIGHTH_BIT_ATI) + _mesa_strncat(ret_str, "|EI", 1024); + + if (mod & GL_SATURATE_BIT_ATI) + _mesa_strncat(ret_str, "|SAT", 1024); + + if (_mesa_strlen(ret_str) == 0) + _mesa_strncat(ret_str, "NONE", 1024); + return ret_str; +} + +static char *atifs_ops[] = {"ColorFragmentOp1ATI", "ColorFragmentOp2ATI", "ColorFragmentOp3ATI", + "AlphaFragmentOp1ATI", "AlphaFragmentOp2ATI", "AlphaFragmentOp3ATI" }; + +static void debug_op(GLint optype, GLuint arg_count, GLenum op, GLuint dst, + GLuint dstMask, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, + GLuint arg3Rep, GLuint arg3Mod) +{ + char *op_name; + + op_name = atifs_ops[(arg_count-1)+(optype?3:0)]; + + fprintf(stderr, "%s(%s, %s", op_name, _mesa_lookup_enum_by_nr(op), + _mesa_lookup_enum_by_nr(dst)); + if (!optype) + fprintf(stderr, ", %d", dstMask); + + fprintf(stderr, ", %s", create_dst_mod_str(dstMod)); + + fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg1), + _mesa_lookup_enum_by_nr(arg1Rep), arg1Mod); + if (arg_count>1) + fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg2), + _mesa_lookup_enum_by_nr(arg2Rep), arg2Mod); + if (arg_count>2) + fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg3), + _mesa_lookup_enum_by_nr(arg3Rep), arg3Mod); + + fprintf(stderr,")\n"); + +} +#endif + +static int check_arith_arg(struct ati_fragment_shader *curProg, + GLuint optype, GLuint arg, GLuint argRep) +{ + GET_CURRENT_CONTEXT(ctx); + + if (((arg < GL_CON_0_ATI) || (arg > GL_CON_7_ATI)) && + ((arg < GL_REG_0_ATI) || (arg > GL_REG_5_ATI)) && + (arg != GL_ZERO) && (arg != GL_ONE) && + (arg != GL_PRIMARY_COLOR_ARB) && (arg != GL_SECONDARY_INTERPOLATOR_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(arg)"); + return 0; + } + if ((arg == GL_SECONDARY_INTERPOLATOR_ATI) && (((optype == 0) && (argRep == GL_ALPHA)) || + ((optype == 1) && ((arg == GL_ALPHA) || (argRep == GL_NONE))))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)"); + return 0; + } + if ((arg == GL_SECONDARY_INTERPOLATOR_ATI) && (((optype == 0) && (argRep == GL_ALPHA)) || + ((optype == 1) && ((arg == GL_ALPHA) || (argRep == GL_NONE))))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)"); + return 0; + } + if ((curProg->cur_pass == 1) && + ((arg == GL_PRIMARY_COLOR_ARB) || (arg == GL_SECONDARY_INTERPOLATOR_ATI))) { + curProg->interpinp1 = GL_TRUE; + } + return 1; +} + +GLuint GLAPIENTRY +_mesa_GenFragmentShadersATI(GLuint range) +{ + GLuint first; + GLuint i; + GET_CURRENT_CONTEXT(ctx); + + if (range == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGenFragmentShadersATI(range)"); + return 0; + } + + if (ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGenFragmentShadersATI(insideShader)"); + return 0; + } + + first = _mesa_HashFindFreeKeyBlock(ctx->Shared->ATIShaders, range); + for (i = 0; i < range; i++) { + _mesa_HashInsert(ctx->Shared->ATIShaders, first + i, &DummyShader); + } + + return first; +} + +void GLAPIENTRY +_mesa_BindFragmentShaderATI(GLuint id) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + struct ati_fragment_shader *newProg; + + if (ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragmentShaderATI(insideShader)"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + if (curProg->Id == id) { + return; + } + + /* unbind current */ + if (curProg->Id != 0) { + curProg->RefCount--; + if (curProg->RefCount <= 0) { + _mesa_HashRemove(ctx->Shared->ATIShaders, id); + } + } + + /* find new shader */ + if (id == 0) { + newProg = ctx->Shared->DefaultFragmentShader; + } + else { + newProg = (struct ati_fragment_shader *) + _mesa_HashLookup(ctx->Shared->ATIShaders, id); + if (!newProg || newProg == &DummyShader) { + /* allocate a new program now */ + newProg = _mesa_new_ati_fragment_shader(ctx, id); + if (!newProg) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFragmentShaderATI"); + return; + } + _mesa_HashInsert(ctx->Shared->ATIShaders, id, newProg); + } + + } + + /* do actual bind */ + ctx->ATIFragmentShader.Current = newProg; + + ASSERT(ctx->ATIFragmentShader.Current); + if (newProg) + newProg->RefCount++; + + /*if (ctx->Driver.BindProgram) + ctx->Driver.BindProgram(ctx, target, prog); */ +} + +void GLAPIENTRY +_mesa_DeleteFragmentShaderATI(GLuint id) +{ + GET_CURRENT_CONTEXT(ctx); + + if (ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteFragmentShaderATI(insideShader)"); + return; + } + + if (id != 0) { + struct ati_fragment_shader *prog = (struct ati_fragment_shader *) + _mesa_HashLookup(ctx->Shared->ATIShaders, id); + if (prog == &DummyShader) { + _mesa_HashRemove(ctx->Shared->ATIShaders, id); + } + else if (prog) { + if (ctx->ATIFragmentShader.Current && + ctx->ATIFragmentShader.Current->Id == id) { + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + _mesa_BindFragmentShaderATI(0); + } + } + + /* The ID is immediately available for re-use now */ + _mesa_HashRemove(ctx->Shared->ATIShaders, id); + prog->RefCount--; + if (prog->RefCount <= 0) { + _mesa_free(prog); + } + } +} + + +void GLAPIENTRY +_mesa_BeginFragmentShaderATI(void) +{ + GLint i; + GET_CURRENT_CONTEXT(ctx); + + if (ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginFragmentShaderATI(insideShader)"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + /* if the shader was already defined free instructions and get new ones + (or, could use the same mem but would need to reinitialize) */ + /* no idea if it's allowed to redefine a shader */ + for (i = 0; i < MAX_NUM_PASSES_ATI; i++) { + if (ctx->ATIFragmentShader.Current->Instructions[i]) + _mesa_free(ctx->ATIFragmentShader.Current->Instructions[i]); + if (ctx->ATIFragmentShader.Current->SetupInst[i]) + _mesa_free(ctx->ATIFragmentShader.Current->SetupInst[i]); + } + + /* malloc the instructions here - not sure if the best place but its + a start */ + for (i = 0; i < MAX_NUM_PASSES_ATI; i++) { + ctx->ATIFragmentShader.Current->Instructions[i] = + (struct atifs_instruction *) + _mesa_calloc(sizeof(struct atifs_instruction) * + (MAX_NUM_INSTRUCTIONS_PER_PASS_ATI)); + ctx->ATIFragmentShader.Current->SetupInst[i] = + (struct atifs_setupinst *) + _mesa_calloc(sizeof(struct atifs_setupinst) * + (MAX_NUM_FRAGMENT_REGISTERS_ATI)); + } + +/* can't rely on calloc for initialization as it's possible to redefine a shader (?) */ + ctx->ATIFragmentShader.Current->LocalConstDef = 0; + ctx->ATIFragmentShader.Current->numArithInstr[0] = 0; + ctx->ATIFragmentShader.Current->numArithInstr[1] = 0; + ctx->ATIFragmentShader.Current->regsAssigned[0] = 0; + ctx->ATIFragmentShader.Current->regsAssigned[1] = 0; + ctx->ATIFragmentShader.Current->NumPasses = 0; + ctx->ATIFragmentShader.Current->cur_pass = 0; + ctx->ATIFragmentShader.Current->last_optype = 0; + ctx->ATIFragmentShader.Current->interpinp1 = GL_FALSE; + ctx->ATIFragmentShader.Current->isValid = GL_FALSE; + ctx->ATIFragmentShader.Current->swizzlerq = 0; + ctx->ATIFragmentShader.Compiling = 1; +} + +void GLAPIENTRY +_mesa_EndFragmentShaderATI(void) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; +#if MESA_DEBUG_ATI_FS + GLint i, j; +#endif + + if (!ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(outsideShader)"); + return; + } + if (curProg->interpinp1 && (ctx->ATIFragmentShader.Current->cur_pass > 1)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(interpinfirstpass)"); + /* according to spec, DON'T return here */ + } + + match_pair_inst(curProg, 0); + ctx->ATIFragmentShader.Compiling = 0; + ctx->ATIFragmentShader.Current->isValid = GL_TRUE; + if ((ctx->ATIFragmentShader.Current->cur_pass == 0) || + (ctx->ATIFragmentShader.Current->cur_pass == 2)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(noarithinst)"); + } + if (ctx->ATIFragmentShader.Current->cur_pass > 1) + ctx->ATIFragmentShader.Current->NumPasses = 2; + else ctx->ATIFragmentShader.Current->NumPasses = 1; + ctx->ATIFragmentShader.Current->cur_pass=0; +#if MESA_DEBUG_ATI_FS + for (j = 0; j < MAX_NUM_PASSES_ATI; j++) { + for (i = 0; i < MAX_NUM_FRAGMENT_REGISTERS_ATI; i++) { + GLuint op = curProg->SetupInst[j][i].Opcode; + const char *op_enum = op > 5 ? _mesa_lookup_enum_by_nr(op) : "0"; + GLuint src = curProg->SetupInst[j][i].src; + GLuint swizzle = curProg->SetupInst[j][i].swizzle; + fprintf(stderr, "%2d %04X %s %d %04X\n", i, op, op_enum, src, + swizzle); + } + for (i = 0; i < curProg->numArithInstr[j]; i++) { + GLuint op0 = curProg->Instructions[j][i].Opcode[0]; + GLuint op1 = curProg->Instructions[j][i].Opcode[1]; + const char *op0_enum = op0 > 5 ? _mesa_lookup_enum_by_nr(op0) : "0"; + const char *op1_enum = op1 > 5 ? _mesa_lookup_enum_by_nr(op1) : "0"; + GLuint count0 = curProg->Instructions[j][i].ArgCount[0]; + GLuint count1 = curProg->Instructions[j][i].ArgCount[1]; + fprintf(stderr, "%2d %04X %s %d %04X %s %d\n", i, op0, op0_enum, count0, + op1, op1_enum, count1); + } + } +#endif + if (ctx->Driver.ProgramStringNotify) + ctx->Driver.ProgramStringNotify( ctx, GL_FRAGMENT_SHADER_ATI, NULL ); +} + +void GLAPIENTRY +_mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + struct atifs_setupinst *curI; + + if (!ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(outsideShader)"); + return; + } + + if (curProg->cur_pass == 1) { + match_pair_inst(curProg, 0); + curProg->cur_pass = 2; + } + if ((curProg->cur_pass > 2) || + ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoord(pass)"); + return; + } + if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI) || + ((dst - GL_REG_0_ATI) >= ctx->Const.MaxTextureUnits)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(dst)"); + return; + } + if (((coord < GL_REG_0_ATI) || (coord > GL_REG_5_ATI)) && + ((coord < GL_TEXTURE0_ARB) || (coord > GL_TEXTURE7_ARB) || + ((coord - GL_TEXTURE0_ARB) >= ctx->Const.MaxTextureUnits))) { + _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(coord)"); + return; + } + if ((curProg->cur_pass == 0) && (coord >= GL_REG_0_ATI)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(coord)"); + return; + } + if (!(swizzle >= GL_SWIZZLE_STR_ATI) && (swizzle <= GL_SWIZZLE_STQ_DQ_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(swizzle)"); + return; + } + if ((swizzle & 1) && (coord >= GL_REG_0_ATI)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(swizzle)"); + return; + } + if (coord <= GL_TEXTURE7_ARB) { + GLuint tmp = coord - GL_TEXTURE0_ARB; + if ((((curProg->swizzlerq >> (tmp * 2)) & 3) != 0) && + (((swizzle & 1) + 1) != ((curProg->swizzlerq >> (tmp * 2)) & 3))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(swizzle)"); + return; + } else { + curProg->swizzlerq |= (((swizzle & 1) + 1) << (tmp * 2)); + } + } + + curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI); + new_tex_inst(curProg); + + /* add the instructions */ + curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI]; + + curI->Opcode = ATI_FRAGMENT_SHADER_PASS_OP; + curI->src = coord; + curI->swizzle = swizzle; + +#if MESA_DEBUG_ATI_FS + _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(coord), + _mesa_lookup_enum_by_nr(swizzle)); +#endif +} + +void GLAPIENTRY +_mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + struct atifs_setupinst *curI; + + if (!ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(outsideShader)"); + return; + } + + if (curProg->cur_pass == 1) { + match_pair_inst(curProg, 0); + curProg->cur_pass = 2; + } + if ((curProg->cur_pass > 2) || + ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(pass)"); + return; + } + if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI) || + ((dst - GL_REG_0_ATI) >= ctx->Const.MaxTextureUnits)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(dst)"); + return; + } + if (((interp < GL_REG_0_ATI) || (interp > GL_REG_5_ATI)) && + ((interp < GL_TEXTURE0_ARB) || (interp > GL_TEXTURE7_ARB) || + ((interp - GL_TEXTURE0_ARB) >= ctx->Const.MaxTextureUnits))) { + /* is this texture5 or texture7? spec is a bit unclear there */ + _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(interp)"); + return; + } + if ((curProg->cur_pass == 0) && (interp >= GL_REG_0_ATI)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(interp)"); + return; + } + if (!(swizzle >= GL_SWIZZLE_STR_ATI) && (swizzle <= GL_SWIZZLE_STQ_DQ_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(swizzle)"); + return; + } + if ((swizzle & 1) && (interp >= GL_REG_0_ATI)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(swizzle)"); + return; + } + if (interp <= GL_TEXTURE7_ARB) { + GLuint tmp = interp - GL_TEXTURE0_ARB; + if ((((curProg->swizzlerq >> (tmp * 2)) & 3) != 0) && + (((swizzle & 1) + 1) != ((curProg->swizzlerq >> (tmp * 2)) & 3))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(swizzle)"); + return; + } else { + curProg->swizzlerq |= (((swizzle & 1) + 1) << (tmp * 2)); + } + } + + curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI); + new_tex_inst(curProg); + + /* add the instructions */ + curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI]; + + curI->Opcode = ATI_FRAGMENT_SHADER_SAMPLE_OP; + curI->src = interp; + curI->swizzle = swizzle; + +#if MESA_DEBUG_ATI_FS + _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(interp), + _mesa_lookup_enum_by_nr(swizzle)); +#endif +} + +static void +_mesa_FragmentOpXATI(GLint optype, GLuint arg_count, GLenum op, GLuint dst, + GLuint dstMask, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, + GLuint arg3Rep, GLuint arg3Mod) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + GLint ci; + struct atifs_instruction *curI; + GLuint modtemp = dstMod & ~GL_SATURATE_BIT_ATI; + + if (!ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(outsideShader)"); + return; + } + + if (curProg->cur_pass==0) + curProg->cur_pass=1; + + else if (curProg->cur_pass==2) + curProg->cur_pass=3; + + /* decide whether this is a new instruction or not ... all color instructions are new, + and alpha instructions might also be new if there was no preceding color inst */ + if ((optype == 0) || (curProg->last_optype == optype)) { + if (curProg->numArithInstr[curProg->cur_pass >> 1] > 7) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(instrCount)"); + return; + } + /* easier to do that here slight side effect invalid instr will still be inserted as nops */ + match_pair_inst(curProg, optype); + new_arith_inst(curProg); + } + curProg->last_optype = optype; + ci = curProg->numArithInstr[curProg->cur_pass >> 1] - 1; + + /* add the instructions */ + curI = &curProg->Instructions[curProg->cur_pass >> 1][ci]; + + /* error checking */ + if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dst)"); + return; + } + if ((modtemp != GL_NONE) && (modtemp != GL_2X_BIT_ATI) && + (modtemp != GL_4X_BIT_ATI) && (modtemp != GL_8X_BIT_ATI) && + (modtemp != GL_HALF_BIT_ATI) && !(modtemp != GL_QUARTER_BIT_ATI) && + (modtemp != GL_EIGHTH_BIT_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dstMod)%x", modtemp); + return; + } + /* op checking? Actually looks like that's missing in the spec but we'll do it anyway */ + if (((op < GL_ADD_ATI) || (op > GL_DOT2_ADD_ATI)) && !(op == GL_MOV_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(op)"); + return; + } + if (optype == 1) { + if (((op == GL_DOT2_ADD_ATI) && (curI->Opcode[0] != GL_DOT2_ADD_ATI)) || + ((op == GL_DOT3_ATI) && (curI->Opcode[0] != GL_DOT3_ATI)) || + ((op == GL_DOT4_ATI) && (curI->Opcode[0] != GL_DOT4_ATI)) || + ((op != GL_DOT4_ATI) && (curI->Opcode[0] == GL_DOT4_ATI))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "AFragmentOpATI(op)"); + return; + } + } + if ((op == GL_DOT4_ATI) && + (((arg1 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg1Rep == GL_ALPHA) || (arg1Rep == GL_NONE))) || + (((arg2 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg2Rep == GL_ALPHA) || (arg2Rep == GL_NONE)))))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)"); + } + + if (!check_arith_arg(curProg, optype, arg1, arg1Rep)) { + return; + } + if (arg2) { + if (!check_arith_arg(curProg, optype, arg2, arg2Rep)) { + return; + } + } + if (arg3) { + if (!check_arith_arg(curProg, optype, arg3, arg3Rep)) { + return; + } + if ((arg1 >= GL_CON_0_ATI) && (arg1 <= GL_CON_7_ATI) && + (arg2 >= GL_CON_0_ATI) && (arg2 <= GL_CON_7_ATI) && + (arg3 >= GL_CON_0_ATI) && (arg3 <= GL_CON_7_ATI) && + (arg1 != arg2) && (arg1 != arg3) && (arg2 != arg3)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(3Consts)"); + return; + } + } + + /* all ok - not all fully validated though (e.g. argNMod - spec doesn't say anything) */ + + curI->Opcode[optype] = op; + curI->SrcReg[optype][0].Index = arg1; + curI->SrcReg[optype][0].argRep = arg1Rep; + curI->SrcReg[optype][0].argMod = arg1Mod; + curI->ArgCount[optype] = arg_count; + + if (arg2) { + curI->SrcReg[optype][1].Index = arg2; + curI->SrcReg[optype][1].argRep = arg2Rep; + curI->SrcReg[optype][1].argMod = arg2Mod; + } + + if (arg3) { + curI->SrcReg[optype][2].Index = arg3; + curI->SrcReg[optype][2].argRep = arg3Rep; + curI->SrcReg[optype][2].argMod = arg3Mod; + } + + curI->DstReg[optype].Index = dst; + curI->DstReg[optype].dstMod = dstMod; + curI->DstReg[optype].dstMask = dstMask; + +#if MESA_DEBUG_ATI_FS + debug_op(optype, arg_count, op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod); +#endif + +} + +void GLAPIENTRY +_mesa_ColorFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 1, op, dst, dstMask, + dstMod, arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0); +} + +void GLAPIENTRY +_mesa_ColorFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, + GLuint arg2Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 2, op, dst, dstMask, + dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, + arg2Mod, 0, 0, 0); +} + +void GLAPIENTRY +_mesa_ColorFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, + GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, + GLuint arg3Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 3, op, dst, dstMask, + dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, + arg2Mod, arg3, arg3Rep, arg3Mod); +} + +void GLAPIENTRY +_mesa_AlphaFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 1, op, dst, 0, dstMod, + arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0); +} + +void GLAPIENTRY +_mesa_AlphaFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 2, op, dst, 0, dstMod, + arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, 0, 0, + 0); +} + +void GLAPIENTRY +_mesa_AlphaFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, + GLuint arg3Rep, GLuint arg3Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 3, op, dst, 0, dstMod, + arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, + arg3Rep, arg3Mod); +} + +void GLAPIENTRY +_mesa_SetFragmentShaderConstantATI(GLuint dst, const GLfloat * value) +{ + GLuint dstindex; + GET_CURRENT_CONTEXT(ctx); + + if ((dst < GL_CON_0_ATI) || (dst > GL_CON_7_ATI)) { + /* spec says nothing about what should happen here but we can't just segfault...*/ + _mesa_error(ctx, GL_INVALID_ENUM, "glSetFragmentShaderConstantATI(dst)"); + return; + } + + dstindex = dst - GL_CON_0_ATI; + if (ctx->ATIFragmentShader.Compiling) { + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + COPY_4V(curProg->Constants[dstindex], value); + curProg->LocalConstDef |= 1 << dstindex; + } + else { + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + COPY_4V(ctx->ATIFragmentShader.GlobalConstants[dstindex], value); + } +} diff --git a/mesalib/src/mesa/shader/atifragshader.h b/mesalib/src/mesa/shader/atifragshader.h new file mode 100644 index 000000000..e1dc20e60 --- /dev/null +++ b/mesalib/src/mesa/shader/atifragshader.h @@ -0,0 +1,123 @@ +/* + * Mesa 3-D graphics library ATI Fragment Shader + * + * Copyright (C) 2004 David Airlie All Rights Reserved. + * + */ + +#ifndef ATIFRAGSHADER_H +#define ATIFRAGSHADER_H + +#include "main/mtypes.h" + +#define MAX_NUM_INSTRUCTIONS_PER_PASS_ATI 8 +#define MAX_NUM_PASSES_ATI 2 +#define MAX_NUM_FRAGMENT_REGISTERS_ATI 6 + +struct ati_fs_opcode_st +{ + GLenum opcode; + GLint num_src_args; +}; + +extern struct ati_fs_opcode_st ati_fs_opcodes[]; + +struct atifragshader_src_register +{ + GLuint Index; + GLuint argRep; + GLuint argMod; +}; + +struct atifragshader_dst_register +{ + GLuint Index; + GLuint dstMod; + GLuint dstMask; +}; + +#define ATI_FRAGMENT_SHADER_COLOR_OP 0 +#define ATI_FRAGMENT_SHADER_ALPHA_OP 1 +#define ATI_FRAGMENT_SHADER_PASS_OP 2 +#define ATI_FRAGMENT_SHADER_SAMPLE_OP 3 + +/* two opcodes - one for color/one for alpha */ +/* up to three source registers for most ops */ +struct atifs_instruction +{ + GLenum Opcode[2]; + GLuint ArgCount[2]; + struct atifragshader_src_register SrcReg[2][3]; + struct atifragshader_dst_register DstReg[2]; +}; + +/* different from arithmetic shader instruction */ +struct atifs_setupinst +{ + GLenum Opcode; + GLuint src; + GLenum swizzle; +}; + + +extern struct ati_fragment_shader * +_mesa_new_ati_fragment_shader(GLcontext *ctx, GLuint id); + +extern void +_mesa_delete_ati_fragment_shader(GLcontext *ctx, + struct ati_fragment_shader *s); + + +extern GLuint GLAPIENTRY _mesa_GenFragmentShadersATI(GLuint range); + +extern void GLAPIENTRY _mesa_BindFragmentShaderATI(GLuint id); + +extern void GLAPIENTRY _mesa_DeleteFragmentShaderATI(GLuint id); + +extern void GLAPIENTRY _mesa_BeginFragmentShaderATI(void); + +extern void GLAPIENTRY _mesa_EndFragmentShaderATI(void); + +extern void GLAPIENTRY +_mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle); + +extern void GLAPIENTRY +_mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle); + +extern void GLAPIENTRY +_mesa_ColorFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod); + +extern void GLAPIENTRY +_mesa_ColorFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, + GLuint arg2Mod); + +extern void GLAPIENTRY +_mesa_ColorFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, + GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, + GLuint arg3Mod); + +extern void GLAPIENTRY +_mesa_AlphaFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod); + +extern void GLAPIENTRY +_mesa_AlphaFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod); + +extern void GLAPIENTRY +_mesa_AlphaFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, + GLuint arg3Rep, GLuint arg3Mod); + +extern void GLAPIENTRY +_mesa_SetFragmentShaderConstantATI(GLuint dst, const GLfloat * value); + +#endif diff --git a/mesalib/src/mesa/shader/descrip.mms b/mesalib/src/mesa/shader/descrip.mms new file mode 100644 index 000000000..19bafd483 --- /dev/null +++ b/mesalib/src/mesa/shader/descrip.mms @@ -0,0 +1,95 @@ +# Makefile for core library for VMS +# contributed by Jouk Jansen joukj@hrem.nano.tudelft.nl +# Last revision : 29 September 2008 +.first + define gl [---.include.gl] + define math [-.math] + define swrast [-.swrast] + define array_cache [-.array_cache] + define glapi [-.glapi] + define main [-.main] + define shader [-.shader] + +.include [---]mms-config. + +##### MACROS ##### + +VPATH = RCS + +INCDIR = [---.include],[.grammar],[-.main],[-.glapi],[.slang] +LIBDIR = [---.lib] +CFLAGS = /include=($(INCDIR),[])/define=(PTHREADS=1,"__extension__=")/name=(as_is,short)/float=ieee/ieee=denorm + +SOURCES = \ + atifragshader.c \ + arbprogparse.c \ + arbprogram.c \ + nvfragparse.c \ + nvprogram.c \ + nvvertparse.c \ + program.c \ + programopt.c \ + prog_debug.c \ + prog_execute.c \ + prog_instruction.c \ + prog_parameter.c \ + prog_print.c \ + prog_cache.c \ + prog_statevars.c \ + shader_api.c prog_uniform.c + +OBJECTS = \ + atifragshader.obj,\ + arbprogparse.obj,\ + arbprogram.obj,\ + nvfragparse.obj,\ + nvprogram.obj,\ + nvvertparse.obj,\ + program.obj,\ + programopt.obj,\ + prog_debug.obj,\ + prog_execute.obj,\ + prog_instruction.obj,\ + prog_parameter.obj,\ + prog_print.obj,\ + prog_statevars.obj,\ + shader_api.obj,prog_uniform.obj,prog_cache.obj + +##### RULES ##### + +VERSION=Mesa V3.4 + +##### TARGETS ##### +all : + $(MMS)$(MMSQUALIFIERS) $(LIBDIR)$(GL_LIB) + set def [.slang] + $(MMS)$(MMSQUALIFIERS) + set def [-.grammar] + $(MMS)$(MMSQUALIFIERS) + set def [-] + +# Make the library +$(LIBDIR)$(GL_LIB) : $(OBJECTS) + @ library $(LIBDIR)$(GL_LIB) $(OBJECTS) + +clean : + purge + delete *.obj;* + +atifragshader.obj : atifragshader.c +arbprogparse.obj : arbprogparse.c +arbprogram.obj : arbprogram.c +nvfragparse.obj : nvfragparse.c +nvprogram.obj : nvprogram.c +nvvertparse.obj : nvvertparse.c +program.obj : program.c +programopt. obj : programopt.c +prog_debug.obj : prog_debug.c +prog_execute.obj : prog_execute.c +prog_instruction.obj : prog_instruction.c +prog_parameter.obj : prog_parameter.c +prog_print.obj : prog_print.c +prog_statevars.obj : prog_statevars.c +shader_api.obj : shader_api.c +prog_uniform.obj : prog_uniform.c +prog_cache.obj : prog_cache.c diff --git a/mesalib/src/mesa/shader/grammar/grammar.c b/mesalib/src/mesa/shader/grammar/grammar.c new file mode 100644 index 000000000..a9775961d --- /dev/null +++ b/mesalib/src/mesa/shader/grammar/grammar.c @@ -0,0 +1,3178 @@ +/* + * Mesa 3-D graphics library + * Version: 6.6 + * + * 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 grammar.c + * syntax parsing engine + * \author Michal Krol + */ + +#ifndef GRAMMAR_PORT_BUILD +#error Do not build this file directly, build your grammar_XXX.c instead, which includes this file +#endif + +/* +*/ + +/* + INTRODUCTION + ------------ + + The task is to check the syntax of an input string. Input string is a stream of ASCII + characters terminated with a null-character ('\0'). Checking it using C language is + difficult and hard to implement without bugs. It is hard to maintain and make changes when + the syntax changes. + + This is because of a high redundancy of the C code. Large blocks of code are duplicated with + only small changes. Even use of macros does not solve the problem because macros cannot + erase the complexity of the problem. + + The resolution is to create a new language that will be highly oriented to our task. Once + we describe a particular syntax, we are done. We can then focus on the code that implements + the language. The size and complexity of it is relatively small than the code that directly + checks the syntax. + + First, we must implement our new language. Here, the language is implemented in C, but it + could also be implemented in any other language. The code is listed below. We must take + a good care that it is bug free. This is simple because the code is simple and clean. + + Next, we must describe the syntax of our new language in itself. Once created and checked + manually that it is correct, we can use it to check another scripts. + + Note that our new language loading code does not have to check the syntax. It is because we + assume that the script describing itself is correct, and other scripts can be syntactically + checked by the former script. The loading code must only do semantic checking which leads us to + simple resolving references. + + THE LANGUAGE + ------------ + + Here I will describe the syntax of the new language (further called "Synek"). It is mainly a + sequence of declarations terminated by a semicolon. The declaration consists of a symbol, + which is an identifier, and its definition. A definition is in turn a sequence of specifiers + connected with ".and" or ".or" operator. These operators cannot be mixed together in a one + definition. Specifier can be a symbol, string, character, character range or a special + keyword ".true" or ".false". + + On the very beginning of the script there is a declaration of a root symbol and is in the form: + .syntax <root_symbol>; + The <root_symbol> must be on of the symbols in declaration sequence. The syntax is correct if + the root symbol evaluates to true. A symbol evaluates to true if the definition associated with + the symbol evaluates to true. Definition evaluation depends on the operator used to connect + specifiers in the definition. If ".and" operator is used, definition evaluates to true if and + only if all the specifiers evaluate to true. If ".or" operator is used, definition evalutes to + true if any of the specifiers evaluates to true. If definition contains only one specifier, + it is evaluated as if it was connected with ".true" keyword by ".and" operator. + + If specifier is a ".true" keyword, it always evaluates to true. + + If specifier is a ".false" keyword, it always evaluates to false. Specifier evaluates to false + when it does not evaluate to true. + + Character range specifier is in the form: + '<first_character>' - '<second_character>' + If specifier is a character range, it evaluates to true if character in the stream is greater + or equal to <first_character> and less or equal to <second_character>. In that situation + the stream pointer is advanced to point to next character in the stream. All C-style escape + sequences are supported although trigraph sequences are not. The comparisions are performed + on 8-bit unsigned integers. + + Character specifier is in the form: + '<single_character>' + It evaluates to true if the following character range specifier evaluates to true: + '<single_character>' - '<single_character>' + + String specifier is in the form: + "<string>" + Let N be the number of characters in <string>. Let <string>[i] designate i-th character in + <string>. Then the string specifier evaluates to true if and only if for i in the range [0, N) + the following character specifier evaluates to true: + '<string>[i]' + If <string>[i] is a quotation mark, '<string>[i]' is replaced with '\<string>[i]'. + + Symbol specifier can be optionally preceded by a ".loop" keyword in the form: + .loop <symbol> (1) + where <symbol> is defined as follows: + <symbol> <definition>; (2) + Construction (1) is replaced by the following code: + <symbol$1> + and declaration (2) is replaced by the following: + <symbol$1> <symbol$2> .or .true; + <symbol$2> <symbol> .and <symbol$1>; + <symbol> <definition>; + + Synek supports also a register mechanizm. User can, in its SYN file, declare a number of + registers that can be accessed in the syn body. Each reg has its name and a default value. + The register is one byte wide. The C code can change the default value by calling + grammar_set_reg8() with grammar id, register name and a new value. As we know, each rule is + a sequence of specifiers joined with .and or .or operator. And now each specifier can be + prefixed with a condition expression in a form ".if (<reg_name> <operator> <hex_literal>)" + where <operator> can be == or !=. If the condition evaluates to false, the specifier + evaluates to .false. Otherwise it evalutes to the specifier. + + ESCAPE SEQUENCES + ---------------- + + Synek supports all escape sequences in character specifiers. The mapping table is listed below. + All occurences of the characters in the first column are replaced with the corresponding + character in the second column. + + Escape sequence Represents + ------------------------------------------------------------------------------------------------ + \a Bell (alert) + \b Backspace + \f Formfeed + \n New line + \r Carriage return + \t Horizontal tab + \v Vertical tab + \' Single quotation mark + \" Double quotation mark + \\ Backslash + \? Literal question mark + \ooo ASCII character in octal notation + \xhhh ASCII character in hexadecimal notation + ------------------------------------------------------------------------------------------------ + + RAISING ERRORS + -------------- + + Any specifier can be followed by a special construction that is executed when the specifier + evaluates to false. The construction is in the form: + .error <ERROR_TEXT> + <ERROR_TEXT> is an identifier declared earlier by error text declaration. The declaration is + in the form: + .errtext <ERROR_TEXT> "<error_desc>" + When specifier evaluates to false and this construction is present, parsing is stopped + immediately and <error_desc> is returned as a result of parsing. The error position is also + returned and it is meant as an offset from the beggining of the stream to the character that + was valid so far. Example: + + (**** syntax script ****) + + .syntax program; + .errtext MISSING_SEMICOLON "missing ';'" + program declaration .and .loop space .and ';' .error MISSING_SEMICOLON .and + .loop space .and '\0'; + declaration "declare" .and .loop space .and identifier; + space ' '; + + (**** sample code ****) + + declare foo , + + In the example above checking the sample code will result in error message "missing ';'" and + error position 12. The sample code is not correct. Note the presence of '\0' specifier to + assure that there is no code after semicolon - only spaces. + <error_desc> can optionally contain identifier surrounded by dollar signs $. In such a case, + the identifier and dollar signs are replaced by a string retrieved by invoking symbol with + the identifier name. The starting position is the error position. The lenght of the resulting + string is the position after invoking the symbol. + + PRODUCTION + ---------- + + Synek not only checks the syntax but it can also produce (emit) bytes associated with specifiers + that evaluate to true. That is, every specifier and optional error construction can be followed + by a number of emit constructions that are in the form: + .emit <parameter> + <paramater> can be a HEX number, identifier, a star * or a dollar $. HEX number is preceded by + 0x or 0X. If <parameter> is an identifier, it must be earlier declared by emit code declaration + in the form: + .emtcode <identifier> <hex_number> + + When given specifier evaluates to true, all emits associated with the specifier are output + in order they were declared. A star means that last-read character should be output instead + of constant value. Example: + + (**** syntax script ****) + + .syntax foobar; + .emtcode WORD_FOO 0x01 + .emtcode WORD_BAR 0x02 + foobar FOO .emit WORD_FOO .or BAR .emit WORD_BAR .or .true .emit 0x00; + FOO "foo" .and SPACE; + BAR "bar" .and SPACE; + SPACE ' ' .or '\0'; + + (**** sample text 1 ****) + + foo + + (**** sample text 2 ****) + + foobar + + For both samples the result will be one-element array. For first sample text it will be + value 1, for second - 0. Note that every text will be accepted because of presence of + .true as an alternative. + + Another example: + + (**** syntax script ****) + + .syntax declaration; + .emtcode VARIABLE 0x01 + declaration "declare" .and .loop space .and + identifier .emit VARIABLE .and (1) + .true .emit 0x00 .and (2) + .loop space .and ';'; + space ' ' .or '\t'; + identifier .loop id_char .emit *; (3) + id_char 'a'-'z' .or 'A'-'Z' .or '_'; + + (**** sample code ****) + + declare fubar; + + In specifier (1) symbol <identifier> is followed by .emit VARIABLE. If it evaluates to + true, VARIABLE constant and then production of the symbol is output. Specifier (2) is used + to terminate the string with null to signal when the string ends. Specifier (3) outputs + all characters that make declared identifier. The result of sample code will be the + following array: + { 1, 'f', 'u', 'b', 'a', 'r', 0 } + + If .emit is followed by dollar $, it means that current position should be output. Current + position is a 32-bit unsigned integer distance from the very beginning of the parsed string to + first character consumed by the specifier associated with the .emit instruction. Current + position is stored in the output buffer in Little-Endian convention (the lowest byte comes + first). +*/ + +#include <stdio.h> + +static void mem_free (void **); + +/* + internal error messages +*/ +static const byte *OUT_OF_MEMORY = (byte *) "internal error 1001: out of physical memory"; +static const byte *UNRESOLVED_REFERENCE = (byte *) "internal error 1002: unresolved reference '$'"; +static const byte *INVALID_GRAMMAR_ID = (byte *) "internal error 1003: invalid grammar object"; +static const byte *INVALID_REGISTER_NAME = (byte *) "internal error 1004: invalid register name: '$'"; +/*static const byte *DUPLICATE_IDENTIFIER = (byte *) "internal error 1005: identifier '$' already defined";*/ +static const byte *UNREFERENCED_IDENTIFIER =(byte *) "internal error 1006: unreferenced identifier '$'"; + +static const byte *error_message = NULL; /* points to one of the error messages above */ +static byte *error_param = NULL; /* this is inserted into error_message in place of $ */ +static int error_position = -1; + +static byte *unknown = (byte *) "???"; + +static void clear_last_error (void) +{ + /* reset error message */ + error_message = NULL; + + /* free error parameter - if error_param is a "???" don't free it - it's static */ + if (error_param != unknown) + mem_free ((void **) (void *) &error_param); + else + error_param = NULL; + + /* reset error position */ + error_position = -1; +} + +static void set_last_error (const byte *msg, byte *param, int pos) +{ + /* error message can be set only once */ + if (error_message != NULL) + { + mem_free ((void **) (void *) ¶m); + return; + } + + error_message = msg; + + /* if param is NULL, set error_param to unknown ("???") */ + /* note: do not try to strdup the "???" - it may be that we are here because of */ + /* out of memory error so strdup can fail */ + if (param != NULL) + error_param = param; + else + error_param = unknown; + + error_position = pos; +} + +/* + memory management routines +*/ +static void *mem_alloc (size_t size) +{ + void *ptr = grammar_alloc_malloc (size); + if (ptr == NULL) + set_last_error (OUT_OF_MEMORY, NULL, -1); + return ptr; +} + +static void *mem_copy (void *dst, const void *src, size_t size) +{ + return grammar_memory_copy (dst, src, size); +} + +static void mem_free (void **ptr) +{ + grammar_alloc_free (*ptr); + *ptr = NULL; +} + +static void *mem_realloc (void *ptr, size_t old_size, size_t new_size) +{ + void *ptr2 = grammar_alloc_realloc (ptr, old_size, new_size); + if (ptr2 == NULL) + set_last_error (OUT_OF_MEMORY, NULL, -1); + return ptr2; +} + +static byte *str_copy_n (byte *dst, const byte *src, size_t max_len) +{ + return grammar_string_copy_n (dst, src, max_len); +} + +static byte *str_duplicate (const byte *str) +{ + byte *new_str = grammar_string_duplicate (str); + if (new_str == NULL) + set_last_error (OUT_OF_MEMORY, NULL, -1); + return new_str; +} + +static int str_equal (const byte *str1, const byte *str2) +{ + return grammar_string_compare (str1, str2) == 0; +} + +static int str_equal_n (const byte *str1, const byte *str2, unsigned int n) +{ + return grammar_string_compare_n (str1, str2, n) == 0; +} + +static int +str_length (const byte *str) +{ + return (int) (grammar_string_length (str)); +} + +/* + useful macros +*/ +#define GRAMMAR_IMPLEMENT_LIST_APPEND(_Ty)\ + static void _Ty##_append (_Ty **x, _Ty *nx) {\ + while (*x) x = &(**x).next;\ + *x = nx;\ + } + +/* + string to byte map typedef +*/ +typedef struct map_byte_ +{ + byte *key; + byte data; + struct map_byte_ *next; +} map_byte; + +static void map_byte_create (map_byte **ma) +{ + *ma = (map_byte *) mem_alloc (sizeof (map_byte)); + if (*ma) + { + (**ma).key = NULL; + (**ma).data = '\0'; + (**ma).next = NULL; + } +} + +static void map_byte_destroy (map_byte **ma) +{ + if (*ma) + { + map_byte_destroy (&(**ma).next); + mem_free ((void **) &(**ma).key); + mem_free ((void **) ma); + } +} + +GRAMMAR_IMPLEMENT_LIST_APPEND(map_byte) + +/* + searches the map for the specified key, + returns pointer to the element with the specified key if it exists + returns NULL otherwise +*/ +static map_byte *map_byte_locate (map_byte **ma, const byte *key) +{ + while (*ma) + { + if (str_equal ((**ma).key, key)) + return *ma; + + ma = &(**ma).next; + } + + set_last_error (UNRESOLVED_REFERENCE, str_duplicate (key), -1); + return NULL; +} + +/* + searches the map for specified key, + if the key is matched, *data is filled with data associated with the key, + returns 0 if the key is matched, + returns 1 otherwise +*/ +static int map_byte_find (map_byte **ma, const byte *key, byte *data) +{ + map_byte *found = map_byte_locate (ma, key); + if (found != NULL) + { + *data = found->data; + + return 0; + } + + return 1; +} + +/* + regbyte context typedef + + Each regbyte consists of its name and a default value. These are static and created at + grammar script compile-time, for example the following line: + .regbyte vertex_blend 0x00 + adds a new regbyte named "vertex_blend" to the static list and initializes it to 0. + When the script is executed, this regbyte can be accessed by name for read and write. When a + particular regbyte is written, a new regbyte_ctx entry is added to the top of the regbyte_ctx + stack. The new entry contains information abot which regbyte it references and its new value. + When a given regbyte is accessed for read, the stack is searched top-down to find an + entry that references the regbyte. The first matching entry is used to return the current + value it holds. If no entry is found, the default value is returned. +*/ +typedef struct regbyte_ctx_ +{ + map_byte *m_regbyte; + byte m_current_value; + struct regbyte_ctx_ *m_prev; +} regbyte_ctx; + +static void regbyte_ctx_create (regbyte_ctx **re) +{ + *re = (regbyte_ctx *) mem_alloc (sizeof (regbyte_ctx)); + if (*re) + { + (**re).m_regbyte = NULL; + (**re).m_prev = NULL; + } +} + +static void regbyte_ctx_destroy (regbyte_ctx **re) +{ + if (*re) + { + mem_free ((void **) re); + } +} + +static byte regbyte_ctx_extract (regbyte_ctx **re, map_byte *reg) +{ + /* first lookup in the register stack */ + while (*re != NULL) + { + if ((**re).m_regbyte == reg) + return (**re).m_current_value; + + re = &(**re).m_prev; + } + + /* if not found - return the default value */ + return reg->data; +} + +/* + emit type typedef +*/ +typedef enum emit_type_ +{ + et_byte, /* explicit number */ + et_stream, /* eaten character */ + et_position /* current position */ +} emit_type; + +/* + emit destination typedef +*/ +typedef enum emit_dest_ +{ + ed_output, /* write to the output buffer */ + ed_regbyte /* write a particular regbyte */ +} emit_dest; + +/* + emit typedef +*/ +typedef struct emit_ +{ + emit_dest m_emit_dest; + emit_type m_emit_type; /* ed_output */ + byte m_byte; /* et_byte */ + map_byte *m_regbyte; /* ed_regbyte */ + byte *m_regname; /* ed_regbyte - temporary */ + struct emit_ *m_next; +} emit; + +static void emit_create (emit **em) +{ + *em = (emit *) mem_alloc (sizeof (emit)); + if (*em) + { + (**em).m_emit_dest = ed_output; + (**em).m_emit_type = et_byte; + (**em).m_byte = '\0'; + (**em).m_regbyte = NULL; + (**em).m_regname = NULL; + (**em).m_next = NULL; + } +} + +static void emit_destroy (emit **em) +{ + if (*em) + { + emit_destroy (&(**em).m_next); + mem_free ((void **) &(**em).m_regname); + mem_free ((void **) em); + } +} + +static unsigned int emit_size (emit *_E) +{ + unsigned int n = 0; + + while (_E != NULL) + { + if (_E->m_emit_dest == ed_output) + { + if (_E->m_emit_type == et_position) + n += 4; /* position is a 32-bit unsigned integer */ + else + n++; + } + _E = _E->m_next; + } + + return n; +} + +static int emit_push (emit *_E, byte *_P, byte c, unsigned int _Pos, regbyte_ctx **_Ctx) +{ + while (_E != NULL) + { + if (_E->m_emit_dest == ed_output) + { + if (_E->m_emit_type == et_byte) + *_P++ = _E->m_byte; + else if (_E->m_emit_type == et_stream) + *_P++ = c; + else /* _Em->type == et_position */ + { + *_P++ = (byte) (_Pos); + *_P++ = (byte) (_Pos >> 8); + *_P++ = (byte) (_Pos >> 16); + *_P++ = (byte) (_Pos >> 24); + } + } + else + { + regbyte_ctx *new_rbc; + regbyte_ctx_create (&new_rbc); + if (new_rbc == NULL) + return 1; + + new_rbc->m_prev = *_Ctx; + new_rbc->m_regbyte = _E->m_regbyte; + *_Ctx = new_rbc; + + if (_E->m_emit_type == et_byte) + new_rbc->m_current_value = _E->m_byte; + else if (_E->m_emit_type == et_stream) + new_rbc->m_current_value = c; + } + + _E = _E->m_next; + } + + return 0; +} + +/* + error typedef +*/ +typedef struct error_ +{ + byte *m_text; + byte *m_token_name; + struct rule_ *m_token; +} error; + +static void error_create (error **er) +{ + *er = (error *) mem_alloc (sizeof (error)); + if (*er) + { + (**er).m_text = NULL; + (**er).m_token_name = NULL; + (**er).m_token = NULL; + } +} + +static void error_destroy (error **er) +{ + if (*er) + { + mem_free ((void **) &(**er).m_text); + mem_free ((void **) &(**er).m_token_name); + mem_free ((void **) er); + } +} + +struct dict_; + +static byte * +error_get_token (error *, struct dict_ *, const byte *, int); + +/* + condition operand type typedef +*/ +typedef enum cond_oper_type_ +{ + cot_byte, /* constant 8-bit unsigned integer */ + cot_regbyte /* pointer to byte register containing the current value */ +} cond_oper_type; + +/* + condition operand typedef +*/ +typedef struct cond_oper_ +{ + cond_oper_type m_type; + byte m_byte; /* cot_byte */ + map_byte *m_regbyte; /* cot_regbyte */ + byte *m_regname; /* cot_regbyte - temporary */ +} cond_oper; + +/* + condition type typedef +*/ +typedef enum cond_type_ +{ + ct_equal, + ct_not_equal +} cond_type; + +/* + condition typedef +*/ +typedef struct cond_ +{ + cond_type m_type; + cond_oper m_operands[2]; +} cond; + +static void cond_create (cond **co) +{ + *co = (cond *) mem_alloc (sizeof (cond)); + if (*co) + { + (**co).m_operands[0].m_regname = NULL; + (**co).m_operands[1].m_regname = NULL; + } +} + +static void cond_destroy (cond **co) +{ + if (*co) + { + mem_free ((void **) &(**co).m_operands[0].m_regname); + mem_free ((void **) &(**co).m_operands[1].m_regname); + mem_free ((void **) co); + } +} + +/* + specifier type typedef +*/ +typedef enum spec_type_ +{ + st_false, + st_true, + st_byte, + st_byte_range, + st_string, + st_identifier, + st_identifier_loop, + st_debug +} spec_type; + +/* + specifier typedef +*/ +typedef struct spec_ +{ + spec_type m_spec_type; + byte m_byte[2]; /* st_byte, st_byte_range */ + byte *m_string; /* st_string */ + struct rule_ *m_rule; /* st_identifier, st_identifier_loop */ + emit *m_emits; + error *m_errtext; + cond *m_cond; + struct spec_ *next; +} spec; + +static void spec_create (spec **sp) +{ + *sp = (spec *) mem_alloc (sizeof (spec)); + if (*sp) + { + (**sp).m_spec_type = st_false; + (**sp).m_byte[0] = '\0'; + (**sp).m_byte[1] = '\0'; + (**sp).m_string = NULL; + (**sp).m_rule = NULL; + (**sp).m_emits = NULL; + (**sp).m_errtext = NULL; + (**sp).m_cond = NULL; + (**sp).next = NULL; + } +} + +static void spec_destroy (spec **sp) +{ + if (*sp) + { + spec_destroy (&(**sp).next); + emit_destroy (&(**sp).m_emits); + error_destroy (&(**sp).m_errtext); + mem_free ((void **) &(**sp).m_string); + cond_destroy (&(**sp).m_cond); + mem_free ((void **) sp); + } +} + +GRAMMAR_IMPLEMENT_LIST_APPEND(spec) + +/* + operator typedef +*/ +typedef enum oper_ +{ + op_none, + op_and, + op_or +} oper; + +/* + rule typedef +*/ +typedef struct rule_ +{ + oper m_oper; + spec *m_specs; + struct rule_ *next; + int m_referenced; +} rule; + +static void rule_create (rule **ru) +{ + *ru = (rule *) mem_alloc (sizeof (rule)); + if (*ru) + { + (**ru).m_oper = op_none; + (**ru).m_specs = NULL; + (**ru).next = NULL; + (**ru).m_referenced = 0; + } +} + +static void rule_destroy (rule **ru) +{ + if (*ru) + { + rule_destroy (&(**ru).next); + spec_destroy (&(**ru).m_specs); + mem_free ((void **) ru); + } +} + +GRAMMAR_IMPLEMENT_LIST_APPEND(rule) + +/* + returns unique grammar id +*/ +static grammar next_valid_grammar_id (void) +{ + static grammar id = 0; + + return ++id; +} + +/* + dictionary typedef +*/ +typedef struct dict_ +{ + rule *m_rulez; + rule *m_syntax; + rule *m_string; + map_byte *m_regbytes; + grammar m_id; + struct dict_ *next; +} dict; + +static void dict_create (dict **di) +{ + *di = (dict *) mem_alloc (sizeof (dict)); + if (*di) + { + (**di).m_rulez = NULL; + (**di).m_syntax = NULL; + (**di).m_string = NULL; + (**di).m_regbytes = NULL; + (**di).m_id = next_valid_grammar_id (); + (**di).next = NULL; + } +} + +static void dict_destroy (dict **di) +{ + if (*di) + { + rule_destroy (&(**di).m_rulez); + map_byte_destroy (&(**di).m_regbytes); + mem_free ((void **) di); + } +} + +GRAMMAR_IMPLEMENT_LIST_APPEND(dict) + +static void dict_find (dict **di, grammar key, dict **data) +{ + while (*di) + { + if ((**di).m_id == key) + { + *data = *di; + return; + } + + di = &(**di).next; + } + + *data = NULL; +} + +static dict *g_dicts = NULL; + +/* + byte array typedef +*/ +typedef struct barray_ +{ + byte *data; + unsigned int len; +} barray; + +static void barray_create (barray **ba) +{ + *ba = (barray *) mem_alloc (sizeof (barray)); + if (*ba) + { + (**ba).data = NULL; + (**ba).len = 0; + } +} + +static void barray_destroy (barray **ba) +{ + if (*ba) + { + mem_free ((void **) &(**ba).data); + mem_free ((void **) ba); + } +} + +/* + reallocates byte array to requested size, + returns 0 on success, + returns 1 otherwise +*/ +static int barray_resize (barray **ba, unsigned int nlen) +{ + byte *new_pointer; + + if (nlen == 0) + { + mem_free ((void **) &(**ba).data); + (**ba).data = NULL; + (**ba).len = 0; + + return 0; + } + else + { + new_pointer = (byte *) mem_realloc ((**ba).data, (**ba).len * sizeof (byte), + nlen * sizeof (byte)); + if (new_pointer) + { + (**ba).data = new_pointer; + (**ba).len = nlen; + + return 0; + } + } + + return 1; +} + +/* + adds byte array pointed by *nb to the end of array pointed by *ba, + returns 0 on success, + returns 1 otherwise +*/ +static int barray_append (barray **ba, barray **nb) +{ + const unsigned int len = (**ba).len; + + if (barray_resize (ba, (**ba).len + (**nb).len)) + return 1; + + mem_copy ((**ba).data + len, (**nb).data, (**nb).len); + + return 0; +} + +/* + adds emit chain pointed by em to the end of array pointed by *ba, + returns 0 on success, + returns 1 otherwise +*/ +static int barray_push (barray **ba, emit *em, byte c, unsigned int pos, regbyte_ctx **rbc) +{ + unsigned int count = emit_size (em); + + if (barray_resize (ba, (**ba).len + count)) + return 1; + + return emit_push (em, (**ba).data + ((**ba).len - count), c, pos, rbc); +} + +/* + byte pool typedef +*/ +typedef struct bytepool_ +{ + byte *_F; + unsigned int _Siz; +} bytepool; + +static void bytepool_destroy (bytepool **by) +{ + if (*by != NULL) + { + mem_free ((void **) &(**by)._F); + mem_free ((void **) by); + } +} + +static void bytepool_create (bytepool **by, int len) +{ + *by = (bytepool *) (mem_alloc (sizeof (bytepool))); + if (*by != NULL) + { + (**by)._F = (byte *) (mem_alloc (sizeof (byte) * len)); + (**by)._Siz = len; + + if ((**by)._F == NULL) + bytepool_destroy (by); + } +} + +static int bytepool_reserve (bytepool *by, unsigned int n) +{ + byte *_P; + + if (n <= by->_Siz) + return 0; + + /* byte pool can only grow and at least by doubling its size */ + n = n >= by->_Siz * 2 ? n : by->_Siz * 2; + + /* reallocate the memory and adjust pointers to the new memory location */ + _P = (byte *) (mem_realloc (by->_F, sizeof (byte) * by->_Siz, sizeof (byte) * n)); + if (_P != NULL) + { + by->_F = _P; + by->_Siz = n; + return 0; + } + + return 1; +} + +/* + string to string map typedef +*/ +typedef struct map_str_ +{ + byte *key; + byte *data; + struct map_str_ *next; +} map_str; + +static void map_str_create (map_str **ma) +{ + *ma = (map_str *) mem_alloc (sizeof (map_str)); + if (*ma) + { + (**ma).key = NULL; + (**ma).data = NULL; + (**ma).next = NULL; + } +} + +static void map_str_destroy (map_str **ma) +{ + if (*ma) + { + map_str_destroy (&(**ma).next); + mem_free ((void **) &(**ma).key); + mem_free ((void **) &(**ma).data); + mem_free ((void **) ma); + } +} + +GRAMMAR_IMPLEMENT_LIST_APPEND(map_str) + +/* + searches the map for specified key, + if the key is matched, *data is filled with data associated with the key, + returns 0 if the key is matched, + returns 1 otherwise +*/ +static int map_str_find (map_str **ma, const byte *key, byte **data) +{ + while (*ma) + { + if (str_equal ((**ma).key, key)) + { + *data = str_duplicate ((**ma).data); + if (*data == NULL) + return 1; + + return 0; + } + + ma = &(**ma).next; + } + + set_last_error (UNRESOLVED_REFERENCE, str_duplicate (key), -1); + return 1; +} + +/* + string to rule map typedef +*/ +typedef struct map_rule_ +{ + byte *key; + rule *data; + struct map_rule_ *next; +} map_rule; + +static void map_rule_create (map_rule **ma) +{ + *ma = (map_rule *) mem_alloc (sizeof (map_rule)); + if (*ma) + { + (**ma).key = NULL; + (**ma).data = NULL; + (**ma).next = NULL; + } +} + +static void map_rule_destroy (map_rule **ma) +{ + if (*ma) + { + map_rule_destroy (&(**ma).next); + mem_free ((void **) &(**ma).key); + mem_free ((void **) ma); + } +} + +GRAMMAR_IMPLEMENT_LIST_APPEND(map_rule) + +/* + searches the map for specified key, + if the key is matched, *data is filled with data associated with the key, + returns 0 if the is matched, + returns 1 otherwise +*/ +static int map_rule_find (map_rule **ma, const byte *key, rule **data) +{ + while (*ma) + { + if (str_equal ((**ma).key, key)) + { + *data = (**ma).data; + + return 0; + } + + ma = &(**ma).next; + } + + set_last_error (UNRESOLVED_REFERENCE, str_duplicate (key), -1); + return 1; +} + +/* + returns 1 if given character is a white space, + returns 0 otherwise +*/ +static int is_space (byte c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\r'; +} + +/* + advances text pointer by 1 if character pointed by *text is a space, + returns 1 if a space has been eaten, + returns 0 otherwise +*/ +static int eat_space (const byte **text) +{ + if (is_space (**text)) + { + (*text)++; + + return 1; + } + + return 0; +} + +/* + returns 1 if text points to C-style comment start string, + returns 0 otherwise +*/ +static int is_comment_start (const byte *text) +{ + return text[0] == '/' && text[1] == '*'; +} + +/* + advances text pointer to first character after C-style comment block - if any, + returns 1 if C-style comment block has been encountered and eaten, + returns 0 otherwise +*/ +static int eat_comment (const byte **text) +{ + if (is_comment_start (*text)) + { + /* *text points to comment block - skip two characters to enter comment body */ + *text += 2; + /* skip any character except consecutive '*' and '/' */ + while (!((*text)[0] == '*' && (*text)[1] == '/')) + (*text)++; + /* skip those two terminating characters */ + *text += 2; + + return 1; + } + + return 0; +} + +/* + advances text pointer to first character that is neither space nor C-style comment block +*/ +static void eat_spaces (const byte **text) +{ + while (eat_space (text) || eat_comment (text)) + ; +} + +/* + resizes string pointed by *ptr to successfully add character c to the end of the string, + returns 0 on success, + returns 1 otherwise +*/ +static int string_grow (byte **ptr, unsigned int *len, byte c) +{ + /* reallocate the string in 16-byte increments */ + if ((*len & 0x0F) == 0x0F || *ptr == NULL) + { + byte *tmp = (byte *) mem_realloc (*ptr, ((*len + 1) & ~0x0F) * sizeof (byte), + ((*len + 1 + 0x10) & ~0x0F) * sizeof (byte)); + if (tmp == NULL) + return 1; + + *ptr = tmp; + } + + if (c) + { + /* append given character */ + (*ptr)[*len] = c; + (*len)++; + } + (*ptr)[*len] = '\0'; + + return 0; +} + +/* + returns 1 if given character is a valid identifier character a-z, A-Z, 0-9 or _ + returns 0 otherwise +*/ +static int is_identifier (byte c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; +} + +/* + copies characters from *text to *id until non-identifier character is encountered, + assumes that *id points to NULL object - caller is responsible for later freeing the string, + text pointer is advanced to point past the copied identifier, + returns 0 if identifier was successfully copied, + returns 1 otherwise +*/ +static int get_identifier (const byte **text, byte **id) +{ + const byte *t = *text; + byte *p = NULL; + unsigned int len = 0; + + if (string_grow (&p, &len, '\0')) + return 1; + + /* loop while next character in buffer is valid for identifiers */ + while (is_identifier (*t)) + { + if (string_grow (&p, &len, *t++)) + { + mem_free ((void **) (void *) &p); + return 1; + } + } + + *text = t; + *id = p; + + return 0; +} + +/* + converts sequence of DEC digits pointed by *text until non-DEC digit is encountered, + advances text pointer past the converted sequence, + returns the converted value +*/ +static unsigned int dec_convert (const byte **text) +{ + unsigned int value = 0; + + while (**text >= '0' && **text <= '9') + { + value = value * 10 + **text - '0'; + (*text)++; + } + + return value; +} + +/* + returns 1 if given character is HEX digit 0-9, A-F or a-f, + returns 0 otherwise +*/ +static int is_hex (byte c) +{ + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); +} + +/* + returns value of passed character as if it was HEX digit +*/ +static unsigned int hex2dec (byte c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return c - 'a' + 10; +} + +/* + converts sequence of HEX digits pointed by *text until non-HEX digit is encountered, + advances text pointer past the converted sequence, + returns the converted value +*/ +static unsigned int hex_convert (const byte **text) +{ + unsigned int value = 0; + + while (is_hex (**text)) + { + value = value * 0x10 + hex2dec (**text); + (*text)++; + } + + return value; +} + +/* + returns 1 if given character is OCT digit 0-7, + returns 0 otherwise +*/ +static int is_oct (byte c) +{ + return c >= '0' && c <= '7'; +} + +/* + returns value of passed character as if it was OCT digit +*/ +static int oct2dec (byte c) +{ + return c - '0'; +} + +static byte get_escape_sequence (const byte **text) +{ + int value = 0; + + /* skip '\' character */ + (*text)++; + + switch (*(*text)++) + { + case '\'': + return '\''; + case '"': + return '\"'; + case '?': + return '\?'; + case '\\': + return '\\'; + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case 'x': + return (byte) hex_convert (text); + } + + (*text)--; + if (is_oct (**text)) + { + value = oct2dec (*(*text)++); + if (is_oct (**text)) + { + value = value * 010 + oct2dec (*(*text)++); + if (is_oct (**text)) + value = value * 010 + oct2dec (*(*text)++); + } + } + + return (byte) value; +} + +/* + copies characters from *text to *str until " or ' character is encountered, + assumes that *str points to NULL object - caller is responsible for later freeing the string, + assumes that *text points to " or ' character that starts the string, + text pointer is advanced to point past the " or ' character, + returns 0 if string was successfully copied, + returns 1 otherwise +*/ +static int get_string (const byte **text, byte **str) +{ + const byte *t = *text; + byte *p = NULL; + unsigned int len = 0; + byte term_char; + + if (string_grow (&p, &len, '\0')) + return 1; + + /* read " or ' character that starts the string */ + term_char = *t++; + /* while next character is not the terminating character */ + while (*t && *t != term_char) + { + byte c; + + if (*t == '\\') + c = get_escape_sequence (&t); + else + c = *t++; + + if (string_grow (&p, &len, c)) + { + mem_free ((void **) (void *) &p); + return 1; + } + } + /* skip " or ' character that ends the string */ + t++; + + *text = t; + *str = p; + return 0; +} + +/* + gets emit code, the syntax is: + ".emtcode" " " <symbol> " " (("0x" | "0X") <hex_value>) | <dec_value> | <character> + assumes that *text already points to <symbol>, + returns 0 if emit code is successfully read, + returns 1 otherwise +*/ +static int get_emtcode (const byte **text, map_byte **ma) +{ + const byte *t = *text; + map_byte *m = NULL; + + map_byte_create (&m); + if (m == NULL) + return 1; + + if (get_identifier (&t, &m->key)) + { + map_byte_destroy (&m); + return 1; + } + eat_spaces (&t); + + if (*t == '\'') + { + byte *c; + + if (get_string (&t, &c)) + { + map_byte_destroy (&m); + return 1; + } + + m->data = (byte) c[0]; + mem_free ((void **) (void *) &c); + } + else if (t[0] == '0' && (t[1] == 'x' || t[1] == 'X')) + { + /* skip HEX "0x" or "0X" prefix */ + t += 2; + m->data = (byte) hex_convert (&t); + } + else + { + m->data = (byte) dec_convert (&t); + } + + eat_spaces (&t); + + *text = t; + *ma = m; + return 0; +} + +/* + gets regbyte declaration, the syntax is: + ".regbyte" " " <symbol> " " (("0x" | "0X") <hex_value>) | <dec_value> | <character> + assumes that *text already points to <symbol>, + returns 0 if regbyte is successfully read, + returns 1 otherwise +*/ +static int get_regbyte (const byte **text, map_byte **ma) +{ + /* pass it to the emtcode parser as it has the same syntax starting at <symbol> */ + return get_emtcode (text, ma); +} + +/* + returns 0 on success, + returns 1 otherwise +*/ +static int get_errtext (const byte **text, map_str **ma) +{ + const byte *t = *text; + map_str *m = NULL; + + map_str_create (&m); + if (m == NULL) + return 1; + + if (get_identifier (&t, &m->key)) + { + map_str_destroy (&m); + return 1; + } + eat_spaces (&t); + + if (get_string (&t, &m->data)) + { + map_str_destroy (&m); + return 1; + } + eat_spaces (&t); + + *text = t; + *ma = m; + return 0; +} + +/* + returns 0 on success, + returns 1 otherwise, +*/ +static int get_error (const byte **text, error **er, map_str *maps) +{ + const byte *t = *text; + byte *temp = NULL; + + if (*t != '.') + return 0; + + t++; + if (get_identifier (&t, &temp)) + return 1; + eat_spaces (&t); + + if (!str_equal ((byte *) "error", temp)) + { + mem_free ((void **) (void *) &temp); + return 0; + } + + mem_free ((void **) (void *) &temp); + + error_create (er); + if (*er == NULL) + return 1; + + if (*t == '\"') + { + if (get_string (&t, &(**er).m_text)) + { + error_destroy (er); + return 1; + } + eat_spaces (&t); + } + else + { + if (get_identifier (&t, &temp)) + { + error_destroy (er); + return 1; + } + eat_spaces (&t); + + if (map_str_find (&maps, temp, &(**er).m_text)) + { + mem_free ((void **) (void *) &temp); + error_destroy (er); + return 1; + } + + mem_free ((void **) (void *) &temp); + } + + /* try to extract "token" from "...$token$..." */ + { + byte *processed = NULL; + unsigned int len = 0; + int i = 0; + + if (string_grow (&processed, &len, '\0')) + { + error_destroy (er); + return 1; + } + + while (i < str_length ((**er).m_text)) + { + /* check if the dollar sign is repeated - if so skip it */ + if ((**er).m_text[i] == '$' && (**er).m_text[i + 1] == '$') + { + if (string_grow (&processed, &len, '$')) + { + mem_free ((void **) (void *) &processed); + error_destroy (er); + return 1; + } + + i += 2; + } + else if ((**er).m_text[i] != '$') + { + if (string_grow (&processed, &len, (**er).m_text[i])) + { + mem_free ((void **) (void *) &processed); + error_destroy (er); + return 1; + } + + i++; + } + else + { + if (string_grow (&processed, &len, '$')) + { + mem_free ((void **) (void *) &processed); + error_destroy (er); + return 1; + } + + { + /* length of token being extracted */ + unsigned int tlen = 0; + + if (string_grow (&(**er).m_token_name, &tlen, '\0')) + { + mem_free ((void **) (void *) &processed); + error_destroy (er); + return 1; + } + + /* skip the dollar sign */ + i++; + + while ((**er).m_text[i] != '$') + { + if (string_grow (&(**er).m_token_name, &tlen, (**er).m_text[i])) + { + mem_free ((void **) (void *) &processed); + error_destroy (er); + return 1; + } + + i++; + } + + /* skip the dollar sign */ + i++; + } + } + } + + mem_free ((void **) &(**er).m_text); + (**er).m_text = processed; + } + + *text = t; + return 0; +} + +/* + returns 0 on success, + returns 1 otherwise, +*/ +static int get_emits (const byte **text, emit **em, map_byte *mapb) +{ + const byte *t = *text; + byte *temp = NULL; + emit *e = NULL; + emit_dest dest; + + if (*t != '.') + return 0; + + t++; + if (get_identifier (&t, &temp)) + return 1; + eat_spaces (&t); + + /* .emit */ + if (str_equal ((byte *) "emit", temp)) + dest = ed_output; + /* .load */ + else if (str_equal ((byte *) "load", temp)) + dest = ed_regbyte; + else + { + mem_free ((void **) (void *) &temp); + return 0; + } + + mem_free ((void **) (void *) &temp); + + emit_create (&e); + if (e == NULL) + return 1; + + e->m_emit_dest = dest; + + if (dest == ed_regbyte) + { + if (get_identifier (&t, &e->m_regname)) + { + emit_destroy (&e); + return 1; + } + eat_spaces (&t); + } + + /* 0xNN */ + if (*t == '0' && (t[1] == 'x' || t[1] == 'X')) + { + t += 2; + e->m_byte = (byte) hex_convert (&t); + + e->m_emit_type = et_byte; + } + /* NNN */ + else if (*t >= '0' && *t <= '9') + { + e->m_byte = (byte) dec_convert (&t); + + e->m_emit_type = et_byte; + } + /* * */ + else if (*t == '*') + { + t++; + + e->m_emit_type = et_stream; + } + /* $ */ + else if (*t == '$') + { + t++; + + e->m_emit_type = et_position; + } + /* 'c' */ + else if (*t == '\'') + { + if (get_string (&t, &temp)) + { + emit_destroy (&e); + return 1; + } + e->m_byte = (byte) temp[0]; + + mem_free ((void **) (void *) &temp); + + e->m_emit_type = et_byte; + } + else + { + if (get_identifier (&t, &temp)) + { + emit_destroy (&e); + return 1; + } + + if (map_byte_find (&mapb, temp, &e->m_byte)) + { + mem_free ((void **) (void *) &temp); + emit_destroy (&e); + return 1; + } + + mem_free ((void **) (void *) &temp); + + e->m_emit_type = et_byte; + } + + eat_spaces (&t); + + if (get_emits (&t, &e->m_next, mapb)) + { + emit_destroy (&e); + return 1; + } + + *text = t; + *em = e; + return 0; +} + +/* + returns 0 on success, + returns 1 otherwise, +*/ +static int get_spec (const byte **text, spec **sp, map_str *maps, map_byte *mapb) +{ + const byte *t = *text; + spec *s = NULL; + + spec_create (&s); + if (s == NULL) + return 1; + + /* first - read optional .if statement */ + if (*t == '.') + { + const byte *u = t; + byte *keyword = NULL; + + /* skip the dot */ + u++; + + if (get_identifier (&u, &keyword)) + { + spec_destroy (&s); + return 1; + } + + /* .if */ + if (str_equal ((byte *) "if", keyword)) + { + cond_create (&s->m_cond); + if (s->m_cond == NULL) + { + spec_destroy (&s); + return 1; + } + + /* skip the left paren */ + eat_spaces (&u); + u++; + + /* get the left operand */ + eat_spaces (&u); + if (get_identifier (&u, &s->m_cond->m_operands[0].m_regname)) + { + spec_destroy (&s); + return 1; + } + s->m_cond->m_operands[0].m_type = cot_regbyte; + + /* get the operator (!= or ==) */ + eat_spaces (&u); + if (*u == '!') + s->m_cond->m_type = ct_not_equal; + else + s->m_cond->m_type = ct_equal; + u += 2; + eat_spaces (&u); + + if (u[0] == '0' && (u[1] == 'x' || u[1] == 'X')) + { + /* skip the 0x prefix */ + u += 2; + + /* get the right operand */ + s->m_cond->m_operands[1].m_byte = hex_convert (&u); + s->m_cond->m_operands[1].m_type = cot_byte; + } + else /*if (*u >= '0' && *u <= '9')*/ + { + /* get the right operand */ + s->m_cond->m_operands[1].m_byte = dec_convert (&u); + s->m_cond->m_operands[1].m_type = cot_byte; + } + + /* skip the right paren */ + eat_spaces (&u); + u++; + + eat_spaces (&u); + + t = u; + } + + mem_free ((void **) (void *) &keyword); + } + + if (*t == '\'') + { + byte *temp = NULL; + + if (get_string (&t, &temp)) + { + spec_destroy (&s); + return 1; + } + eat_spaces (&t); + + if (*t == '-') + { + byte *temp2 = NULL; + + /* skip the '-' character */ + t++; + eat_spaces (&t); + + if (get_string (&t, &temp2)) + { + mem_free ((void **) (void *) &temp); + spec_destroy (&s); + return 1; + } + eat_spaces (&t); + + s->m_spec_type = st_byte_range; + s->m_byte[0] = *temp; + s->m_byte[1] = *temp2; + + mem_free ((void **) (void *) &temp2); + } + else + { + s->m_spec_type = st_byte; + *s->m_byte = *temp; + } + + mem_free ((void **) (void *) &temp); + } + else if (*t == '"') + { + if (get_string (&t, &s->m_string)) + { + spec_destroy (&s); + return 1; + } + eat_spaces (&t); + + s->m_spec_type = st_string; + } + else if (*t == '.') + { + byte *keyword = NULL; + + /* skip the dot */ + t++; + + if (get_identifier (&t, &keyword)) + { + spec_destroy (&s); + return 1; + } + eat_spaces (&t); + + /* .true */ + if (str_equal ((byte *) "true", keyword)) + { + s->m_spec_type = st_true; + } + /* .false */ + else if (str_equal ((byte *) "false", keyword)) + { + s->m_spec_type = st_false; + } + /* .debug */ + else if (str_equal ((byte *) "debug", keyword)) + { + s->m_spec_type = st_debug; + } + /* .loop */ + else if (str_equal ((byte *) "loop", keyword)) + { + if (get_identifier (&t, &s->m_string)) + { + mem_free ((void **) (void *) &keyword); + spec_destroy (&s); + return 1; + } + eat_spaces (&t); + + s->m_spec_type = st_identifier_loop; + } + mem_free ((void **) (void *) &keyword); + } + else + { + if (get_identifier (&t, &s->m_string)) + { + spec_destroy (&s); + return 1; + } + eat_spaces (&t); + + s->m_spec_type = st_identifier; + } + + if (get_error (&t, &s->m_errtext, maps)) + { + spec_destroy (&s); + return 1; + } + + if (get_emits (&t, &s->m_emits, mapb)) + { + spec_destroy (&s); + return 1; + } + + *text = t; + *sp = s; + return 0; +} + +/* + returns 0 on success, + returns 1 otherwise, +*/ +static int get_rule (const byte **text, rule **ru, map_str *maps, map_byte *mapb) +{ + const byte *t = *text; + rule *r = NULL; + + rule_create (&r); + if (r == NULL) + return 1; + + if (get_spec (&t, &r->m_specs, maps, mapb)) + { + rule_destroy (&r); + return 1; + } + + while (*t != ';') + { + byte *op = NULL; + spec *sp = NULL; + + /* skip the dot that precedes "and" or "or" */ + t++; + + /* read "and" or "or" keyword */ + if (get_identifier (&t, &op)) + { + rule_destroy (&r); + return 1; + } + eat_spaces (&t); + + if (r->m_oper == op_none) + { + /* .and */ + if (str_equal ((byte *) "and", op)) + r->m_oper = op_and; + /* .or */ + else + r->m_oper = op_or; + } + + mem_free ((void **) (void *) &op); + + if (get_spec (&t, &sp, maps, mapb)) + { + rule_destroy (&r); + return 1; + } + + spec_append (&r->m_specs, sp); + } + + /* skip the semicolon */ + t++; + eat_spaces (&t); + + *text = t; + *ru = r; + return 0; +} + +/* + returns 0 on success, + returns 1 otherwise, +*/ +static int update_dependency (map_rule *mapr, byte *symbol, rule **ru) +{ + if (map_rule_find (&mapr, symbol, ru)) + return 1; + + (**ru).m_referenced = 1; + + return 0; +} + +/* + returns 0 on success, + returns 1 otherwise, +*/ +static int update_dependencies (dict *di, map_rule *mapr, byte **syntax_symbol, + byte **string_symbol, map_byte *regbytes) +{ + rule *rulez = di->m_rulez; + + /* update dependecies for the root and lexer symbols */ + if (update_dependency (mapr, *syntax_symbol, &di->m_syntax) || + (*string_symbol != NULL && update_dependency (mapr, *string_symbol, &di->m_string))) + return 1; + + mem_free ((void **) syntax_symbol); + mem_free ((void **) string_symbol); + + /* update dependecies for the rest of the rules */ + while (rulez) + { + spec *sp = rulez->m_specs; + + /* iterate through all the specifiers */ + while (sp) + { + /* update dependency for identifier */ + if (sp->m_spec_type == st_identifier || sp->m_spec_type == st_identifier_loop) + { + if (update_dependency (mapr, sp->m_string, &sp->m_rule)) + return 1; + + mem_free ((void **) &sp->m_string); + } + + /* some errtexts reference to a rule */ + if (sp->m_errtext && sp->m_errtext->m_token_name) + { + if (update_dependency (mapr, sp->m_errtext->m_token_name, &sp->m_errtext->m_token)) + return 1; + + mem_free ((void **) &sp->m_errtext->m_token_name); + } + + /* update dependency for condition */ + if (sp->m_cond) + { + int i; + for (i = 0; i < 2; i++) + if (sp->m_cond->m_operands[i].m_type == cot_regbyte) + { + sp->m_cond->m_operands[i].m_regbyte = map_byte_locate (®bytes, + sp->m_cond->m_operands[i].m_regname); + + if (sp->m_cond->m_operands[i].m_regbyte == NULL) + return 1; + + mem_free ((void **) &sp->m_cond->m_operands[i].m_regname); + } + } + + /* update dependency for all .load instructions */ + if (sp->m_emits) + { + emit *em = sp->m_emits; + while (em != NULL) + { + if (em->m_emit_dest == ed_regbyte) + { + em->m_regbyte = map_byte_locate (®bytes, em->m_regname); + + if (em->m_regbyte == NULL) + return 1; + + mem_free ((void **) &em->m_regname); + } + + em = em->m_next; + } + } + + sp = sp->next; + } + + rulez = rulez->next; + } + + /* check for unreferenced symbols */ + rulez = di->m_rulez; + while (rulez != NULL) + { + if (!rulez->m_referenced) + { + map_rule *ma = mapr; + while (ma) + { + if (ma->data == rulez) + { + set_last_error (UNREFERENCED_IDENTIFIER, str_duplicate (ma->key), -1); + return 1; + } + ma = ma->next; + } + } + rulez = rulez->next; + } + + return 0; +} + +static int satisfies_condition (cond *co, regbyte_ctx *ctx) +{ + byte values[2]; + int i; + + if (co == NULL) + return 1; + + for (i = 0; i < 2; i++) + switch (co->m_operands[i].m_type) + { + case cot_byte: + values[i] = co->m_operands[i].m_byte; + break; + case cot_regbyte: + values[i] = regbyte_ctx_extract (&ctx, co->m_operands[i].m_regbyte); + break; + } + + switch (co->m_type) + { + case ct_equal: + return values[0] == values[1]; + case ct_not_equal: + return values[0] != values[1]; + } + + return 0; +} + +static void free_regbyte_ctx_stack (regbyte_ctx *top, regbyte_ctx *limit) +{ + while (top != limit) + { + regbyte_ctx *rbc = top->m_prev; + regbyte_ctx_destroy (&top); + top = rbc; + } +} + +typedef enum match_result_ +{ + mr_not_matched, /* the examined string does not match */ + mr_matched, /* the examined string matches */ + mr_error_raised, /* mr_not_matched + error has been raised */ + mr_dont_emit, /* used by identifier loops only */ + mr_internal_error /* an internal error has occured such as out of memory */ +} match_result; + +/* + * This function does the main job. It parses the text and generates output data. + */ +static match_result +match (dict *di, const byte *text, int *index, rule *ru, barray **ba, int filtering_string, + regbyte_ctx **rbc) +{ + int ind = *index; + match_result status = mr_not_matched; + spec *sp = ru->m_specs; + regbyte_ctx *ctx = *rbc; + + /* for every specifier in the rule */ + while (sp) + { + int i, len, save_ind = ind; + barray *array = NULL; + + if (satisfies_condition (sp->m_cond, ctx)) + { + switch (sp->m_spec_type) + { + case st_identifier: + barray_create (&array); + if (array == NULL) + { + free_regbyte_ctx_stack (ctx, *rbc); + return mr_internal_error; + } + + status = match (di, text, &ind, sp->m_rule, &array, filtering_string, &ctx); + + if (status == mr_internal_error) + { + free_regbyte_ctx_stack (ctx, *rbc); + barray_destroy (&array); + return mr_internal_error; + } + break; + case st_string: + len = str_length (sp->m_string); + + /* prefilter the stream */ + if (!filtering_string && di->m_string) + { + barray *ba; + int filter_index = 0; + match_result result; + regbyte_ctx *null_ctx = NULL; + + barray_create (&ba); + if (ba == NULL) + { + free_regbyte_ctx_stack (ctx, *rbc); + return mr_internal_error; + } + + result = match (di, text + ind, &filter_index, di->m_string, &ba, 1, &null_ctx); + + if (result == mr_internal_error) + { + free_regbyte_ctx_stack (ctx, *rbc); + barray_destroy (&ba); + return mr_internal_error; + } + + if (result != mr_matched) + { + barray_destroy (&ba); + status = mr_not_matched; + break; + } + + barray_destroy (&ba); + + if (filter_index != len || !str_equal_n (sp->m_string, text + ind, len)) + { + status = mr_not_matched; + break; + } + + status = mr_matched; + ind += len; + } + else + { + status = mr_matched; + for (i = 0; status == mr_matched && i < len; i++) + if (text[ind + i] != sp->m_string[i]) + status = mr_not_matched; + + if (status == mr_matched) + ind += len; + } + break; + case st_byte: + status = text[ind] == *sp->m_byte ? mr_matched : mr_not_matched; + if (status == mr_matched) + ind++; + break; + case st_byte_range: + status = (text[ind] >= sp->m_byte[0] && text[ind] <= sp->m_byte[1]) ? + mr_matched : mr_not_matched; + if (status == mr_matched) + ind++; + break; + case st_true: + status = mr_matched; + break; + case st_false: + status = mr_not_matched; + break; + case st_debug: + status = ru->m_oper == op_and ? mr_matched : mr_not_matched; + break; + case st_identifier_loop: + barray_create (&array); + if (array == NULL) + { + free_regbyte_ctx_stack (ctx, *rbc); + return mr_internal_error; + } + + status = mr_dont_emit; + for (;;) + { + match_result result; + + save_ind = ind; + result = match (di, text, &ind, sp->m_rule, &array, filtering_string, &ctx); + + if (result == mr_error_raised) + { + status = result; + break; + } + else if (result == mr_matched) + { + if (barray_push (ba, sp->m_emits, text[ind - 1], save_ind, &ctx) || + barray_append (ba, &array)) + { + free_regbyte_ctx_stack (ctx, *rbc); + barray_destroy (&array); + return mr_internal_error; + } + barray_destroy (&array); + barray_create (&array); + if (array == NULL) + { + free_regbyte_ctx_stack (ctx, *rbc); + return mr_internal_error; + } + } + else if (result == mr_internal_error) + { + free_regbyte_ctx_stack (ctx, *rbc); + barray_destroy (&array); + return mr_internal_error; + } + else + break; + } + break; + } + } + else + { + status = mr_not_matched; + } + + if (status == mr_error_raised) + { + free_regbyte_ctx_stack (ctx, *rbc); + barray_destroy (&array); + + return mr_error_raised; + } + + if (ru->m_oper == op_and && status != mr_matched && status != mr_dont_emit) + { + free_regbyte_ctx_stack (ctx, *rbc); + barray_destroy (&array); + + if (sp->m_errtext) + { + set_last_error (sp->m_errtext->m_text, error_get_token (sp->m_errtext, di, text, + ind), ind); + + return mr_error_raised; + } + + return mr_not_matched; + } + + if (status == mr_matched) + { + if (sp->m_emits) + if (barray_push (ba, sp->m_emits, text[ind - 1], save_ind, &ctx)) + { + free_regbyte_ctx_stack (ctx, *rbc); + barray_destroy (&array); + return mr_internal_error; + } + + if (array) + if (barray_append (ba, &array)) + { + free_regbyte_ctx_stack (ctx, *rbc); + barray_destroy (&array); + return mr_internal_error; + } + } + + barray_destroy (&array); + + /* if the rule operator is a logical or, we pick up the first matching specifier */ + if (ru->m_oper == op_or && (status == mr_matched || status == mr_dont_emit)) + { + *index = ind; + *rbc = ctx; + return mr_matched; + } + + sp = sp->next; + } + + /* everything went fine - all specifiers match up */ + if (ru->m_oper == op_and && (status == mr_matched || status == mr_dont_emit)) + { + *index = ind; + *rbc = ctx; + return mr_matched; + } + + free_regbyte_ctx_stack (ctx, *rbc); + return mr_not_matched; +} + +static match_result +fast_match (dict *di, const byte *text, int *index, rule *ru, int *_PP, bytepool *_BP, + int filtering_string, regbyte_ctx **rbc) +{ + int ind = *index; + int _P = filtering_string ? 0 : *_PP; + int _P2; + match_result status = mr_not_matched; + spec *sp = ru->m_specs; + regbyte_ctx *ctx = *rbc; + + /* for every specifier in the rule */ + while (sp) + { + int i, len, save_ind = ind; + + _P2 = _P + (sp->m_emits ? emit_size (sp->m_emits) : 0); + if (bytepool_reserve (_BP, _P2)) + { + free_regbyte_ctx_stack (ctx, *rbc); + return mr_internal_error; + } + + if (satisfies_condition (sp->m_cond, ctx)) + { + switch (sp->m_spec_type) + { + case st_identifier: + status = fast_match (di, text, &ind, sp->m_rule, &_P2, _BP, filtering_string, &ctx); + + if (status == mr_internal_error) + { + free_regbyte_ctx_stack (ctx, *rbc); + return mr_internal_error; + } + break; + case st_string: + len = str_length (sp->m_string); + + /* prefilter the stream */ + if (!filtering_string && di->m_string) + { + int filter_index = 0; + match_result result; + regbyte_ctx *null_ctx = NULL; + + result = fast_match (di, text + ind, &filter_index, di->m_string, NULL, _BP, 1, &null_ctx); + + if (result == mr_internal_error) + { + free_regbyte_ctx_stack (ctx, *rbc); + return mr_internal_error; + } + + if (result != mr_matched) + { + status = mr_not_matched; + break; + } + + if (filter_index != len || !str_equal_n (sp->m_string, text + ind, len)) + { + status = mr_not_matched; + break; + } + + status = mr_matched; + ind += len; + } + else + { + status = mr_matched; + for (i = 0; status == mr_matched && i < len; i++) + if (text[ind + i] != sp->m_string[i]) + status = mr_not_matched; + + if (status == mr_matched) + ind += len; + } + break; + case st_byte: + status = text[ind] == *sp->m_byte ? mr_matched : mr_not_matched; + if (status == mr_matched) + ind++; + break; + case st_byte_range: + status = (text[ind] >= sp->m_byte[0] && text[ind] <= sp->m_byte[1]) ? + mr_matched : mr_not_matched; + if (status == mr_matched) + ind++; + break; + case st_true: + status = mr_matched; + break; + case st_false: + status = mr_not_matched; + break; + case st_debug: + status = ru->m_oper == op_and ? mr_matched : mr_not_matched; + break; + case st_identifier_loop: + status = mr_dont_emit; + for (;;) + { + match_result result; + + save_ind = ind; + result = fast_match (di, text, &ind, sp->m_rule, &_P2, _BP, filtering_string, &ctx); + + if (result == mr_error_raised) + { + status = result; + break; + } + else if (result == mr_matched) + { + if (!filtering_string) + { + if (sp->m_emits != NULL) + { + if (emit_push (sp->m_emits, _BP->_F + _P, text[ind - 1], save_ind, &ctx)) + { + free_regbyte_ctx_stack (ctx, *rbc); + return mr_internal_error; + } + } + + _P = _P2; + _P2 += sp->m_emits ? emit_size (sp->m_emits) : 0; + if (bytepool_reserve (_BP, _P2)) + { + free_regbyte_ctx_stack (ctx, *rbc); + return mr_internal_error; + } + } + } + else if (result == mr_internal_error) + { + free_regbyte_ctx_stack (ctx, *rbc); + return mr_internal_error; + } + else + break; + } + break; + } + } + else + { + status = mr_not_matched; + } + + if (status == mr_error_raised) + { + free_regbyte_ctx_stack (ctx, *rbc); + + return mr_error_raised; + } + + if (ru->m_oper == op_and && status != mr_matched && status != mr_dont_emit) + { + free_regbyte_ctx_stack (ctx, *rbc); + + if (sp->m_errtext) + { + set_last_error (sp->m_errtext->m_text, error_get_token (sp->m_errtext, di, text, + ind), ind); + + return mr_error_raised; + } + + return mr_not_matched; + } + + if (status == mr_matched) + { + if (sp->m_emits != NULL) { + const byte ch = (ind <= 0) ? 0 : text[ind - 1]; + if (emit_push (sp->m_emits, _BP->_F + _P, ch, save_ind, &ctx)) + { + free_regbyte_ctx_stack (ctx, *rbc); + return mr_internal_error; + } + + } + _P = _P2; + } + + /* if the rule operator is a logical or, we pick up the first matching specifier */ + if (ru->m_oper == op_or && (status == mr_matched || status == mr_dont_emit)) + { + *index = ind; + *rbc = ctx; + if (!filtering_string) + *_PP = _P; + return mr_matched; + } + + sp = sp->next; + } + + /* everything went fine - all specifiers match up */ + if (ru->m_oper == op_and && (status == mr_matched || status == mr_dont_emit)) + { + *index = ind; + *rbc = ctx; + if (!filtering_string) + *_PP = _P; + return mr_matched; + } + + free_regbyte_ctx_stack (ctx, *rbc); + return mr_not_matched; +} + +static byte * +error_get_token (error *er, dict *di, const byte *text, int ind) +{ + byte *str = NULL; + + if (er->m_token) + { + barray *ba; + int filter_index = 0; + regbyte_ctx *ctx = NULL; + + barray_create (&ba); + if (ba != NULL) + { + if (match (di, text + ind, &filter_index, er->m_token, &ba, 0, &ctx) == mr_matched && + filter_index) + { + str = (byte *) mem_alloc (filter_index + 1); + if (str != NULL) + { + str_copy_n (str, text + ind, filter_index); + str[filter_index] = '\0'; + } + } + barray_destroy (&ba); + } + } + + return str; +} + +typedef struct grammar_load_state_ +{ + dict *di; + byte *syntax_symbol; + byte *string_symbol; + map_str *maps; + map_byte *mapb; + map_rule *mapr; +} grammar_load_state; + +static void grammar_load_state_create (grammar_load_state **gr) +{ + *gr = (grammar_load_state *) mem_alloc (sizeof (grammar_load_state)); + if (*gr) + { + (**gr).di = NULL; + (**gr).syntax_symbol = NULL; + (**gr).string_symbol = NULL; + (**gr).maps = NULL; + (**gr).mapb = NULL; + (**gr).mapr = NULL; + } +} + +static void grammar_load_state_destroy (grammar_load_state **gr) +{ + if (*gr) + { + dict_destroy (&(**gr).di); + mem_free ((void **) &(**gr).syntax_symbol); + mem_free ((void **) &(**gr).string_symbol); + map_str_destroy (&(**gr).maps); + map_byte_destroy (&(**gr).mapb); + map_rule_destroy (&(**gr).mapr); + mem_free ((void **) gr); + } +} + + +static void error_msg(int line, const char *msg) +{ + fprintf(stderr, "Error in grammar_load_from_text() at line %d: %s\n", line, msg); +} + + +/* + the API +*/ +grammar grammar_load_from_text (const byte *text) +{ + grammar_load_state *g = NULL; + grammar id = 0; + + clear_last_error (); + + grammar_load_state_create (&g); + if (g == NULL) { + error_msg(__LINE__, ""); + return 0; + } + + dict_create (&g->di); + if (g->di == NULL) + { + grammar_load_state_destroy (&g); + error_msg(__LINE__, ""); + return 0; + } + + eat_spaces (&text); + + /* skip ".syntax" keyword */ + text += 7; + eat_spaces (&text); + + /* retrieve root symbol */ + if (get_identifier (&text, &g->syntax_symbol)) + { + grammar_load_state_destroy (&g); + error_msg(__LINE__, ""); + return 0; + } + eat_spaces (&text); + + /* skip semicolon */ + text++; + eat_spaces (&text); + + while (*text) + { + byte *symbol = NULL; + int is_dot = *text == '.'; + + if (is_dot) + text++; + + if (get_identifier (&text, &symbol)) + { + grammar_load_state_destroy (&g); + error_msg(__LINE__, ""); + return 0; + } + eat_spaces (&text); + + /* .emtcode */ + if (is_dot && str_equal (symbol, (byte *) "emtcode")) + { + map_byte *ma = NULL; + + mem_free ((void **) (void *) &symbol); + + if (get_emtcode (&text, &ma)) + { + grammar_load_state_destroy (&g); + error_msg(__LINE__, ""); + return 0; + } + + map_byte_append (&g->mapb, ma); + } + /* .regbyte */ + else if (is_dot && str_equal (symbol, (byte *) "regbyte")) + { + map_byte *ma = NULL; + + mem_free ((void **) (void *) &symbol); + + if (get_regbyte (&text, &ma)) + { + grammar_load_state_destroy (&g); + error_msg(__LINE__, ""); + return 0; + } + + map_byte_append (&g->di->m_regbytes, ma); + } + /* .errtext */ + else if (is_dot && str_equal (symbol, (byte *) "errtext")) + { + map_str *ma = NULL; + + mem_free ((void **) (void *) &symbol); + + if (get_errtext (&text, &ma)) + { + grammar_load_state_destroy (&g); + error_msg(__LINE__, ""); + return 0; + } + + map_str_append (&g->maps, ma); + } + /* .string */ + else if (is_dot && str_equal (symbol, (byte *) "string")) + { + mem_free ((void **) (void *) &symbol); + + if (g->di->m_string != NULL) + { + grammar_load_state_destroy (&g); + error_msg(__LINE__, ""); + return 0; + } + + if (get_identifier (&text, &g->string_symbol)) + { + grammar_load_state_destroy (&g); + error_msg(__LINE__, ""); + return 0; + } + + /* skip semicolon */ + eat_spaces (&text); + text++; + eat_spaces (&text); + } + else + { + rule *ru = NULL; + map_rule *ma = NULL; + + if (get_rule (&text, &ru, g->maps, g->mapb)) + { + grammar_load_state_destroy (&g); + error_msg(__LINE__, ""); + return 0; + } + + rule_append (&g->di->m_rulez, ru); + + /* if a rule consist of only one specifier, give it an ".and" operator */ + if (ru->m_oper == op_none) + ru->m_oper = op_and; + + map_rule_create (&ma); + if (ma == NULL) + { + grammar_load_state_destroy (&g); + error_msg(__LINE__, ""); + return 0; + } + + ma->key = symbol; + ma->data = ru; + map_rule_append (&g->mapr, ma); + } + } + + if (update_dependencies (g->di, g->mapr, &g->syntax_symbol, &g->string_symbol, + g->di->m_regbytes)) + { + grammar_load_state_destroy (&g); + error_msg(__LINE__, "update_dependencies() failed"); + return 0; + } + + dict_append (&g_dicts, g->di); + id = g->di->m_id; + g->di = NULL; + + grammar_load_state_destroy (&g); + + return id; +} + +int grammar_set_reg8 (grammar id, const byte *name, byte value) +{ + dict *di = NULL; + map_byte *reg = NULL; + + clear_last_error (); + + dict_find (&g_dicts, id, &di); + if (di == NULL) + { + set_last_error (INVALID_GRAMMAR_ID, NULL, -1); + return 0; + } + + reg = map_byte_locate (&di->m_regbytes, name); + if (reg == NULL) + { + set_last_error (INVALID_REGISTER_NAME, str_duplicate (name), -1); + return 0; + } + + reg->data = value; + return 1; +} + +/* + internal checking function used by both grammar_check and grammar_fast_check functions +*/ +static int _grammar_check (grammar id, const byte *text, byte **prod, unsigned int *size, + unsigned int estimate_prod_size, int use_fast_path) +{ + dict *di = NULL; + int index = 0; + + clear_last_error (); + + dict_find (&g_dicts, id, &di); + if (di == NULL) + { + set_last_error (INVALID_GRAMMAR_ID, NULL, -1); + return 0; + } + + *prod = NULL; + *size = 0; + + if (use_fast_path) + { + regbyte_ctx *rbc = NULL; + bytepool *bp = NULL; + int _P = 0; + + bytepool_create (&bp, estimate_prod_size); + if (bp == NULL) + return 0; + + if (fast_match (di, text, &index, di->m_syntax, &_P, bp, 0, &rbc) != mr_matched) + { + bytepool_destroy (&bp); + free_regbyte_ctx_stack (rbc, NULL); + return 0; + } + + free_regbyte_ctx_stack (rbc, NULL); + + *prod = bp->_F; + *size = _P; + bp->_F = NULL; + bytepool_destroy (&bp); + } + else + { + regbyte_ctx *rbc = NULL; + barray *ba = NULL; + + barray_create (&ba); + if (ba == NULL) + return 0; + + if (match (di, text, &index, di->m_syntax, &ba, 0, &rbc) != mr_matched) + { + barray_destroy (&ba); + free_regbyte_ctx_stack (rbc, NULL); + return 0; + } + + free_regbyte_ctx_stack (rbc, NULL); + + *prod = (byte *) mem_alloc (ba->len * sizeof (byte)); + if (*prod == NULL) + { + barray_destroy (&ba); + return 0; + } + + mem_copy (*prod, ba->data, ba->len * sizeof (byte)); + *size = ba->len; + barray_destroy (&ba); + } + + return 1; +} + +int grammar_check (grammar id, const byte *text, byte **prod, unsigned int *size) +{ + return _grammar_check (id, text, prod, size, 0, 0); +} + +int grammar_fast_check (grammar id, const byte *text, byte **prod, unsigned int *size, + unsigned int estimate_prod_size) +{ + return _grammar_check (id, text, prod, size, estimate_prod_size, 1); +} + +int grammar_destroy (grammar id) +{ + dict **di = &g_dicts; + + clear_last_error (); + + while (*di != NULL) + { + if ((**di).m_id == id) + { + dict *tmp = *di; + *di = (**di).next; + dict_destroy (&tmp); + return 1; + } + + di = &(**di).next; + } + + set_last_error (INVALID_GRAMMAR_ID, NULL, -1); + return 0; +} + +static void append_character (const char x, byte *text, int *dots_made, int *len, int size) +{ + if (*dots_made == 0) + { + if (*len < size - 1) + { + text[(*len)++] = x; + text[*len] = '\0'; + } + else + { + int i; + for (i = 0; i < 3; i++) + if (--(*len) >= 0) + text[*len] = '.'; + *dots_made = 1; + } + } +} + +void grammar_get_last_error (byte *text, unsigned int size, int *pos) +{ + int len = 0, dots_made = 0; + const byte *p = error_message; + + *text = '\0'; + + if (p) + { + while (*p) + { + if (*p == '$') + { + const byte *r = error_param; + + while (*r) + { + append_character (*r++, text, &dots_made, &len, (int) size); + } + + p++; + } + else + { + append_character (*p++, text, &dots_made, &len, size); + } + } + } + + *pos = error_position; +} diff --git a/mesalib/src/mesa/shader/grammar/grammar.h b/mesalib/src/mesa/shader/grammar/grammar.h new file mode 100644 index 000000000..591e38aef --- /dev/null +++ b/mesalib/src/mesa/shader/grammar/grammar.h @@ -0,0 +1,103 @@ +/* + * Mesa 3-D graphics library + * Version: 6.2 + * + * Copyright (C) 1999-2004 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GRAMMAR_H +#define GRAMMAR_H + + +#ifndef GRAMMAR_PORT_INCLUDE +#error Do not include this file directly, include your grammar_XXX.h instead +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +void grammar_alloc_free (void *); +void *grammar_alloc_malloc (size_t); +void *grammar_alloc_realloc (void *, size_t, size_t); +void *grammar_memory_copy (void *, const void *, size_t); +int grammar_string_compare (const byte *, const byte *); +int grammar_string_compare_n (const byte *, const byte *, size_t); +byte *grammar_string_copy (byte *, const byte *); +byte *grammar_string_copy_n (byte *, const byte *, size_t); +byte *grammar_string_duplicate (const byte *); +unsigned int grammar_string_length (const byte *); + +/* + loads grammar script from null-terminated ASCII <text> + returns unique grammar id to grammar object + returns 0 if an error occurs (call grammar_get_last_error to retrieve the error text) +*/ +grammar grammar_load_from_text (const byte *text); + +/* + sets a new <value> to a register <name> for grammar <id> + returns 0 on error (call grammar_get_last_error to retrieve the error text) + returns 1 on success +*/ +int grammar_set_reg8 (grammar id, const byte *name, byte value); + +/* + this function is obsolete, use only for debugging purposes + + checks if a null-terminated <text> matches given grammar <id> + returns 0 on error (call grammar_get_last_error to retrieve the error text) + returns 1 on success, the <prod> points to newly allocated buffer with production and <size> + is filled with the production size + call grammar_alloc_free to free the memory block pointed by <prod> +*/ +int grammar_check (grammar id, const byte *text, byte **prod, unsigned int *size); + +/* + does the same what grammar_check does but much more (approx. 4 times) faster + use this function instead of grammar_check + <estimate_prod_size> is a hint - the initial production buffer size will be of this size, + but if more room is needed it will be safely resized; set it to 0x1000 or so +*/ +int grammar_fast_check (grammar id, const byte *text, byte **prod, unsigned int *size, + unsigned int estimate_prod_size); + +/* + destroys grammar object identified by <id> + returns 0 on error (call grammar_get_last_error to retrieve the error text) + returns 1 on success +*/ +int grammar_destroy (grammar id); + +/* + retrieves last grammar error reported either by grammar_load_from_text, grammar_check + or grammar_destroy + the user allocated <text> buffer receives error description, <pos> points to error position, + <size> is the size of the text buffer to fill in - it must be at least 4 bytes long, +*/ +void grammar_get_last_error (byte *text, unsigned int size, int *pos); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/mesalib/src/mesa/shader/grammar/grammar_crt.c b/mesalib/src/mesa/shader/grammar/grammar_crt.c new file mode 100644 index 000000000..d2c95d1c8 --- /dev/null +++ b/mesalib/src/mesa/shader/grammar/grammar_crt.c @@ -0,0 +1,64 @@ +#include "grammar_crt.h" + +#define GRAMMAR_PORT_BUILD 1 +#include "grammar.c" +#undef GRAMMAR_PORT_BUILD + + +void grammar_alloc_free (void *ptr) +{ + free (ptr); +} + +void *grammar_alloc_malloc (size_t size) +{ + return malloc (size); +} + +void *grammar_alloc_realloc (void *ptr, size_t old_size, size_t size) +{ + return realloc (ptr, size); +} + +void *grammar_memory_copy (void *dst, const void * src, size_t size) +{ + return memcpy (dst, src, size); +} + +int grammar_string_compare (const byte *str1, const byte *str2) +{ + return strcmp ((const char *) str1, (const char *) str2); +} + +int grammar_string_compare_n (const byte *str1, const byte *str2, size_t n) +{ + return strncmp ((const char *) str1, (const char *) str2, n); +} + +byte *grammar_string_copy (byte *dst, const byte *src) +{ + return (byte *) strcpy ((char *) dst, (const char *) src); +} + +byte *grammar_string_copy_n (byte *dst, const byte *src, size_t n) +{ + return (byte *) strncpy ((char *) dst, (const char *) src, n); +} + +unsigned int grammar_string_length (const byte *str) +{ + return strlen ((const char *) str); +} + +byte *grammar_string_duplicate (const byte *src) +{ + const unsigned int size = grammar_string_length (src); + byte *str = grammar_alloc_malloc (size + 1); + if (str != NULL) + { + grammar_memory_copy (str, src, size); + str[size] = '\0'; + } + return str; +} + diff --git a/mesalib/src/mesa/shader/grammar/grammar_crt.h b/mesalib/src/mesa/shader/grammar/grammar_crt.h new file mode 100644 index 000000000..492711e96 --- /dev/null +++ b/mesalib/src/mesa/shader/grammar/grammar_crt.h @@ -0,0 +1,20 @@ +#ifndef GRAMMAR_CRT_H +#define GRAMMAR_CRT_H + + +#include <stdlib.h> +#include <malloc.h> +#include <string.h> + + +typedef unsigned long grammar; +typedef unsigned char byte; + + +#define GRAMMAR_PORT_INCLUDE 1 +#include "grammar.h" +#undef GRAMMAR_PORT_INCLUDE + + +#endif + diff --git a/mesalib/src/mesa/shader/grammar/grammar_mesa.c b/mesalib/src/mesa/shader/grammar/grammar_mesa.c new file mode 100644 index 000000000..eb962505b --- /dev/null +++ b/mesalib/src/mesa/shader/grammar/grammar_mesa.c @@ -0,0 +1,87 @@ +/* + * Mesa 3-D graphics library + * Version: 6.1 + * + * Copyright (C) 1999-2004 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file grammar_mesa.c + * mesa3d port to syntax parsing engine + * \author Michal Krol + */ + +#include "grammar_mesa.h" + +#define GRAMMAR_PORT_BUILD 1 +#include "grammar.c" +#undef GRAMMAR_PORT_BUILD + + +void grammar_alloc_free (void *ptr) +{ + _mesa_free (ptr); +} + +void *grammar_alloc_malloc (size_t size) +{ + return _mesa_malloc (size); +} + +void *grammar_alloc_realloc (void *ptr, size_t old_size, size_t size) +{ + return _mesa_realloc (ptr, old_size, size); +} + +void *grammar_memory_copy (void *dst, const void * src, size_t size) +{ + return _mesa_memcpy (dst, src, size); +} + +int grammar_string_compare (const byte *str1, const byte *str2) +{ + return _mesa_strcmp ((const char *) str1, (const char *) str2); +} + +int grammar_string_compare_n (const byte *str1, const byte *str2, size_t n) +{ + return _mesa_strncmp ((const char *) str1, (const char *) str2, n); +} + +byte *grammar_string_copy (byte *dst, const byte *src) +{ + return (byte *) _mesa_strcpy ((char *) dst, (const char *) src); +} + +byte *grammar_string_copy_n (byte *dst, const byte *src, size_t n) +{ + return (byte *) _mesa_strncpy ((char *) dst, (const char *) src, n); +} + +byte *grammar_string_duplicate (const byte *src) +{ + return (byte *) _mesa_strdup ((const char *) src); +} + +unsigned int grammar_string_length (const byte *str) +{ + return (unsigned int)_mesa_strlen ((const char *) str); +} + diff --git a/mesalib/src/mesa/shader/grammar/grammar_mesa.h b/mesalib/src/mesa/shader/grammar/grammar_mesa.h new file mode 100644 index 000000000..6c92c5812 --- /dev/null +++ b/mesalib/src/mesa/shader/grammar/grammar_mesa.h @@ -0,0 +1,43 @@ +/* + * Mesa 3-D graphics library + * Version: 6.1 + * + * Copyright (C) 1999-2004 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef GRAMMAR_MESA_H +#define GRAMMAR_MESA_H + + +#include "main/imports.h" +/* NOTE: include Mesa 3-D specific headers here */ + + +typedef GLuint grammar; +typedef GLubyte byte; + + +#define GRAMMAR_PORT_INCLUDE 1 +#include "grammar.h" +#undef GRAMMAR_PORT_INCLUDE + + +#endif + diff --git a/mesalib/src/mesa/shader/grammar/grammar_syn.h b/mesalib/src/mesa/shader/grammar/grammar_syn.h new file mode 100644 index 000000000..840a1ab62 --- /dev/null +++ b/mesalib/src/mesa/shader/grammar/grammar_syn.h @@ -0,0 +1,202 @@ +".syntax grammar;\n" +".emtcode DECLARATION_END 0\n" +".emtcode DECLARATION_EMITCODE 1\n" +".emtcode DECLARATION_ERRORTEXT 2\n" +".emtcode DECLARATION_REGBYTE 3\n" +".emtcode DECLARATION_LEXER 4\n" +".emtcode DECLARATION_RULE 5\n" +".emtcode SPECIFIER_END 0\n" +".emtcode SPECIFIER_AND_TAG 1\n" +".emtcode SPECIFIER_OR_TAG 2\n" +".emtcode SPECIFIER_CHARACTER_RANGE 3\n" +".emtcode SPECIFIER_CHARACTER 4\n" +".emtcode SPECIFIER_STRING 5\n" +".emtcode SPECIFIER_IDENTIFIER 6\n" +".emtcode SPECIFIER_TRUE 7\n" +".emtcode SPECIFIER_FALSE 8\n" +".emtcode SPECIFIER_DEBUG 9\n" +".emtcode IDENTIFIER_SIMPLE 0\n" +".emtcode IDENTIFIER_LOOP 1\n" +".emtcode ERROR_NOT_PRESENT 0\n" +".emtcode ERROR_PRESENT 1\n" +".emtcode EMIT_NULL 0\n" +".emtcode EMIT_INTEGER 1\n" +".emtcode EMIT_IDENTIFIER 2\n" +".emtcode EMIT_CHARACTER 3\n" +".emtcode EMIT_LAST_CHARACTER 4\n" +".emtcode EMIT_CURRENT_POSITION 5\n" +".errtext INVALID_GRAMMAR \"internal error 2001: invalid grammar script\"\n" +".errtext SYNTAX_EXPECTED \"internal error 2002: '.syntax' keyword expected\"\n" +".errtext IDENTIFIER_EXPECTED \"internal error 2003: identifier expected\"\n" +".errtext MISSING_SEMICOLON \"internal error 2004: missing ';'\"\n" +".errtext INTEGER_EXPECTED \"internal error 2005: integer value expected\"\n" +".errtext STRING_EXPECTED \"internal error 2006: string expected\"\n" +"grammar\n" +" grammar_1 .error INVALID_GRAMMAR;\n" +"grammar_1\n" +" optional_space .and \".syntax\" .error SYNTAX_EXPECTED .and space .and identifier .and\n" +" semicolon .and declaration_list .and optional_space .and '\\0' .emit DECLARATION_END;\n" +"optional_space\n" +" space .or .true;\n" +"space\n" +" single_space .and .loop single_space;\n" +"single_space\n" +" white_char .or comment_block;\n" +"white_char\n" +" ' ' .or '\\t' .or '\\n' .or '\\r';\n" +"comment_block\n" +" '/' .and '*' .and comment_rest;\n" +"comment_rest\n" +" .loop comment_char_no_star .and comment_rest_1;\n" +"comment_rest_1\n" +" comment_end .or comment_rest_2;\n" +"comment_rest_2\n" +" '*' .and comment_rest;\n" +"comment_char_no_star\n" +" '\\x2B'-'\\xFF' .or '\\x01'-'\\x29';\n" +"comment_end\n" +" '*' .and '/';\n" +"identifier\n" +" identifier_ne .error IDENTIFIER_EXPECTED;\n" +"identifier_ne\n" +" first_idchar .emit * .and .loop follow_idchar .emit * .and .true .emit '\\0';\n" +"first_idchar\n" +" 'a'-'z' .or 'A'-'Z' .or '_';\n" +"follow_idchar\n" +" first_idchar .or digit_dec;\n" +"digit_dec\n" +" '0'-'9';\n" +"semicolon\n" +" optional_space .and ';' .error MISSING_SEMICOLON .and optional_space;\n" +"declaration_list\n" +" declaration .and .loop declaration;\n" +"declaration\n" +" emitcode_definition .emit DECLARATION_EMITCODE .or\n" +" errortext_definition .emit DECLARATION_ERRORTEXT .or\n" +" regbyte_definition .emit DECLARATION_REGBYTE .or\n" +" lexer_definition .emit DECLARATION_LEXER .or\n" +" rule_definition .emit DECLARATION_RULE;\n" +"emitcode_definition\n" +" \".emtcode\" .and space .and identifier .and space .and integer .and space_or_null;\n" +"integer\n" +" integer_ne .error INTEGER_EXPECTED;\n" +"integer_ne\n" +" hex_integer .emit 0x10 .or dec_integer .emit 10;\n" +"hex_integer\n" +" hex_prefix .and digit_hex .emit * .and .loop digit_hex .emit * .and .true .emit '\\0';\n" +"hex_prefix\n" +" '0' .and hex_prefix_1;\n" +"hex_prefix_1\n" +" 'x' .or 'X';\n" +"digit_hex\n" +" '0'-'9' .or 'a'-'f' .or 'A'-'F';\n" +"dec_integer\n" +" digit_dec .emit * .and .loop digit_dec .emit * .and .true .emit '\\0';\n" +"space_or_null\n" +" space .or '\\0';\n" +"errortext_definition\n" +" \".errtext\" .and space .and identifier .and space .and string .and space_or_null;\n" +"string\n" +" string_ne .error STRING_EXPECTED;\n" +"string_ne\n" +" '\"' .and .loop string_char_double_quotes .and '\"' .emit '\\0';\n" +"string_char_double_quotes\n" +" escape_sequence .or string_char .emit * .or '\\'' .emit *;\n" +"string_char\n" +" '\\x5D'-'\\xFF' .or '\\x28'-'\\x5B' .or '\\x23'-'\\x26' .or '\\x0E'-'\\x21' .or '\\x0B'-'\\x0C' .or\n" +" '\\x01'-'\\x09';\n" +"escape_sequence\n" +" '\\\\' .emit * .and escape_code;\n" +"escape_code\n" +" simple_escape_code .emit * .or hex_escape_code .or oct_escape_code;\n" +"simple_escape_code\n" +" '\\'' .or '\"' .or '?' .or '\\\\' .or 'a' .or 'b' .or 'f' .or 'n' .or 'r' .or 't' .or 'v';\n" +"hex_escape_code\n" +" 'x' .emit * .and digit_hex .emit * .and .loop digit_hex .emit *;\n" +"oct_escape_code\n" +" digit_oct .emit * .and optional_digit_oct .and optional_digit_oct;\n" +"digit_oct\n" +" '0'-'7';\n" +"optional_digit_oct\n" +" digit_oct .emit * .or .true;\n" +"regbyte_definition\n" +" \".regbyte\" .and space .and identifier .and space .and integer .and space_or_null;\n" +"lexer_definition\n" +" \".string\" .and space .and identifier .and semicolon;\n" +"rule_definition\n" +" identifier_ne .and space .and definition;\n" +"definition\n" +" specifier .and optional_specifiers_and_or .and semicolon .emit SPECIFIER_END;\n" +"optional_specifiers_and_or\n" +" and_specifiers .emit SPECIFIER_AND_TAG .or or_specifiers .emit SPECIFIER_OR_TAG .or .true;\n" +"specifier\n" +" specifier_condition .and optional_space .and specifier_rule;\n" +"specifier_condition\n" +" specifier_condition_1 .or .true;\n" +"specifier_condition_1\n" +" \".if\" .and optional_space .and '(' .and optional_space .and left_operand .and operator .and\n" +" right_operand .and optional_space .and ')';\n" +"left_operand\n" +" identifier;\n" +"operator\n" +" operator_1 .or operator_2;\n" +"operator_1\n" +" optional_space .and '!' .and '=' .and optional_space;\n" +"operator_2\n" +" optional_space .and '=' .and '=' .and optional_space;\n" +"right_operand\n" +" integer;\n" +"specifier_rule\n" +" specifier_rule_1 .and optional_error .and .loop emit .and .true .emit EMIT_NULL;\n" +"specifier_rule_1\n" +" character_range .emit SPECIFIER_CHARACTER_RANGE .or\n" +" character .emit SPECIFIER_CHARACTER .or\n" +" string_ne .emit SPECIFIER_STRING .or\n" +" \".true\" .emit SPECIFIER_TRUE .or\n" +" \".false\" .emit SPECIFIER_FALSE .or\n" +" \".debug\" .emit SPECIFIER_DEBUG .or\n" +" advanced_identifier .emit SPECIFIER_IDENTIFIER;\n" +"character\n" +" '\\'' .and string_char_single_quotes .and '\\'' .emit '\\0';\n" +"string_char_single_quotes\n" +" escape_sequence .or string_char .emit * .or '\"' .emit *;\n" +"character_range\n" +" character .and optional_space .and '-' .and optional_space .and character;\n" +"advanced_identifier\n" +" optional_loop .and identifier;\n" +"optional_loop\n" +" optional_loop_1 .emit IDENTIFIER_LOOP .or .true .emit IDENTIFIER_SIMPLE;\n" +"optional_loop_1\n" +" \".loop\" .and space;\n" +"optional_error\n" +" error .emit ERROR_PRESENT .or .true .emit ERROR_NOT_PRESENT;\n" +"error\n" +" space .and \".error\" .and space .and identifier;\n" +"emit\n" +" emit_output .or emit_regbyte;\n" +"emit_output\n" +" space .and \".emit\" .and space .and emit_param;\n" +"emit_param\n" +" integer_ne .emit EMIT_INTEGER .or\n" +" identifier_ne .emit EMIT_IDENTIFIER .or\n" +" character .emit EMIT_CHARACTER .or\n" +" '*' .emit EMIT_LAST_CHARACTER .or\n" +" '$' .emit EMIT_CURRENT_POSITION;\n" +"emit_regbyte\n" +" space .and \".load\" .and space .and identifier .and space .and emit_param;\n" +"and_specifiers\n" +" and_specifier .and .loop and_specifier;\n" +"or_specifiers\n" +" or_specifier .and .loop or_specifier;\n" +"and_specifier\n" +" space .and \".and\" .and space .and specifier;\n" +"or_specifier\n" +" space .and \".or\" .and space .and specifier;\n" +".string __string_filter;\n" +"__string_filter\n" +" __first_identifier_char .and .loop __next_identifier_char;\n" +"__first_identifier_char\n" +" 'a'-'z' .or 'A'-'Z' .or '_' .or '.';\n" +"__next_identifier_char\n" +" 'a'-'z' .or 'A'-'Z' .or '_' .or '0'-'9';\n" +"" diff --git a/mesalib/src/mesa/shader/hash_table.c b/mesalib/src/mesa/shader/hash_table.c new file mode 100644 index 000000000..881179f9d --- /dev/null +++ b/mesalib/src/mesa/shader/hash_table.c @@ -0,0 +1,163 @@ +/* + * 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. + */ + +/** + * \file hash_table.c + * \brief Implementation of a generic, opaque hash table data type. + * + * \author Ian Romanick <ian.d.romanick@intel.com> + */ +#include <stdlib.h> +#include <string.h> + +#include <assert.h> + +#include "main/imports.h" +#include "main/simple_list.h" +#include "hash_table.h" + +struct node { + struct node *next; + struct node *prev; +}; + +struct hash_table { + hash_func_t hash; + hash_compare_func_t compare; + + unsigned num_buckets; + struct node buckets[1]; +}; + + +struct hash_node { + struct node link; + const void *key; + void *data; +}; + + +struct hash_table * +hash_table_ctor(unsigned num_buckets, hash_func_t hash, + hash_compare_func_t compare) +{ + struct hash_table *ht; + unsigned i; + + + if (num_buckets < 16) { + num_buckets = 16; + } + + ht = _mesa_malloc(sizeof(*ht) + ((num_buckets - 1) + * sizeof(ht->buckets[0]))); + if (ht != NULL) { + ht->hash = hash; + ht->compare = compare; + ht->num_buckets = num_buckets; + + for (i = 0; i < num_buckets; i++) { + make_empty_list(& ht->buckets[i]); + } + } + + return ht; +} + + +void +hash_table_dtor(struct hash_table *ht) +{ + hash_table_clear(ht); + _mesa_free(ht); +} + + +void +hash_table_clear(struct hash_table *ht) +{ + struct node *node; + struct node *temp; + unsigned i; + + + for (i = 0; i < ht->num_buckets; i++) { + foreach_s(node, temp, & ht->buckets[i]) { + remove_from_list(node); + _mesa_free(node); + } + + assert(is_empty_list(& ht->buckets[i])); + } +} + + +void * +hash_table_find(struct hash_table *ht, const void *key) +{ + const unsigned hash_value = (*ht->hash)(key); + const unsigned bucket = hash_value % ht->num_buckets; + struct node *node; + + foreach(node, & ht->buckets[bucket]) { + struct hash_node *hn = (struct hash_node *) node; + + if ((*ht->compare)(hn->key, key) == 0) { + return hn->data; + } + } + + return NULL; +} + + +void +hash_table_insert(struct hash_table *ht, void *data, const void *key) +{ + const unsigned hash_value = (*ht->hash)(key); + const unsigned bucket = hash_value % ht->num_buckets; + struct hash_node *node; + + node = _mesa_calloc(sizeof(*node)); + + node->data = data; + node->key = key; + + insert_at_head(& ht->buckets[bucket], & node->link); +} + + +unsigned +hash_table_string_hash(const void *key) +{ + const char *str = (const char *) key; + unsigned hash = 5381; + + + while (*str != '\0') { + hash = (hash * 33) + *str; + str++; + } + + return hash; +} diff --git a/mesalib/src/mesa/shader/hash_table.h b/mesalib/src/mesa/shader/hash_table.h new file mode 100644 index 000000000..7b302f5db --- /dev/null +++ b/mesalib/src/mesa/shader/hash_table.h @@ -0,0 +1,117 @@ +/* + * 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. + */ + +/** + * \file hash_table.h + * \brief Implementation of a generic, opaque hash table data type. + * + * \author Ian Romanick <ian.d.romanick@intel.com> + */ + +#ifndef HASH_TABLE_H +#define HASH_TABLE_H + +#include <string.h> + +struct hash_table; + +typedef unsigned (*hash_func_t)(const void *key); +typedef int (*hash_compare_func_t)(const void *key1, const void *key2); + +/** + * Hash table constructor + * + * Creates a hash table with the specified number of buckets. The supplied + * \c hash and \c compare routines are used when adding elements to the table + * and when searching for elements in the table. + * + * \param num_buckets Number of buckets (bins) in the hash table. + * \param hash Function used to compute hash value of input keys. + * \param compare Function used to compare keys. + */ +extern struct hash_table *hash_table_ctor(unsigned num_buckets, + hash_func_t hash, hash_compare_func_t compare); + + +/** + * Release all memory associated with a hash table + * + * \warning + * This function cannot release memory occupied either by keys or data. + */ +extern void hash_table_dtor(struct hash_table *ht); + + +/** + * Flush all entries from a hash table + * + * \param ht Table to be cleared of its entries. + */ +extern void hash_table_clear(struct hash_table *ht); + + +/** + * Search a hash table for a specific element + * + * \param ht Table to be searched + * \param key Key of the desired element + * + * \return + * The \c data value supplied to \c hash_table_insert when the element with + * the matching key was added. If no matching key exists in the table, + * \c NULL is returned. + */ +extern void *hash_table_find(struct hash_table *ht, const void *key); + + +/** + * Add an element to a hash table + */ +extern void hash_table_insert(struct hash_table *ht, void *data, + const void *key); + + +/** + * Compute hash value of a string + * + * Computes the hash value of a string using the DJB2 algorithm developed by + * Professor Daniel J. Bernstein. It was published on comp.lang.c once upon + * a time. I was unable to find the original posting in the archives. + * + * \param key Pointer to a NUL terminated string to be hashed. + * + * \sa hash_table_string_compare + */ +extern unsigned hash_table_string_hash(const void *key); + + +/** + * Compare two strings used as keys + * + * This is just a macro wrapper around \c strcmp. + * + * \sa hash_table_string_hash + */ +#define hash_table_string_compare ((hash_compare_func_t) strcmp) + +#endif /* HASH_TABLE_H */ diff --git a/mesalib/src/mesa/shader/lex.yy.c b/mesalib/src/mesa/shader/lex.yy.c new file mode 100644 index 000000000..709426f3a --- /dev/null +++ b/mesalib/src/mesa/shader/lex.yy.c @@ -0,0 +1,3574 @@ + +#line 3 "lex.yy.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin ,yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart (FILE *input_file ,yyscan_t yyscanner ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void yypop_buffer_state (yyscan_t yyscanner ); + +static void yyensure_buffer_stack (yyscan_t yyscanner ); +static void yy_load_buffer_state (yyscan_t yyscanner ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *yyalloc (yy_size_t ,yyscan_t yyscanner ); +void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); +void yyfree (void * ,yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); +static int yy_get_next_buffer (yyscan_t yyscanner ); +static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 183 +#define YY_END_OF_BUFFER 184 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[675] = + { 0, + 0, 0, 184, 182, 180, 179, 182, 182, 152, 178, + 154, 154, 154, 154, 152, 152, 152, 152, 152, 152, + 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, + 152, 152, 152, 152, 180, 0, 0, 181, 152, 0, + 153, 155, 175, 175, 0, 0, 0, 0, 175, 0, + 0, 0, 0, 0, 0, 0, 132, 176, 133, 134, + 166, 166, 166, 166, 0, 154, 0, 140, 141, 142, + 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, + 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, + 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, + + 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, + 152, 152, 152, 152, 152, 152, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 174, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 173, 173, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 163, 163, 163, 164, 164, 165, 156, + 155, 156, 0, 157, 11, 13, 152, 15, 152, 152, + 16, 18, 152, 20, 22, 24, 26, 6, 28, 30, + 31, 33, 35, 38, 36, 40, 41, 43, 45, 47, + + 49, 51, 152, 152, 152, 53, 55, 152, 57, 59, + 61, 152, 63, 65, 67, 69, 152, 71, 73, 75, + 77, 152, 152, 152, 152, 152, 152, 0, 0, 0, + 0, 155, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 93, 94, 96, 0, 171, 0, 0, 0, + 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 170, 169, 169, 122, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 160, 160, + 161, 162, 0, 158, 152, 152, 152, 152, 152, 152, + 152, 152, 143, 152, 152, 152, 152, 152, 152, 152, + + 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, + 152, 152, 152, 144, 152, 152, 152, 152, 152, 152, + 152, 152, 10, 152, 152, 152, 152, 152, 152, 152, + 152, 152, 152, 0, 177, 0, 0, 0, 86, 87, + 0, 0, 0, 0, 0, 0, 0, 98, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 168, 0, 0, 0, + 126, 0, 128, 0, 0, 0, 0, 0, 0, 167, + 159, 152, 152, 152, 4, 152, 152, 152, 152, 152, + 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, + + 152, 152, 152, 152, 152, 152, 9, 152, 152, 152, + 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, + 152, 152, 152, 152, 82, 152, 152, 0, 0, 0, + 0, 0, 88, 89, 0, 0, 0, 0, 97, 0, + 0, 101, 104, 0, 0, 0, 0, 0, 0, 0, + 115, 116, 0, 0, 0, 0, 121, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 152, 152, 152, + 152, 152, 152, 5, 152, 152, 152, 152, 152, 152, + 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, + 152, 7, 8, 152, 152, 152, 152, 152, 152, 152, + + 152, 152, 152, 152, 152, 152, 152, 152, 152, 83, + 152, 79, 0, 0, 0, 0, 137, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 107, 0, 111, 112, + 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 130, 131, 0, 0, 138, 12, 3, 14, + 148, 149, 152, 17, 19, 21, 23, 25, 27, 29, + 32, 34, 39, 37, 42, 44, 46, 48, 50, 52, + 54, 56, 58, 60, 62, 152, 152, 152, 64, 66, + 68, 70, 72, 74, 76, 78, 152, 81, 139, 0, + 0, 84, 0, 90, 0, 0, 0, 99, 0, 0, + + 0, 0, 0, 0, 113, 0, 0, 119, 106, 0, + 0, 0, 0, 0, 0, 135, 0, 152, 145, 146, + 152, 80, 0, 0, 0, 0, 92, 95, 100, 0, + 0, 105, 0, 0, 0, 118, 0, 0, 0, 0, + 127, 129, 0, 152, 152, 2, 1, 0, 91, 0, + 103, 0, 109, 117, 0, 0, 124, 125, 136, 152, + 147, 0, 102, 0, 120, 123, 152, 85, 108, 152, + 152, 150, 151, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 5, 1, 6, 7, 1, 1, 1, 1, + 1, 1, 8, 1, 8, 9, 1, 10, 11, 12, + 13, 14, 15, 15, 15, 15, 15, 1, 1, 1, + 1, 1, 1, 1, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 7, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 1, 1, 1, 1, 41, 1, 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, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[68] = + { 0, + 1, 1, 1, 1, 1, 1, 2, 1, 3, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2 + } ; + +static yyconst flex_int16_t yy_base[678] = + { 0, + 0, 0, 954, 955, 66, 955, 948, 949, 0, 69, + 85, 128, 140, 152, 151, 58, 39, 48, 75, 927, + 158, 160, 73, 59, 71, 170, 54, 920, 890, 889, + 901, 885, 899, 898, 142, 927, 939, 955, 0, 206, + 955, 189, 168, 171, 53, 27, 66, 119, 175, 899, + 885, 123, 170, 883, 895, 183, 955, 198, 225, 99, + 212, 219, 223, 227, 285, 297, 308, 955, 955, 955, + 904, 917, 911, 165, 900, 903, 899, 914, 224, 896, + 910, 194, 896, 909, 900, 913, 890, 901, 892, 294, + 893, 884, 893, 884, 883, 884, 878, 884, 895, 881, + + 878, 890, 893, 880, 873, 889, 865, 193, 139, 885, + 861, 846, 841, 858, 834, 839, 865, 167, 854, 259, + 849, 325, 282, 851, 832, 302, 842, 838, 833, 43, + 839, 825, 841, 838, 829, 305, 309, 831, 820, 834, + 837, 819, 834, 821, 818, 825, 275, 833, 254, 299, + 317, 327, 331, 810, 827, 828, 821, 803, 310, 804, + 826, 817, 316, 327, 331, 335, 339, 343, 347, 955, + 405, 416, 422, 428, 825, 240, 849, 0, 848, 831, + 821, 820, 840, 818, 817, 816, 815, 0, 814, 0, + 813, 812, 0, 811, 810, 0, 809, 808, 807, 806, + + 805, 804, 820, 813, 826, 800, 799, 805, 797, 796, + 795, 816, 793, 792, 791, 790, 800, 788, 787, 786, + 785, 777, 776, 761, 761, 760, 759, 802, 774, 762, + 434, 442, 416, 766, 186, 763, 757, 757, 751, 764, + 764, 749, 955, 955, 764, 752, 418, 759, 281, 756, + 762, 308, 757, 955, 748, 755, 754, 757, 743, 742, + 746, 741, 278, 746, 420, 428, 430, 955, 738, 736, + 736, 744, 745, 727, 421, 732, 738, 419, 426, 430, + 434, 438, 496, 502, 752, 764, 750, 749, 742, 756, + 746, 745, 0, 744, 743, 742, 741, 740, 739, 738, + + 737, 736, 735, 734, 733, 732, 731, 730, 733, 726, + 733, 726, 725, 0, 724, 723, 722, 725, 720, 719, + 718, 717, 0, 716, 715, 714, 713, 691, 685, 690, + 696, 679, 694, 315, 955, 693, 683, 687, 955, 955, + 677, 686, 672, 689, 672, 675, 669, 955, 670, 669, + 666, 673, 666, 674, 670, 680, 677, 659, 665, 672, + 656, 655, 673, 655, 667, 666, 955, 665, 655, 659, + 955, 646, 955, 651, 651, 659, 642, 643, 653, 955, + 955, 685, 667, 683, 0, 507, 681, 681, 680, 679, + 678, 677, 676, 675, 674, 673, 672, 671, 670, 669, + + 668, 667, 666, 665, 652, 645, 0, 662, 661, 660, + 659, 658, 636, 656, 655, 654, 653, 652, 651, 650, + 649, 618, 621, 601, 0, 602, 595, 602, 601, 602, + 594, 612, 955, 955, 594, 592, 602, 595, 955, 590, + 607, 330, 955, 598, 582, 583, 592, 583, 582, 582, + 955, 581, 590, 580, 596, 593, 955, 592, 590, 579, + 580, 576, 568, 575, 570, 571, 566, 592, 592, 590, + 604, 603, 598, 0, 586, 585, 584, 583, 582, 581, + 580, 579, 578, 577, 576, 575, 574, 573, 572, 571, + 570, 0, 0, 569, 568, 567, 566, 565, 509, 564, + + 563, 562, 561, 560, 559, 558, 557, 535, 535, 0, + 542, 0, 576, 575, 524, 542, 955, 537, 532, 525, + 521, 533, 523, 521, 517, 533, 524, 523, 955, 955, + 526, 955, 521, 514, 503, 514, 506, 510, 523, 518, + 521, 503, 955, 955, 515, 504, 955, 0, 0, 0, + 0, 0, 543, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 539, 538, 536, 0, 0, + 0, 0, 0, 0, 0, 0, 494, 0, 0, 545, + 544, 955, 491, 955, 495, 495, 504, 955, 488, 502, + + 483, 485, 482, 490, 955, 468, 479, 955, 955, 483, + 479, 472, 470, 470, 483, 955, 467, 507, 0, 0, + 507, 0, 514, 513, 472, 433, 955, 955, 955, 435, + 435, 955, 429, 386, 377, 955, 366, 365, 323, 328, + 955, 955, 339, 348, 337, 955, 955, 307, 955, 305, + 955, 257, 955, 955, 247, 221, 955, 955, 955, 236, + 0, 213, 955, 150, 955, 955, 232, 955, 955, 162, + 138, 0, 0, 955, 541, 108, 544 + } ; + +static yyconst flex_int16_t yy_def[678] = + { 0, + 674, 1, 674, 674, 674, 674, 674, 675, 676, 674, + 674, 674, 674, 674, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 674, 674, 675, 674, 676, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 677, 674, 674, 674, 674, 674, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 676, 676, 676, + 676, 676, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 676, 676, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 676, + 676, 674, 674, 674, 674, 674, 676, 674, 674, 676, + 676, 676, 676, 0, 674, 674, 674 + } ; + +static yyconst flex_int16_t yy_nxt[1023] = + { 0, + 4, 5, 6, 5, 7, 8, 9, 4, 10, 11, + 12, 13, 14, 11, 11, 15, 9, 16, 17, 18, + 19, 9, 9, 9, 20, 21, 22, 9, 23, 24, + 9, 25, 26, 27, 9, 9, 9, 28, 9, 9, + 9, 9, 9, 9, 9, 9, 29, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 30, 9, 31, 32, + 33, 9, 34, 9, 9, 9, 9, 35, 79, 35, + 40, 80, 129, 108, 96, 81, 130, 41, 42, 42, + 42, 42, 42, 42, 76, 82, 77, 97, 98, 240, + 99, 109, 78, 65, 66, 66, 66, 66, 66, 66, + + 83, 241, 94, 100, 67, 127, 84, 95, 128, 39, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 131, + 132, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 67, 133, 61, 62, 63, 64, 65, 66, 66, 66, + 66, 66, 66, 35, 160, 35, 68, 67, 65, 66, + 66, 66, 66, 66, 66, 219, 673, 161, 69, 67, + 65, 66, 66, 66, 66, 66, 66, 71, 220, 72, + 70, 67, 140, 67, 134, 90, 73, 135, 141, 86, + 672, 87, 74, 91, 75, 67, 88, 101, 92, 89, + 178, 102, 103, 104, 93, 105, 179, 67, 42, 42, + + 42, 42, 42, 42, 106, 189, 107, 40, 122, 123, + 123, 142, 126, 123, 669, 123, 136, 137, 123, 217, + 124, 124, 123, 190, 147, 143, 123, 125, 125, 123, + 218, 337, 144, 123, 122, 148, 184, 185, 149, 151, + 152, 150, 670, 671, 338, 153, 186, 118, 119, 45, + 46, 47, 48, 154, 50, 51, 123, 162, 52, 53, + 54, 55, 56, 57, 120, 59, 60, 668, 155, 121, + 156, 286, 667, 157, 158, 163, 163, 163, 163, 666, + 287, 159, 164, 163, 165, 166, 167, 163, 163, 168, + 169, 163, 163, 163, 171, 171, 171, 171, 171, 171, + + 230, 665, 664, 260, 172, 65, 66, 66, 66, 66, + 66, 66, 198, 261, 154, 173, 67, 174, 174, 174, + 174, 174, 174, 233, 233, 364, 349, 257, 365, 233, + 172, 199, 231, 258, 232, 232, 232, 232, 232, 232, + 233, 350, 67, 233, 233, 236, 233, 233, 262, 233, + 247, 233, 233, 353, 263, 273, 233, 663, 233, 233, + 233, 428, 662, 233, 233, 274, 354, 233, 265, 233, + 661, 264, 266, 267, 233, 233, 660, 429, 233, 278, + 278, 278, 278, 524, 659, 233, 525, 658, 657, 233, + 278, 278, 278, 278, 279, 278, 278, 280, 281, 278, + + 278, 278, 278, 278, 278, 278, 282, 278, 278, 278, + 278, 278, 278, 278, 42, 42, 42, 42, 42, 42, + 656, 655, 654, 283, 122, 284, 284, 284, 284, 284, + 284, 174, 174, 174, 174, 174, 174, 174, 174, 174, + 174, 174, 174, 232, 232, 232, 232, 232, 232, 653, + 122, 232, 232, 232, 232, 232, 232, 335, 335, 335, + 335, 335, 335, 335, 374, 335, 375, 335, 376, 335, + 335, 367, 335, 652, 335, 335, 335, 335, 335, 651, + 650, 377, 380, 380, 380, 380, 335, 649, 335, 380, + 380, 380, 380, 381, 380, 380, 380, 380, 380, 380, + + 380, 380, 380, 380, 380, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 471, 472, 576, + 577, 648, 647, 646, 645, 644, 643, 642, 641, 640, + 639, 638, 637, 636, 635, 634, 633, 632, 631, 473, + 578, 37, 37, 37, 170, 170, 630, 629, 628, 627, + 626, 625, 624, 623, 622, 621, 620, 619, 618, 617, + 616, 615, 614, 613, 612, 611, 610, 609, 608, 607, + 606, 605, 604, 603, 602, 601, 600, 599, 598, 597, + 596, 595, 594, 593, 592, 591, 590, 589, 588, 587, + 586, 585, 584, 583, 582, 581, 580, 579, 575, 574, + + 573, 572, 571, 570, 569, 568, 567, 566, 565, 564, + 563, 562, 561, 560, 559, 558, 557, 556, 555, 554, + 553, 552, 551, 550, 549, 548, 547, 546, 545, 544, + 543, 542, 541, 540, 539, 538, 537, 536, 535, 534, + 533, 532, 531, 530, 529, 528, 527, 526, 523, 522, + 521, 520, 519, 518, 517, 516, 515, 514, 513, 512, + 511, 510, 509, 508, 507, 506, 505, 504, 503, 502, + 501, 500, 499, 498, 497, 496, 495, 494, 493, 492, + 491, 490, 489, 488, 487, 486, 485, 484, 483, 482, + 481, 480, 479, 478, 477, 476, 475, 474, 470, 469, + + 468, 467, 466, 465, 464, 463, 462, 461, 460, 459, + 458, 457, 456, 455, 454, 453, 452, 451, 450, 449, + 448, 447, 446, 445, 444, 443, 442, 441, 440, 439, + 438, 437, 436, 435, 434, 433, 432, 431, 430, 427, + 426, 425, 424, 423, 422, 421, 420, 419, 418, 417, + 416, 415, 414, 413, 412, 411, 410, 409, 408, 407, + 406, 405, 404, 403, 402, 401, 400, 399, 398, 397, + 396, 395, 394, 393, 392, 391, 390, 389, 388, 387, + 386, 385, 384, 383, 382, 379, 378, 373, 372, 371, + 370, 369, 368, 366, 363, 362, 361, 360, 359, 358, + + 357, 356, 355, 352, 351, 348, 347, 346, 345, 344, + 343, 342, 341, 340, 339, 336, 264, 236, 334, 333, + 332, 331, 330, 329, 328, 327, 326, 325, 324, 323, + 322, 321, 320, 319, 318, 317, 316, 315, 314, 313, + 312, 311, 310, 309, 308, 307, 306, 305, 304, 303, + 302, 301, 300, 299, 298, 297, 296, 295, 294, 293, + 292, 291, 290, 289, 288, 285, 277, 276, 275, 272, + 271, 270, 269, 268, 259, 256, 255, 254, 253, 252, + 251, 250, 249, 248, 246, 245, 244, 243, 242, 239, + 238, 237, 235, 234, 162, 229, 228, 227, 226, 225, + + 224, 223, 222, 221, 216, 215, 214, 213, 212, 211, + 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, + 200, 197, 196, 195, 194, 193, 192, 191, 188, 187, + 183, 182, 181, 180, 177, 176, 175, 146, 145, 139, + 138, 38, 117, 116, 115, 114, 113, 112, 111, 110, + 85, 38, 36, 674, 3, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674 + } ; + +static yyconst flex_int16_t yy_chk[1023] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5, 17, 5, + 10, 17, 46, 27, 24, 18, 46, 10, 10, 10, + 10, 10, 10, 10, 16, 18, 16, 24, 25, 130, + 25, 27, 16, 11, 11, 11, 11, 11, 11, 11, + + 19, 130, 23, 25, 11, 45, 19, 23, 45, 676, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 47, + 47, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 11, 47, 10, 10, 10, 10, 12, 12, 12, 12, + 12, 12, 12, 35, 60, 35, 12, 12, 13, 13, + 13, 13, 13, 13, 13, 109, 671, 60, 13, 13, + 14, 14, 14, 14, 14, 14, 14, 15, 109, 15, + 14, 14, 52, 12, 48, 22, 15, 48, 52, 21, + 670, 21, 15, 22, 15, 13, 21, 26, 22, 21, + 74, 26, 26, 26, 22, 26, 74, 14, 42, 42, + + 42, 42, 42, 42, 26, 82, 26, 40, 42, 43, + 43, 53, 44, 44, 664, 43, 49, 49, 44, 108, + 118, 43, 49, 82, 56, 53, 43, 118, 43, 44, + 108, 235, 53, 49, 42, 56, 79, 79, 56, 58, + 58, 56, 667, 667, 235, 58, 79, 40, 40, 40, + 40, 40, 40, 58, 40, 40, 58, 61, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 662, 59, 40, + 59, 176, 660, 59, 59, 61, 61, 61, 61, 656, + 176, 59, 62, 62, 62, 62, 63, 63, 63, 63, + 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, + + 120, 655, 652, 149, 65, 66, 66, 66, 66, 66, + 66, 66, 90, 149, 120, 67, 66, 67, 67, 67, + 67, 67, 67, 123, 123, 263, 249, 147, 263, 123, + 65, 90, 122, 147, 122, 122, 122, 122, 122, 122, + 123, 249, 66, 126, 126, 126, 136, 136, 150, 126, + 137, 137, 136, 252, 150, 159, 137, 650, 151, 151, + 126, 334, 648, 136, 151, 159, 252, 137, 152, 152, + 645, 151, 153, 153, 152, 151, 644, 334, 153, 163, + 163, 163, 163, 442, 643, 152, 442, 640, 639, 153, + 164, 164, 164, 164, 165, 165, 165, 165, 166, 166, + + 166, 166, 167, 167, 167, 167, 168, 168, 168, 168, + 169, 169, 169, 169, 171, 171, 171, 171, 171, 171, + 638, 637, 635, 172, 171, 172, 172, 172, 172, 172, + 172, 173, 173, 173, 173, 173, 173, 174, 174, 174, + 174, 174, 174, 231, 231, 231, 231, 231, 231, 634, + 171, 232, 232, 232, 232, 232, 232, 233, 233, 247, + 247, 265, 265, 233, 275, 247, 275, 265, 275, 266, + 266, 267, 267, 633, 233, 266, 247, 267, 265, 631, + 630, 275, 278, 278, 278, 278, 266, 626, 267, 279, + 279, 279, 279, 280, 280, 280, 280, 281, 281, 281, + + 281, 282, 282, 282, 282, 283, 283, 283, 283, 283, + 283, 284, 284, 284, 284, 284, 284, 386, 386, 499, + 499, 625, 624, 623, 621, 618, 617, 615, 614, 613, + 612, 611, 610, 607, 606, 604, 603, 602, 601, 386, + 499, 675, 675, 675, 677, 677, 600, 599, 597, 596, + 595, 593, 591, 590, 587, 578, 577, 576, 553, 546, + 545, 542, 541, 540, 539, 538, 537, 536, 535, 534, + 533, 531, 528, 527, 526, 525, 524, 523, 522, 521, + 520, 519, 518, 516, 515, 514, 513, 511, 509, 508, + 507, 506, 505, 504, 503, 502, 501, 500, 498, 497, + + 496, 495, 494, 491, 490, 489, 488, 487, 486, 485, + 484, 483, 482, 481, 480, 479, 478, 477, 476, 475, + 473, 472, 471, 470, 469, 468, 467, 466, 465, 464, + 463, 462, 461, 460, 459, 458, 456, 455, 454, 453, + 452, 450, 449, 448, 447, 446, 445, 444, 441, 440, + 438, 437, 436, 435, 432, 431, 430, 429, 428, 427, + 426, 424, 423, 422, 421, 420, 419, 418, 417, 416, + 415, 414, 413, 412, 411, 410, 409, 408, 406, 405, + 404, 403, 402, 401, 400, 399, 398, 397, 396, 395, + 394, 393, 392, 391, 390, 389, 388, 387, 384, 383, + + 382, 379, 378, 377, 376, 375, 374, 372, 370, 369, + 368, 366, 365, 364, 363, 362, 361, 360, 359, 358, + 357, 356, 355, 354, 353, 352, 351, 350, 349, 347, + 346, 345, 344, 343, 342, 341, 338, 337, 336, 333, + 332, 331, 330, 329, 328, 327, 326, 325, 324, 322, + 321, 320, 319, 318, 317, 316, 315, 313, 312, 311, + 310, 309, 308, 307, 306, 305, 304, 303, 302, 301, + 300, 299, 298, 297, 296, 295, 294, 292, 291, 290, + 289, 288, 287, 286, 285, 277, 276, 274, 273, 272, + 271, 270, 269, 264, 262, 261, 260, 259, 258, 257, + + 256, 255, 253, 251, 250, 248, 246, 245, 242, 241, + 240, 239, 238, 237, 236, 234, 230, 229, 228, 227, + 226, 225, 224, 223, 222, 221, 220, 219, 218, 217, + 216, 215, 214, 213, 212, 211, 210, 209, 208, 207, + 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, + 195, 194, 192, 191, 189, 187, 186, 185, 184, 183, + 182, 181, 180, 179, 177, 175, 162, 161, 160, 158, + 157, 156, 155, 154, 148, 146, 145, 144, 143, 142, + 141, 140, 139, 138, 135, 134, 133, 132, 131, 129, + 128, 127, 125, 124, 121, 119, 117, 116, 115, 114, + + 113, 112, 111, 110, 107, 106, 105, 104, 103, 102, + 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, + 91, 89, 88, 87, 86, 85, 84, 83, 81, 80, + 78, 77, 76, 75, 73, 72, 71, 55, 54, 51, + 50, 37, 36, 34, 33, 32, 31, 30, 29, 28, + 20, 8, 7, 3, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674, 674, 674, 674, 674, 674, 674, 674, 674, + 674, 674 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "program_lexer.l" +#line 2 "program_lexer.l" +/* + * 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 "main/glheader.h" +#include "prog_instruction.h" +#include "prog_statevars.h" + +#include "program_parser.h" +#include "program_parse.tab.h" + +#define require_ARB_vp (yyextra->mode == ARB_vertex) +#define require_ARB_fp (yyextra->mode == ARB_fragment) +#define require_shadow (yyextra->option.Shadow) +#define require_rect (yyextra->option.TexRect) +#define require_texarray (yyextra->option.TexArray) + +#define return_token_or_IDENTIFIER(condition, token) \ + do { \ + if (condition) { \ + return token; \ + } else { \ + yylval->string = strdup(yytext); \ + return IDENTIFIER; \ + } \ + } while (0) + +#define return_token_or_DOT(condition, token) \ + do { \ + if (condition) { \ + return token; \ + } else { \ + yyless(1); \ + return DOT; \ + } \ + } while (0) + + +#define return_opcode(condition, token, opcode, sat) \ + do { \ + if (condition) { \ + yylval->temp_inst.Opcode = OPCODE_ ## opcode; \ + yylval->temp_inst.SaturateMode = SATURATE_ ## sat; \ + return token; \ + } else { \ + yylval->string = strdup(yytext); \ + return IDENTIFIER; \ + } \ + } while (0) + +#define SWIZZLE_INVAL MAKE_SWIZZLE4(SWIZZLE_NIL, SWIZZLE_NIL, \ + SWIZZLE_NIL, SWIZZLE_NIL) + +static unsigned +mask_from_char(char c) +{ + switch (c) { + case 'x': + case 'r': + return WRITEMASK_X; + case 'y': + case 'g': + return WRITEMASK_Y; + case 'z': + case 'b': + return WRITEMASK_Z; + case 'w': + case 'a': + return WRITEMASK_W; + } + + return 0; +} + +static unsigned +swiz_from_char(char c) +{ + switch (c) { + case 'x': + case 'r': + return SWIZZLE_X; + case 'y': + case 'g': + return SWIZZLE_Y; + case 'z': + case 'b': + return SWIZZLE_Z; + case 'w': + case 'a': + return SWIZZLE_W; + } + + return 0; +} + +#define YY_USER_ACTION \ + do { \ + yylloc->first_column = yylloc->last_column; \ + yylloc->last_column += yyleng; \ + if ((yylloc->first_line == 1) \ + && (yylloc->first_column == 1)) { \ + yylloc->position = 1; \ + } else { \ + yylloc->position += yylloc->last_column - yylloc->first_column; \ + } \ + } while(0); + +#define YY_EXTRA_TYPE struct asm_parser_state * +#line 1007 "lex.yy.c" + +#define INITIAL 0 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + YYLTYPE * yylloc_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals (yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + + # define yylloc yyg->yylloc_r + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (yyscan_t yyscanner ); + +int yyget_debug (yyscan_t yyscanner ); + +void yyset_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *yyget_in (yyscan_t yyscanner ); + +void yyset_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *yyget_out (yyscan_t yyscanner ); + +void yyset_out (FILE * out_str ,yyscan_t yyscanner ); + +int yyget_leng (yyscan_t yyscanner ); + +char *yyget_text (yyscan_t yyscanner ); + +int yyget_lineno (yyscan_t yyscanner ); + +void yyset_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * yyget_lval (yyscan_t yyscanner ); + +void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + + YYLTYPE *yyget_lloc (yyscan_t yyscanner ); + + void yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (yyscan_t yyscanner ); +#else +extern int yywrap (yyscan_t yyscanner ); +#endif +#endif + + static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner); + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (yyscan_t yyscanner ); +#else +static int input (yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + unsigned n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex \ + (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + +#line 136 "program_lexer.l" + + +#line 1251 "lex.yy.c" + + yylval = yylval_param; + + yylloc = yylloc_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + yy_load_buffer_state(yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 675 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 955 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 138 "program_lexer.l" +{ return ARBvp_10; } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 139 "program_lexer.l" +{ return ARBfp_10; } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 140 "program_lexer.l" +{ + yylval->integer = at_address; + return_token_or_IDENTIFIER(require_ARB_vp, ADDRESS); +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 144 "program_lexer.l" +{ return ALIAS; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 145 "program_lexer.l" +{ return ATTRIB; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 146 "program_lexer.l" +{ return END; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 147 "program_lexer.l" +{ return OPTION; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 148 "program_lexer.l" +{ return OUTPUT; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 149 "program_lexer.l" +{ return PARAM; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 150 "program_lexer.l" +{ yylval->integer = at_temp; return TEMP; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 152 "program_lexer.l" +{ return_opcode( 1, VECTOR_OP, ABS, OFF); } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 153 "program_lexer.l" +{ return_opcode(require_ARB_fp, VECTOR_OP, ABS, ZERO_ONE); } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 154 "program_lexer.l" +{ return_opcode( 1, BIN_OP, ADD, OFF); } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 155 "program_lexer.l" +{ return_opcode(require_ARB_fp, BIN_OP, ADD, ZERO_ONE); } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 156 "program_lexer.l" +{ return_opcode(require_ARB_vp, ARL, ARL, OFF); } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 158 "program_lexer.l" +{ return_opcode(require_ARB_fp, TRI_OP, CMP, OFF); } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 159 "program_lexer.l" +{ return_opcode(require_ARB_fp, TRI_OP, CMP, ZERO_ONE); } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 160 "program_lexer.l" +{ return_opcode(require_ARB_fp, SCALAR_OP, COS, OFF); } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 161 "program_lexer.l" +{ return_opcode(require_ARB_fp, SCALAR_OP, COS, ZERO_ONE); } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 163 "program_lexer.l" +{ return_opcode( 1, BIN_OP, DP3, OFF); } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 164 "program_lexer.l" +{ return_opcode(require_ARB_fp, BIN_OP, DP3, ZERO_ONE); } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 165 "program_lexer.l" +{ return_opcode( 1, BIN_OP, DP4, OFF); } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 166 "program_lexer.l" +{ return_opcode(require_ARB_fp, BIN_OP, DP4, ZERO_ONE); } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 167 "program_lexer.l" +{ return_opcode( 1, BIN_OP, DPH, OFF); } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 168 "program_lexer.l" +{ return_opcode(require_ARB_fp, BIN_OP, DPH, ZERO_ONE); } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 169 "program_lexer.l" +{ return_opcode( 1, BIN_OP, DST, OFF); } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 170 "program_lexer.l" +{ return_opcode(require_ARB_fp, BIN_OP, DST, ZERO_ONE); } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 172 "program_lexer.l" +{ return_opcode( 1, SCALAR_OP, EX2, OFF); } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 173 "program_lexer.l" +{ return_opcode(require_ARB_fp, SCALAR_OP, EX2, ZERO_ONE); } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 174 "program_lexer.l" +{ return_opcode(require_ARB_vp, SCALAR_OP, EXP, OFF); } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 176 "program_lexer.l" +{ return_opcode( 1, VECTOR_OP, FLR, OFF); } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 177 "program_lexer.l" +{ return_opcode(require_ARB_fp, VECTOR_OP, FLR, ZERO_ONE); } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 178 "program_lexer.l" +{ return_opcode( 1, VECTOR_OP, FRC, OFF); } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 179 "program_lexer.l" +{ return_opcode(require_ARB_fp, VECTOR_OP, FRC, ZERO_ONE); } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 181 "program_lexer.l" +{ return_opcode(require_ARB_fp, KIL, KIL, OFF); } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 183 "program_lexer.l" +{ return_opcode( 1, VECTOR_OP, LIT, OFF); } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 184 "program_lexer.l" +{ return_opcode(require_ARB_fp, VECTOR_OP, LIT, ZERO_ONE); } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 185 "program_lexer.l" +{ return_opcode( 1, SCALAR_OP, LG2, OFF); } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 186 "program_lexer.l" +{ return_opcode(require_ARB_fp, SCALAR_OP, LG2, ZERO_ONE); } + YY_BREAK +case 40: +YY_RULE_SETUP +#line 187 "program_lexer.l" +{ return_opcode(require_ARB_vp, SCALAR_OP, LOG, OFF); } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 188 "program_lexer.l" +{ return_opcode(require_ARB_fp, TRI_OP, LRP, OFF); } + YY_BREAK +case 42: +YY_RULE_SETUP +#line 189 "program_lexer.l" +{ return_opcode(require_ARB_fp, TRI_OP, LRP, ZERO_ONE); } + YY_BREAK +case 43: +YY_RULE_SETUP +#line 191 "program_lexer.l" +{ return_opcode( 1, TRI_OP, MAD, OFF); } + YY_BREAK +case 44: +YY_RULE_SETUP +#line 192 "program_lexer.l" +{ return_opcode(require_ARB_fp, TRI_OP, MAD, ZERO_ONE); } + YY_BREAK +case 45: +YY_RULE_SETUP +#line 193 "program_lexer.l" +{ return_opcode( 1, BIN_OP, MAX, OFF); } + YY_BREAK +case 46: +YY_RULE_SETUP +#line 194 "program_lexer.l" +{ return_opcode(require_ARB_fp, BIN_OP, MAX, ZERO_ONE); } + YY_BREAK +case 47: +YY_RULE_SETUP +#line 195 "program_lexer.l" +{ return_opcode( 1, BIN_OP, MIN, OFF); } + YY_BREAK +case 48: +YY_RULE_SETUP +#line 196 "program_lexer.l" +{ return_opcode(require_ARB_fp, BIN_OP, MIN, ZERO_ONE); } + YY_BREAK +case 49: +YY_RULE_SETUP +#line 197 "program_lexer.l" +{ return_opcode( 1, VECTOR_OP, MOV, OFF); } + YY_BREAK +case 50: +YY_RULE_SETUP +#line 198 "program_lexer.l" +{ return_opcode(require_ARB_fp, VECTOR_OP, MOV, ZERO_ONE); } + YY_BREAK +case 51: +YY_RULE_SETUP +#line 199 "program_lexer.l" +{ return_opcode( 1, BIN_OP, MUL, OFF); } + YY_BREAK +case 52: +YY_RULE_SETUP +#line 200 "program_lexer.l" +{ return_opcode(require_ARB_fp, BIN_OP, MUL, ZERO_ONE); } + YY_BREAK +case 53: +YY_RULE_SETUP +#line 202 "program_lexer.l" +{ return_opcode( 1, BINSC_OP, POW, OFF); } + YY_BREAK +case 54: +YY_RULE_SETUP +#line 203 "program_lexer.l" +{ return_opcode(require_ARB_fp, BINSC_OP, POW, ZERO_ONE); } + YY_BREAK +case 55: +YY_RULE_SETUP +#line 205 "program_lexer.l" +{ return_opcode( 1, SCALAR_OP, RCP, OFF); } + YY_BREAK +case 56: +YY_RULE_SETUP +#line 206 "program_lexer.l" +{ return_opcode(require_ARB_fp, SCALAR_OP, RCP, ZERO_ONE); } + YY_BREAK +case 57: +YY_RULE_SETUP +#line 207 "program_lexer.l" +{ return_opcode( 1, SCALAR_OP, RSQ, OFF); } + YY_BREAK +case 58: +YY_RULE_SETUP +#line 208 "program_lexer.l" +{ return_opcode(require_ARB_fp, SCALAR_OP, RSQ, ZERO_ONE); } + YY_BREAK +case 59: +YY_RULE_SETUP +#line 210 "program_lexer.l" +{ return_opcode(require_ARB_fp, SCALAR_OP, SCS, OFF); } + YY_BREAK +case 60: +YY_RULE_SETUP +#line 211 "program_lexer.l" +{ return_opcode(require_ARB_fp, SCALAR_OP, SCS, ZERO_ONE); } + YY_BREAK +case 61: +YY_RULE_SETUP +#line 212 "program_lexer.l" +{ return_opcode( 1, BIN_OP, SGE, OFF); } + YY_BREAK +case 62: +YY_RULE_SETUP +#line 213 "program_lexer.l" +{ return_opcode(require_ARB_fp, BIN_OP, SGE, ZERO_ONE); } + YY_BREAK +case 63: +YY_RULE_SETUP +#line 214 "program_lexer.l" +{ return_opcode(require_ARB_fp, SCALAR_OP, SIN, OFF); } + YY_BREAK +case 64: +YY_RULE_SETUP +#line 215 "program_lexer.l" +{ return_opcode(require_ARB_fp, SCALAR_OP, SIN, ZERO_ONE); } + YY_BREAK +case 65: +YY_RULE_SETUP +#line 216 "program_lexer.l" +{ return_opcode( 1, BIN_OP, SLT, OFF); } + YY_BREAK +case 66: +YY_RULE_SETUP +#line 217 "program_lexer.l" +{ return_opcode(require_ARB_fp, BIN_OP, SLT, ZERO_ONE); } + YY_BREAK +case 67: +YY_RULE_SETUP +#line 218 "program_lexer.l" +{ return_opcode( 1, BIN_OP, SUB, OFF); } + YY_BREAK +case 68: +YY_RULE_SETUP +#line 219 "program_lexer.l" +{ return_opcode(require_ARB_fp, BIN_OP, SUB, ZERO_ONE); } + YY_BREAK +case 69: +YY_RULE_SETUP +#line 220 "program_lexer.l" +{ return_opcode( 1, SWZ, SWZ, OFF); } + YY_BREAK +case 70: +YY_RULE_SETUP +#line 221 "program_lexer.l" +{ return_opcode(require_ARB_fp, SWZ, SWZ, ZERO_ONE); } + YY_BREAK +case 71: +YY_RULE_SETUP +#line 223 "program_lexer.l" +{ return_opcode(require_ARB_fp, SAMPLE_OP, TEX, OFF); } + YY_BREAK +case 72: +YY_RULE_SETUP +#line 224 "program_lexer.l" +{ return_opcode(require_ARB_fp, SAMPLE_OP, TEX, ZERO_ONE); } + YY_BREAK +case 73: +YY_RULE_SETUP +#line 225 "program_lexer.l" +{ return_opcode(require_ARB_fp, SAMPLE_OP, TXB, OFF); } + YY_BREAK +case 74: +YY_RULE_SETUP +#line 226 "program_lexer.l" +{ return_opcode(require_ARB_fp, SAMPLE_OP, TXB, ZERO_ONE); } + YY_BREAK +case 75: +YY_RULE_SETUP +#line 227 "program_lexer.l" +{ return_opcode(require_ARB_fp, SAMPLE_OP, TXP, OFF); } + YY_BREAK +case 76: +YY_RULE_SETUP +#line 228 "program_lexer.l" +{ return_opcode(require_ARB_fp, SAMPLE_OP, TXP, ZERO_ONE); } + YY_BREAK +case 77: +YY_RULE_SETUP +#line 230 "program_lexer.l" +{ return_opcode( 1, BIN_OP, XPD, OFF); } + YY_BREAK +case 78: +YY_RULE_SETUP +#line 231 "program_lexer.l" +{ return_opcode(require_ARB_fp, BIN_OP, XPD, ZERO_ONE); } + YY_BREAK +case 79: +YY_RULE_SETUP +#line 233 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_vp, VERTEX); } + YY_BREAK +case 80: +YY_RULE_SETUP +#line 234 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp, FRAGMENT); } + YY_BREAK +case 81: +YY_RULE_SETUP +#line 235 "program_lexer.l" +{ return PROGRAM; } + YY_BREAK +case 82: +YY_RULE_SETUP +#line 236 "program_lexer.l" +{ return STATE; } + YY_BREAK +case 83: +YY_RULE_SETUP +#line 237 "program_lexer.l" +{ return RESULT; } + YY_BREAK +case 84: +YY_RULE_SETUP +#line 239 "program_lexer.l" +{ return AMBIENT; } + YY_BREAK +case 85: +YY_RULE_SETUP +#line 240 "program_lexer.l" +{ return ATTENUATION; } + YY_BREAK +case 86: +YY_RULE_SETUP +#line 241 "program_lexer.l" +{ return BACK; } + YY_BREAK +case 87: +YY_RULE_SETUP +#line 242 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, CLIP); } + YY_BREAK +case 88: +YY_RULE_SETUP +#line 243 "program_lexer.l" +{ return COLOR; } + YY_BREAK +case 89: +YY_RULE_SETUP +#line 244 "program_lexer.l" +{ return_token_or_DOT(require_ARB_fp, DEPTH); } + YY_BREAK +case 90: +YY_RULE_SETUP +#line 245 "program_lexer.l" +{ return DIFFUSE; } + YY_BREAK +case 91: +YY_RULE_SETUP +#line 246 "program_lexer.l" +{ return DIRECTION; } + YY_BREAK +case 92: +YY_RULE_SETUP +#line 247 "program_lexer.l" +{ return EMISSION; } + YY_BREAK +case 93: +YY_RULE_SETUP +#line 248 "program_lexer.l" +{ return ENV; } + YY_BREAK +case 94: +YY_RULE_SETUP +#line 249 "program_lexer.l" +{ return EYE; } + YY_BREAK +case 95: +YY_RULE_SETUP +#line 250 "program_lexer.l" +{ return FOGCOORD; } + YY_BREAK +case 96: +YY_RULE_SETUP +#line 251 "program_lexer.l" +{ return FOG; } + YY_BREAK +case 97: +YY_RULE_SETUP +#line 252 "program_lexer.l" +{ return FRONT; } + YY_BREAK +case 98: +YY_RULE_SETUP +#line 253 "program_lexer.l" +{ return HALF; } + YY_BREAK +case 99: +YY_RULE_SETUP +#line 254 "program_lexer.l" +{ return INVERSE; } + YY_BREAK +case 100: +YY_RULE_SETUP +#line 255 "program_lexer.l" +{ return INVTRANS; } + YY_BREAK +case 101: +YY_RULE_SETUP +#line 256 "program_lexer.l" +{ return LIGHT; } + YY_BREAK +case 102: +YY_RULE_SETUP +#line 257 "program_lexer.l" +{ return LIGHTMODEL; } + YY_BREAK +case 103: +YY_RULE_SETUP +#line 258 "program_lexer.l" +{ return LIGHTPROD; } + YY_BREAK +case 104: +YY_RULE_SETUP +#line 259 "program_lexer.l" +{ return LOCAL; } + YY_BREAK +case 105: +YY_RULE_SETUP +#line 260 "program_lexer.l" +{ return MATERIAL; } + YY_BREAK +case 106: +YY_RULE_SETUP +#line 261 "program_lexer.l" +{ return MAT_PROGRAM; } + YY_BREAK +case 107: +YY_RULE_SETUP +#line 262 "program_lexer.l" +{ return MATRIX; } + YY_BREAK +case 108: +YY_RULE_SETUP +#line 263 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, MATRIXINDEX); } + YY_BREAK +case 109: +YY_RULE_SETUP +#line 264 "program_lexer.l" +{ return MODELVIEW; } + YY_BREAK +case 110: +YY_RULE_SETUP +#line 265 "program_lexer.l" +{ return MVP; } + YY_BREAK +case 111: +YY_RULE_SETUP +#line 266 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, NORMAL); } + YY_BREAK +case 112: +YY_RULE_SETUP +#line 267 "program_lexer.l" +{ return OBJECT; } + YY_BREAK +case 113: +YY_RULE_SETUP +#line 268 "program_lexer.l" +{ return PALETTE; } + YY_BREAK +case 114: +YY_RULE_SETUP +#line 269 "program_lexer.l" +{ return PARAMS; } + YY_BREAK +case 115: +YY_RULE_SETUP +#line 270 "program_lexer.l" +{ return PLANE; } + YY_BREAK +case 116: +YY_RULE_SETUP +#line 271 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, POINT_TOK); } + YY_BREAK +case 117: +YY_RULE_SETUP +#line 272 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, POINTSIZE); } + YY_BREAK +case 118: +YY_RULE_SETUP +#line 273 "program_lexer.l" +{ return POSITION; } + YY_BREAK +case 119: +YY_RULE_SETUP +#line 274 "program_lexer.l" +{ return PRIMARY; } + YY_BREAK +case 120: +YY_RULE_SETUP +#line 275 "program_lexer.l" +{ return PROJECTION; } + YY_BREAK +case 121: +YY_RULE_SETUP +#line 276 "program_lexer.l" +{ return_token_or_DOT(require_ARB_fp, RANGE); } + YY_BREAK +case 122: +YY_RULE_SETUP +#line 277 "program_lexer.l" +{ return ROW; } + YY_BREAK +case 123: +YY_RULE_SETUP +#line 278 "program_lexer.l" +{ return SCENECOLOR; } + YY_BREAK +case 124: +YY_RULE_SETUP +#line 279 "program_lexer.l" +{ return SECONDARY; } + YY_BREAK +case 125: +YY_RULE_SETUP +#line 280 "program_lexer.l" +{ return SHININESS; } + YY_BREAK +case 126: +YY_RULE_SETUP +#line 281 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, SIZE_TOK); } + YY_BREAK +case 127: +YY_RULE_SETUP +#line 282 "program_lexer.l" +{ return SPECULAR; } + YY_BREAK +case 128: +YY_RULE_SETUP +#line 283 "program_lexer.l" +{ return SPOT; } + YY_BREAK +case 129: +YY_RULE_SETUP +#line 284 "program_lexer.l" +{ return TEXCOORD; } + YY_BREAK +case 130: +YY_RULE_SETUP +#line 285 "program_lexer.l" +{ return_token_or_DOT(require_ARB_fp, TEXENV); } + YY_BREAK +case 131: +YY_RULE_SETUP +#line 286 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, TEXGEN); } + YY_BREAK +case 132: +YY_RULE_SETUP +#line 287 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, TEXGEN_Q); } + YY_BREAK +case 133: +YY_RULE_SETUP +#line 288 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, TEXGEN_S); } + YY_BREAK +case 134: +YY_RULE_SETUP +#line 289 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, TEXGEN_T); } + YY_BREAK +case 135: +YY_RULE_SETUP +#line 290 "program_lexer.l" +{ return TEXTURE; } + YY_BREAK +case 136: +YY_RULE_SETUP +#line 291 "program_lexer.l" +{ return TRANSPOSE; } + YY_BREAK +case 137: +YY_RULE_SETUP +#line 292 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, VTXATTRIB); } + YY_BREAK +case 138: +YY_RULE_SETUP +#line 293 "program_lexer.l" +{ return_token_or_DOT(require_ARB_vp, WEIGHT); } + YY_BREAK +case 139: +YY_RULE_SETUP +#line 295 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp, TEXTURE_UNIT); } + YY_BREAK +case 140: +YY_RULE_SETUP +#line 296 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp, TEX_1D); } + YY_BREAK +case 141: +YY_RULE_SETUP +#line 297 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp, TEX_2D); } + YY_BREAK +case 142: +YY_RULE_SETUP +#line 298 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp, TEX_3D); } + YY_BREAK +case 143: +YY_RULE_SETUP +#line 299 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp, TEX_CUBE); } + YY_BREAK +case 144: +YY_RULE_SETUP +#line 300 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_rect, TEX_RECT); } + YY_BREAK +case 145: +YY_RULE_SETUP +#line 301 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow, TEX_SHADOW1D); } + YY_BREAK +case 146: +YY_RULE_SETUP +#line 302 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow, TEX_SHADOW2D); } + YY_BREAK +case 147: +YY_RULE_SETUP +#line 303 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_rect, TEX_SHADOWRECT); } + YY_BREAK +case 148: +YY_RULE_SETUP +#line 304 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_texarray, TEX_ARRAY1D); } + YY_BREAK +case 149: +YY_RULE_SETUP +#line 305 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_texarray, TEX_ARRAY2D); } + YY_BREAK +case 150: +YY_RULE_SETUP +#line 306 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_texarray, TEX_ARRAYSHADOW1D); } + YY_BREAK +case 151: +YY_RULE_SETUP +#line 307 "program_lexer.l" +{ return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_texarray, TEX_ARRAYSHADOW2D); } + YY_BREAK +case 152: +YY_RULE_SETUP +#line 309 "program_lexer.l" +{ + yylval->string = strdup(yytext); + return IDENTIFIER; +} + YY_BREAK +case 153: +YY_RULE_SETUP +#line 314 "program_lexer.l" +{ return DOT_DOT; } + YY_BREAK +case 154: +YY_RULE_SETUP +#line 316 "program_lexer.l" +{ + yylval->integer = strtol(yytext, NULL, 10); + return INTEGER; +} + YY_BREAK +case 155: +YY_RULE_SETUP +#line 320 "program_lexer.l" +{ + yylval->real = strtod(yytext, NULL); + return REAL; +} + YY_BREAK +case 156: +/* rule 156 can match eol */ +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ +yyg->yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 324 "program_lexer.l" +{ + yylval->real = strtod(yytext, NULL); + return REAL; +} + YY_BREAK +case 157: +YY_RULE_SETUP +#line 328 "program_lexer.l" +{ + yylval->real = strtod(yytext, NULL); + return REAL; +} + YY_BREAK +case 158: +YY_RULE_SETUP +#line 332 "program_lexer.l" +{ + yylval->real = strtod(yytext, NULL); + return REAL; +} + YY_BREAK +case 159: +YY_RULE_SETUP +#line 337 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_NOOP; + yylval->swiz_mask.mask = WRITEMASK_XYZW; + return MASK4; +} + YY_BREAK +case 160: +YY_RULE_SETUP +#line 343 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XY + | mask_from_char(yytext[3]); + return MASK3; +} + YY_BREAK +case 161: +YY_RULE_SETUP +#line 349 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XZW; + return MASK3; +} + YY_BREAK +case 162: +YY_RULE_SETUP +#line 354 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_YZW; + return MASK3; +} + YY_BREAK +case 163: +YY_RULE_SETUP +#line 360 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_X + | mask_from_char(yytext[2]); + return MASK2; +} + YY_BREAK +case 164: +YY_RULE_SETUP +#line 366 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_Y + | mask_from_char(yytext[2]); + return MASK2; +} + YY_BREAK +case 165: +YY_RULE_SETUP +#line 372 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_ZW; + return MASK2; +} + YY_BREAK +case 166: +YY_RULE_SETUP +#line 378 "program_lexer.l" +{ + const unsigned s = swiz_from_char(yytext[1]); + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(s, s, s, s); + yylval->swiz_mask.mask = mask_from_char(yytext[1]); + return MASK1; +} + YY_BREAK +case 167: +YY_RULE_SETUP +#line 385 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(swiz_from_char(yytext[1]), + swiz_from_char(yytext[2]), + swiz_from_char(yytext[3]), + swiz_from_char(yytext[4])); + yylval->swiz_mask.mask = 0; + return SWIZZLE; +} + YY_BREAK +case 168: +YY_RULE_SETUP +#line 394 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_NOOP; + yylval->swiz_mask.mask = WRITEMASK_XYZW; + return_token_or_DOT(require_ARB_fp, MASK4); +} + YY_BREAK +case 169: +YY_RULE_SETUP +#line 400 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XY + | mask_from_char(yytext[3]); + return_token_or_DOT(require_ARB_fp, MASK3); +} + YY_BREAK +case 170: +YY_RULE_SETUP +#line 406 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XZW; + return_token_or_DOT(require_ARB_fp, MASK3); +} + YY_BREAK +case 171: +YY_RULE_SETUP +#line 411 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_YZW; + return_token_or_DOT(require_ARB_fp, MASK3); +} + YY_BREAK +case 172: +YY_RULE_SETUP +#line 417 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_X + | mask_from_char(yytext[2]); + return_token_or_DOT(require_ARB_fp, MASK2); +} + YY_BREAK +case 173: +YY_RULE_SETUP +#line 423 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_Y + | mask_from_char(yytext[2]); + return_token_or_DOT(require_ARB_fp, MASK2); +} + YY_BREAK +case 174: +YY_RULE_SETUP +#line 429 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_ZW; + return_token_or_DOT(require_ARB_fp, MASK2); +} + YY_BREAK +case 175: +YY_RULE_SETUP +#line 435 "program_lexer.l" +{ + const unsigned s = swiz_from_char(yytext[1]); + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(s, s, s, s); + yylval->swiz_mask.mask = mask_from_char(yytext[1]); + return_token_or_DOT(require_ARB_fp, MASK1); +} + YY_BREAK +case 176: +YY_RULE_SETUP +#line 443 "program_lexer.l" +{ + if (require_ARB_vp) { + return TEXGEN_R; + } else { + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, + SWIZZLE_X, SWIZZLE_X); + yylval->swiz_mask.mask = WRITEMASK_X; + return MASK1; + } +} + YY_BREAK +case 177: +YY_RULE_SETUP +#line 454 "program_lexer.l" +{ + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(swiz_from_char(yytext[1]), + swiz_from_char(yytext[2]), + swiz_from_char(yytext[3]), + swiz_from_char(yytext[4])); + yylval->swiz_mask.mask = 0; + return_token_or_DOT(require_ARB_fp, SWIZZLE); +} + YY_BREAK +case 178: +YY_RULE_SETUP +#line 463 "program_lexer.l" +{ return DOT; } + YY_BREAK +case 179: +/* rule 179 can match eol */ +YY_RULE_SETUP +#line 465 "program_lexer.l" +{ + yylloc->first_line++; + yylloc->first_column = 1; + yylloc->last_line++; + yylloc->last_column = 1; + yylloc->position++; +} + YY_BREAK +case 180: +YY_RULE_SETUP +#line 472 "program_lexer.l" +/* eat whitespace */ ; + YY_BREAK +case 181: +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ +yyg->yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 473 "program_lexer.l" +/* eat comments */ ; + YY_BREAK +case 182: +YY_RULE_SETUP +#line 474 "program_lexer.l" +{ return yytext[0]; } + YY_BREAK +case 183: +YY_RULE_SETUP +#line 475 "program_lexer.l" +ECHO; + YY_BREAK +#line 2383 "lex.yy.c" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = yyg->yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 675 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + register int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + register char *yy_cp = yyg->yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 675 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 674); + + return yy_is_jam ? 0 : yy_current_state; +} + + static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner) +{ + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_cp = yyg->yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yyg->yy_hold_char; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yyg->yy_n_chars + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + yyg->yytext_ptr = yy_bp; + yyg->yy_hold_char = *yy_cp; + yyg->yy_c_buf_p = yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap(yyscanner ) ) + return EOF; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + yy_load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ,yyscanner ); + + yyfree((void *) b ,yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + int num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "yyset_lineno called with no buffer" , yyscanner); + + yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param yyscanner The scanner object. + */ +void yyset_column (int column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "yyset_column called with no buffer" , yyscanner); + + yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; +} + +void yyset_out (FILE * out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +YYLTYPE *yyget_lloc (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylloc; +} + +void yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylloc = yylloc_param; +} + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int yylex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ + +int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) + +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = (char *) 0; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 475 "program_lexer.l" + + + +void +_mesa_program_lexer_ctor(void **scanner, struct asm_parser_state *state, + const char *string, size_t len) +{ + yylex_init_extra(state,scanner); + yy_scan_bytes(string,len,*scanner); +} + +void +_mesa_program_lexer_dtor(void *scanner) +{ + yylex_destroy(scanner); +} + diff --git a/mesalib/src/mesa/shader/nvfragparse.c b/mesalib/src/mesa/shader/nvfragparse.c new file mode 100644 index 000000000..0fd55524a --- /dev/null +++ b/mesalib/src/mesa/shader/nvfragparse.c @@ -0,0 +1,1582 @@ +/* + * 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); + _mesa_free((void *) lineStr); +#else + (void) lineNo; +#endif + + /* Check that no error was already recorded. Only record the first one. */ + if (parseState->ctx->Program.ErrorString[0] == 0) { + _mesa_set_program_error(parseState->ctx, + parseState->pos - parseState->start, + msg); + } +} + + +#define RETURN_ERROR \ +do { \ + record_error(parseState, "Unexpected end of input.", __LINE__); \ + return GL_FALSE; \ +} while(0) + +#define RETURN_ERROR1(msg) \ +do { \ + record_error(parseState, msg, __LINE__); \ + return GL_FALSE; \ +} while(0) + +#define RETURN_ERROR2(msg1, msg2) \ +do { \ + char err[1000]; \ + _mesa_sprintf(err, "%s %s", msg1, msg2); \ + record_error(parseState, err, __LINE__); \ + return GL_FALSE; \ +} while(0) + + + + +/* + * Search a list of instruction structures for a match. + */ +static struct instruction_pattern +MatchInstruction(const GLubyte *token) +{ + const struct instruction_pattern *inst; + struct instruction_pattern result; + + for (inst = Instructions; inst->name; inst++) { + if (_mesa_strncmp((const char *) token, inst->name, 3) == 0) { + /* matched! */ + int i = 3; + result = *inst; + result.suffixes = 0; + /* look at suffix */ + if (token[i] == 'R') { + result.suffixes |= _R; + i++; + } + else if (token[i] == 'H') { + result.suffixes |= _H; + i++; + } + else if (token[i] == 'X') { + result.suffixes |= _X; + i++; + } + if (token[i] == 'C') { + result.suffixes |= _C; + i++; + } + if (token[i] == '_' && token[i+1] == 'S' && + token[i+2] == 'A' && token[i+3] == 'T') { + result.suffixes |= _S; + } + return result; + } + } + result.opcode = MAX_OPCODE; /* i.e. invalid instruction */ + return result; +} + + + + +/**********************************************************************/ + + +static GLboolean IsLetter(GLubyte b) +{ + return (b >= 'a' && b <= 'z') || + (b >= 'A' && b <= 'Z') || + (b == '_') || + (b == '$'); +} + + +static GLboolean IsDigit(GLubyte b) +{ + return b >= '0' && b <= '9'; +} + + +static GLboolean IsWhitespace(GLubyte b) +{ + return b == ' ' || b == '\t' || b == '\n' || b == '\r'; +} + + +/** + * Starting at 'str' find the next token. A token can be an integer, + * an identifier or punctuation symbol. + * \return <= 0 we found an error, else, return number of characters parsed. + */ +static GLint +GetToken(struct parse_state *parseState, GLubyte *token) +{ + const GLubyte *str = parseState->pos; + GLint i = 0, j = 0; + + token[0] = 0; + + /* skip whitespace and comments */ + while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) { + if (str[i] == '#') { + /* skip comment */ + while (str[i] && (str[i] != '\n' && str[i] != '\r')) { + i++; + } + if (str[i] == '\n' || str[i] == '\r') + parseState->curLine = str + i + 1; + } + else { + /* skip whitespace */ + if (str[i] == '\n' || str[i] == '\r') + parseState->curLine = str + i + 1; + i++; + } + } + + if (str[i] == 0) + return -i; + + /* try matching an integer */ + while (str[i] && IsDigit(str[i])) { + token[j++] = str[i++]; + } + if (j > 0 || !str[i]) { + token[j] = 0; + return i; + } + + /* try matching an identifier */ + if (IsLetter(str[i])) { + while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) { + token[j++] = str[i++]; + } + token[j] = 0; + return i; + } + + /* punctuation character */ + if (str[i]) { + token[0] = str[i++]; + token[1] = 0; + return i; + } + + /* end of input */ + token[0] = 0; + return i; +} + + +/** + * Get next token from input stream and increment stream pointer past token. + */ +static GLboolean +Parse_Token(struct parse_state *parseState, GLubyte *token) +{ + GLint i; + i = GetToken(parseState, token); + if (i <= 0) { + parseState->pos += (-i); + return GL_FALSE; + } + parseState->pos += i; + return GL_TRUE; +} + + +/** + * Get next token from input stream but don't increment stream pointer. + */ +static GLboolean +Peek_Token(struct parse_state *parseState, GLubyte *token) +{ + GLint i, len; + i = GetToken(parseState, token); + if (i <= 0) { + parseState->pos += (-i); + return GL_FALSE; + } + len = (GLint)_mesa_strlen((const char *) token); + parseState->pos += (i - len); + return GL_TRUE; +} + + +/**********************************************************************/ + +static const char *InputRegisters[MAX_NV_FRAGMENT_PROGRAM_INPUTS + 1] = { + "WPOS", "COL0", "COL1", "FOGC", + "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL +}; + + + +/**********************************************************************/ + +/** + * Try to match 'pattern' as the next token after any whitespace/comments. + */ +static GLboolean +Parse_String(struct parse_state *parseState, const char *pattern) +{ + const GLubyte *m; + GLint i; + + /* skip whitespace and comments */ + while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') { + if (*parseState->pos == '#') { + while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) { + parseState->pos += 1; + } + if (*parseState->pos == '\n' || *parseState->pos == '\r') + parseState->curLine = parseState->pos + 1; + } + else { + /* skip whitespace */ + if (*parseState->pos == '\n' || *parseState->pos == '\r') + parseState->curLine = parseState->pos + 1; + parseState->pos += 1; + } + } + + /* Try to match the pattern */ + m = parseState->pos; + for (i = 0; pattern[i]; i++) { + if (*m != (GLubyte) pattern[i]) + return GL_FALSE; + m += 1; + } + parseState->pos = m; + + return GL_TRUE; /* success */ +} + + +static GLboolean +Parse_Identifier(struct parse_state *parseState, GLubyte *ident) +{ + if (!Parse_Token(parseState, ident)) + RETURN_ERROR; + if (IsLetter(ident[0])) + return GL_TRUE; + else + RETURN_ERROR1("Expected an identfier"); +} + + +/** + * Parse a floating point constant, or a defined symbol name. + * [+/-]N[.N[eN]] + * Output: number[0 .. 3] will get the value. + */ +static GLboolean +Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number) +{ + char *end = NULL; + + *number = (GLfloat) _mesa_strtod((const char *) parseState->pos, &end); + + if (end && end > (char *) parseState->pos) { + /* got a number */ + parseState->pos = (GLubyte *) end; + number[1] = *number; + number[2] = *number; + number[3] = *number; + return GL_TRUE; + } + else { + /* should be an identifier */ + GLubyte ident[100]; + const GLfloat *constant; + if (!Parse_Identifier(parseState, ident)) + RETURN_ERROR1("Expected an identifier"); + constant = _mesa_lookup_parameter_value(parseState->parameters, + -1, (const char *) ident); + /* XXX Check that it's a constant and not a parameter */ + if (!constant) { + RETURN_ERROR1("Undefined symbol"); + } + else { + COPY_4V(number, constant); + return GL_TRUE; + } + } +} + + + +/** + * Parse a vector constant, one of: + * { float } + * { float, float } + * { float, float, float } + * { float, float, float, float } + */ +static GLboolean +Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec) +{ + /* "{" was already consumed */ + + ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0); + + if (!Parse_ScalarConstant(parseState, vec+0)) /* X */ + return GL_FALSE; + + if (Parse_String(parseState, "}")) { + return GL_TRUE; + } + + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected comma in vector constant"); + + if (!Parse_ScalarConstant(parseState, vec+1)) /* Y */ + return GL_FALSE; + + if (Parse_String(parseState, "}")) { + return GL_TRUE; + } + + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected comma in vector constant"); + + if (!Parse_ScalarConstant(parseState, vec+2)) /* Z */ + return GL_FALSE; + + if (Parse_String(parseState, "}")) { + return GL_TRUE; + } + + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected comma in vector constant"); + + if (!Parse_ScalarConstant(parseState, vec+3)) /* W */ + return GL_FALSE; + + if (!Parse_String(parseState, "}")) + RETURN_ERROR1("Expected closing brace in vector constant"); + + return GL_TRUE; +} + + +/** + * Parse <number>, <varname> or {a, b, c, d}. + * Return number of values in the vector or scalar, or zero if parse error. + */ +static GLuint +Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec) +{ + if (Parse_String(parseState, "{")) { + return Parse_VectorConstant(parseState, vec); + } + else { + GLboolean b = Parse_ScalarConstant(parseState, vec); + if (b) { + vec[1] = vec[2] = vec[3] = vec[0]; + } + return b; + } +} + + +/** + * Parse a texture image source: + * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT] + */ +static GLboolean +Parse_TextureImageId(struct parse_state *parseState, + GLubyte *texUnit, GLubyte *texTargetBit) +{ + GLubyte imageSrc[100]; + GLint unit; + + if (!Parse_Token(parseState, imageSrc)) + RETURN_ERROR; + + if (imageSrc[0] != 'T' || + imageSrc[1] != 'E' || + imageSrc[2] != 'X') { + RETURN_ERROR1("Expected TEX# source"); + } + unit = _mesa_atoi((const char *) imageSrc + 3); + if ((unit < 0 || unit > MAX_TEXTURE_IMAGE_UNITS) || + (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) { + RETURN_ERROR1("Invalied TEX# source index"); + } + *texUnit = unit; + + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + + if (Parse_String(parseState, "1D")) { + *texTargetBit = TEXTURE_1D_BIT; + } + else if (Parse_String(parseState, "2D")) { + *texTargetBit = TEXTURE_2D_BIT; + } + else if (Parse_String(parseState, "3D")) { + *texTargetBit = TEXTURE_3D_BIT; + } + else if (Parse_String(parseState, "CUBE")) { + *texTargetBit = TEXTURE_CUBE_BIT; + } + else if (Parse_String(parseState, "RECT")) { + *texTargetBit = TEXTURE_RECT_BIT; + } + else { + RETURN_ERROR1("Invalid texture target token"); + } + + /* update record of referenced texture units */ + parseState->texturesUsed[*texUnit] |= *texTargetBit; + if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) { + RETURN_ERROR1("Only one texture target can be used per texture unit."); + } + + return GL_TRUE; +} + + +/** + * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix + * like .wxyz, .xxyy, etc and return the swizzle indexes. + */ +static GLboolean +Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4]) +{ + if (token[1] == 0) { + /* single letter swizzle (scalar) */ + if (token[0] == 'x') + ASSIGN_4V(swizzle, 0, 0, 0, 0); + else if (token[0] == 'y') + ASSIGN_4V(swizzle, 1, 1, 1, 1); + else if (token[0] == 'z') + ASSIGN_4V(swizzle, 2, 2, 2, 2); + else if (token[0] == 'w') + ASSIGN_4V(swizzle, 3, 3, 3, 3); + else + return GL_FALSE; + } + else { + /* 4-component swizzle (vector) */ + GLint k; + for (k = 0; token[k] && k < 4; k++) { + if (token[k] == 'x') + swizzle[k] = 0; + else if (token[k] == 'y') + swizzle[k] = 1; + else if (token[k] == 'z') + swizzle[k] = 2; + else if (token[k] == 'w') + swizzle[k] = 3; + else + return GL_FALSE; + } + if (k != 4) + return GL_FALSE; + } + return GL_TRUE; +} + + +static GLboolean +Parse_CondCodeMask(struct parse_state *parseState, + struct prog_dst_register *dstReg) +{ + if (Parse_String(parseState, "EQ")) + dstReg->CondMask = COND_EQ; + else if (Parse_String(parseState, "GE")) + dstReg->CondMask = COND_GE; + else if (Parse_String(parseState, "GT")) + dstReg->CondMask = COND_GT; + else if (Parse_String(parseState, "LE")) + dstReg->CondMask = COND_LE; + else if (Parse_String(parseState, "LT")) + dstReg->CondMask = COND_LT; + else if (Parse_String(parseState, "NE")) + dstReg->CondMask = COND_NE; + else if (Parse_String(parseState, "TR")) + dstReg->CondMask = COND_TR; + else if (Parse_String(parseState, "FL")) + dstReg->CondMask = COND_FL; + else + RETURN_ERROR1("Invalid condition code mask"); + + /* look for optional .xyzw swizzle */ + if (Parse_String(parseState, ".")) { + GLubyte token[100]; + GLuint swz[4]; + + if (!Parse_Token(parseState, token)) /* get xyzw suffix */ + RETURN_ERROR; + + if (!Parse_SwizzleSuffix(token, swz)) + RETURN_ERROR1("Invalid swizzle suffix"); + + dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]); + } + + return GL_TRUE; +} + + +/** + * Parse a temporary register: Rnn or Hnn + */ +static GLboolean +Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum) +{ + GLubyte token[100]; + + /* Should be 'R##' or 'H##' */ + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + if (token[0] != 'R' && token[0] != 'H') + RETURN_ERROR1("Expected R## or H##"); + + if (IsDigit(token[1])) { + GLint reg = _mesa_atoi((const char *) (token + 1)); + if (token[0] == 'H') + reg += 32; + if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS) + RETURN_ERROR1("Invalid temporary register name"); + *tempRegNum = reg; + } + else { + RETURN_ERROR1("Invalid temporary register name"); + } + + return GL_TRUE; +} + + +/** + * Parse a write-only dummy register: RC or HC. + */ +static GLboolean +Parse_DummyReg(struct parse_state *parseState, GLint *regNum) +{ + if (Parse_String(parseState, "RC")) { + *regNum = 0; + } + else if (Parse_String(parseState, "HC")) { + *regNum = 1; + } + else { + RETURN_ERROR1("Invalid write-only register name"); + } + + return GL_TRUE; +} + + +/** + * Parse a program local parameter register "p[##]" + */ +static GLboolean +Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum) +{ + GLubyte token[100]; + + if (!Parse_String(parseState, "p[")) + RETURN_ERROR1("Expected p["); + + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (IsDigit(token[0])) { + /* a numbered program parameter register */ + GLint reg = _mesa_atoi((const char *) token); + if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS) + RETURN_ERROR1("Invalid constant program number"); + *regNum = reg; + } + else { + RETURN_ERROR; + } + + if (!Parse_String(parseState, "]")) + RETURN_ERROR1("Expected ]"); + + return GL_TRUE; +} + + +/** + * Parse f[name] - fragment input register + */ +static GLboolean +Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum) +{ + GLubyte token[100]; + GLint j; + + /* Match 'f[' */ + if (!Parse_String(parseState, "f[")) + RETURN_ERROR1("Expected f["); + + /* get <name> and look for match */ + if (!Parse_Token(parseState, token)) { + RETURN_ERROR; + } + for (j = 0; InputRegisters[j]; j++) { + if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) { + *tempRegNum = j; + parseState->inputsRead |= (1 << j); + break; + } + } + if (!InputRegisters[j]) { + /* unknown input register label */ + RETURN_ERROR2("Invalid register name", token); + } + + /* Match '[' */ + if (!Parse_String(parseState, "]")) + RETURN_ERROR1("Expected ]"); + + return GL_TRUE; +} + + +static GLboolean +Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum) +{ + GLubyte token[100]; + + /* 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 (_mesa_strcmp((char *) token, "COLR") == 0 || + _mesa_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 (_mesa_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 (_mesa_strcmp((const char *) token, "RC") == 0 || + _mesa_strcmp((const char *) token, "HC") == 0) { + /* a write-only register */ + dstReg->File = PROGRAM_WRITE_ONLY; + if (!Parse_DummyReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else if (token[0] == 'R' || token[0] == 'H') { + /* a temporary register */ + dstReg->File = PROGRAM_TEMPORARY; + if (!Parse_TempReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else if (token[0] == 'o') { + /* an output register */ + dstReg->File = PROGRAM_OUTPUT; + if (!Parse_OutputReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else { + RETURN_ERROR1("Invalid destination register name"); + } + + /* Parse optional write mask */ + if (Parse_String(parseState, ".")) { + /* got a mask */ + GLint k = 0; + + if (!Parse_Token(parseState, token)) /* get xyzw writemask */ + RETURN_ERROR; + + dstReg->WriteMask = 0; + + if (token[k] == 'x') { + dstReg->WriteMask |= WRITEMASK_X; + k++; + } + if (token[k] == 'y') { + dstReg->WriteMask |= WRITEMASK_Y; + k++; + } + if (token[k] == 'z') { + dstReg->WriteMask |= WRITEMASK_Z; + k++; + } + if (token[k] == 'w') { + dstReg->WriteMask |= WRITEMASK_W; + k++; + } + if (k == 0) { + RETURN_ERROR1("Invalid writemask character"); + } + + } + else { + dstReg->WriteMask = WRITEMASK_XYZW; + } + + /* optional condition code mask */ + if (Parse_String(parseState, "(")) { + /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */ + /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */ + if (!Parse_CondCodeMask(parseState, dstReg)) + RETURN_ERROR; + + if (!Parse_String(parseState, ")")) /* consume ")" */ + RETURN_ERROR1("Expected )"); + + return GL_TRUE; + } + else { + /* no cond code mask */ + dstReg->CondMask = COND_TR; + dstReg->CondSwizzle = SWIZZLE_NOOP; + return GL_TRUE; + } +} + + +/** + * Parse a vector source (register, constant, etc): + * <vectorSrc> ::= <absVectorSrc> + * | <baseVectorSrc> + * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|" + */ +static GLboolean +Parse_VectorSrc(struct parse_state *parseState, + struct prog_src_register *srcReg) +{ + GLfloat sign = 1.0F; + GLubyte token[100]; + GLint idx; + 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*) _mesa_malloc(len + 1); + + _mesa_memcpy(msg, str, len); + msg[len] = 0; + inst->Data = msg; + + if (Parse_String(parseState, ",")) { + /* got an optional register to print */ + GLubyte token[100]; + GetToken(parseState, token); + if (token[0] == 'o') { + /* dst reg */ + if (!Parse_OutputReg(parseState, &idx)) + RETURN_ERROR; + inst->SrcReg[0].Index = idx; + inst->SrcReg[0].File = PROGRAM_OUTPUT; + } + else { + /* src reg */ + if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + } + } + else { + inst->SrcReg[0].File = PROGRAM_UNDEFINED; + } + + inst->SrcReg[0].Swizzle = SWIZZLE_NOOP; + inst->SrcReg[0].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 */ + _mesa_bzero(&parseState, sizeof(struct parse_state)); + parseState.ctx = ctx; + parseState.start = programString; + parseState.program = program; + parseState.numInst = 0; + parseState.curLine = programString; + parseState.parameters = _mesa_new_parameter_list(); + + /* Reset error state */ + _mesa_set_program_error(ctx, -1, NULL); + + /* check the program header */ + if (_mesa_strncmp((const char *) programString, "!!FP1.0", 7) == 0) { + target = GL_FRAGMENT_PROGRAM_NV; + parseState.pos = programString + 7; + } + else if (_mesa_strncmp((const char *) programString, "!!FCP1.0", 8) == 0) { + /* fragment / register combiner program - not supported */ + _mesa_set_program_error(ctx, 0, "Invalid fragment program header"); + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); + return; + } + else { + /* invalid header */ + _mesa_set_program_error(ctx, 0, "Invalid fragment program header"); + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); + return; + } + + /* make sure target and header match */ + if (target != dstTarget) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glLoadProgramNV(target mismatch 0x%x != 0x%x)", + target, dstTarget); + return; + } + + if (Parse_InstructionSequence(&parseState, instBuffer)) { + GLuint u; + /* successful parse! */ + + if (parseState.outputsWritten == 0) { + /* must write at least one output! */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "Invalid fragment program - no outputs written."); + return; + } + + /* copy the compiled instructions */ + assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS); + newInst = _mesa_alloc_instructions(parseState.numInst); + if (!newInst) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + return; /* out of memory */ + } + _mesa_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) { + _mesa_free(program->Base.Instructions); + } + program->Base.Instructions = newInst; + program->Base.NumInstructions = parseState.numInst; + program->Base.InputsRead = parseState.inputsRead; + program->Base.OutputsWritten = parseState.outputsWritten; + for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++) + program->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 + _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id); + _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0); + _mesa_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/shader/nvfragparse.h b/mesalib/src/mesa/shader/nvfragparse.h new file mode 100644 index 000000000..544ab80c5 --- /dev/null +++ b/mesalib/src/mesa/shader/nvfragparse.h @@ -0,0 +1,43 @@ + +/* + * Mesa 3-D graphics library + * Version: 5.1 + * + * Copyright (C) 1999-2002 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Brian Paul + */ + + +#ifndef NVFRAGPARSE_H +#define NVFRAGPARSE_H + + +extern void +_mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum target, + const GLubyte *str, GLsizei len, + struct gl_fragment_program *program); + + +extern const char * +_mesa_nv_fragment_input_register_name(GLuint i); + +#endif diff --git a/mesalib/src/mesa/shader/nvprogram.c b/mesalib/src/mesa/shader/nvprogram.c new file mode 100644 index 000000000..471a7358a --- /dev/null +++ b/mesalib/src/mesa/shader/nvprogram.c @@ -0,0 +1,890 @@ +/* + * 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 nvprogram.c + * NVIDIA vertex/fragment program state management functions. + * \author Brian Paul + */ + +/* + * Regarding GL_NV_fragment/vertex_program, GL_NV_vertex_program1_1, etc: + * + * Portions of this software may use or implement intellectual + * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims + * any and all warranties with respect to such intellectual property, + * including any use thereof or modifications thereto. + */ + +#include "main/glheader.h" +#include "main/context.h" +#include "main/hash.h" +#include "main/imports.h" +#include "main/macros.h" +#include "program.h" +#include "prog_parameter.h" +#include "prog_instruction.h" +#include "nvfragparse.h" +#include "nvvertparse.h" +#include "nvprogram.h" + + + +/** + * Execute a vertex state program. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params) +{ + struct gl_vertex_program *vprog; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target != GL_VERTEX_STATE_PROGRAM_NV) { + _mesa_error(ctx, GL_INVALID_ENUM, "glExecuteProgramNV"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + vprog = (struct gl_vertex_program *) _mesa_lookup_program(ctx, id); + + if (!vprog || vprog->Base.Target != GL_VERTEX_STATE_PROGRAM_NV) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glExecuteProgramNV"); + return; + } + + _mesa_problem(ctx, "glExecuteProgramNV() not supported"); +} + + +/** + * Determine if a set of programs is resident in hardware. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +GLboolean GLAPIENTRY +_mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids, + GLboolean *residences) +{ + GLint i, j; + GLboolean allResident = GL_TRUE; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV(n)"); + return GL_FALSE; + } + + for (i = 0; i < n; i++) { + const struct gl_program *prog; + if (ids[i] == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV"); + return GL_FALSE; + } + prog = _mesa_lookup_program(ctx, ids[i]); + if (!prog) { + _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV"); + return GL_FALSE; + } + if (prog->Resident) { + if (!allResident) + residences[i] = GL_TRUE; + } + else { + if (allResident) { + allResident = GL_FALSE; + for (j = 0; j < i; j++) + residences[j] = GL_TRUE; + } + residences[i] = GL_FALSE; + } + } + + return allResident; +} + + +/** + * Request that a set of programs be resident in hardware. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids) +{ + GLint i; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(n)"); + return; + } + + /* just error checking for now */ + for (i = 0; i < n; i++) { + struct gl_program *prog; + + if (ids[i] == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)"); + return; + } + + prog = _mesa_lookup_program(ctx, ids[i]); + if (!prog) { + _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)"); + return; + } + + /* XXX this is really a hardware thing we should hook out */ + prog->Resident = GL_TRUE; + } +} + + +/** + * Get a program parameter register. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetProgramParameterfvNV(GLenum target, GLuint index, + GLenum pname, GLfloat *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV) { + if (pname == GL_PROGRAM_PARAMETER_NV) { + if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) { + COPY_4V(params, ctx->VertexProgram.Parameters[index]); + } + else { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetProgramParameterfvNV(index)"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(pname)"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterfvNV(target)"); + return; + } +} + + +/** + * Get a program parameter register. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetProgramParameterdvNV(GLenum target, GLuint index, + GLenum pname, GLdouble *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV) { + if (pname == GL_PROGRAM_PARAMETER_NV) { + if (index < MAX_NV_VERTEX_PROGRAM_PARAMS) { + COPY_4V(params, ctx->VertexProgram.Parameters[index]); + } + else { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetProgramParameterdvNV(index)"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(pname)"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramParameterdvNV(target)"); + return; + } +} + + +/** + * Get a program attribute. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params) +{ + struct gl_program *prog; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + prog = _mesa_lookup_program(ctx, id); + if (!prog) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV"); + return; + } + + switch (pname) { + case GL_PROGRAM_TARGET_NV: + *params = prog->Target; + return; + case GL_PROGRAM_LENGTH_NV: + *params = prog->String ?(GLint)_mesa_strlen((char *) prog->String) : 0; + return; + case GL_PROGRAM_RESIDENT_NV: + *params = prog->Resident; + return; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)"); + return; + } +} + + +/** + * Get the program source code. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program) +{ + struct gl_program *prog; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (pname != GL_PROGRAM_STRING_NV) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringNV(pname)"); + return; + } + + prog = _mesa_lookup_program(ctx, id); + if (!prog) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramStringNV"); + return; + } + + if (prog->String) { + MEMCPY(program, prog->String, _mesa_strlen((char *) prog->String)); + } + else { + program[0] = 0; + } +} + + +/** + * Get matrix tracking information. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetTrackMatrixivNV(GLenum target, GLuint address, + GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV + && ctx->Extensions.NV_vertex_program) { + GLuint i; + + if ((address & 0x3) || address >= MAX_NV_VERTEX_PROGRAM_PARAMS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetTrackMatrixivNV(address)"); + return; + } + + i = address / 4; + + switch (pname) { + case GL_TRACK_MATRIX_NV: + params[0] = (GLint) ctx->VertexProgram.TrackMatrix[i]; + return; + case GL_TRACK_MATRIX_TRANSFORM_NV: + params[0] = (GLint) ctx->VertexProgram.TrackMatrixTransform[i]; + return; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV"); + return; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTrackMatrixivNV"); + return; + } +} + + +/** + * Get a vertex (or vertex array) attribute. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params) +{ + const struct gl_client_array *array; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)"); + return; + } + + array = &ctx->Array.ArrayObj->VertexAttrib[index]; + + switch (pname) { + case GL_ATTRIB_ARRAY_SIZE_NV: + params[0] = array->Size; + break; + case GL_ATTRIB_ARRAY_STRIDE_NV: + params[0] = array->Stride; + break; + case GL_ATTRIB_ARRAY_TYPE_NV: + params[0] = array->Type; + break; + case GL_CURRENT_ATTRIB_NV: + if (index == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetVertexAttribdvNV(index == 0)"); + return; + } + FLUSH_CURRENT(ctx, 0); + COPY_4V(params, ctx->Current.Attrib[index]); + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV"); + return; + } +} + +/** + * Get a vertex (or vertex array) attribute. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params) +{ + const struct gl_client_array *array; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)"); + return; + } + + array = &ctx->Array.ArrayObj->VertexAttrib[index]; + + switch (pname) { + case GL_ATTRIB_ARRAY_SIZE_NV: + params[0] = (GLfloat) array->Size; + break; + case GL_ATTRIB_ARRAY_STRIDE_NV: + params[0] = (GLfloat) array->Stride; + break; + case GL_ATTRIB_ARRAY_TYPE_NV: + params[0] = (GLfloat) array->Type; + break; + case GL_CURRENT_ATTRIB_NV: + if (index == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetVertexAttribfvNV(index == 0)"); + return; + } + FLUSH_CURRENT(ctx, 0); + COPY_4V(params, ctx->Current.Attrib[index]); + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV"); + return; + } +} + +/** + * Get a vertex (or vertex array) attribute. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params) +{ + const struct gl_client_array *array; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribdvNV(index)"); + return; + } + + array = &ctx->Array.ArrayObj->VertexAttrib[index]; + + switch (pname) { + case GL_ATTRIB_ARRAY_SIZE_NV: + params[0] = array->Size; + break; + case GL_ATTRIB_ARRAY_STRIDE_NV: + params[0] = array->Stride; + break; + case GL_ATTRIB_ARRAY_TYPE_NV: + params[0] = array->Type; + break; + case GL_CURRENT_ATTRIB_NV: + if (index == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetVertexAttribivNV(index == 0)"); + return; + } + FLUSH_CURRENT(ctx, 0); + params[0] = (GLint) ctx->Current.Attrib[index][0]; + params[1] = (GLint) ctx->Current.Attrib[index][1]; + params[2] = (GLint) ctx->Current.Attrib[index][2]; + params[3] = (GLint) ctx->Current.Attrib[index][3]; + break; + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB: + params[0] = array->BufferObj->Name; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribdvNV"); + return; + } +} + + +/** + * Get a vertex array attribute pointer. + * \note Not compiled into display lists. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerNV(index)"); + return; + } + + if (pname != GL_ATTRIB_ARRAY_POINTER_NV) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerNV(pname)"); + return; + } + + *pointer = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[index].Ptr; +} + +void +_mesa_emit_nv_temp_initialization(GLcontext *ctx, + struct gl_program *program) +{ + struct prog_instruction *inst; + int i; + + if (!ctx->Shader.EmitNVTempInitialization) + return; + + /* We'll swizzle up a zero temporary so we can use it for the + * ARL. + */ + if (program->NumTemporaries == 0) + program->NumTemporaries = 1; + + _mesa_insert_instructions(program, 0, program->NumTemporaries + 1); + + for (i = 0; i < program->NumTemporaries; i++) { + struct prog_instruction *inst = &program->Instructions[i]; + + inst->Opcode = OPCODE_SWZ; + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = i; + inst->DstReg.WriteMask = WRITEMASK_XYZW; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = 0; + inst->SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_ZERO, + SWIZZLE_ZERO, + SWIZZLE_ZERO, + SWIZZLE_ZERO); + } + + inst = &program->Instructions[i]; + inst->Opcode = OPCODE_ARL; + inst->DstReg.File = PROGRAM_ADDRESS; + inst->DstReg.Index = 0; + inst->DstReg.WriteMask = WRITEMASK_XYZW; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = 0; + inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; + + if (program->NumAddressRegs == 0) + program->NumAddressRegs = 1; +} + +void +_mesa_setup_nv_temporary_count(GLcontext *ctx, struct gl_program *program) +{ + int i; + + program->NumTemporaries = 0; + for (i = 0; i < program->NumInstructions; i++) { + struct prog_instruction *inst = &program->Instructions[i]; + + if (inst->DstReg.File == PROGRAM_TEMPORARY) { + program->NumTemporaries = MAX2(program->NumTemporaries, + inst->DstReg.Index + 1); + } + if (inst->SrcReg[0].File == PROGRAM_TEMPORARY) { + program->NumTemporaries = MAX2(program->NumTemporaries, + inst->SrcReg[0].Index + 1); + } + if (inst->SrcReg[1].File == PROGRAM_TEMPORARY) { + program->NumTemporaries = MAX2(program->NumTemporaries, + inst->SrcReg[1].Index + 1); + } + if (inst->SrcReg[2].File == PROGRAM_TEMPORARY) { + program->NumTemporaries = MAX2(program->NumTemporaries, + inst->SrcReg[2].Index + 1); + } + } +} + +/** + * Load/parse/compile a program. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len, + const GLubyte *program) +{ + struct gl_program *prog; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (id == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)"); + return; + } + + if (len < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(len)"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + prog = _mesa_lookup_program(ctx, id); + + if (prog && prog->Target != 0 && prog->Target != target) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)"); + return; + } + + if ((target == GL_VERTEX_PROGRAM_NV || + target == GL_VERTEX_STATE_PROGRAM_NV) + && ctx->Extensions.NV_vertex_program) { + struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog; + if (!vprog || prog == &_mesa_DummyProgram) { + vprog = (struct gl_vertex_program *) + ctx->Driver.NewProgram(ctx, target, id); + if (!vprog) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + return; + } + _mesa_HashInsert(ctx->Shared->Programs, id, vprog); + } + _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog); + } + else if (target == GL_FRAGMENT_PROGRAM_NV + && ctx->Extensions.NV_fragment_program) { + struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog; + if (!fprog || prog == &_mesa_DummyProgram) { + fprog = (struct gl_fragment_program *) + ctx->Driver.NewProgram(ctx, target, id); + if (!fprog) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + return; + } + _mesa_HashInsert(ctx->Shared->Programs, id, fprog); + } + _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog); + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)"); + } +} + + + +/** + * Set a sequence of program parameter registers. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_ProgramParameters4dvNV(GLenum target, GLuint index, + GLuint num, const GLdouble *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) { + GLuint i; + if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4dvNV"); + return; + } + for (i = 0; i < num; i++) { + ctx->VertexProgram.Parameters[index + i][0] = (GLfloat) params[0]; + ctx->VertexProgram.Parameters[index + i][1] = (GLfloat) params[1]; + ctx->VertexProgram.Parameters[index + i][2] = (GLfloat) params[2]; + ctx->VertexProgram.Parameters[index + i][3] = (GLfloat) params[3]; + params += 4; + }; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4dvNV"); + return; + } +} + + +/** + * Set a sequence of program parameter registers. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_ProgramParameters4fvNV(GLenum target, GLuint index, + GLuint num, const GLfloat *params) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) { + GLuint i; + if (index + num > MAX_NV_VERTEX_PROGRAM_PARAMS) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameters4fvNV"); + return; + } + for (i = 0; i < num; i++) { + COPY_4V(ctx->VertexProgram.Parameters[index + i], params); + params += 4; + } + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameters4fvNV"); + return; + } +} + + + +/** + * Setup tracking of matrices into program parameter registers. + * \note Called from the GL API dispatcher. + */ +void GLAPIENTRY +_mesa_TrackMatrixNV(GLenum target, GLuint address, + GLenum matrix, GLenum transform) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + if (target == GL_VERTEX_PROGRAM_NV && ctx->Extensions.NV_vertex_program) { + if (address & 0x3) { + /* addr must be multiple of four */ + _mesa_error(ctx, GL_INVALID_VALUE, "glTrackMatrixNV(address)"); + return; + } + + switch (matrix) { + case GL_NONE: + case GL_MODELVIEW: + case GL_PROJECTION: + case GL_TEXTURE: + case GL_COLOR: + case GL_MODELVIEW_PROJECTION_NV: + case GL_MATRIX0_NV: + case GL_MATRIX1_NV: + case GL_MATRIX2_NV: + case GL_MATRIX3_NV: + case GL_MATRIX4_NV: + case GL_MATRIX5_NV: + case GL_MATRIX6_NV: + case GL_MATRIX7_NV: + /* OK, fallthrough */ + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(matrix)"); + return; + } + + switch (transform) { + case GL_IDENTITY_NV: + case GL_INVERSE_NV: + case GL_TRANSPOSE_NV: + case GL_INVERSE_TRANSPOSE_NV: + /* OK, fallthrough */ + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(transform)"); + return; + } + + ctx->VertexProgram.TrackMatrix[address / 4] = matrix; + ctx->VertexProgram.TrackMatrixTransform[address / 4] = transform; + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, "glTrackMatrixNV(target)"); + return; + } +} + + +void GLAPIENTRY +_mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name, + GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + struct gl_program *prog; + struct gl_fragment_program *fragProg; + GLfloat *v; + + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + prog = _mesa_lookup_program(ctx, id); + if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramNamedParameterNV"); + return; + } + + if (len <= 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(len)"); + return; + } + + fragProg = (struct gl_fragment_program *) prog; + v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, len, + (char *) name); + if (v) { + v[0] = x; + v[1] = y; + v[2] = z; + v[3] = w; + return; + } + + _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(name)"); +} + + +void GLAPIENTRY +_mesa_ProgramNamedParameter4fvNV(GLuint id, GLsizei len, const GLubyte *name, + const float v[]) +{ + _mesa_ProgramNamedParameter4fNV(id, len, name, v[0], v[1], v[2], v[3]); +} + + +void GLAPIENTRY +_mesa_ProgramNamedParameter4dNV(GLuint id, GLsizei len, const GLubyte *name, + GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + _mesa_ProgramNamedParameter4fNV(id, len, name, (GLfloat)x, (GLfloat)y, + (GLfloat)z, (GLfloat)w); +} + + +void GLAPIENTRY +_mesa_ProgramNamedParameter4dvNV(GLuint id, GLsizei len, const GLubyte *name, + const double v[]) +{ + _mesa_ProgramNamedParameter4fNV(id, len, name, + (GLfloat)v[0], (GLfloat)v[1], + (GLfloat)v[2], (GLfloat)v[3]); +} + + +void GLAPIENTRY +_mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name, + GLfloat *params) +{ + struct gl_program *prog; + struct gl_fragment_program *fragProg; + const GLfloat *v; + + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + prog = _mesa_lookup_program(ctx, id); + if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramNamedParameterNV"); + return; + } + + if (len <= 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV"); + return; + } + + fragProg = (struct gl_fragment_program *) prog; + v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, + len, (char *) name); + if (v) { + params[0] = v[0]; + params[1] = v[1]; + params[2] = v[2]; + params[3] = v[3]; + return; + } + + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV"); +} + + +void GLAPIENTRY +_mesa_GetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name, + GLdouble *params) +{ + GLfloat floatParams[4]; + _mesa_GetProgramNamedParameterfvNV(id, len, name, floatParams); + COPY_4V(params, floatParams); +} diff --git a/mesalib/src/mesa/shader/nvprogram.h b/mesalib/src/mesa/shader/nvprogram.h new file mode 100644 index 000000000..8ee59661b --- /dev/null +++ b/mesalib/src/mesa/shader/nvprogram.h @@ -0,0 +1,113 @@ +/* + * Mesa 3-D graphics library + * Version: 5.1 + * + * Copyright (C) 1999-2003 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Brian Paul + */ + + +#ifndef NVPROGRAM_H +#define NVPROGRAM_H + + +extern void GLAPIENTRY +_mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params); + +extern GLboolean GLAPIENTRY +_mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids, GLboolean *residences); + +extern void GLAPIENTRY +_mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids); + +extern void GLAPIENTRY +_mesa_GetProgramParameterfvNV(GLenum target, GLuint index, GLenum pname, GLfloat *params); + +extern void GLAPIENTRY +_mesa_GetProgramParameterdvNV(GLenum target, GLuint index, GLenum pname, GLdouble *params); + +extern void GLAPIENTRY +_mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params); + +extern void GLAPIENTRY +_mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program); + +extern void GLAPIENTRY +_mesa_GetTrackMatrixivNV(GLenum target, GLuint address, GLenum pname, GLint *params); + +extern void GLAPIENTRY +_mesa_GetVertexAttribdvNV(GLuint index, GLenum pname, GLdouble *params); + +extern void GLAPIENTRY +_mesa_GetVertexAttribfvNV(GLuint index, GLenum pname, GLfloat *params); + +extern void GLAPIENTRY +_mesa_GetVertexAttribivNV(GLuint index, GLenum pname, GLint *params); + +extern void GLAPIENTRY +_mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer); + +extern void GLAPIENTRY +_mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len, const GLubyte *program); + +extern void GLAPIENTRY +_mesa_ProgramParameters4dvNV(GLenum target, GLuint index, GLuint num, const GLdouble *params); + +extern void GLAPIENTRY +_mesa_ProgramParameters4fvNV(GLenum target, GLuint index, GLuint num, const GLfloat *params); + +extern void GLAPIENTRY +_mesa_TrackMatrixNV(GLenum target, GLuint address, GLenum matrix, GLenum transform); + + +extern void GLAPIENTRY +_mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name, + GLfloat x, GLfloat y, GLfloat z, GLfloat w); + +extern void GLAPIENTRY +_mesa_ProgramNamedParameter4fvNV(GLuint id, GLsizei len, const GLubyte *name, + const float v[]); + +extern void GLAPIENTRY +_mesa_ProgramNamedParameter4dNV(GLuint id, GLsizei len, const GLubyte *name, + GLdouble x, GLdouble y, GLdouble z, GLdouble w); + +extern void GLAPIENTRY +_mesa_ProgramNamedParameter4dvNV(GLuint id, GLsizei len, const GLubyte *name, + const double v[]); + +extern void GLAPIENTRY +_mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name, + GLfloat *params); + +extern void GLAPIENTRY +_mesa_GetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name, + GLdouble *params); + +extern void +_mesa_setup_nv_temporary_count(GLcontext *ctx, struct gl_program *program); + +extern void +_mesa_emit_nv_temp_initialization(GLcontext *ctx, + struct gl_program *program); + +#endif diff --git a/mesalib/src/mesa/shader/nvvertparse.c b/mesalib/src/mesa/shader/nvvertparse.c new file mode 100644 index 000000000..857401605 --- /dev/null +++ b/mesalib/src/mesa/shader/nvvertparse.c @@ -0,0 +1,1455 @@ +/* + * 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/macros.h" +#include "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; + GLuint numInst; /* number of instructions parsed */ +}; + + +/* + * Called whenever we find an error during parsing. + */ +static void +record_error(struct parse_state *parseState, const char *msg, int lineNo) +{ +#ifdef DEBUG + GLint line, column; + const GLubyte *lineStr; + lineStr = _mesa_find_line_column(parseState->start, + parseState->pos, &line, &column); + _mesa_debug(parseState->ctx, + "nvfragparse.c(%d): line %d, column %d:%s (%s)\n", + lineNo, line, column, (char *) lineStr, msg); + _mesa_free((void *) lineStr); +#else + (void) lineNo; +#endif + + /* Check that no error was already recorded. Only record the first one. */ + if (parseState->ctx->Program.ErrorString[0] == 0) { + _mesa_set_program_error(parseState->ctx, + parseState->pos - parseState->start, + msg); + } +} + + +#define RETURN_ERROR \ +do { \ + record_error(parseState, "Unexpected end of input.", __LINE__); \ + return GL_FALSE; \ +} while(0) + +#define RETURN_ERROR1(msg) \ +do { \ + record_error(parseState, msg, __LINE__); \ + return GL_FALSE; \ +} while(0) + +#define RETURN_ERROR2(msg1, msg2) \ +do { \ + char err[1000]; \ + _mesa_sprintf(err, "%s %s", msg1, msg2); \ + record_error(parseState, err, __LINE__); \ + return GL_FALSE; \ +} while(0) + + + + + +static GLboolean IsLetter(GLubyte b) +{ + return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z'); +} + + +static GLboolean IsDigit(GLubyte b) +{ + return b >= '0' && b <= '9'; +} + + +static GLboolean IsWhitespace(GLubyte b) +{ + return b == ' ' || b == '\t' || b == '\n' || b == '\r'; +} + + +/** + * Starting at 'str' find the next token. A token can be an integer, + * an identifier or punctuation symbol. + * \return <= 0 we found an error, else, return number of characters parsed. + */ +static GLint +GetToken(struct parse_state *parseState, GLubyte *token) +{ + const GLubyte *str = parseState->pos; + GLint i = 0, j = 0; + + token[0] = 0; + + /* skip whitespace and comments */ + while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) { + if (str[i] == '#') { + /* skip comment */ + while (str[i] && (str[i] != '\n' && str[i] != '\r')) { + i++; + } + if (str[i] == '\n' || str[i] == '\r') + parseState->curLine = str + i + 1; + } + else { + /* skip whitespace */ + if (str[i] == '\n' || str[i] == '\r') + parseState->curLine = str + i + 1; + i++; + } + } + + if (str[i] == 0) + return -i; + + /* try matching an integer */ + while (str[i] && IsDigit(str[i])) { + token[j++] = str[i++]; + } + if (j > 0 || !str[i]) { + token[j] = 0; + return i; + } + + /* try matching an identifier */ + if (IsLetter(str[i])) { + while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) { + token[j++] = str[i++]; + } + token[j] = 0; + return i; + } + + /* punctuation character */ + if (str[i]) { + token[0] = str[i++]; + token[1] = 0; + return i; + } + + /* end of input */ + token[0] = 0; + return i; +} + + +/** + * Get next token from input stream and increment stream pointer past token. + */ +static GLboolean +Parse_Token(struct parse_state *parseState, GLubyte *token) +{ + GLint i; + i = GetToken(parseState, token); + if (i <= 0) { + parseState->pos += (-i); + return GL_FALSE; + } + parseState->pos += i; + return GL_TRUE; +} + + +/** + * Get next token from input stream but don't increment stream pointer. + */ +static GLboolean +Peek_Token(struct parse_state *parseState, GLubyte *token) +{ + GLint i, len; + i = GetToken(parseState, token); + if (i <= 0) { + parseState->pos += (-i); + return GL_FALSE; + } + len = (GLint)_mesa_strlen((const char *) token); + parseState->pos += (i - len); + return GL_TRUE; +} + + +/** + * Try to match 'pattern' as the next token after any whitespace/comments. + * Advance the current parsing position only if we match the pattern. + * \return GL_TRUE if pattern is matched, GL_FALSE otherwise. + */ +static GLboolean +Parse_String(struct parse_state *parseState, const char *pattern) +{ + const GLubyte *m; + GLint i; + + /* skip whitespace and comments */ + while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') { + if (*parseState->pos == '#') { + while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) { + parseState->pos += 1; + } + if (*parseState->pos == '\n' || *parseState->pos == '\r') + parseState->curLine = parseState->pos + 1; + } + else { + /* skip whitespace */ + if (*parseState->pos == '\n' || *parseState->pos == '\r') + parseState->curLine = parseState->pos + 1; + parseState->pos += 1; + } + } + + /* Try to match the pattern */ + m = parseState->pos; + for (i = 0; pattern[i]; i++) { + if (*m != (GLubyte) pattern[i]) + return GL_FALSE; + m += 1; + } + parseState->pos = m; + + return GL_TRUE; /* success */ +} + + +/**********************************************************************/ + +static const char *InputRegisters[MAX_NV_VERTEX_PROGRAM_INPUTS + 1] = { + "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7", + "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL +}; + +static const char *OutputRegisters[MAX_NV_VERTEX_PROGRAM_OUTPUTS + 1] = { + "HPOS", "COL0", "COL1", "FOGC", + "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", + "PSIZ", "BFC0", "BFC1", NULL +}; + + + +/** + * Parse a temporary register: Rnn + */ +static GLboolean +Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum) +{ + GLubyte token[100]; + + /* Should be 'R##' */ + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + if (token[0] != 'R') + RETURN_ERROR1("Expected R##"); + + if (IsDigit(token[1])) { + GLint reg = _mesa_atoi((char *) (token + 1)); + if (reg >= MAX_NV_VERTEX_PROGRAM_TEMPS) + RETURN_ERROR1("Bad temporary register name"); + *tempRegNum = reg; + } + else { + RETURN_ERROR1("Bad temporary register name"); + } + + return GL_TRUE; +} + + +/** + * Parse address register "A0.x" + */ +static GLboolean +Parse_AddrReg(struct parse_state *parseState) +{ + /* match 'A0' */ + if (!Parse_String(parseState, "A0")) + RETURN_ERROR; + + /* match '.' */ + if (!Parse_String(parseState, ".")) + RETURN_ERROR; + + /* match 'x' */ + if (!Parse_String(parseState, "x")) + RETURN_ERROR; + + return GL_TRUE; +} + + +/** + * Parse absolute program parameter register "c[##]" + */ +static GLboolean +Parse_AbsParamReg(struct parse_state *parseState, GLint *regNum) +{ + GLubyte token[100]; + + if (!Parse_String(parseState, "c")) + RETURN_ERROR; + + if (!Parse_String(parseState, "[")) + RETURN_ERROR; + + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (IsDigit(token[0])) { + /* a numbered program parameter register */ + GLint reg = _mesa_atoi((char *) token); + if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS) + RETURN_ERROR1("Bad program parameter number"); + *regNum = reg; + } + else { + RETURN_ERROR; + } + + if (!Parse_String(parseState, "]")) + RETURN_ERROR; + + return GL_TRUE; +} + + +static GLboolean +Parse_ParamReg(struct parse_state *parseState, struct prog_src_register *srcReg) +{ + GLubyte token[100]; + + if (!Parse_String(parseState, "c")) + RETURN_ERROR; + + if (!Parse_String(parseState, "[")) + RETURN_ERROR; + + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + if (IsDigit(token[0])) { + /* a numbered program parameter register */ + GLint reg; + (void) Parse_Token(parseState, token); + reg = _mesa_atoi((char *) token); + if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS) + RETURN_ERROR1("Bad program parameter number"); + srcReg->File = PROGRAM_ENV_PARAM; + srcReg->Index = reg; + } + else if (_mesa_strcmp((const char *) token, "A0") == 0) { + /* address register "A0.x" */ + if (!Parse_AddrReg(parseState)) + RETURN_ERROR; + + srcReg->RelAddr = GL_TRUE; + srcReg->File = PROGRAM_ENV_PARAM; + /* Look for +/-N offset */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + if (token[0] == '-' || token[0] == '+') { + const GLubyte sign = token[0]; + (void) Parse_Token(parseState, token); /* consume +/- */ + + /* an integer should be next */ + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (IsDigit(token[0])) { + const GLint k = _mesa_atoi((char *) token); + if (sign == '-') { + if (k > 64) + RETURN_ERROR1("Bad address offset"); + srcReg->Index = -k; + } + else { + if (k > 63) + RETURN_ERROR1("Bad address offset"); + srcReg->Index = k; + } + } + else { + RETURN_ERROR; + } + } + else { + /* probably got a ']', catch it below */ + } + } + else { + RETURN_ERROR; + } + + /* Match closing ']' */ + if (!Parse_String(parseState, "]")) + RETURN_ERROR; + + return GL_TRUE; +} + + +/** + * Parse v[#] or v[<name>] + */ +static GLboolean +Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum) +{ + GLubyte token[100]; + GLint j; + + /* Match 'v' */ + if (!Parse_String(parseState, "v")) + RETURN_ERROR; + + /* Match '[' */ + if (!Parse_String(parseState, "[")) + RETURN_ERROR; + + /* match number or named register */ + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (parseState->isStateProgram && token[0] != '0') + RETURN_ERROR1("Only v[0] accessible in vertex state programs"); + + if (IsDigit(token[0])) { + GLint reg = _mesa_atoi((char *) token); + if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS) + RETURN_ERROR1("Bad vertex attribute register name"); + *tempRegNum = reg; + } + else { + for (j = 0; InputRegisters[j]; j++) { + if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) { + *tempRegNum = j; + break; + } + } + if (!InputRegisters[j]) { + /* unknown input register label */ + RETURN_ERROR2("Bad register name", token); + } + } + + /* Match '[' */ + if (!Parse_String(parseState, "]")) + RETURN_ERROR; + + return GL_TRUE; +} + + +static GLboolean +Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum) +{ + GLubyte token[100]; + GLint start, j; + + /* Match 'o' */ + if (!Parse_String(parseState, "o")) + RETURN_ERROR; + + /* Match '[' */ + if (!Parse_String(parseState, "[")) + RETURN_ERROR; + + /* Get output reg name */ + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (parseState->isPositionInvariant) + start = 1; /* skip HPOS register name */ + else + start = 0; + + /* try to match an output register name */ + for (j = start; OutputRegisters[j]; j++) { + if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) { + *outputRegNum = j; + break; + } + } + if (!OutputRegisters[j]) + RETURN_ERROR1("Unrecognized output register name"); + + /* Match ']' */ + if (!Parse_String(parseState, "]")) + RETURN_ERROR1("Expected ]"); + + return GL_TRUE; +} + + +static GLboolean +Parse_MaskedDstReg(struct parse_state *parseState, struct prog_dst_register *dstReg) +{ + GLubyte token[100]; + GLint idx; + + /* Dst reg can be R<n> or o[n] */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + if (token[0] == 'R') { + /* a temporary register */ + dstReg->File = PROGRAM_TEMPORARY; + if (!Parse_TempReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else if (!parseState->isStateProgram && token[0] == 'o') { + /* an output register */ + dstReg->File = PROGRAM_OUTPUT; + if (!Parse_OutputReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else if (parseState->isStateProgram && token[0] == 'c' && + parseState->isStateProgram) { + /* absolute program parameter register */ + /* Only valid for vertex state programs */ + dstReg->File = PROGRAM_ENV_PARAM; + if (!Parse_AbsParamReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else { + RETURN_ERROR1("Bad destination register name"); + } + + /* Parse optional write mask */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + if (token[0] == '.') { + /* got a mask */ + GLint k = 0; + + if (!Parse_String(parseState, ".")) + RETURN_ERROR; + + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + dstReg->WriteMask = 0; + + if (token[k] == 'x') { + dstReg->WriteMask |= WRITEMASK_X; + k++; + } + if (token[k] == 'y') { + dstReg->WriteMask |= WRITEMASK_Y; + k++; + } + if (token[k] == 'z') { + dstReg->WriteMask |= WRITEMASK_Z; + k++; + } + if (token[k] == 'w') { + dstReg->WriteMask |= WRITEMASK_W; + k++; + } + if (k == 0) { + RETURN_ERROR1("Bad writemask character"); + } + return GL_TRUE; + } + else { + dstReg->WriteMask = WRITEMASK_XYZW; + return GL_TRUE; + } +} + + +static GLboolean +Parse_SwizzleSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg) +{ + GLubyte token[100]; + GLint idx; + + srcReg->RelAddr = GL_FALSE; + + /* check for '-' */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + if (token[0] == '-') { + (void) Parse_String(parseState, "-"); + srcReg->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*) _mesa_malloc(len + 1); + + _mesa_memcpy(msg, str, len); + msg[len] = 0; + inst->Data = msg; + + /* comma */ + if (Parse_String(parseState, ",")) { + + /* The second argument is a register name */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + srcReg->RelAddr = GL_FALSE; + srcReg->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 = 0; + } + + /* semicolon */ + if (!Parse_String(parseState, ";")) + RETURN_ERROR; + + return GL_TRUE; +} + + +static GLboolean +Parse_OptionSequence(struct parse_state *parseState, + struct prog_instruction program[]) +{ + (void) program; + while (1) { + if (!Parse_String(parseState, "OPTION")) + return GL_TRUE; /* ok, not an OPTION statement */ + if (Parse_String(parseState, "NV_position_invariant")) { + parseState->isPositionInvariant = GL_TRUE; + } + else { + RETURN_ERROR1("unexpected OPTION statement"); + } + if (!Parse_String(parseState, ";")) + return GL_FALSE; + } +} + + +static GLboolean +Parse_InstructionSequence(struct parse_state *parseState, + struct prog_instruction program[]) +{ + while (1) { + struct prog_instruction *inst = program + parseState->numInst; + + /* Initialize the instruction */ + _mesa_init_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; + + /* Reset error state */ + _mesa_set_program_error(ctx, -1, NULL); + + /* check the program header */ + if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) { + target = GL_VERTEX_PROGRAM_NV; + parseState.pos = programString + 7; + parseState.isStateProgram = GL_FALSE; + } + else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) { + target = GL_VERTEX_PROGRAM_NV; + parseState.pos = programString + 7; + parseState.isStateProgram = GL_FALSE; + parseState.isVersion1_1 = GL_TRUE; + } + else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) { + target = GL_VERTEX_STATE_PROGRAM_NV; + parseState.pos = programString + 8; + parseState.isStateProgram = GL_TRUE; + } + else { + /* invalid header */ + ctx->Program.ErrorPos = 0; + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); + return; + } + + /* make sure target and header match */ + if (target != dstTarget) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glLoadProgramNV(target mismatch)"); + return; + } + + + if (Parse_Program(&parseState, instBuffer)) { + 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"); + _mesa_free(programString); + return; /* out of memory */ + } + _mesa_copy_instructions(newInst, instBuffer, parseState.numInst); + + /* install the program */ + program->Base.Target = target; + if (program->Base.String) { + _mesa_free(program->Base.String); + } + program->Base.String = programString; + program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB; + if (program->Base.Instructions) { + _mesa_free(program->Base.Instructions); + } + program->Base.Instructions = newInst; + program->Base.InputsRead = parseState.inputsRead; + 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 + _mesa_printf("--- glLoadProgramNV result ---\n"); + _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0); + _mesa_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; + + 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/shader/nvvertparse.h b/mesalib/src/mesa/shader/nvvertparse.h new file mode 100644 index 000000000..9919e2238 --- /dev/null +++ b/mesalib/src/mesa/shader/nvvertparse.h @@ -0,0 +1,45 @@ +/* + * Mesa 3-D graphics library + * Version: 5.1 + * + * Copyright (C) 1999-2003 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Brian Paul + */ + + +#ifndef NVVERTPARSE_H +#define NVVERTPARSE_H + + +extern void +_mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum target, + const GLubyte *str, GLsizei len, + struct gl_vertex_program *program); + + +extern 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/shader/prog_cache.c b/mesalib/src/mesa/shader/prog_cache.c new file mode 100644 index 000000000..9437e5961 --- /dev/null +++ b/mesalib/src/mesa/shader/prog_cache.c @@ -0,0 +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 "shader/prog_cache.h" +#include "shader/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**) _mesa_malloc(size * sizeof(*items)); + _mesa_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; + } + + _mesa_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; + _mesa_free(c->key); + _mesa_reference_program(ctx, &c->program, NULL); + _mesa_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 **) + _mesa_calloc(cache->size * sizeof(struct cache_item)); + if (!cache->items) { + _mesa_free(cache); + return NULL; + } + } + return cache; +} + + +void +_mesa_delete_program_cache(GLcontext *ctx, struct gl_program_cache *cache) +{ + clear_cache(ctx, cache); + _mesa_free(cache->items); + _mesa_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 = _mesa_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/shader/prog_cache.h b/mesalib/src/mesa/shader/prog_cache.h new file mode 100644 index 000000000..4e1ccac03 --- /dev/null +++ b/mesalib/src/mesa/shader/prog_cache.h @@ -0,0 +1,55 @@ +/************************************************************************** + * + * 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 + + +/** 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 */ diff --git a/mesalib/src/mesa/shader/prog_execute.c b/mesalib/src/mesa/shader/prog_execute.c new file mode 100644 index 000000000..69b81e724 --- /dev/null +++ b/mesalib/src/mesa/shader/prog_execute.c @@ -0,0 +1,1757 @@ +/* + * 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/context.h" +#include "program.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) ( *((GLuint *) (void *)&x) = 0x7F800000 ) +#define SET_NEG_INFINITY(x) ( *((GLuint *) (void *)&x) = 0xFF800000 ) +#elif defined(VMS) +#define SET_POS_INFINITY(x) x = __MAXFLOAT +#define SET_NEG_INFINITY(x) x = -__MAXFLOAT +#else +#define SET_POS_INFINITY(x) x = (GLfloat) HUGE_VAL +#define SET_NEG_INFINITY(x) x = (GLfloat) -HUGE_VAL +#endif + +#define SET_FLOAT_BITS(x, bits) ((fi_type *) (void *) &(x))->i = bits + + +static const GLfloat ZeroVec[4] = { 0.0F, 0.0F, 0.0F, 0.0F }; + + + +/** + * 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]; + } +} + + +/** + * 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(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 + } +} + + + +/** + * 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]); + } + break; + case OPCODE_BGNLOOP: + /* no-op */ + break; + case OPCODE_ENDLOOP: + /* subtract 1 here since pc is incremented by for(pc) loop */ + 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) */ + /* fall-through */ + case OPCODE_BRK: /* break out of loop (conditional) */ + /* fall-through */ + case OPCODE_CONT: /* continue loop (conditional) */ + if (eval_condition(machine, inst)) { + /* take branch */ + /* 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); + } + 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) _mesa_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) _mesa_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) _mesa_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; + /* 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 - 1; + } + } + break; + case OPCODE_ELSE: + /* goto ENDIF */ + assert(inst->BranchTarget >= 0); + pc = inst->BranchTarget - 1; + 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 = 0.0F; + } + else { + val = 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.0; + else + result[2] = (GLfloat) _mesa_pow(a[1], a[3]); + } + else { + result[2] = 0.0; + } + 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] = (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) _mesa_pow(a[0], b[0]); + 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) _mesa_cos(a[0]); + result[1] = (GLfloat) _mesa_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) _mesa_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_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 */ + { + GLfloat a[4], result[4]; + const GLuint *rawBits = (const GLuint *) a; + GLhalfNV hx, hy; + fetch_vector1(&inst->SrcReg[0], machine, a); + hx = rawBits[0] & 0xffff; + hy = rawBits[0] >> 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 */ + { + GLfloat a[4], result[4]; + const GLuint *rawBits = (const GLuint *) a; + GLushort usx, usy; + fetch_vector1(&inst->SrcReg[0], machine, a); + usx = rawBits[0] & 0xffff; + usy = rawBits[0] >> 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 */ + { + GLfloat a[4], result[4]; + const GLuint *rawBits = (const GLuint *) a; + fetch_vector1(&inst->SrcReg[0], machine, a); + result[0] = (((rawBits[0] >> 0) & 0xff) - 128) / 127.0F; + result[1] = (((rawBits[0] >> 8) & 0xff) - 128) / 127.0F; + result[2] = (((rawBits[0] >> 16) & 0xff) - 128) / 127.0F; + result[3] = (((rawBits[0] >> 24) & 0xff) - 128) / 127.0F; + store_vector4(inst, machine, result); + } + break; + case OPCODE_UP4UB: /* unpack four GLubytes */ + { + GLfloat a[4], result[4]; + const GLuint *rawBits = (const GLuint *) a; + fetch_vector1(&inst->SrcReg[0], machine, a); + result[0] = ((rawBits[0] >> 0) & 0xff) / 255.0F; + result[1] = ((rawBits[0] >> 8) & 0xff) / 255.0F; + result[2] = ((rawBits[0] >> 16) & 0xff) / 255.0F; + result[3] = ((rawBits[0] >> 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 != -1) { + GLfloat a[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + _mesa_printf("%s%g, %g, %g, %g\n", (const char *) inst->Data, + a[0], a[1], a[2], a[3]); + } + else { + _mesa_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) { + _mesa_problem(ctx, "Infinite loop detected in fragment program"); + return GL_TRUE; + } + + } /* for pc */ + + return GL_TRUE; +} diff --git a/mesalib/src/mesa/shader/prog_execute.h b/mesalib/src/mesa/shader/prog_execute.h new file mode 100644 index 000000000..adefc5439 --- /dev/null +++ b/mesalib/src/mesa/shader/prog_execute.h @@ -0,0 +1,85 @@ +/* + * 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" + + +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 */ diff --git a/mesalib/src/mesa/shader/prog_instruction.c b/mesalib/src/mesa/shader/prog_instruction.c new file mode 100644 index 000000000..44c961927 --- /dev/null +++ b/mesalib/src/mesa/shader/prog_instruction.c @@ -0,0 +1,352 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 1999-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. + */ + + +#include "main/glheader.h" +#include "main/imports.h" +#include "main/mtypes.h" +#include "prog_instruction.h" + + +/** + * Initialize program instruction fields to defaults. + * \param inst first instruction to initialize + * \param count number of instructions to initialize + */ +void +_mesa_init_instructions(struct prog_instruction *inst, GLuint count) +{ + GLuint i; + + _mesa_bzero(inst, count * sizeof(struct prog_instruction)); + + for (i = 0; i < count; i++) { + inst[i].SrcReg[0].File = PROGRAM_UNDEFINED; + inst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP; + inst[i].SrcReg[1].File = PROGRAM_UNDEFINED; + inst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; + inst[i].SrcReg[2].File = PROGRAM_UNDEFINED; + inst[i].SrcReg[2].Swizzle = SWIZZLE_NOOP; + + inst[i].DstReg.File = PROGRAM_UNDEFINED; + inst[i].DstReg.WriteMask = WRITEMASK_XYZW; + inst[i].DstReg.CondMask = COND_TR; + inst[i].DstReg.CondSwizzle = SWIZZLE_NOOP; + + inst[i].SaturateMode = SATURATE_OFF; + inst[i].Precision = FLOAT32; + } +} + + +/** + * Allocate an array of program instructions. + * \param numInst number of instructions + * \return pointer to instruction memory + */ +struct prog_instruction * +_mesa_alloc_instructions(GLuint numInst) +{ + return (struct prog_instruction *) + _mesa_calloc(numInst * sizeof(struct prog_instruction)); +} + + +/** + * Reallocate memory storing an array of program instructions. + * This is used when we need to append additional instructions onto an + * program. + * \param oldInst pointer to first of old/src instructions + * \param numOldInst number of instructions at <oldInst> + * \param numNewInst desired size of new instruction array. + * \return pointer to start of new instruction array. + */ +struct prog_instruction * +_mesa_realloc_instructions(struct prog_instruction *oldInst, + GLuint numOldInst, GLuint numNewInst) +{ + struct prog_instruction *newInst; + + newInst = (struct prog_instruction *) + _mesa_realloc(oldInst, + numOldInst * sizeof(struct prog_instruction), + numNewInst * sizeof(struct prog_instruction)); + + return newInst; +} + + +/** + * Copy an array of program instructions. + * \param dest pointer to destination. + * \param src pointer to source. + * \param n number of instructions to copy. + * \return pointer to destination. + */ +struct prog_instruction * +_mesa_copy_instructions(struct prog_instruction *dest, + const struct prog_instruction *src, GLuint n) +{ + GLuint i; + _mesa_memcpy(dest, src, n * sizeof(struct prog_instruction)); + for (i = 0; i < n; i++) { + if (src[i].Comment) + dest[i].Comment = _mesa_strdup(src[i].Comment); + } + return dest; +} + + +/** + * Free an array of instructions + */ +void +_mesa_free_instructions(struct prog_instruction *inst, GLuint count) +{ + GLuint i; + for (i = 0; i < count; i++) { + if (inst[i].Data) + _mesa_free(inst[i].Data); + if (inst[i].Comment) + _mesa_free((char *) inst[i].Comment); + } + _mesa_free(inst); +} + + +/** + * Basic info about each instruction + */ +struct instruction_info +{ + gl_inst_opcode Opcode; + const char *Name; + GLuint NumSrcRegs; + GLuint NumDstRegs; +}; + +/** + * Instruction info + * \note Opcode should equal array index! + */ +static const struct instruction_info InstInfo[MAX_OPCODE] = { + { OPCODE_NOP, "NOP", 0, 0 }, + { OPCODE_ABS, "ABS", 1, 1 }, + { OPCODE_ADD, "ADD", 2, 1 }, + { OPCODE_AND, "AND", 2, 1 }, + { OPCODE_ARA, "ARA", 1, 1 }, + { OPCODE_ARL, "ARL", 1, 1 }, + { OPCODE_ARL_NV, "ARL_NV", 1, 1 }, + { OPCODE_ARR, "ARL", 1, 1 }, + { OPCODE_BGNLOOP,"BGNLOOP", 0, 0 }, + { OPCODE_BGNSUB, "BGNSUB", 0, 0 }, + { OPCODE_BRA, "BRA", 0, 0 }, + { OPCODE_BRK, "BRK", 0, 0 }, + { OPCODE_CAL, "CAL", 0, 0 }, + { OPCODE_CMP, "CMP", 3, 1 }, + { OPCODE_CONT, "CONT", 0, 0 }, + { OPCODE_COS, "COS", 1, 1 }, + { OPCODE_DDX, "DDX", 1, 1 }, + { OPCODE_DDY, "DDY", 1, 1 }, + { OPCODE_DP2, "DP2", 2, 1 }, + { OPCODE_DP2A, "DP2A", 3, 1 }, + { OPCODE_DP3, "DP3", 2, 1 }, + { OPCODE_DP4, "DP4", 2, 1 }, + { OPCODE_DPH, "DPH", 2, 1 }, + { OPCODE_DST, "DST", 2, 1 }, + { OPCODE_ELSE, "ELSE", 0, 0 }, + { OPCODE_END, "END", 0, 0 }, + { OPCODE_ENDIF, "ENDIF", 0, 0 }, + { OPCODE_ENDLOOP,"ENDLOOP", 0, 0 }, + { OPCODE_ENDSUB, "ENDSUB", 0, 0 }, + { OPCODE_EX2, "EX2", 1, 1 }, + { OPCODE_EXP, "EXP", 1, 1 }, + { OPCODE_FLR, "FLR", 1, 1 }, + { OPCODE_FRC, "FRC", 1, 1 }, + { OPCODE_IF, "IF", 1, 0 }, + { OPCODE_KIL, "KIL", 1, 0 }, + { OPCODE_KIL_NV, "KIL_NV", 0, 0 }, + { OPCODE_LG2, "LG2", 1, 1 }, + { OPCODE_LIT, "LIT", 1, 1 }, + { OPCODE_LOG, "LOG", 1, 1 }, + { OPCODE_LRP, "LRP", 3, 1 }, + { OPCODE_MAD, "MAD", 3, 1 }, + { OPCODE_MAX, "MAX", 2, 1 }, + { OPCODE_MIN, "MIN", 2, 1 }, + { OPCODE_MOV, "MOV", 1, 1 }, + { OPCODE_MUL, "MUL", 2, 1 }, + { OPCODE_NOISE1, "NOISE1", 1, 1 }, + { OPCODE_NOISE2, "NOISE2", 1, 1 }, + { OPCODE_NOISE3, "NOISE3", 1, 1 }, + { OPCODE_NOISE4, "NOISE4", 1, 1 }, + { OPCODE_NOT, "NOT", 1, 1 }, + { OPCODE_NRM3, "NRM3", 1, 1 }, + { OPCODE_NRM4, "NRM4", 1, 1 }, + { OPCODE_OR, "OR", 2, 1 }, + { OPCODE_PK2H, "PK2H", 1, 1 }, + { OPCODE_PK2US, "PK2US", 1, 1 }, + { OPCODE_PK4B, "PK4B", 1, 1 }, + { OPCODE_PK4UB, "PK4UB", 1, 1 }, + { OPCODE_POW, "POW", 2, 1 }, + { OPCODE_POPA, "POPA", 0, 0 }, + { OPCODE_PRINT, "PRINT", 1, 0 }, + { OPCODE_PUSHA, "PUSHA", 0, 0 }, + { OPCODE_RCC, "RCC", 1, 1 }, + { OPCODE_RCP, "RCP", 1, 1 }, + { OPCODE_RET, "RET", 0, 0 }, + { OPCODE_RFL, "RFL", 1, 1 }, + { OPCODE_RSQ, "RSQ", 1, 1 }, + { OPCODE_SCS, "SCS", 1, 1 }, + { OPCODE_SEQ, "SEQ", 2, 1 }, + { OPCODE_SFL, "SFL", 0, 1 }, + { OPCODE_SGE, "SGE", 2, 1 }, + { OPCODE_SGT, "SGT", 2, 1 }, + { OPCODE_SIN, "SIN", 1, 1 }, + { OPCODE_SLE, "SLE", 2, 1 }, + { OPCODE_SLT, "SLT", 2, 1 }, + { OPCODE_SNE, "SNE", 2, 1 }, + { OPCODE_SSG, "SSG", 1, 1 }, + { OPCODE_STR, "STR", 0, 1 }, + { OPCODE_SUB, "SUB", 2, 1 }, + { OPCODE_SWZ, "SWZ", 1, 1 }, + { OPCODE_TEX, "TEX", 1, 1 }, + { OPCODE_TXB, "TXB", 1, 1 }, + { OPCODE_TXD, "TXD", 3, 1 }, + { OPCODE_TXL, "TXL", 1, 1 }, + { OPCODE_TXP, "TXP", 1, 1 }, + { OPCODE_TXP_NV, "TXP_NV", 1, 1 }, + { OPCODE_TRUNC, "TRUNC", 1, 1 }, + { OPCODE_UP2H, "UP2H", 1, 1 }, + { OPCODE_UP2US, "UP2US", 1, 1 }, + { OPCODE_UP4B, "UP4B", 1, 1 }, + { OPCODE_UP4UB, "UP4UB", 1, 1 }, + { OPCODE_X2D, "X2D", 3, 1 }, + { OPCODE_XOR, "XOR", 2, 1 }, + { OPCODE_XPD, "XPD", 2, 1 } +}; + + +/** + * Return the number of src registers for the given instruction/opcode. + */ +GLuint +_mesa_num_inst_src_regs(gl_inst_opcode opcode) +{ + ASSERT(opcode < MAX_OPCODE); + ASSERT(opcode == InstInfo[opcode].Opcode); + ASSERT(OPCODE_XPD == InstInfo[OPCODE_XPD].Opcode); + return InstInfo[opcode].NumSrcRegs; +} + + +/** + * Return the number of dst registers for the given instruction/opcode. + */ +GLuint +_mesa_num_inst_dst_regs(gl_inst_opcode opcode) +{ + ASSERT(opcode < MAX_OPCODE); + ASSERT(opcode == InstInfo[opcode].Opcode); + ASSERT(OPCODE_XPD == InstInfo[OPCODE_XPD].Opcode); + return InstInfo[opcode].NumDstRegs; +} + + +GLboolean +_mesa_is_tex_instruction(gl_inst_opcode opcode) +{ + return (opcode == OPCODE_TEX || + opcode == OPCODE_TXB || + opcode == OPCODE_TXD || + opcode == OPCODE_TXL || + opcode == OPCODE_TXP); +} + + +/** + * Check if there's a potential src/dst register data dependency when + * using SOA execution. + * Example: + * MOV T, T.yxwz; + * This would expand into: + * MOV t0, t1; + * MOV t1, t0; + * MOV t2, t3; + * MOV t3, t2; + * The second instruction will have the wrong value for t0 if executed as-is. + */ +GLboolean +_mesa_check_soa_dependencies(const struct prog_instruction *inst) +{ + GLuint i, chan; + + if (inst->DstReg.WriteMask == WRITEMASK_X || + inst->DstReg.WriteMask == WRITEMASK_Y || + inst->DstReg.WriteMask == WRITEMASK_Z || + inst->DstReg.WriteMask == WRITEMASK_W || + inst->DstReg.WriteMask == 0x0) { + /* no chance of data dependency */ + return GL_FALSE; + } + + /* loop over src regs */ + for (i = 0; i < 3; i++) { + if (inst->SrcReg[i].File == inst->DstReg.File && + inst->SrcReg[i].Index == inst->DstReg.Index) { + /* loop over dest channels */ + GLuint channelsWritten = 0x0; + for (chan = 0; chan < 4; chan++) { + if (inst->DstReg.WriteMask & (1 << chan)) { + /* check if we're reading a channel that's been written */ + GLuint swizzle = GET_SWZ(inst->SrcReg[i].Swizzle, chan); + if (swizzle <= SWIZZLE_W && + (channelsWritten & (1 << swizzle))) { + return GL_TRUE; + } + + channelsWritten |= (1 << chan); + } + } + } + } + return GL_FALSE; +} + + +/** + * Return string name for given program opcode. + */ +const char * +_mesa_opcode_string(gl_inst_opcode opcode) +{ + if (opcode < MAX_OPCODE) + return InstInfo[opcode].Name; + else { + static char s[20]; + _mesa_snprintf(s, sizeof(s), "OP%u", opcode); + return s; + } +} + diff --git a/mesalib/src/mesa/shader/prog_instruction.h b/mesalib/src/mesa/shader/prog_instruction.h new file mode 100644 index 000000000..39a221eea --- /dev/null +++ b/mesalib/src/mesa/shader/prog_instruction.h @@ -0,0 +1,439 @@ +/* + * 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/mfeatures.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 then or equal to zero */ +#define COND_LE 6 /**< less then or equal to zero */ +#define COND_NE 7 /**< not equal to zero */ +#define COND_TR 8 /**< always true */ +#define COND_FL 9 /**< always false */ +/*@}*/ + + +/** + * Instruction precision for GL_NV_fragment_program + */ +/*@{*/ +#define FLOAT32 0x1 +#define FLOAT16 0x2 +#define FIXED12 0x4 +/*@}*/ + + +/** + * Saturation modes when storing values. + */ +/*@{*/ +#define SATURATE_OFF 0 +#define SATURATE_ZERO_ONE 1 +#define SATURATE_PLUS_MINUS_ONE 2 +/*@}*/ + + +/** + * Per-component negation masks + */ +/*@{*/ +#define NEGATE_X 0x1 +#define NEGATE_Y 0x2 +#define NEGATE_Z 0x4 +#define NEGATE_W 0x8 +#define NEGATE_XYZ 0x7 +#define NEGATE_XYZW 0xf +#define NEGATE_NONE 0x0 +/*@}*/ + + +/** + * Program instruction opcodes, for both vertex and fragment programs. + * \note changes to this opcode list must be reflected in t_vb_arbprogram.c + */ +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 */ + 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 */ + OPCODE_CMP, /* X */ + OPCODE_CONT, /* opt */ + OPCODE_COS, /* X 2 X X */ + OPCODE_DDX, /* X X */ + OPCODE_DDY, /* X X */ + OPCODE_DP2, /* 2 */ + 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_END, /* X X X X opt */ + 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 */ + 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, /* */ + OPCODE_NRM4, /* */ + 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 */ + 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; +}; + + +/** + * 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; + /*@}*/ + GLuint pad:28; +}; + + +/** + * 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 BGNLOOP (which 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/shader/prog_noise.c b/mesalib/src/mesa/shader/prog_noise.c new file mode 100644 index 000000000..1713ddb5f --- /dev/null +++ b/mesalib/src/mesa/shader/prog_noise.c @@ -0,0 +1,638 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * SimplexNoise1234 + * Copyright (c) 2003-2005, Stefan Gustavson + * + * Contact: stegu@itn.liu.se + */ + +/** + * \file + * \brief C implementation of Perlin Simplex Noise over 1, 2, 3 and 4 dims. + * \author Stefan Gustavson (stegu@itn.liu.se) + * + * + * This implementation is "Simplex Noise" as presented by + * Ken Perlin at a relatively obscure and not often cited course + * session "Real-Time Shading" at Siggraph 2001 (before real + * time shading actually took on), under the title "hardware noise". + * The 3D function is numerically equivalent to his Java reference + * code available in the PDF course notes, although I re-implemented + * it from scratch to get more readable code. The 1D, 2D and 4D cases + * were implemented from scratch by me from Ken Perlin's text. + * + * This file has no dependencies on any other file, not even its own + * header file. The header file is made for use by external code only. + */ + + +#include "main/imports.h" +#include "prog_noise.h" + +#define FASTFLOOR(x) ( ((x)>0) ? ((int)x) : (((int)x)-1) ) + +/* + * --------------------------------------------------------------------- + * Static data + */ + +/** + * Permutation table. This is just a random jumble of all numbers 0-255, + * repeated twice to avoid wrapping the index at 255 for each lookup. + * This needs to be exactly the same for all instances on all platforms, + * so it's easiest to just keep it as static explicit data. + * This also removes the need for any initialisation of this class. + * + * Note that making this an int[] instead of a char[] might make the + * code run faster on platforms with a high penalty for unaligned single + * byte addressing. Intel x86 is generally single-byte-friendly, but + * some other CPUs are faster with 4-aligned reads. + * However, a char[] is smaller, which avoids cache trashing, and that + * is probably the most important aspect on most architectures. + * This array is accessed a *lot* by the noise functions. + * A vector-valued noise over 3D accesses it 96 times, and a + * float-valued 4D noise 64 times. We want this to fit in the cache! + */ +unsigned char perm[512] = { 151, 160, 137, 91, 90, 15, + 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, + 99, 37, 240, 21, 10, 23, + 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, + 11, 32, 57, 177, 33, + 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, + 134, 139, 48, 27, 166, + 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, + 55, 46, 245, 40, 244, + 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, + 18, 169, 200, 196, + 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, + 226, 250, 124, 123, + 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, + 17, 182, 189, 28, 42, + 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, + 167, 43, 172, 9, + 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, + 218, 246, 97, 228, + 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, + 249, 14, 239, 107, + 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, + 127, 4, 150, 254, + 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, + 215, 61, 156, 180, + 151, 160, 137, 91, 90, 15, + 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, + 99, 37, 240, 21, 10, 23, + 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, + 11, 32, 57, 177, 33, + 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, + 134, 139, 48, 27, 166, + 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, + 55, 46, 245, 40, 244, + 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, + 18, 169, 200, 196, + 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, + 226, 250, 124, 123, + 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, + 17, 182, 189, 28, 42, + 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, + 167, 43, 172, 9, + 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, + 218, 246, 97, 228, + 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, + 249, 14, 239, 107, + 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, + 127, 4, 150, 254, + 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, + 215, 61, 156, 180 +}; + +/* + * --------------------------------------------------------------------- + */ + +/* + * Helper functions to compute gradients-dot-residualvectors (1D to 4D) + * Note that these generate gradients of more than unit length. To make + * a close match with the value range of classic Perlin noise, the final + * noise values need to be rescaled to fit nicely within [-1,1]. + * (The simplex noise functions as such also have different scaling.) + * Note also that these noise functions are the most practical and useful + * signed version of Perlin noise. To return values according to the + * RenderMan specification from the SL noise() and pnoise() functions, + * the noise values need to be scaled and offset to [0,1], like this: + * float SLnoise = (SimplexNoise1234::noise(x,y,z) + 1.0) * 0.5; + */ + +static float +grad1(int hash, float x) +{ + int h = hash & 15; + float grad = 1.0f + (h & 7); /* Gradient value 1.0, 2.0, ..., 8.0 */ + if (h & 8) + grad = -grad; /* Set a random sign for the gradient */ + return (grad * x); /* Multiply the gradient with the distance */ +} + +static float +grad2(int hash, float x, float y) +{ + int h = hash & 7; /* Convert low 3 bits of hash code */ + float u = h < 4 ? x : y; /* into 8 simple gradient directions, */ + float v = h < 4 ? y : x; /* and compute the dot product with (x,y). */ + return ((h & 1) ? -u : u) + ((h & 2) ? -2.0f * v : 2.0f * v); +} + +static float +grad3(int hash, float x, float y, float z) +{ + int h = hash & 15; /* Convert low 4 bits of hash code into 12 simple */ + float u = h < 8 ? x : y; /* gradient directions, and compute dot product. */ + float v = h < 4 ? y : h == 12 || h == 14 ? x : z; /* Fix repeats at h = 12 to 15 */ + return ((h & 1) ? -u : u) + ((h & 2) ? -v : v); +} + +static float +grad4(int hash, float x, float y, float z, float t) +{ + int h = hash & 31; /* Convert low 5 bits of hash code into 32 simple */ + float u = h < 24 ? x : y; /* gradient directions, and compute dot product. */ + float v = h < 16 ? y : z; + float w = h < 8 ? z : t; + return ((h & 1) ? -u : u) + ((h & 2) ? -v : v) + ((h & 4) ? -w : w); +} + +/** + * A lookup table to traverse the simplex around a given point in 4D. + * Details can be found where this table is used, in the 4D noise method. + * TODO: This should not be required, backport it from Bill's GLSL code! + */ +static unsigned char simplex[64][4] = { + {0, 1, 2, 3}, {0, 1, 3, 2}, {0, 0, 0, 0}, {0, 2, 3, 1}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 2, 3, 0}, + {0, 2, 1, 3}, {0, 0, 0, 0}, {0, 3, 1, 2}, {0, 3, 2, 1}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 3, 2, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {1, 2, 0, 3}, {0, 0, 0, 0}, {1, 3, 0, 2}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {2, 3, 0, 1}, {2, 3, 1, 0}, + {1, 0, 2, 3}, {1, 0, 3, 2}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {2, 0, 3, 1}, {0, 0, 0, 0}, {2, 1, 3, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {2, 0, 1, 3}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {3, 0, 1, 2}, {3, 0, 2, 1}, {0, 0, 0, 0}, {3, 1, 2, 0}, + {2, 1, 0, 3}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, + {3, 1, 0, 2}, {0, 0, 0, 0}, {3, 2, 0, 1}, {3, 2, 1, 0} +}; + + +/** 1D simplex noise */ +GLfloat +_mesa_noise1(GLfloat x) +{ + int i0 = FASTFLOOR(x); + int i1 = i0 + 1; + float x0 = x - i0; + float x1 = x0 - 1.0f; + float t1 = 1.0f - x1 * x1; + float n0, n1; + + float t0 = 1.0f - x0 * x0; +/* if(t0 < 0.0f) t0 = 0.0f; // this never happens for the 1D case */ + t0 *= t0; + n0 = t0 * t0 * grad1(perm[i0 & 0xff], x0); + +/* if(t1 < 0.0f) t1 = 0.0f; // this never happens for the 1D case */ + t1 *= t1; + n1 = t1 * t1 * grad1(perm[i1 & 0xff], x1); + /* The maximum value of this noise is 8*(3/4)^4 = 2.53125 */ + /* A factor of 0.395 would scale to fit exactly within [-1,1], but */ + /* we want to match PRMan's 1D noise, so we scale it down some more. */ + return 0.25f * (n0 + n1); +} + + +/** 2D simplex noise */ +GLfloat +_mesa_noise2(GLfloat x, GLfloat y) +{ +#define F2 0.366025403f /* F2 = 0.5*(sqrt(3.0)-1.0) */ +#define G2 0.211324865f /* G2 = (3.0-Math.sqrt(3.0))/6.0 */ + + float n0, n1, n2; /* Noise contributions from the three corners */ + + /* Skew the input space to determine which simplex cell we're in */ + float s = (x + y) * F2; /* Hairy factor for 2D */ + float xs = x + s; + float ys = y + s; + int i = FASTFLOOR(xs); + int j = FASTFLOOR(ys); + + float t = (float) (i + j) * G2; + float X0 = i - t; /* Unskew the cell origin back to (x,y) space */ + float Y0 = j - t; + float x0 = x - X0; /* The x,y distances from the cell origin */ + float y0 = y - Y0; + + float x1, y1, x2, y2; + int ii, jj; + float t0, t1, t2; + + /* For the 2D case, the simplex shape is an equilateral triangle. */ + /* Determine which simplex we are in. */ + int i1, j1; /* Offsets for second (middle) corner of simplex in (i,j) coords */ + if (x0 > y0) { + i1 = 1; + j1 = 0; + } /* lower triangle, XY order: (0,0)->(1,0)->(1,1) */ + else { + i1 = 0; + j1 = 1; + } /* upper triangle, YX order: (0,0)->(0,1)->(1,1) */ + + /* A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and */ + /* a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where */ + /* c = (3-sqrt(3))/6 */ + + x1 = x0 - i1 + G2; /* Offsets for middle corner in (x,y) unskewed coords */ + y1 = y0 - j1 + G2; + x2 = x0 - 1.0f + 2.0f * G2; /* Offsets for last corner in (x,y) unskewed coords */ + y2 = y0 - 1.0f + 2.0f * G2; + + /* Wrap the integer indices at 256, to avoid indexing perm[] out of bounds */ + ii = i % 256; + jj = j % 256; + + /* Calculate the contribution from the three corners */ + t0 = 0.5f - x0 * x0 - y0 * y0; + if (t0 < 0.0f) + n0 = 0.0f; + else { + t0 *= t0; + n0 = t0 * t0 * grad2(perm[ii + perm[jj]], x0, y0); + } + + t1 = 0.5f - x1 * x1 - y1 * y1; + if (t1 < 0.0f) + n1 = 0.0f; + else { + t1 *= t1; + n1 = t1 * t1 * grad2(perm[ii + i1 + perm[jj + j1]], x1, y1); + } + + t2 = 0.5f - x2 * x2 - y2 * y2; + if (t2 < 0.0f) + n2 = 0.0f; + else { + t2 *= t2; + n2 = t2 * t2 * grad2(perm[ii + 1 + perm[jj + 1]], x2, y2); + } + + /* Add contributions from each corner to get the final noise value. */ + /* The result is scaled to return values in the interval [-1,1]. */ + return 40.0f * (n0 + n1 + n2); /* TODO: The scale factor is preliminary! */ +} + + +/** 3D simplex noise */ +GLfloat +_mesa_noise3(GLfloat x, GLfloat y, GLfloat z) +{ +/* Simple skewing factors for the 3D case */ +#define F3 0.333333333f +#define G3 0.166666667f + + float n0, n1, n2, n3; /* Noise contributions from the four corners */ + + /* Skew the input space to determine which simplex cell we're in */ + float s = (x + y + z) * F3; /* Very nice and simple skew factor for 3D */ + float xs = x + s; + float ys = y + s; + float zs = z + s; + int i = FASTFLOOR(xs); + int j = FASTFLOOR(ys); + int k = FASTFLOOR(zs); + + float t = (float) (i + j + k) * G3; + float X0 = i - t; /* Unskew the cell origin back to (x,y,z) space */ + float Y0 = j - t; + float Z0 = k - t; + float x0 = x - X0; /* The x,y,z distances from the cell origin */ + float y0 = y - Y0; + float z0 = z - Z0; + + float x1, y1, z1, x2, y2, z2, x3, y3, z3; + int ii, jj, kk; + float t0, t1, t2, t3; + + /* For the 3D case, the simplex shape is a slightly irregular tetrahedron. */ + /* Determine which simplex we are in. */ + int i1, j1, k1; /* Offsets for second corner of simplex in (i,j,k) coords */ + int i2, j2, k2; /* Offsets for third corner of simplex in (i,j,k) coords */ + +/* This code would benefit from a backport from the GLSL version! */ + if (x0 >= y0) { + if (y0 >= z0) { + i1 = 1; + j1 = 0; + k1 = 0; + i2 = 1; + j2 = 1; + k2 = 0; + } /* X Y Z order */ + else if (x0 >= z0) { + i1 = 1; + j1 = 0; + k1 = 0; + i2 = 1; + j2 = 0; + k2 = 1; + } /* X Z Y order */ + else { + i1 = 0; + j1 = 0; + k1 = 1; + i2 = 1; + j2 = 0; + k2 = 1; + } /* Z X Y order */ + } + else { /* x0<y0 */ + if (y0 < z0) { + i1 = 0; + j1 = 0; + k1 = 1; + i2 = 0; + j2 = 1; + k2 = 1; + } /* Z Y X order */ + else if (x0 < z0) { + i1 = 0; + j1 = 1; + k1 = 0; + i2 = 0; + j2 = 1; + k2 = 1; + } /* Y Z X order */ + else { + i1 = 0; + j1 = 1; + k1 = 0; + i2 = 1; + j2 = 1; + k2 = 0; + } /* Y X Z order */ + } + + /* A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in + * (x,y,z), a step of (0,1,0) in (i,j,k) means a step of + * (-c,1-c,-c) in (x,y,z), and a step of (0,0,1) in (i,j,k) means a + * step of (-c,-c,1-c) in (x,y,z), where c = 1/6. + */ + + x1 = x0 - i1 + G3; /* Offsets for second corner in (x,y,z) coords */ + y1 = y0 - j1 + G3; + z1 = z0 - k1 + G3; + x2 = x0 - i2 + 2.0f * G3; /* Offsets for third corner in (x,y,z) coords */ + y2 = y0 - j2 + 2.0f * G3; + z2 = z0 - k2 + 2.0f * G3; + x3 = x0 - 1.0f + 3.0f * G3;/* Offsets for last corner in (x,y,z) coords */ + y3 = y0 - 1.0f + 3.0f * G3; + z3 = z0 - 1.0f + 3.0f * G3; + + /* Wrap the integer indices at 256 to avoid indexing perm[] out of bounds */ + ii = i % 256; + jj = j % 256; + kk = k % 256; + + /* Calculate the contribution from the four corners */ + t0 = 0.6f - x0 * x0 - y0 * y0 - z0 * z0; + if (t0 < 0.0f) + n0 = 0.0f; + else { + t0 *= t0; + n0 = t0 * t0 * grad3(perm[ii + perm[jj + perm[kk]]], x0, y0, z0); + } + + t1 = 0.6f - x1 * x1 - y1 * y1 - z1 * z1; + if (t1 < 0.0f) + n1 = 0.0f; + else { + t1 *= t1; + n1 = + t1 * t1 * grad3(perm[ii + i1 + perm[jj + j1 + perm[kk + k1]]], x1, + y1, z1); + } + + t2 = 0.6f - x2 * x2 - y2 * y2 - z2 * z2; + if (t2 < 0.0f) + n2 = 0.0f; + else { + t2 *= t2; + n2 = + t2 * t2 * grad3(perm[ii + i2 + perm[jj + j2 + perm[kk + k2]]], x2, + y2, z2); + } + + t3 = 0.6f - x3 * x3 - y3 * y3 - z3 * z3; + if (t3 < 0.0f) + n3 = 0.0f; + else { + t3 *= t3; + n3 = + t3 * t3 * grad3(perm[ii + 1 + perm[jj + 1 + perm[kk + 1]]], x3, y3, + z3); + } + + /* Add contributions from each corner to get the final noise value. + * The result is scaled to stay just inside [-1,1] + */ + return 32.0f * (n0 + n1 + n2 + n3); /* TODO: The scale factor is preliminary! */ +} + + +/** 4D simplex noise */ +GLfloat +_mesa_noise4(GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + /* The skewing and unskewing factors are hairy again for the 4D case */ +#define F4 0.309016994f /* F4 = (Math.sqrt(5.0)-1.0)/4.0 */ +#define G4 0.138196601f /* G4 = (5.0-Math.sqrt(5.0))/20.0 */ + + float n0, n1, n2, n3, n4; /* Noise contributions from the five corners */ + + /* Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in */ + float s = (x + y + z + w) * F4; /* Factor for 4D skewing */ + float xs = x + s; + float ys = y + s; + float zs = z + s; + float ws = w + s; + int i = FASTFLOOR(xs); + int j = FASTFLOOR(ys); + int k = FASTFLOOR(zs); + int l = FASTFLOOR(ws); + + float t = (i + j + k + l) * G4; /* Factor for 4D unskewing */ + float X0 = i - t; /* Unskew the cell origin back to (x,y,z,w) space */ + float Y0 = j - t; + float Z0 = k - t; + float W0 = l - t; + + float x0 = x - X0; /* The x,y,z,w distances from the cell origin */ + float y0 = y - Y0; + float z0 = z - Z0; + float w0 = w - W0; + + /* For the 4D case, the simplex is a 4D shape I won't even try to describe. + * To find out which of the 24 possible simplices we're in, we need to + * determine the magnitude ordering of x0, y0, z0 and w0. + * The method below is a good way of finding the ordering of x,y,z,w and + * then find the correct traversal order for the simplex we're in. + * First, six pair-wise comparisons are performed between each possible pair + * of the four coordinates, and the results are used to add up binary bits + * for an integer index. + */ + int c1 = (x0 > y0) ? 32 : 0; + int c2 = (x0 > z0) ? 16 : 0; + int c3 = (y0 > z0) ? 8 : 0; + int c4 = (x0 > w0) ? 4 : 0; + int c5 = (y0 > w0) ? 2 : 0; + int c6 = (z0 > w0) ? 1 : 0; + int c = c1 + c2 + c3 + c4 + c5 + c6; + + int i1, j1, k1, l1; /* The integer offsets for the second simplex corner */ + int i2, j2, k2, l2; /* The integer offsets for the third simplex corner */ + int i3, j3, k3, l3; /* The integer offsets for the fourth simplex corner */ + + float x1, y1, z1, w1, x2, y2, z2, w2, x3, y3, z3, w3, x4, y4, z4, w4; + int ii, jj, kk, ll; + float t0, t1, t2, t3, t4; + + /* + * simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some + * order. Many values of c will never occur, since e.g. x>y>z>w + * makes x<z, y<w and x<w impossible. Only the 24 indices which + * have non-zero entries make any sense. We use a thresholding to + * set the coordinates in turn from the largest magnitude. The + * number 3 in the "simplex" array is at the position of the + * largest coordinate. + */ + i1 = simplex[c][0] >= 3 ? 1 : 0; + j1 = simplex[c][1] >= 3 ? 1 : 0; + k1 = simplex[c][2] >= 3 ? 1 : 0; + l1 = simplex[c][3] >= 3 ? 1 : 0; + /* The number 2 in the "simplex" array is at the second largest coordinate. */ + i2 = simplex[c][0] >= 2 ? 1 : 0; + j2 = simplex[c][1] >= 2 ? 1 : 0; + k2 = simplex[c][2] >= 2 ? 1 : 0; + l2 = simplex[c][3] >= 2 ? 1 : 0; + /* The number 1 in the "simplex" array is at the second smallest coordinate. */ + i3 = simplex[c][0] >= 1 ? 1 : 0; + j3 = simplex[c][1] >= 1 ? 1 : 0; + k3 = simplex[c][2] >= 1 ? 1 : 0; + l3 = simplex[c][3] >= 1 ? 1 : 0; + /* The fifth corner has all coordinate offsets = 1, so no need to look that up. */ + + x1 = x0 - i1 + G4; /* Offsets for second corner in (x,y,z,w) coords */ + y1 = y0 - j1 + G4; + z1 = z0 - k1 + G4; + w1 = w0 - l1 + G4; + x2 = x0 - i2 + 2.0f * G4; /* Offsets for third corner in (x,y,z,w) coords */ + y2 = y0 - j2 + 2.0f * G4; + z2 = z0 - k2 + 2.0f * G4; + w2 = w0 - l2 + 2.0f * G4; + x3 = x0 - i3 + 3.0f * G4; /* Offsets for fourth corner in (x,y,z,w) coords */ + y3 = y0 - j3 + 3.0f * G4; + z3 = z0 - k3 + 3.0f * G4; + w3 = w0 - l3 + 3.0f * G4; + x4 = x0 - 1.0f + 4.0f * G4; /* Offsets for last corner in (x,y,z,w) coords */ + y4 = y0 - 1.0f + 4.0f * G4; + z4 = z0 - 1.0f + 4.0f * G4; + w4 = w0 - 1.0f + 4.0f * G4; + + /* Wrap the integer indices at 256, to avoid indexing perm[] out of bounds */ + ii = i % 256; + jj = j % 256; + kk = k % 256; + ll = l % 256; + + /* Calculate the contribution from the five corners */ + t0 = 0.6f - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0; + if (t0 < 0.0f) + n0 = 0.0f; + else { + t0 *= t0; + n0 = + t0 * t0 * grad4(perm[ii + perm[jj + perm[kk + perm[ll]]]], x0, y0, + z0, w0); + } + + t1 = 0.6f - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1; + if (t1 < 0.0f) + n1 = 0.0f; + else { + t1 *= t1; + n1 = + t1 * t1 * + grad4(perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]]]], + x1, y1, z1, w1); + } + + t2 = 0.6f - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2; + if (t2 < 0.0f) + n2 = 0.0f; + else { + t2 *= t2; + n2 = + t2 * t2 * + grad4(perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]]]], + x2, y2, z2, w2); + } + + t3 = 0.6f - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3; + if (t3 < 0.0f) + n3 = 0.0f; + else { + t3 *= t3; + n3 = + t3 * t3 * + grad4(perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]]]], + x3, y3, z3, w3); + } + + t4 = 0.6f - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4; + if (t4 < 0.0f) + n4 = 0.0f; + else { + t4 *= t4; + n4 = + t4 * t4 * + grad4(perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]]]], x4, + y4, z4, w4); + } + + /* Sum up and scale the result to cover the range [-1,1] */ + return 27.0f * (n0 + n1 + n2 + n3 + n4); /* TODO: The scale factor is preliminary! */ +} diff --git a/mesalib/src/mesa/shader/prog_noise.h b/mesalib/src/mesa/shader/prog_noise.h new file mode 100644 index 000000000..c4779479f --- /dev/null +++ b/mesalib/src/mesa/shader/prog_noise.h @@ -0,0 +1,34 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef PROG_NOISE +#define PROG_NOISE + +extern GLfloat _mesa_noise1(GLfloat); +extern GLfloat _mesa_noise2(GLfloat, GLfloat); +extern GLfloat _mesa_noise3(GLfloat, GLfloat, GLfloat); +extern GLfloat _mesa_noise4(GLfloat, GLfloat, GLfloat, GLfloat); + +#endif + diff --git a/mesalib/src/mesa/shader/prog_optimize.c b/mesalib/src/mesa/shader/prog_optimize.c new file mode 100644 index 000000000..be903106a --- /dev/null +++ b/mesalib/src/mesa/shader/prog_optimize.c @@ -0,0 +1,832 @@ +/* + * 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 + + +static GLboolean dbg = GL_FALSE; + + +/** + * 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 */ + } + } + } + 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]; + } + } +} + + +/** + * Consolidate temporary registers to use low numbers. For example, if the + * shader only uses temps 4, 5, 8, replace them with 0, 1, 2. + */ +static void +_mesa_consolidate_registers(struct gl_program *prog) +{ + GLboolean tempUsed[MAX_PROGRAM_TEMPS]; + GLint tempMap[MAX_PROGRAM_TEMPS]; + GLuint tempMax = 0, i; + + if (dbg) { + _mesa_printf("Optimize: Begin register consolidation\n"); + } + + memset(tempUsed, 0, sizeof(tempUsed)); + + for (i = 0; i < MAX_PROGRAM_TEMPS; i++) { + tempMap[i] = -1; + } + + /* set tempUsed[i] if temporary [i] is referenced */ + 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; + for (j = 0; j < numSrc; j++) { + if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { + const GLuint index = inst->SrcReg[j].Index; + ASSERT(index < MAX_PROGRAM_TEMPS); + tempUsed[index] = GL_TRUE; + tempMax = MAX2(tempMax, index); + break; + } + } + if (inst->DstReg.File == PROGRAM_TEMPORARY) { + const GLuint index = inst->DstReg.Index; + ASSERT(index < MAX_PROGRAM_TEMPS); + tempUsed[index] = GL_TRUE; + tempMax = MAX2(tempMax, index); + } + } + + /* allocate a new index for each temp that's used */ + { + GLuint freeTemp = 0; + for (i = 0; i <= tempMax; i++) { + if (tempUsed[i]) { + tempMap[i] = freeTemp++; + /*_mesa_printf("replace %u with %u\n", i, tempMap[i]);*/ + } + } + if (freeTemp == tempMax + 1) { + /* no consolidation possible */ + return; + } + if (dbg) { + _mesa_printf("Replace regs 0..%u with 0..%u\n", tempMax, freeTemp-1); + } + } + + replace_regs(prog, PROGRAM_TEMPORARY, tempMap); + + if (dbg) { + _mesa_printf("Optimize: End register consolidation\n"); + } +} + + +/** + * 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 void +_mesa_remove_dead_code(struct gl_program *prog) +{ + GLboolean tempWritten[MAX_PROGRAM_TEMPS], tempRead[MAX_PROGRAM_TEMPS]; + GLboolean *removeInst; /* per-instruction removal flag */ + GLuint i, rem; + + memset(tempWritten, 0, sizeof(tempWritten)); + memset(tempRead, 0, sizeof(tempRead)); + + if (dbg) { + _mesa_printf("Optimize: Begin dead code removal\n"); + /*_mesa_print_program(prog);*/ + } + + removeInst = (GLboolean *) + _mesa_calloc(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; + ASSERT(index < MAX_PROGRAM_TEMPS); + + if (inst->SrcReg[j].RelAddr) { + if (dbg) + _mesa_printf("abort remove dead code (indirect temp)\n"); + return; + } + + tempRead[index] = GL_TRUE; + } + } + + /* check dst reg */ + if (inst->DstReg.File == PROGRAM_TEMPORARY) { + const GLuint index = inst->DstReg.Index; + ASSERT(index < MAX_PROGRAM_TEMPS); + + if (inst->DstReg.RelAddr) { + if (dbg) + _mesa_printf("abort remove dead code (indirect temp)\n"); + return; + } + + tempWritten[index] = GL_TRUE; + 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] = GL_TRUE; + } + } + } + + if (dbg) { + for (i = 0; i < MAX_PROGRAM_TEMPS; i++) { + if (tempWritten[i] && !tempRead[i]) + _mesa_printf("Remove writes to tmp %u\n", i); + } + } + + /* find instructions that write to dead registers, flag for removal */ + for (i = 0; i < prog->NumInstructions; i++) { + const struct prog_instruction *inst = prog->Instructions + i; + if (inst->DstReg.File == PROGRAM_TEMPORARY) { + GLint index = inst->DstReg.Index; + removeInst[i] = (tempWritten[index] && !tempRead[index]); + if (dbg && removeInst[i]) { + _mesa_printf("Remove inst %u: ", i); + _mesa_print_instruction(inst); + } + } + } + + /* now remove the instructions which aren't needed */ + rem = remove_instructions(prog, removeInst); + + _mesa_free(removeInst); + + if (dbg) { + _mesa_printf("Optimize: End dead code removal. %u instructions removed\n", rem); + /*_mesa_print_program(prog);*/ + } +} + + +enum temp_use +{ + READ, + WRITE, + FLOW, + END +}; + +/** + * Scan forward in program from 'start' for the next occurance of TEMP[index]. + * Return READ, WRITE, FLOW or END to indicate the next usage or an indicator + * that we can't look further. + */ +static enum temp_use +find_next_temp_use(const struct gl_program *prog, GLuint start, GLuint index) +{ + 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_ENDLOOP: + case OPCODE_BGNSUB: + case OPCODE_ENDSUB: + return FLOW; + default: + { + const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); + GLuint j; + for (j = 0; j < numSrc; j++) { + if (inst->SrcReg[j].File == PROGRAM_TEMPORARY && + inst->SrcReg[j].Index == index) + return READ; + } + if (inst->DstReg.File == PROGRAM_TEMPORARY && + inst->DstReg.Index == index) + return WRITE; + } + } + } + + return END; +} + + +/** + * Try to remove extraneous MOV instructions from the given program. + */ +static void +_mesa_remove_extra_moves(struct gl_program *prog) +{ + GLboolean *removeInst; /* per-instruction removal flag */ + GLuint i, rem, loopNesting = 0, subroutineNesting = 0; + + if (dbg) { + _mesa_printf("Optimize: Begin remove extra moves\n"); + _mesa_print_program(prog); + } + + removeInst = (GLboolean *) + _mesa_calloc(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 *inst = prog->Instructions + i; + + switch (inst->Opcode) { + case OPCODE_BGNLOOP: + loopNesting++; + break; + case OPCODE_ENDLOOP: + loopNesting--; + break; + case OPCODE_BGNSUB: + subroutineNesting++; + break; + case OPCODE_ENDSUB: + subroutineNesting--; + break; + case OPCODE_MOV: + if (i > 0 && + loopNesting == 0 && + subroutineNesting == 0 && + inst->SrcReg[0].File == PROGRAM_TEMPORARY && + inst->SrcReg[0].Swizzle == SWIZZLE_XYZW) { + /* see if this MOV can be removed */ + const GLuint tempIndex = inst->SrcReg[0].Index; + struct prog_instruction *prevInst; + GLuint prevI; + + /* get pointer to previous instruction */ + prevI = i - 1; + while (removeInst[prevI] && prevI > 0) + prevI--; + prevInst = prog->Instructions + prevI; + + if (prevInst->DstReg.File == PROGRAM_TEMPORARY && + prevInst->DstReg.Index == tempIndex && + prevInst->DstReg.WriteMask == WRITEMASK_XYZW) { + + enum temp_use next_use = + find_next_temp_use(prog, i + 1, tempIndex); + + 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; + */ + + /* patch up prev inst */ + prevInst->DstReg.File = inst->DstReg.File; + prevInst->DstReg.Index = inst->DstReg.Index; + + /* flag this instruction for removal */ + removeInst[i] = GL_TRUE; + + if (dbg) { + _mesa_printf("Remove MOV at %u\n", i); + _mesa_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); + + if (dbg) { + _mesa_printf("Optimize: End remove extra moves. %u instructions removed\n", rem); + /*_mesa_print_program(prog);*/ + } +} + + +/** 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[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 +} + + +/** + * Update the intermediate interval info for register 'index' and + * instruction 'ic'. + */ +static void +update_interval(GLint intBegin[], GLint intEnd[], GLuint index, GLuint ic) +{ + ASSERT(index < 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[MAX_PROGRAM_TEMPS], + GLint intEnd[MAX_PROGRAM_TEMPS]) +{ + struct loop_info + { + GLuint Start, End; /**< Start, end instructions of loop */ + }; + struct loop_info loopStack[MAX_LOOP_NESTING]; + GLuint loopStackDepth = 0; + GLuint i; + + for (i = 0; i < 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, index, i); + if (loopStackDepth > 0) { + /* extend temp register's interval to end of loop */ + GLuint loopEnd = loopStack[loopStackDepth - 1].End; + update_interval(intBegin, intEnd, index, loopEnd); + } + } + } + if (inst->DstReg.File == PROGRAM_TEMPORARY) { + const GLuint index = inst->DstReg.Index; + if (inst->DstReg.RelAddr) + return GL_FALSE; + update_interval(intBegin, intEnd, index, i); + if (loopStackDepth > 0) { + /* extend temp register's interval to end of loop */ + GLuint loopEnd = loopStack[loopStackDepth - 1].End; + update_interval(intBegin, intEnd, index, loopEnd); + } + } + } + } + + 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[MAX_PROGRAM_TEMPS], intEnd[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) { + _mesa_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 < 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; + _mesa_printf("Reg[%d] live [%d, %d]:", + inv->Reg, inv->Start, inv->End); + if (1) { + int j; + for (j = 0; j < inv->Start; j++) + _mesa_printf(" "); + for (j = inv->Start; j <= inv->End; j++) + _mesa_printf("x"); + } + _mesa_printf("\n"); + } + } + + return GL_TRUE; +} + + +/** Scan the array of used register flags to find free entry */ +static GLint +alloc_register(GLboolean usedRegs[MAX_PROGRAM_TEMPS]) +{ + GLuint k; + for (k = 0; k < 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[MAX_PROGRAM_TEMPS]; + GLboolean usedRegs[MAX_PROGRAM_TEMPS]; + GLuint i; + GLint maxTemp = -1; + + if (dbg) { + _mesa_printf("Optimize: Begin live-interval register reallocation\n"); + _mesa_print_program(prog); + } + + for (i = 0; i < MAX_PROGRAM_TEMPS; i++){ + registerMap[i] = -1; + usedRegs[i] = GL_FALSE; + } + + if (!find_live_intervals(prog, &liveIntervals)) { + if (dbg) + _mesa_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) + _mesa_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 < 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) + _mesa_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) + _mesa_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) + _mesa_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 < 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) { + _mesa_printf("Optimize: End live-interval register reallocation\n"); + _mesa_printf("Num temp regs before: %u after: %u\n", + liveIntervals.Num, maxTemp + 1); + _mesa_print_program(prog); + } +} + + +/** + * Apply optimizations to the given program to eliminate unnecessary + * instructions, temp regs, etc. + */ +void +_mesa_optimize_program(GLcontext *ctx, struct gl_program *program) +{ + if (1) + _mesa_remove_dead_code(program); + + if (0) /* not tested much yet */ + _mesa_remove_extra_moves(program); + + if (0) + _mesa_consolidate_registers(program); + else + _mesa_reallocate_registers(program); +} diff --git a/mesalib/src/mesa/shader/prog_optimize.h b/mesalib/src/mesa/shader/prog_optimize.h new file mode 100644 index 000000000..43894a272 --- /dev/null +++ b/mesalib/src/mesa/shader/prog_optimize.h @@ -0,0 +1,45 @@ +/* + * 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" + + +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 diff --git a/mesalib/src/mesa/shader/prog_parameter.c b/mesalib/src/mesa/shader/prog_parameter.c new file mode 100644 index 000000000..2f029b02e --- /dev/null +++ b/mesalib/src/mesa/shader/prog_parameter.c @@ -0,0 +1,750 @@ +/* + * 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 *) + _mesa_calloc(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)) { + _mesa_free(p->Parameters); + _mesa_align_free(p->ParameterValues); + _mesa_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) + _mesa_free((void *) paramList->Parameters[i].Name); + } + _mesa_free(paramList->Parameters); + if (paramList->ParameterValues) + _mesa_align_free(paramList->ParameterValues); + _mesa_free(paramList); +} + + +/** + * Add a new parameter to a parameter list. + * 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; + + _mesa_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 < 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] && + _mesa_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 }; + * We'll search the parameter list for an existing instance of the + * constant. If swizzleOut is non-null, we'll try swizzling when + * looking for a match. + * + * \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 (_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 a uniform to the parameter list. + * Note that if the uniform is an array, size may be greater than + * what's implied by the datatype. + * \param name uniform's name + * \param size number of floats to allocate + * \param datatype GL_FLOAT_VEC3, GL_FLOAT_MAT4, etc. + */ +GLint +_mesa_add_uniform(struct gl_program_parameter_list *paramList, + const char *name, GLuint size, GLenum datatype, + const GLfloat *values) +{ + GLint i = _mesa_lookup_parameter_index(paramList, -1, name); + ASSERT(datatype != GL_NONE); + if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_UNIFORM) { + ASSERT(paramList->Parameters[i].Size == size); + ASSERT(paramList->Parameters[i].DataType == datatype); + /* already in list */ + return i; + } + else { + i = _mesa_add_parameter(paramList, PROGRAM_UNIFORM, name, + size, datatype, values, NULL, 0x0); + return i; + } +} + + +/** + * Mark the named uniform as 'used'. + */ +void +_mesa_use_uniform(struct gl_program_parameter_list *paramList, + const char *name) +{ + GLuint i; + for (i = 0; i < paramList->NumParameters; i++) { + struct gl_program_parameter *p = paramList->Parameters + i; + if ((p->Type == PROGRAM_UNIFORM || p->Type == PROGRAM_SAMPLER) && + _mesa_strcmp(p->Name, name) == 0) { + p->Used = GL_TRUE; + /* Note that large uniforms may occupy several slots so we're + * not done searching yet. + */ + } + } +} + + +/** + * Add a sampler to the parameter list. + * \param name uniform's name + * \param datatype GL_SAMPLER_2D, GL_SAMPLER_2D_RECT_ARB, etc. + * \param index the sampler number (as seen in TEX instructions) + * \return sampler index (starting at zero) or -1 if error + */ +GLint +_mesa_add_sampler(struct gl_program_parameter_list *paramList, + const char *name, GLenum datatype) +{ + GLint i = _mesa_lookup_parameter_index(paramList, -1, name); + if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_SAMPLER) { + ASSERT(paramList->Parameters[i].Size == 1); + ASSERT(paramList->Parameters[i].DataType == datatype); + /* already in list */ + return (GLint) paramList->ParameterValues[i][0]; + } + else { + GLuint i; + const GLint size = 1; /* a sampler is basically a texture unit number */ + GLfloat value[4]; + GLint numSamplers = 0; + for (i = 0; i < paramList->NumParameters; i++) { + if (paramList->Parameters[i].Type == PROGRAM_SAMPLER) + numSamplers++; + } + value[0] = (GLfloat) numSamplers; + value[1] = value[2] = value[3] = 0.0F; + (void) _mesa_add_parameter(paramList, PROGRAM_SAMPLER, name, + size, datatype, value, NULL, 0x0); + return numSamplers; + } +} + + +/** + * Add parameter representing a varying variable. + */ +GLint +_mesa_add_varying(struct gl_program_parameter_list *paramList, + const char *name, GLuint size, 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, GL_NONE, 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() */ + _mesa_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) +{ + GLuint 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 && + _mesa_strcmp(paramList->Parameters[i].Name, name) == 0) + return i; + } + } + else { + /* name is not null-terminated, use nameLen */ + for (i = 0; i < (GLint) paramList->NumParameters; i++) { + if (paramList->Parameters[i].Name && + _mesa_strncmp(paramList->Parameters[i].Name, name, nameLen) == 0 + && _mesa_strlen(paramList->Parameters[i].Name) == (size_t)nameLen) + return i; + } + } + return -1; +} + + +/** + * 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) + return -1; + + 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 < 4; 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->Used = p->Used; + 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 = _mesa_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/shader/prog_parameter.h b/mesalib/src/mesa/shader/prog_parameter.h new file mode 100644 index 000000000..d1fcf47e6 --- /dev/null +++ b/mesalib/src/mesa/shader/prog_parameter.h @@ -0,0 +1,174 @@ +/* + * 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 + */ + +#ifndef PROG_PARAMETER_H +#define PROG_PARAMETER_H + +#include "main/mtypes.h" +#include "prog_statevars.h" + + +/** + * Program parameter flags + */ +/*@{*/ +#define PROG_PARAM_BIT_CENTROID 0x1 /**< for varying vars (GLSL 1.20) */ +#define PROG_PARAM_BIT_INVARIANT 0x2 /**< for varying vars (GLSL 1.20) */ +#define PROG_PARAM_BIT_FLAT 0x4 /**< for varying vars (GLSL 1.30) */ +#define PROG_PARAM_BIT_LINEAR 0x8 /**< for varying vars (GLSL 1.30) */ +/*@}*/ + + + +/** + * Program parameter. + * Used by shaders/programs for uniforms, constants, varying vars, etc. + */ +struct gl_program_parameter +{ + const char *Name; /**< Null-terminated string */ + gl_register_file Type; /**< PROGRAM_NAMED_PARAM, CONSTANT or STATE_VAR */ + GLenum DataType; /**< GL_FLOAT, GL_FLOAT_VEC2, etc */ + GLuint Size; /**< Number of components (1..4) */ + GLboolean Used; /**< Helper flag for GLSL uniform tracking */ + GLboolean Initialized; /**< Has the ParameterValue[] been set? */ + GLbitfield Flags; /**< Bitmask of PROG_PARAM_*_BIT */ + /** + * A sequence of STATE_* tokens and integers to identify GL state. + */ + gl_state_index StateIndexes[STATE_LENGTH]; +}; + + +/** + * List of gl_program_parameter instances. + */ +struct gl_program_parameter_list +{ + GLuint Size; /**< allocated size of Parameters, ParameterValues */ + GLuint NumParameters; /**< number of parameters in arrays */ + struct gl_program_parameter *Parameters; /**< Array [Size] */ + GLfloat (*ParameterValues)[4]; /**< Array [Size] of GLfloat[4] */ + GLbitfield StateFlags; /**< _NEW_* flags indicating which state changes + might invalidate ParameterValues[] */ +}; + + +extern struct gl_program_parameter_list * +_mesa_new_parameter_list(void); + +extern struct gl_program_parameter_list * +_mesa_new_parameter_list_sized(unsigned size); + +extern void +_mesa_free_parameter_list(struct gl_program_parameter_list *paramList); + +extern struct gl_program_parameter_list * +_mesa_clone_parameter_list(const struct gl_program_parameter_list *list); + +extern struct gl_program_parameter_list * +_mesa_combine_parameter_lists(const struct gl_program_parameter_list *a, + const struct gl_program_parameter_list *b); + +static INLINE GLuint +_mesa_num_parameters(const struct gl_program_parameter_list *list) +{ + return list ? list->NumParameters : 0; +} + +extern 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); + +extern GLint +_mesa_add_named_parameter(struct gl_program_parameter_list *paramList, + const char *name, const GLfloat values[4]); + +extern GLint +_mesa_add_named_constant(struct gl_program_parameter_list *paramList, + const char *name, const GLfloat values[4], + GLuint size); + +extern GLint +_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList, + const GLfloat values[4], GLuint size, + GLuint *swizzleOut); + +extern GLint +_mesa_add_uniform(struct gl_program_parameter_list *paramList, + const char *name, GLuint size, GLenum datatype, + const GLfloat *values); + +extern void +_mesa_use_uniform(struct gl_program_parameter_list *paramList, + const char *name); + +extern GLint +_mesa_add_sampler(struct gl_program_parameter_list *paramList, + const char *name, GLenum datatype); + +extern GLint +_mesa_add_varying(struct gl_program_parameter_list *paramList, + const char *name, GLuint size, GLbitfield flags); + +extern GLint +_mesa_add_attribute(struct gl_program_parameter_list *paramList, + const char *name, GLint size, GLenum datatype, GLint attrib); + +extern GLint +_mesa_add_state_reference(struct gl_program_parameter_list *paramList, + const gl_state_index stateTokens[STATE_LENGTH]); + +extern GLfloat * +_mesa_lookup_parameter_value(const struct gl_program_parameter_list *paramList, + GLsizei nameLen, const char *name); + +extern GLint +_mesa_lookup_parameter_index(const struct gl_program_parameter_list *paramList, + GLsizei nameLen, const char *name); + +extern GLboolean +_mesa_lookup_parameter_constant(const struct gl_program_parameter_list *list, + const GLfloat v[], GLuint vSize, + GLint *posOut, GLuint *swizzleOut); + +extern GLuint +_mesa_longest_parameter_name(const struct gl_program_parameter_list *list, + gl_register_file type); + +extern GLuint +_mesa_num_parameters_of_type(const struct gl_program_parameter_list *list, + gl_register_file type); + + +#endif /* PROG_PARAMETER_H */ diff --git a/mesalib/src/mesa/shader/prog_parameter_layout.c b/mesalib/src/mesa/shader/prog_parameter_layout.c new file mode 100644 index 000000000..1c37b3a7a --- /dev/null +++ b/mesalib/src/mesa/shader/prog_parameter_layout.c @@ -0,0 +1,217 @@ +/* + * 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. + */ + +/** + * \file prog_parameter_layout.c + * \brief Helper functions to layout storage for program parameters + * + * \author Ian Romanick <ian.d.romanick@intel.com> + */ + +#include "main/mtypes.h" +#include "prog_parameter.h" +#include "prog_parameter_layout.h" +#include "prog_instruction.h" +#include "program_parser.h" + +unsigned +_mesa_combine_swizzles(unsigned base, unsigned applied) +{ + unsigned swiz = 0; + unsigned i; + + for (i = 0; i < 4; i++) { + const unsigned s = GET_SWZ(applied, i); + + swiz |= ((s <= SWIZZLE_W) ? GET_SWZ(base, s) : s) << (i * 3); + } + + return swiz; +} + + +/** + * Copy indirect access array from one parameter list to another + * + * \param src Parameter array copied from + * \param dst Parameter array copied to + * \param first Index of first element in \c src to copy + * \param count Number of elements to copy + * + * \return + * The location in \c dst of the first element copied from \c src on + * success. -1 on failure. + * + * \warning + * This function assumes that there is already enough space available in + * \c dst to hold all of the elements that will be copied over. + */ +static int +copy_indirect_accessed_array(struct gl_program_parameter_list *src, + struct gl_program_parameter_list *dst, + unsigned first, unsigned count) +{ + const int base = dst->NumParameters; + unsigned i; + unsigned j; + + + for (i = first; i < (first + count); i++) { + struct gl_program_parameter *curr = & src->Parameters[i]; + + + if (curr->Type == PROGRAM_CONSTANT) { + j = dst->NumParameters; + } else { + for (j = 0; j < dst->NumParameters; j++) { + if (memcmp(dst->Parameters[j].StateIndexes, curr->StateIndexes, + sizeof(curr->StateIndexes)) == 0) { + return -1; + } + } + } + + assert(j == dst->NumParameters); + + memcpy(& dst->Parameters[j], curr, + sizeof(dst->Parameters[j])); + memcpy(dst->ParameterValues[j], src->ParameterValues[i], + sizeof(GLfloat) * 4); + curr->Name = NULL; + + dst->NumParameters++; + } + + return base; +} + + +/** + * XXX description??? + * \return GL_TRUE for success, GL_FALSE for failure + */ +GLboolean +_mesa_layout_parameters(struct asm_parser_state *state) +{ + struct gl_program_parameter_list *layout; + struct asm_instruction *inst; + unsigned i; + + + layout = + _mesa_new_parameter_list_sized(state->prog->Parameters->NumParameters); + + + /* PASS 1: Move any parameters that are accessed indirectly from the + * original parameter list to the new parameter list. + */ + for (inst = state->inst_head; inst != NULL; inst = inst->next) { + for (i = 0; i < 3; i++) { + if (inst->SrcReg[i].Base.RelAddr) { + /* Only attempt to add the to the new parameter list once. + */ + if (!inst->SrcReg[i].Symbol->pass1_done) { + const int new_begin = + copy_indirect_accessed_array(state->prog->Parameters, layout, + inst->SrcReg[i].Symbol->param_binding_begin, + inst->SrcReg[i].Symbol->param_binding_length); + + if (new_begin < 0) { + return GL_FALSE; + } + + inst->SrcReg[i].Symbol->param_binding_begin = new_begin; + inst->SrcReg[i].Symbol->pass1_done = 1; + } + + /* Previously the Index was just the offset from the parameter + * array. Now that the base of the parameter array is known, the + * index can be updated to its actual value. + */ + inst->Base.SrcReg[i] = inst->SrcReg[i].Base; + inst->Base.SrcReg[i].Index += + inst->SrcReg[i].Symbol->param_binding_begin; + } + } + } + + + /* PASS 2: Move any parameters that are not accessed indirectly from the + * original parameter list to the new parameter list. + */ + for (inst = state->inst_head; inst != NULL; inst = inst->next) { + for (i = 0; i < 3; i++) { + const struct gl_program_parameter *p; + const int idx = inst->SrcReg[i].Base.Index; + unsigned swizzle = SWIZZLE_NOOP; + + + /* All relative addressed operands were processed on the first + * pass. Just skip them here. + */ + if (inst->SrcReg[i].Base.RelAddr) { + continue; + } + + + if ((inst->SrcReg[i].Base.File <= PROGRAM_VARYING ) + || (inst->SrcReg[i].Base.File >= PROGRAM_WRITE_ONLY)) { + continue; + } + + inst->Base.SrcReg[i] = inst->SrcReg[i].Base; + p = & state->prog->Parameters->Parameters[idx]; + + switch (p->Type) { + case PROGRAM_CONSTANT: { + const float *const v = + state->prog->Parameters->ParameterValues[idx]; + + inst->Base.SrcReg[i].Index = + _mesa_add_unnamed_constant(layout, v, p->Size, & swizzle); + + inst->Base.SrcReg[i].Swizzle = + _mesa_combine_swizzles(swizzle, inst->Base.SrcReg[i].Swizzle); + break; + } + + case PROGRAM_STATE_VAR: + inst->Base.SrcReg[i].Index = + _mesa_add_state_reference(layout, p->StateIndexes); + break; + + default: + break; + } + + inst->SrcReg[i].Base.File = p->Type; + inst->Base.SrcReg[i].File = p->Type; + } + } + + + _mesa_free_parameter_list(state->prog->Parameters); + state->prog->Parameters = layout; + + return GL_TRUE; +} diff --git a/mesalib/src/mesa/shader/prog_parameter_layout.h b/mesalib/src/mesa/shader/prog_parameter_layout.h new file mode 100644 index 000000000..99a7b6c72 --- /dev/null +++ b/mesalib/src/mesa/shader/prog_parameter_layout.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +/** + * \file prog_parameter_layout.h + * \brief Helper functions to layout storage for program parameters + * + * \author Ian Romanick <ian.d.romanick@intel.com> + */ + +#pragma once + +#ifndef PROG_PARAMETER_LAYOUT_H +#define PROG_PARAMETER_LAYOUT_H + +extern unsigned _mesa_combine_swizzles(unsigned base, unsigned applied); + +struct asm_parser_state; + +extern GLboolean _mesa_layout_parameters(struct asm_parser_state *state); + +#endif /* PROG_PARAMETER_LAYOUT_H */ diff --git a/mesalib/src/mesa/shader/prog_print.c b/mesalib/src/mesa/shader/prog_print.c new file mode 100644 index 000000000..b71735aa8 --- /dev/null +++ b/mesalib/src/mesa/shader/prog_print.c @@ -0,0 +1,1019 @@ +/* + * 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]" + }; + + 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]; + } +} + + +/** + * 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) +{ + static char str[100]; + const char *addr = relAddr ? "ADDR+" : ""; + + str[0] = 0; + + switch (mode) { + case PROG_PRINT_DEBUG: + _mesa_sprintf(str, "%s[%s%d]", file_string(f, mode), addr, index); + break; + + case PROG_PRINT_ARB: + switch (f) { + case PROGRAM_INPUT: + _mesa_sprintf(str, "%s", arb_input_attrib_string(index, prog->Target)); + break; + case PROGRAM_OUTPUT: + _mesa_sprintf(str, "%s", arb_output_attrib_string(index, prog->Target)); + break; + case PROGRAM_TEMPORARY: + _mesa_sprintf(str, "temp%d", index); + break; + case PROGRAM_ENV_PARAM: + _mesa_sprintf(str, "program.env[%s%d]", addr, index); + break; + case PROGRAM_LOCAL_PARAM: + _mesa_sprintf(str, "program.local[%s%d]", addr, index); + break; + case PROGRAM_VARYING: /* extension */ + _mesa_sprintf(str, "varying[%s%d]", addr, index); + break; + case PROGRAM_CONSTANT: /* extension */ + _mesa_sprintf(str, "constant[%s%d]", addr, index); + break; + case PROGRAM_UNIFORM: /* extension */ + _mesa_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); + _mesa_sprintf(str, state); + _mesa_free(state); + } + break; + case PROGRAM_ADDRESS: + _mesa_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) + _mesa_sprintf(str, "v[%d]", index); + else + _mesa_sprintf(str, "f[%d]", index); + break; + case PROGRAM_OUTPUT: + _mesa_sprintf(str, "o[%d]", index); + break; + case PROGRAM_TEMPORARY: + _mesa_sprintf(str, "R%d", index); + break; + case PROGRAM_ENV_PARAM: + _mesa_sprintf(str, "c[%d]", index); + break; + case PROGRAM_VARYING: /* extension */ + _mesa_sprintf(str, "varying[%s%d]", addr, index); + break; + case PROGRAM_UNIFORM: /* extension */ + _mesa_sprintf(str, "uniform[%s%d]", addr, index); + break; + case PROGRAM_CONSTANT: /* extension */ + _mesa_sprintf(str, "constant[%s%d]", addr, index); + break; + case PROGRAM_STATE_VAR: /* extension */ + _mesa_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) { + _mesa_printf(".xyzw\n"); + } + else { + const char *s = _mesa_swizzle_string(swizzle, 0, 0); + _mesa_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) +{ + _mesa_fprintf(f, "%s%s", + reg_string((gl_register_file) dstReg->File, + dstReg->Index, mode, dstReg->RelAddr, prog), + _mesa_writemask_string(dstReg->WriteMask)); + + if (dstReg->CondMask != COND_TR) { + _mesa_fprintf(f, " (%s.%s)", + _mesa_condcode_string(dstReg->CondMask), + _mesa_swizzle_string(dstReg->CondSwizzle, + GL_FALSE, GL_FALSE)); + } + +#if 0 + _mesa_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 ? "|" : ""; + + _mesa_fprintf(f, "%s%s%s%s", + abs, + reg_string((gl_register_file) srcReg->File, + srcReg->Index, mode, srcReg->RelAddr, prog), + _mesa_swizzle_string(srcReg->Swizzle, + srcReg->Negate, GL_FALSE), + abs); +#if 0 + _mesa_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) + _mesa_fprintf(f, "; # %s\n", inst->Comment); + else + _mesa_fprintf(f, ";\n"); +} + + +static void +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; + + _mesa_fprintf(f, "%s", opcode_string); + if (inst->CondUpdate) + _mesa_fprintf(f, ".C"); + + /* frag prog only */ + if (inst->SaturateMode == SATURATE_ZERO_ONE) + _mesa_fprintf(f, "_SAT"); + + _mesa_fprintf(f, " "); + if (inst->DstReg.File != PROGRAM_UNDEFINED) { + fprint_dst_reg(f, &inst->DstReg, mode, prog); + } + else { + _mesa_fprintf(f, " ???"); + } + + if (numRegs > 0) + _mesa_fprintf(f, ", "); + + for (j = 0; j < numRegs; j++) { + fprint_src_reg(f, inst->SrcReg + j, mode, prog); + if (j + 1 < numRegs) + _mesa_fprintf(f, ", "); + } + + fprint_comment(f, inst); +} + + +void +_mesa_print_alu_instruction(const struct prog_instruction *inst, + const char *opcode_string, GLuint numRegs) +{ + 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++) { + _mesa_fprintf(f, " "); + } + + switch (inst->Opcode) { + case OPCODE_PRINT: + _mesa_fprintf(f, "PRINT '%s'", inst->Data); + if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { + _mesa_fprintf(f, ", "); + _mesa_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) + _mesa_fprintf(f, " # %s", inst->Comment); + fprint_comment(f, inst); + break; + case OPCODE_SWZ: + _mesa_fprintf(f, "SWZ"); + if (inst->SaturateMode == SATURATE_ZERO_ONE) + _mesa_fprintf(f, "_SAT"); + _mesa_fprintf(f, " "); + fprint_dst_reg(f, &inst->DstReg, mode, prog); + _mesa_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: + _mesa_fprintf(f, "%s", _mesa_opcode_string(inst->Opcode)); + if (inst->SaturateMode == SATURATE_ZERO_ONE) + _mesa_fprintf(f, "_SAT"); + _mesa_fprintf(f, " "); + fprint_dst_reg(f, &inst->DstReg, mode, prog); + _mesa_fprintf(f, ", "); + fprint_src_reg(f, &inst->SrcReg[0], mode, prog); + _mesa_fprintf(f, ", texture[%d], ", inst->TexSrcUnit); + switch (inst->TexSrcTarget) { + case TEXTURE_1D_INDEX: _mesa_fprintf(f, "1D"); break; + case TEXTURE_2D_INDEX: _mesa_fprintf(f, "2D"); break; + case TEXTURE_3D_INDEX: _mesa_fprintf(f, "3D"); break; + case TEXTURE_CUBE_INDEX: _mesa_fprintf(f, "CUBE"); break; + case TEXTURE_RECT_INDEX: _mesa_fprintf(f, "RECT"); break; + default: + ; + } + if (inst->TexShadow) + _mesa_fprintf(f, " SHADOW"); + fprint_comment(f, inst); + break; + + case OPCODE_KIL: + _mesa_fprintf(f, "%s", _mesa_opcode_string(inst->Opcode)); + _mesa_fprintf(f, " "); + fprint_src_reg(f, &inst->SrcReg[0], mode, prog); + fprint_comment(f, inst); + break; + case OPCODE_KIL_NV: + _mesa_fprintf(f, "%s", _mesa_opcode_string(inst->Opcode)); + _mesa_fprintf(f, " "); + _mesa_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: + _mesa_fprintf(f, "ARL "); + fprint_dst_reg(f, &inst->DstReg, mode, prog); + _mesa_fprintf(f, ", "); + fprint_src_reg(f, &inst->SrcReg[0], mode, prog); + fprint_comment(f, inst); + break; + case OPCODE_BRA: + _mesa_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 */ + _mesa_fprintf(f, "IF "); + fprint_src_reg(f, &inst->SrcReg[0], mode, prog); + _mesa_fprintf(f, "; "); + } + else { + /* Use cond codes */ + _mesa_fprintf(f, "IF (%s%s);", + _mesa_condcode_string(inst->DstReg.CondMask), + _mesa_swizzle_string(inst->DstReg.CondSwizzle, + 0, GL_FALSE)); + } + _mesa_fprintf(f, " # (if false, goto %d)", inst->BranchTarget); + fprint_comment(f, inst); + return indent + 3; + case OPCODE_ELSE: + _mesa_fprintf(f, "ELSE; # (goto %d)\n", inst->BranchTarget); + return indent + 3; + case OPCODE_ENDIF: + _mesa_fprintf(f, "ENDIF;\n"); + break; + case OPCODE_BGNLOOP: + _mesa_fprintf(f, "BGNLOOP; # (end at %d)\n", inst->BranchTarget); + return indent + 3; + case OPCODE_ENDLOOP: + _mesa_fprintf(f, "ENDLOOP; # (goto %d)\n", inst->BranchTarget); + break; + case OPCODE_BRK: + case OPCODE_CONT: + _mesa_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) { + _mesa_fprintf(f, "%s:\n", inst->Comment); /* comment is label */ + return indent; + } + else { + _mesa_fprintf(f, "BGNSUB"); + fprint_comment(f, inst); + return indent + 3; + } + case OPCODE_ENDSUB: + if (mode == PROG_PRINT_DEBUG) { + _mesa_fprintf(f, "ENDSUB"); + fprint_comment(f, inst); + } + break; + case OPCODE_CAL: + if (mode == PROG_PRINT_NV) { + _mesa_fprintf(f, "CAL %s; # (goto %d)\n", inst->Comment, inst->BranchTarget); + } + else { + _mesa_fprintf(f, "CAL %u", inst->BranchTarget); + fprint_comment(f, inst); + } + break; + case OPCODE_RET: + _mesa_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: + _mesa_fprintf(f, "END\n"); + break; + case OPCODE_NOP: + if (mode == PROG_PRINT_DEBUG) { + _mesa_fprintf(f, "NOP"); + fprint_comment(f, inst); + } + else if (inst->Comment) { + /* ARB/NV extensions don't have NOP instruction */ + _mesa_fprintf(f, "# %s\n", inst->Comment); + } + break; + /* XXX may need other special-case instructions */ + default: + if (inst->Opcode < MAX_OPCODE) { + /* typical alu instruction */ + fprint_alu_instruction(f, inst, + _mesa_opcode_string(inst->Opcode), + _mesa_num_inst_src_regs(inst->Opcode), + mode, prog); + } + else { + 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) + _mesa_fprintf(f, "!!ARBvp1.0\n"); + else if (mode == PROG_PRINT_NV) + _mesa_fprintf(f, "!!VP1.0\n"); + else + _mesa_fprintf(f, "# Vertex Program/Shader\n"); + break; + case GL_FRAGMENT_PROGRAM_ARB: + case GL_FRAGMENT_PROGRAM_NV: + if (mode == PROG_PRINT_ARB) + _mesa_fprintf(f, "!!ARBfp1.0\n"); + else if (mode == PROG_PRINT_NV) + _mesa_fprintf(f, "!!FP1.0\n"); + else + _mesa_fprintf(f, "# Fragment Program/Shader\n"); + break; + } + + for (i = 0; i < prog->NumInstructions; i++) { + if (lineNumbers) + _mesa_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 value (as a string). + * Insert a comma to separate each group of 8 bits. + * XXX move to imports.[ch] if useful elsewhere. + */ +static const char * +binary(GLbitfield val) +{ + static char buf[50]; + GLint i, len = 0; + for (i = 31; i >= 0; --i) { + if (val & (1 << 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; + + _mesa_fprintf(f, "InputsRead: 0x%x (0b%s)\n", + prog->InputsRead, binary(prog->InputsRead)); + _mesa_fprintf(f, "OutputsWritten: 0x%x (0b%s)\n", + prog->OutputsWritten, binary(prog->OutputsWritten)); + _mesa_fprintf(f, "NumInstructions=%d\n", prog->NumInstructions); + _mesa_fprintf(f, "NumTemporaries=%d\n", prog->NumTemporaries); + _mesa_fprintf(f, "NumParameters=%d\n", prog->NumParameters); + _mesa_fprintf(f, "NumAttributes=%d\n", prog->NumAttributes); + _mesa_fprintf(f, "NumAddressRegs=%d\n", prog->NumAddressRegs); + _mesa_fprintf(f, "SamplersUsed: 0x%x (0b%s)\n", + prog->SamplersUsed, binary(prog->SamplersUsed)); + _mesa_fprintf(f, "Samplers=[ "); + for (i = 0; i < MAX_SAMPLERS; i++) { + _mesa_fprintf(f, "%d ", prog->SamplerUnits[i]); + } + _mesa_fprintf(f, "]\n"); + + _mesa_load_state_parameters(ctx, prog->Parameters); + +#if 0 + _mesa_fprintf(f, "Local Params:\n"); + for (i = 0; i < MAX_PROGRAM_LOCAL_PARAMS; i++){ + const GLfloat *p = prog->LocalParams[i]; + _mesa_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; + + _mesa_fprintf(f, "param list %p\n", (void *) list); + _mesa_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]; + _mesa_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) + _mesa_fprintf(f, " Centroid"); + if (param->Flags & PROG_PARAM_BIT_INVARIANT) + _mesa_fprintf(f, " Invariant"); + if (param->Flags & PROG_PARAM_BIT_FLAT) + _mesa_fprintf(f, " Flat"); + if (param->Flags & PROG_PARAM_BIT_LINEAR) + _mesa_fprintf(f, " Linear"); + _mesa_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 + type = "vert"; + + _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"); + if (!shader->CompileStatus) { + fprintf(f, "/* Log Info: */\n"); + fputs(shader->InfoLog, f); + } + else { + 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/shader/prog_print.h b/mesalib/src/mesa/shader/prog_print.h new file mode 100644 index 000000000..fc286ded5 --- /dev/null +++ b/mesalib/src/mesa/shader/prog_print.h @@ -0,0 +1,94 @@ +/* + * 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 + + +/** + * 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_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_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 */ diff --git a/mesalib/src/mesa/shader/prog_statevars.c b/mesalib/src/mesa/shader/prog_statevars.c new file mode 100644 index 000000000..058d4bbaf --- /dev/null +++ b/mesalib/src/mesa/shader/prog_statevars.c @@ -0,0 +1,1120 @@ +/* + * 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/hash.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) { + matrix = ctx->TextureMatrixStack[index].Top; + } + else if (mat == STATE_PROGRAM_MATRIX) { + 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_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_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_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]; + _mesa_sprintf(s, "[%d]", index); + append(dst, s); +} + +/** + * Make a string from the given state vector. + * For example, return "state.matrix.texture[2].inverse". + * Use _mesa_free() to deallocate the string. + */ +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) + _mesa_sprintf(tmp, ".row[%d]", firstRow); + else + _mesa_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_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) { + mat = ctx->TextureMatrixStack[ctx->Texture.CurrentUnit].Top; + } + else if (ctx->VertexProgram.TrackMatrix[i] == GL_COLOR) { + mat = ctx->ColorMatrixStack.Top; + } + else if (ctx->VertexProgram.TrackMatrix[i]==GL_MODELVIEW_PROJECTION_NV) { + /* XXX verify the combined matrix is up to date */ + mat = &ctx->_ModelProjectMatrix; + } + else if (ctx->VertexProgram.TrackMatrix[i] >= GL_MATRIX0_NV && + ctx->VertexProgram.TrackMatrix[i] <= GL_MATRIX7_NV) { + GLuint n = ctx->VertexProgram.TrackMatrix[i] - GL_MATRIX0_NV; + ASSERT(n < MAX_PROGRAM_MATRICES); + mat = ctx->ProgramMatrixStack[n].Top; + } + else { + /* no matrix is tracked, but we leave the register values as-is */ + assert(ctx->VertexProgram.TrackMatrix[i] == GL_NONE); + continue; + } + + /* load the matrix 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/shader/prog_statevars.h b/mesalib/src/mesa/shader/prog_statevars.h new file mode 100644 index 000000000..1180d9eaa --- /dev/null +++ b/mesalib/src/mesa/shader/prog_statevars.h @@ -0,0 +1,145 @@ +/* + * 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_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 */ diff --git a/mesalib/src/mesa/shader/prog_uniform.c b/mesalib/src/mesa/shader/prog_uniform.c new file mode 100644 index 000000000..064271314 --- /dev/null +++ b/mesalib/src/mesa/shader/prog_uniform.c @@ -0,0 +1,165 @@ +/* + * 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. + */ + +/** + * \file prog_uniform.c + * Shader uniform functions. + * \author Brian Paul + */ + +#include "main/imports.h" +#include "main/mtypes.h" +#include "prog_uniform.h" + + +struct gl_uniform_list * +_mesa_new_uniform_list(void) +{ + return CALLOC_STRUCT(gl_uniform_list); +} + + +void +_mesa_free_uniform_list(struct gl_uniform_list *list) +{ + GLuint i; + for (i = 0; i < list->NumUniforms; i++) { + _mesa_free((void *) list->Uniforms[i].Name); + } + _mesa_free(list->Uniforms); + _mesa_free(list); +} + + +struct gl_uniform * +_mesa_append_uniform(struct gl_uniform_list *list, + const char *name, GLenum target, GLuint progPos) +{ + const GLuint oldNum = list->NumUniforms; + struct gl_uniform *uniform; + GLint index; + + assert(target == GL_VERTEX_PROGRAM_ARB || + target == GL_FRAGMENT_PROGRAM_ARB); + + index = _mesa_lookup_uniform(list, name); + if (index < 0) { + /* not found - append to list */ + + if (oldNum + 1 > list->Size) { + /* Need to grow the list array (alloc some extra) */ + list->Size += 4; + + /* realloc arrays */ + list->Uniforms = (struct gl_uniform *) + _mesa_realloc(list->Uniforms, + oldNum * sizeof(struct gl_uniform), + list->Size * sizeof(struct gl_uniform)); + } + + if (!list->Uniforms) { + /* out of memory */ + list->NumUniforms = 0; + list->Size = 0; + return GL_FALSE; + } + + uniform = list->Uniforms + oldNum; + + uniform->Name = _mesa_strdup(name); + uniform->VertPos = -1; + uniform->FragPos = -1; + uniform->Initialized = GL_FALSE; + + list->NumUniforms++; + } + else { + /* found */ + uniform = list->Uniforms + index; + } + + /* update position for the vertex or fragment program */ + if (target == GL_VERTEX_PROGRAM_ARB) { + if (uniform->VertPos != -1) { + /* this uniform is already in the list - that shouldn't happen */ + return GL_FALSE; + } + uniform->VertPos = progPos; + } + else { + if (uniform->FragPos != -1) { + /* this uniform is already in the list - that shouldn't happen */ + return GL_FALSE; + } + uniform->FragPos = progPos; + } + + return uniform; +} + + +/** + * Return the location/index of the named uniform in the uniform list, + * or -1 if not found. + */ +GLint +_mesa_lookup_uniform(const struct gl_uniform_list *list, const char *name) +{ + GLuint i; + for (i = 0; list && i < list->NumUniforms; i++) { + if (!_mesa_strcmp(list->Uniforms[i].Name, name)) { + return i; + } + } + return -1; +} + + +GLint +_mesa_longest_uniform_name(const struct gl_uniform_list *list) +{ + GLint max = 0; + GLuint i; + for (i = 0; list && i < list->NumUniforms; i++) { + GLint len = (GLint)_mesa_strlen(list->Uniforms[i].Name); + if (len > max) + max = len; + } + return max; +} + + +void +_mesa_print_uniforms(const struct gl_uniform_list *list) +{ + GLuint i; + printf("Uniform list %p:\n", (void *) list); + for (i = 0; i < list->NumUniforms; i++) { + printf("%d: %s %d %d\n", + i, + list->Uniforms[i].Name, + list->Uniforms[i].VertPos, + list->Uniforms[i].FragPos); + } +} diff --git a/mesalib/src/mesa/shader/prog_uniform.h b/mesalib/src/mesa/shader/prog_uniform.h new file mode 100644 index 000000000..22a2bfd97 --- /dev/null +++ b/mesalib/src/mesa/shader/prog_uniform.h @@ -0,0 +1,92 @@ +/* + * 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. + */ + +/** + * \file prog_uniform.c + * Shader uniform functions. + * \author Brian Paul + */ + +#ifndef PROG_UNIFORM_H +#define PROG_UNIFORM_H + +#include "main/mtypes.h" +#include "prog_statevars.h" + + +/** + * Shader program uniform variable. + * The glGetUniformLocation() and glUniform() commands will use this + * information. + * Note that a uniform such as "binormal" might be used in both the + * vertex shader and the fragment shader. When glUniform() is called to + * set the uniform's value, it must be updated in both the vertex and + * fragment shaders. The uniform may be in different locations in the + * two shaders so we keep track of that here. + */ +struct gl_uniform +{ + const char *Name; /**< Null-terminated string */ + GLint VertPos; + GLint FragPos; + GLboolean Initialized; /**< For debug. Has this uniform been set? */ +#if 0 + GLenum DataType; /**< GL_FLOAT, GL_FLOAT_VEC2, etc */ + GLuint Size; /**< Number of components (1..4) */ +#endif +}; + + +/** + * List of gl_uniforms + */ +struct gl_uniform_list +{ + GLuint Size; /**< allocated size of Uniforms array */ + GLuint NumUniforms; /**< number of uniforms in the array */ + struct gl_uniform *Uniforms; /**< Array [Size] */ +}; + + +extern struct gl_uniform_list * +_mesa_new_uniform_list(void); + +extern void +_mesa_free_uniform_list(struct gl_uniform_list *list); + +extern struct gl_uniform * +_mesa_append_uniform(struct gl_uniform_list *list, + const char *name, GLenum target, GLuint progPos); + +extern GLint +_mesa_lookup_uniform(const struct gl_uniform_list *list, const char *name); + +extern GLint +_mesa_longest_uniform_name(const struct gl_uniform_list *list); + +extern void +_mesa_print_uniforms(const struct gl_uniform_list *list); + + +#endif /* PROG_UNIFORM_H */ diff --git a/mesalib/src/mesa/shader/program.c b/mesalib/src/mesa/shader/program.c new file mode 100644 index 000000000..2cd6eb8a3 --- /dev/null +++ b/mesalib/src/mesa/shader/program.c @@ -0,0 +1,889 @@ +/* + * 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. + */ + ASSERT(ctx->Const.VertexProgram.MaxUniformComponents / 4 + <= (1 << INST_INDEX_BITS)); + ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents / 4 + <= (1 << INST_INDEX_BITS)); + + /* 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 = GL_TRUE; +#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 + + + /* 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 + /* XXX probably move this stuff */ +#if FEATURE_ATI_fragment_shader + if (ctx->ATIFragmentShader.Current) { + ctx->ATIFragmentShader.Current->RefCount--; + if (ctx->ATIFragmentShader.Current->RefCount <= 0) { + _mesa_free(ctx->ATIFragmentShader.Current); + } + } +#endif + _mesa_free((void *) ctx->Program.ErrorString); +} + + +/** + * 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 + + /* XXX probably move this stuff */ +#if FEATURE_ATI_fragment_shader + if (ctx->ATIFragmentShader.Current) { + ctx->ATIFragmentShader.Current->RefCount--; + if (ctx->ATIFragmentShader.Current->RefCount <= 0) { + _mesa_free(ctx->ATIFragmentShader.Current); + } + } + 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; + _mesa_free((void *) ctx->Program.ErrorString); + if (!string) + string = ""; + ctx->Program.ErrorString = _mesa_strdup(string); +} + + +/** + * Find the line number and column for 'pos' within 'string'. + * Return a copy of the line which contains 'pos'. Free the line with + * _mesa_free(). + * \param string the program string + * \param pos the position within the string + * \param line returns the line number corresponding to 'pos'. + * \param col returns the column number corresponding to 'pos'. + * \return copy of the line containing 'pos'. + */ +const GLubyte * +_mesa_find_line_column(const GLubyte *string, const GLubyte *pos, + GLint *line, GLint *col) +{ + const GLubyte *lineStart = string; + const GLubyte *p = string; + GLubyte *s; + int len; + + *line = 1; + + while (p != pos) { + if (*p == (GLubyte) '\n') { + (*line)++; + lineStart = p + 1; + } + p++; + } + + *col = (pos - lineStart) + 1; + + /* return copy of this line */ + while (*p != 0 && *p != '\n') + p++; + len = p - lineStart; + s = (GLubyte *) _mesa_malloc(len + 1); + _mesa_memcpy(s, lineStart, len); + s[len] = 0; + + return s; +} + + +/** + * Initialize a new vertex/fragment program object. + */ +static struct gl_program * +_mesa_init_program_struct( GLcontext *ctx, struct gl_program *prog, + GLenum target, GLuint id) +{ + (void) ctx; + if (prog) { + GLuint i; + _mesa_bzero(prog, 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; +} + + +/** + * 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; + 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) + _mesa_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); + } + + /* XXX this is a little ugly */ + if (prog->Target == GL_VERTEX_PROGRAM_ARB) { + struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog; + if (vprog->TnlData) + _mesa_free(vprog->TnlData); + } + + _mesa_free(prog); +} + + +/** + * Return the gl_program object for a given ID. + * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of + * casts elsewhere. + */ +struct gl_program * +_mesa_lookup_program(GLcontext *ctx, GLuint id) +{ + if (id) + return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id); + else + return NULL; +} + + +/** + * 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); + } + 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" : "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" : "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->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; + } + 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 > 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->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->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; + 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; + + 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(newProg, PROGRAM_TEMPORARY); + if (tempReg < 0) { + _mesa_problem(ctx, "No free temp regs found in " + "_mesa_combine_programs(), using 31"); + tempReg = 31; + } + /* 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; +} + + + + +/** + * Scan the given program to find a free register of the given type. + * \param regFile - PROGRAM_INPUT, PROGRAM_OUTPUT or PROGRAM_TEMPORARY + */ +GLint +_mesa_find_free_register(const struct gl_program *prog, GLuint regFile) +{ + GLboolean used[MAX_PROGRAM_TEMPS]; + GLuint i, k; + + assert(regFile == PROGRAM_INPUT || + regFile == PROGRAM_OUTPUT || + regFile == PROGRAM_TEMPORARY); + + _mesa_memset(used, 0, sizeof(used)); + + 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); + + for (k = 0; k < n; k++) { + if (inst->SrcReg[k].File == regFile) { + used[inst->SrcReg[k].Index] = GL_TRUE; + } + } + } + + for (i = 0; i < MAX_PROGRAM_TEMPS; 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 + } + + } +} diff --git a/mesalib/src/mesa/shader/program.h b/mesalib/src/mesa/shader/program.h new file mode 100644 index 000000000..56a4191f5 --- /dev/null +++ b/mesalib/src/mesa/shader/program.h @@ -0,0 +1,129 @@ +/* + * 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_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); +} + +extern struct gl_program * +_mesa_clone_program(GLcontext *ctx, const struct gl_program *prog); + +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 GLint +_mesa_find_free_register(const struct gl_program *prog, GLuint regFile); + +extern void +_mesa_postprocess_program(GLcontext *ctx, struct gl_program *prog); + + +#endif /* PROGRAM_H */ diff --git a/mesalib/src/mesa/shader/program_lexer.l b/mesalib/src/mesa/shader/program_lexer.l new file mode 100644 index 000000000..d24021748 --- /dev/null +++ b/mesalib/src/mesa/shader/program_lexer.l @@ -0,0 +1,489 @@ +%{ +/* + * 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 "main/glheader.h" +#include "prog_instruction.h" +#include "prog_statevars.h" + +#include "program_parser.h" +#include "program_parse.tab.h" + +#define require_ARB_vp (yyextra->mode == ARB_vertex) +#define require_ARB_fp (yyextra->mode == ARB_fragment) +#define require_shadow (yyextra->option.Shadow) +#define require_rect (yyextra->option.TexRect) +#define require_texarray (yyextra->option.TexArray) + +#define return_token_or_IDENTIFIER(condition, token) \ + do { \ + if (condition) { \ + return token; \ + } else { \ + yylval->string = strdup(yytext); \ + return IDENTIFIER; \ + } \ + } while (0) + +#define return_token_or_DOT(condition, token) \ + do { \ + if (condition) { \ + return token; \ + } else { \ + yyless(1); \ + return DOT; \ + } \ + } while (0) + + +#define return_opcode(condition, token, opcode, sat) \ + do { \ + if (condition) { \ + yylval->temp_inst.Opcode = OPCODE_ ## opcode; \ + yylval->temp_inst.SaturateMode = SATURATE_ ## sat; \ + return token; \ + } else { \ + yylval->string = strdup(yytext); \ + return IDENTIFIER; \ + } \ + } while (0) + +#define SWIZZLE_INVAL MAKE_SWIZZLE4(SWIZZLE_NIL, SWIZZLE_NIL, \ + SWIZZLE_NIL, SWIZZLE_NIL) + +static unsigned +mask_from_char(char c) +{ + switch (c) { + case 'x': + case 'r': + return WRITEMASK_X; + case 'y': + case 'g': + return WRITEMASK_Y; + case 'z': + case 'b': + return WRITEMASK_Z; + case 'w': + case 'a': + return WRITEMASK_W; + } + + return 0; +} + +static unsigned +swiz_from_char(char c) +{ + switch (c) { + case 'x': + case 'r': + return SWIZZLE_X; + case 'y': + case 'g': + return SWIZZLE_Y; + case 'z': + case 'b': + return SWIZZLE_Z; + case 'w': + case 'a': + return SWIZZLE_W; + } + + return 0; +} + +#define YY_USER_ACTION \ + do { \ + yylloc->first_column = yylloc->last_column; \ + yylloc->last_column += yyleng; \ + if ((yylloc->first_line == 1) \ + && (yylloc->first_column == 1)) { \ + yylloc->position = 1; \ + } else { \ + yylloc->position += yylloc->last_column - yylloc->first_column; \ + } \ + } while(0); + +#define YY_EXTRA_TYPE struct asm_parser_state * +%} + +num [0-9]+ +exp [Ee][-+]?[0-9]+ +frac "."[0-9]+ +dot "."[ \t]* + +%option bison-bridge bison-locations reentrant noyywrap +%% + +"!!ARBvp1.0" { return ARBvp_10; } +"!!ARBfp1.0" { return ARBfp_10; } +ADDRESS { + yylval->integer = at_address; + return_token_or_IDENTIFIER(require_ARB_vp, ADDRESS); +} +ALIAS { return ALIAS; } +ATTRIB { return ATTRIB; } +END { return END; } +OPTION { return OPTION; } +OUTPUT { return OUTPUT; } +PARAM { return PARAM; } +TEMP { yylval->integer = at_temp; return TEMP; } + +ABS { return_opcode( 1, VECTOR_OP, ABS, OFF); } +ABS_SAT { return_opcode(require_ARB_fp, VECTOR_OP, ABS, ZERO_ONE); } +ADD { return_opcode( 1, BIN_OP, ADD, OFF); } +ADD_SAT { return_opcode(require_ARB_fp, BIN_OP, ADD, ZERO_ONE); } +ARL { return_opcode(require_ARB_vp, ARL, ARL, OFF); } + +CMP { return_opcode(require_ARB_fp, TRI_OP, CMP, OFF); } +CMP_SAT { return_opcode(require_ARB_fp, TRI_OP, CMP, ZERO_ONE); } +COS { return_opcode(require_ARB_fp, SCALAR_OP, COS, OFF); } +COS_SAT { return_opcode(require_ARB_fp, SCALAR_OP, COS, ZERO_ONE); } + +DP3 { return_opcode( 1, BIN_OP, DP3, OFF); } +DP3_SAT { return_opcode(require_ARB_fp, BIN_OP, DP3, ZERO_ONE); } +DP4 { return_opcode( 1, BIN_OP, DP4, OFF); } +DP4_SAT { return_opcode(require_ARB_fp, BIN_OP, DP4, ZERO_ONE); } +DPH { return_opcode( 1, BIN_OP, DPH, OFF); } +DPH_SAT { return_opcode(require_ARB_fp, BIN_OP, DPH, ZERO_ONE); } +DST { return_opcode( 1, BIN_OP, DST, OFF); } +DST_SAT { return_opcode(require_ARB_fp, BIN_OP, DST, ZERO_ONE); } + +EX2 { return_opcode( 1, SCALAR_OP, EX2, OFF); } +EX2_SAT { return_opcode(require_ARB_fp, SCALAR_OP, EX2, ZERO_ONE); } +EXP { return_opcode(require_ARB_vp, SCALAR_OP, EXP, OFF); } + +FLR { return_opcode( 1, VECTOR_OP, FLR, OFF); } +FLR_SAT { return_opcode(require_ARB_fp, VECTOR_OP, FLR, ZERO_ONE); } +FRC { return_opcode( 1, VECTOR_OP, FRC, OFF); } +FRC_SAT { return_opcode(require_ARB_fp, VECTOR_OP, FRC, ZERO_ONE); } + +KIL { return_opcode(require_ARB_fp, KIL, KIL, OFF); } + +LIT { return_opcode( 1, VECTOR_OP, LIT, OFF); } +LIT_SAT { return_opcode(require_ARB_fp, VECTOR_OP, LIT, ZERO_ONE); } +LG2 { return_opcode( 1, SCALAR_OP, LG2, OFF); } +LG2_SAT { return_opcode(require_ARB_fp, SCALAR_OP, LG2, ZERO_ONE); } +LOG { return_opcode(require_ARB_vp, SCALAR_OP, LOG, OFF); } +LRP { return_opcode(require_ARB_fp, TRI_OP, LRP, OFF); } +LRP_SAT { return_opcode(require_ARB_fp, TRI_OP, LRP, ZERO_ONE); } + +MAD { return_opcode( 1, TRI_OP, MAD, OFF); } +MAD_SAT { return_opcode(require_ARB_fp, TRI_OP, MAD, ZERO_ONE); } +MAX { return_opcode( 1, BIN_OP, MAX, OFF); } +MAX_SAT { return_opcode(require_ARB_fp, BIN_OP, MAX, ZERO_ONE); } +MIN { return_opcode( 1, BIN_OP, MIN, OFF); } +MIN_SAT { return_opcode(require_ARB_fp, BIN_OP, MIN, ZERO_ONE); } +MOV { return_opcode( 1, VECTOR_OP, MOV, OFF); } +MOV_SAT { return_opcode(require_ARB_fp, VECTOR_OP, MOV, ZERO_ONE); } +MUL { return_opcode( 1, BIN_OP, MUL, OFF); } +MUL_SAT { return_opcode(require_ARB_fp, BIN_OP, MUL, ZERO_ONE); } + +POW { return_opcode( 1, BINSC_OP, POW, OFF); } +POW_SAT { return_opcode(require_ARB_fp, BINSC_OP, POW, ZERO_ONE); } + +RCP { return_opcode( 1, SCALAR_OP, RCP, OFF); } +RCP_SAT { return_opcode(require_ARB_fp, SCALAR_OP, RCP, ZERO_ONE); } +RSQ { return_opcode( 1, SCALAR_OP, RSQ, OFF); } +RSQ_SAT { return_opcode(require_ARB_fp, SCALAR_OP, RSQ, ZERO_ONE); } + +SCS { return_opcode(require_ARB_fp, SCALAR_OP, SCS, OFF); } +SCS_SAT { return_opcode(require_ARB_fp, SCALAR_OP, SCS, ZERO_ONE); } +SGE { return_opcode( 1, BIN_OP, SGE, OFF); } +SGE_SAT { return_opcode(require_ARB_fp, BIN_OP, SGE, ZERO_ONE); } +SIN { return_opcode(require_ARB_fp, SCALAR_OP, SIN, OFF); } +SIN_SAT { return_opcode(require_ARB_fp, SCALAR_OP, SIN, ZERO_ONE); } +SLT { return_opcode( 1, BIN_OP, SLT, OFF); } +SLT_SAT { return_opcode(require_ARB_fp, BIN_OP, SLT, ZERO_ONE); } +SUB { return_opcode( 1, BIN_OP, SUB, OFF); } +SUB_SAT { return_opcode(require_ARB_fp, BIN_OP, SUB, ZERO_ONE); } +SWZ { return_opcode( 1, SWZ, SWZ, OFF); } +SWZ_SAT { return_opcode(require_ARB_fp, SWZ, SWZ, ZERO_ONE); } + +TEX { return_opcode(require_ARB_fp, SAMPLE_OP, TEX, OFF); } +TEX_SAT { return_opcode(require_ARB_fp, SAMPLE_OP, TEX, ZERO_ONE); } +TXB { return_opcode(require_ARB_fp, SAMPLE_OP, TXB, OFF); } +TXB_SAT { return_opcode(require_ARB_fp, SAMPLE_OP, TXB, ZERO_ONE); } +TXP { return_opcode(require_ARB_fp, SAMPLE_OP, TXP, OFF); } +TXP_SAT { return_opcode(require_ARB_fp, SAMPLE_OP, TXP, ZERO_ONE); } + +XPD { return_opcode( 1, BIN_OP, XPD, OFF); } +XPD_SAT { return_opcode(require_ARB_fp, BIN_OP, XPD, ZERO_ONE); } + +vertex { return_token_or_IDENTIFIER(require_ARB_vp, VERTEX); } +fragment { return_token_or_IDENTIFIER(require_ARB_fp, FRAGMENT); } +program { return PROGRAM; } +state { return STATE; } +result { return RESULT; } + +{dot}ambient { return AMBIENT; } +{dot}attenuation { return ATTENUATION; } +{dot}back { return BACK; } +{dot}clip { return_token_or_DOT(require_ARB_vp, CLIP); } +{dot}color { return COLOR; } +{dot}depth { return_token_or_DOT(require_ARB_fp, DEPTH); } +{dot}diffuse { return DIFFUSE; } +{dot}direction { return DIRECTION; } +{dot}emission { return EMISSION; } +{dot}env { return ENV; } +{dot}eye { return EYE; } +{dot}fogcoord { return FOGCOORD; } +{dot}fog { return FOG; } +{dot}front { return FRONT; } +{dot}half { return HALF; } +{dot}inverse { return INVERSE; } +{dot}invtrans { return INVTRANS; } +{dot}light { return LIGHT; } +{dot}lightmodel { return LIGHTMODEL; } +{dot}lightprod { return LIGHTPROD; } +{dot}local { return LOCAL; } +{dot}material { return MATERIAL; } +{dot}program { return MAT_PROGRAM; } +{dot}matrix { return MATRIX; } +{dot}matrixindex { return_token_or_DOT(require_ARB_vp, MATRIXINDEX); } +{dot}modelview { return MODELVIEW; } +{dot}mvp { return MVP; } +{dot}normal { return_token_or_DOT(require_ARB_vp, NORMAL); } +{dot}object { return OBJECT; } +{dot}palette { return PALETTE; } +{dot}params { return PARAMS; } +{dot}plane { return PLANE; } +{dot}point { return_token_or_DOT(require_ARB_vp, POINT_TOK); } +{dot}pointsize { return_token_or_DOT(require_ARB_vp, POINTSIZE); } +{dot}position { return POSITION; } +{dot}primary { return PRIMARY; } +{dot}projection { return PROJECTION; } +{dot}range { return_token_or_DOT(require_ARB_fp, RANGE); } +{dot}row { return ROW; } +{dot}scenecolor { return SCENECOLOR; } +{dot}secondary { return SECONDARY; } +{dot}shininess { return SHININESS; } +{dot}size { return_token_or_DOT(require_ARB_vp, SIZE_TOK); } +{dot}specular { return SPECULAR; } +{dot}spot { return SPOT; } +{dot}texcoord { return TEXCOORD; } +{dot}texenv { return_token_or_DOT(require_ARB_fp, TEXENV); } +{dot}texgen { return_token_or_DOT(require_ARB_vp, TEXGEN); } +{dot}q { return_token_or_DOT(require_ARB_vp, TEXGEN_Q); } +{dot}s { return_token_or_DOT(require_ARB_vp, TEXGEN_S); } +{dot}t { return_token_or_DOT(require_ARB_vp, TEXGEN_T); } +{dot}texture { return TEXTURE; } +{dot}transpose { return TRANSPOSE; } +{dot}attrib { return_token_or_DOT(require_ARB_vp, VTXATTRIB); } +{dot}weight { return_token_or_DOT(require_ARB_vp, WEIGHT); } + +texture { return_token_or_IDENTIFIER(require_ARB_fp, TEXTURE_UNIT); } +1D { return_token_or_IDENTIFIER(require_ARB_fp, TEX_1D); } +2D { return_token_or_IDENTIFIER(require_ARB_fp, TEX_2D); } +3D { return_token_or_IDENTIFIER(require_ARB_fp, TEX_3D); } +CUBE { return_token_or_IDENTIFIER(require_ARB_fp, TEX_CUBE); } +RECT { return_token_or_IDENTIFIER(require_ARB_fp && require_rect, TEX_RECT); } +SHADOW1D { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow, TEX_SHADOW1D); } +SHADOW2D { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow, TEX_SHADOW2D); } +SHADOWRECT { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_rect, TEX_SHADOWRECT); } +ARRAY1D { return_token_or_IDENTIFIER(require_ARB_fp && require_texarray, TEX_ARRAY1D); } +ARRAY2D { return_token_or_IDENTIFIER(require_ARB_fp && require_texarray, TEX_ARRAY2D); } +ARRAYSHADOW1D { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_texarray, TEX_ARRAYSHADOW1D); } +ARRAYSHADOW2D { return_token_or_IDENTIFIER(require_ARB_fp && require_shadow && require_texarray, TEX_ARRAYSHADOW2D); } + +[_a-zA-Z$][_a-zA-Z0-9$]* { + yylval->string = strdup(yytext); + return IDENTIFIER; +} + +".." { return DOT_DOT; } + +{num} { + yylval->integer = strtol(yytext, NULL, 10); + return INTEGER; +} +{num}?{frac}{exp}? { + yylval->real = strtod(yytext, NULL); + return REAL; +} +{num}"."/[^.] { + yylval->real = strtod(yytext, NULL); + return REAL; +} +{num}{exp} { + yylval->real = strtod(yytext, NULL); + return REAL; +} +{num}"."{exp} { + yylval->real = strtod(yytext, NULL); + return REAL; +} + +".xyzw" { + yylval->swiz_mask.swizzle = SWIZZLE_NOOP; + yylval->swiz_mask.mask = WRITEMASK_XYZW; + return MASK4; +} + +".xy"[zw] { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XY + | mask_from_char(yytext[3]); + return MASK3; +} +".xzw" { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XZW; + return MASK3; +} +".yzw" { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_YZW; + return MASK3; +} + +".x"[yzw] { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_X + | mask_from_char(yytext[2]); + return MASK2; +} +".y"[zw] { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_Y + | mask_from_char(yytext[2]); + return MASK2; +} +".zw" { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_ZW; + return MASK2; +} + +"."[xyzw] { + const unsigned s = swiz_from_char(yytext[1]); + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(s, s, s, s); + yylval->swiz_mask.mask = mask_from_char(yytext[1]); + return MASK1; +} + +"."[xyzw]{4} { + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(swiz_from_char(yytext[1]), + swiz_from_char(yytext[2]), + swiz_from_char(yytext[3]), + swiz_from_char(yytext[4])); + yylval->swiz_mask.mask = 0; + return SWIZZLE; +} + +".rgba" { + yylval->swiz_mask.swizzle = SWIZZLE_NOOP; + yylval->swiz_mask.mask = WRITEMASK_XYZW; + return_token_or_DOT(require_ARB_fp, MASK4); +} + +".rg"[ba] { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XY + | mask_from_char(yytext[3]); + return_token_or_DOT(require_ARB_fp, MASK3); +} +".rba" { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_XZW; + return_token_or_DOT(require_ARB_fp, MASK3); +} +".gba" { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_YZW; + return_token_or_DOT(require_ARB_fp, MASK3); +} + +".r"[gba] { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_X + | mask_from_char(yytext[2]); + return_token_or_DOT(require_ARB_fp, MASK2); +} +".g"[ba] { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_Y + | mask_from_char(yytext[2]); + return_token_or_DOT(require_ARB_fp, MASK2); +} +".ba" { + yylval->swiz_mask.swizzle = SWIZZLE_INVAL; + yylval->swiz_mask.mask = WRITEMASK_ZW; + return_token_or_DOT(require_ARB_fp, MASK2); +} + +"."[gba] { + const unsigned s = swiz_from_char(yytext[1]); + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(s, s, s, s); + yylval->swiz_mask.mask = mask_from_char(yytext[1]); + return_token_or_DOT(require_ARB_fp, MASK1); +} + + +".r" { + if (require_ARB_vp) { + return TEXGEN_R; + } else { + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, + SWIZZLE_X, SWIZZLE_X); + yylval->swiz_mask.mask = WRITEMASK_X; + return MASK1; + } +} + +"."[rgba]{4} { + yylval->swiz_mask.swizzle = MAKE_SWIZZLE4(swiz_from_char(yytext[1]), + swiz_from_char(yytext[2]), + swiz_from_char(yytext[3]), + swiz_from_char(yytext[4])); + yylval->swiz_mask.mask = 0; + return_token_or_DOT(require_ARB_fp, SWIZZLE); +} + +"." { return DOT; } + +\n { + yylloc->first_line++; + yylloc->first_column = 1; + yylloc->last_line++; + yylloc->last_column = 1; + yylloc->position++; +} +[ \t\r]+ /* eat whitespace */ ; +#.*$ /* eat comments */ ; +. { return yytext[0]; } +%% + +void +_mesa_program_lexer_ctor(void **scanner, struct asm_parser_state *state, + const char *string, size_t len) +{ + yylex_init_extra(state, scanner); + yy_scan_bytes(string, len, *scanner); +} + +void +_mesa_program_lexer_dtor(void *scanner) +{ + yylex_destroy(scanner); +} diff --git a/mesalib/src/mesa/shader/program_parse.tab.c b/mesalib/src/mesa/shader/program_parse.tab.c new file mode 100644 index 000000000..9f2d4de90 --- /dev/null +++ b/mesalib/src/mesa/shader/program_parse.tab.c @@ -0,0 +1,5249 @@ + +/* 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.h" +#include "prog_parameter.h" +#include "prog_parameter_layout.h" +#include "prog_statevars.h" +#include "prog_instruction.h" + +#include "symbol_table.h" +#include "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); + +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 init_src_reg(struct asm_src_register *r); + +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); + +#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 174 "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, + INTEGER = 277, + REAL = 278, + AMBIENT = 279, + ATTENUATION = 280, + BACK = 281, + CLIP = 282, + COLOR = 283, + DEPTH = 284, + DIFFUSE = 285, + DIRECTION = 286, + EMISSION = 287, + ENV = 288, + EYE = 289, + FOG = 290, + FOGCOORD = 291, + FRAGMENT = 292, + FRONT = 293, + HALF = 294, + INVERSE = 295, + INVTRANS = 296, + LIGHT = 297, + LIGHTMODEL = 298, + LIGHTPROD = 299, + LOCAL = 300, + MATERIAL = 301, + MAT_PROGRAM = 302, + MATRIX = 303, + MATRIXINDEX = 304, + MODELVIEW = 305, + MVP = 306, + NORMAL = 307, + OBJECT = 308, + PALETTE = 309, + PARAMS = 310, + PLANE = 311, + POINT_TOK = 312, + POINTSIZE = 313, + POSITION = 314, + PRIMARY = 315, + PROGRAM = 316, + PROJECTION = 317, + RANGE = 318, + RESULT = 319, + ROW = 320, + SCENECOLOR = 321, + SECONDARY = 322, + SHININESS = 323, + SIZE_TOK = 324, + SPECULAR = 325, + SPOT = 326, + STATE = 327, + TEXCOORD = 328, + TEXENV = 329, + TEXGEN = 330, + TEXGEN_Q = 331, + TEXGEN_R = 332, + TEXGEN_S = 333, + TEXGEN_T = 334, + TEXTURE = 335, + TRANSPOSE = 336, + TEXTURE_UNIT = 337, + TEX_1D = 338, + TEX_2D = 339, + TEX_3D = 340, + TEX_CUBE = 341, + TEX_RECT = 342, + TEX_SHADOW1D = 343, + TEX_SHADOW2D = 344, + TEX_SHADOWRECT = 345, + TEX_ARRAY1D = 346, + TEX_ARRAY2D = 347, + TEX_ARRAYSHADOW1D = 348, + TEX_ARRAYSHADOW2D = 349, + VERTEX = 350, + VTXATTRIB = 351, + WEIGHT = 352, + IDENTIFIER = 353, + MASK4 = 354, + MASK3 = 355, + MASK2 = 356, + MASK1 = 357, + SWIZZLE = 358, + DOT_DOT = 359, + DOT = 360 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 214 of yacc.c */ +#line 107 "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 343 "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 249 "program_parse.y" + +extern int yylex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param, + void *yyscanner); + + +/* Line 264 of yacc.c */ +#line 374 "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 342 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 115 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 134 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 264 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 436 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 360 + +#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, + 2, 2, 2, 110, 107, 111, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 106, + 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, 108, 2, 109, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 113, 2, 114, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 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 +}; + +#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, 57, 62, 67, 74, 81, 90, + 99, 102, 105, 107, 109, 111, 113, 115, 117, 119, + 121, 123, 125, 127, 129, 136, 140, 144, 147, 150, + 158, 161, 163, 165, 167, 169, 174, 176, 178, 180, + 182, 184, 186, 188, 192, 193, 196, 199, 201, 203, + 205, 207, 209, 211, 213, 215, 217, 218, 220, 222, + 224, 226, 227, 229, 231, 233, 235, 237, 239, 244, + 247, 250, 252, 255, 257, 260, 262, 265, 270, 275, + 277, 278, 282, 284, 286, 289, 291, 294, 296, 298, + 302, 309, 310, 312, 315, 320, 322, 326, 328, 330, + 332, 334, 336, 338, 340, 342, 344, 346, 349, 352, + 355, 358, 361, 364, 367, 370, 373, 376, 379, 382, + 386, 388, 390, 392, 398, 400, 402, 404, 407, 409, + 411, 414, 416, 419, 426, 428, 432, 434, 436, 438, + 440, 442, 447, 449, 451, 453, 455, 457, 459, 462, + 464, 466, 472, 474, 477, 479, 481, 487, 490, 491, + 498, 502, 503, 505, 507, 509, 511, 513, 516, 518, + 520, 523, 528, 533, 534, 538, 540, 542, 544, 547, + 549, 551, 553, 555, 561, 563, 567, 573, 579, 581, + 585, 591, 593, 595, 597, 599, 601, 603, 605, 607, + 609, 613, 619, 627, 637, 640, 643, 645, 647, 648, + 649, 653, 654, 658, 662, 664, 669, 672, 675, 678, + 681, 685, 688, 692, 693, 695, 697, 698, 700, 702, + 703, 705, 707, 708, 710, 712, 713, 717, 718, 722, + 723, 727, 729, 731, 733 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int16 yyrhs[] = +{ + 116, 0, -1, 117, 118, 120, 12, -1, 3, -1, + 4, -1, 118, 119, -1, -1, 8, 98, 106, -1, + 120, 121, -1, -1, 122, 106, -1, 158, 106, -1, + 123, -1, 124, -1, 125, -1, 126, -1, 127, -1, + 128, -1, 129, -1, 130, -1, 135, -1, 131, -1, + 132, -1, 19, 139, 107, 136, -1, 18, 138, 107, + 137, -1, 16, 138, 107, 136, -1, 14, 138, 107, + 136, 107, 136, -1, 13, 138, 107, 137, 107, 137, + -1, 17, 138, 107, 137, 107, 137, 107, 137, -1, + 15, 138, 107, 137, 107, 133, 107, 134, -1, 20, + 137, -1, 82, 243, -1, 83, -1, 84, -1, 85, + -1, 86, -1, 87, -1, 88, -1, 89, -1, 90, + -1, 91, -1, 92, -1, 93, -1, 94, -1, 21, + 138, 107, 143, 107, 140, -1, 229, 143, 155, -1, + 229, 143, 156, -1, 144, 157, -1, 152, 154, -1, + 141, 107, 141, 107, 141, 107, 141, -1, 229, 142, + -1, 22, -1, 98, -1, 98, -1, 160, -1, 145, + 108, 146, 109, -1, 174, -1, 236, -1, 98, -1, + 98, -1, 147, -1, 148, -1, 22, -1, 152, 153, + 149, -1, -1, 110, 150, -1, 111, 151, -1, 22, + -1, 22, -1, 98, -1, 102, -1, 102, -1, 102, + -1, 102, -1, 99, -1, 103, -1, -1, 99, -1, + 100, -1, 101, -1, 102, -1, -1, 159, -1, 166, + -1, 230, -1, 232, -1, 235, -1, 248, -1, 7, + 98, 112, 160, -1, 95, 161, -1, 37, 165, -1, + 59, -1, 97, 163, -1, 52, -1, 28, 241, -1, + 36, -1, 73, 242, -1, 49, 108, 164, 109, -1, + 96, 108, 162, 109, -1, 22, -1, -1, 108, 164, + 109, -1, 22, -1, 59, -1, 28, 241, -1, 36, + -1, 73, 242, -1, 167, -1, 168, -1, 10, 98, + 170, -1, 10, 98, 108, 169, 109, 171, -1, -1, + 22, -1, 112, 173, -1, 112, 113, 172, 114, -1, + 175, -1, 172, 107, 175, -1, 177, -1, 213, -1, + 223, -1, 177, -1, 213, -1, 224, -1, 176, -1, + 214, -1, 223, -1, 177, -1, 72, 201, -1, 72, + 178, -1, 72, 180, -1, 72, 183, -1, 72, 185, + -1, 72, 191, -1, 72, 187, -1, 72, 194, -1, + 72, 196, -1, 72, 198, -1, 72, 200, -1, 72, + 212, -1, 46, 240, 179, -1, 189, -1, 32, -1, + 68, -1, 42, 108, 190, 109, 181, -1, 189, -1, + 59, -1, 25, -1, 71, 182, -1, 39, -1, 31, + -1, 43, 184, -1, 24, -1, 240, 66, -1, 44, + 108, 190, 109, 240, 186, -1, 189, -1, 74, 244, + 188, -1, 28, -1, 24, -1, 30, -1, 70, -1, + 22, -1, 75, 242, 192, 193, -1, 34, -1, 53, + -1, 78, -1, 79, -1, 77, -1, 76, -1, 35, + 195, -1, 28, -1, 55, -1, 27, 108, 197, 109, + 56, -1, 22, -1, 57, 199, -1, 69, -1, 25, + -1, 203, 65, 108, 206, 109, -1, 203, 202, -1, + -1, 65, 108, 206, 104, 206, 109, -1, 48, 207, + 204, -1, -1, 205, -1, 40, -1, 81, -1, 41, + -1, 22, -1, 50, 208, -1, 62, -1, 51, -1, + 80, 242, -1, 54, 108, 210, 109, -1, 47, 108, + 211, 109, -1, -1, 108, 209, 109, -1, 22, -1, + 22, -1, 22, -1, 29, 63, -1, 217, -1, 220, + -1, 215, -1, 218, -1, 61, 33, 108, 216, 109, + -1, 221, -1, 221, 104, 221, -1, 61, 33, 108, + 221, 109, -1, 61, 45, 108, 219, 109, -1, 222, + -1, 222, 104, 222, -1, 61, 45, 108, 222, 109, + -1, 22, -1, 22, -1, 225, -1, 227, -1, 226, + -1, 227, -1, 228, -1, 23, -1, 22, -1, 113, + 228, 114, -1, 113, 228, 107, 228, 114, -1, 113, + 228, 107, 228, 107, 228, 114, -1, 113, 228, 107, + 228, 107, 228, 107, 228, 114, -1, 229, 23, -1, + 229, 22, -1, 110, -1, 111, -1, -1, -1, 11, + 231, 234, -1, -1, 5, 233, 234, -1, 234, 107, + 98, -1, 98, -1, 9, 98, 112, 236, -1, 64, + 59, -1, 64, 36, -1, 64, 237, -1, 64, 58, + -1, 64, 73, 242, -1, 64, 29, -1, 28, 238, + 239, -1, -1, 38, -1, 26, -1, -1, 60, -1, + 67, -1, -1, 38, -1, 26, -1, -1, 60, -1, + 67, -1, -1, 108, 245, 109, -1, -1, 108, 246, + 109, -1, -1, 108, 247, 109, -1, 22, -1, 22, + -1, 22, -1, 6, 98, 112, 98, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 256, 256, 259, 267, 279, 280, 283, 305, 306, + 309, 324, 327, 332, 339, 340, 341, 342, 343, 344, + 345, 348, 349, 352, 358, 365, 372, 380, 387, 395, + 440, 447, 453, 454, 455, 456, 457, 458, 459, 460, + 461, 462, 463, 464, 467, 480, 493, 506, 528, 537, + 570, 577, 592, 642, 684, 695, 716, 726, 732, 763, + 780, 780, 782, 789, 801, 802, 803, 806, 818, 830, + 848, 859, 871, 873, 874, 875, 876, 879, 879, 879, + 879, 880, 883, 884, 885, 886, 887, 888, 891, 909, + 913, 919, 923, 927, 931, 940, 949, 953, 958, 964, + 975, 975, 976, 978, 982, 986, 990, 996, 996, 998, + 1014, 1037, 1040, 1051, 1057, 1063, 1064, 1071, 1077, 1083, + 1091, 1097, 1103, 1111, 1117, 1123, 1131, 1132, 1135, 1136, + 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1148, + 1157, 1161, 1165, 1171, 1180, 1184, 1188, 1197, 1201, 1207, + 1213, 1220, 1225, 1233, 1243, 1245, 1253, 1259, 1263, 1267, + 1273, 1284, 1293, 1297, 1302, 1306, 1310, 1314, 1320, 1327, + 1331, 1337, 1345, 1356, 1363, 1367, 1373, 1383, 1394, 1398, + 1416, 1425, 1428, 1434, 1438, 1442, 1448, 1459, 1464, 1469, + 1474, 1479, 1484, 1492, 1495, 1500, 1513, 1521, 1532, 1540, + 1540, 1542, 1542, 1544, 1554, 1559, 1566, 1576, 1585, 1590, + 1597, 1607, 1617, 1629, 1629, 1630, 1630, 1632, 1642, 1650, + 1660, 1668, 1676, 1685, 1696, 1700, 1706, 1707, 1708, 1711, + 1711, 1714, 1714, 1717, 1723, 1731, 1744, 1753, 1762, 1766, + 1775, 1784, 1795, 1802, 1807, 1816, 1828, 1831, 1840, 1851, + 1852, 1853, 1856, 1857, 1858, 1861, 1862, 1865, 1866, 1869, + 1870, 1873, 1884, 1895, 1906 +}; +#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", "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", "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", + "texImageUnit", "texTarget", "SWZ_instruction", "scalarSrcReg", + "swizzleSrcReg", "maskedDstReg", "maskedAddrReg", "extendedSwizzle", + "extSwizComp", "extSwizSel", "srcReg", "dstReg", "progParamArray", + "progParamArrayMem", "progParamArrayAbs", "progParamArrayRel", + "addrRegRelOffset", "addrRegPosOffset", "addrRegNegOffset", "addrReg", + "addrComponent", "addrWriteMask", "scalarSuffix", "swizzleSuffix", + "optionalMask", "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", + "ADDRESS_statement", "@2", "varNameList", "OUTPUT_statement", + "resultBinding", "resultColBinding", "optResultFaceType", + "optResultColorType", "optFaceType", "optColorType", + "optTexCoordUnitNum", "optTexImageUnitNum", "optLegacyTexUnitNum", + "texCoordUnitNum", "texImageUnitNum", "legacyTexUnitNum", + "ALIAS_statement", 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, 59, 44, 91, 93, + 43, 45, 61, 123, 125 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 115, 116, 117, 117, 118, 118, 119, 120, 120, + 121, 121, 122, 122, 123, 123, 123, 123, 123, 123, + 123, 124, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 134, 134, 134, 134, 134, 134, 134, + 134, 134, 134, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 142, 143, 143, 143, 143, 144, 144, 145, + 146, 146, 147, 148, 149, 149, 149, 150, 151, 152, + 153, 154, 155, 156, 156, 156, 156, 157, 157, 157, + 157, 157, 158, 158, 158, 158, 158, 158, 159, 160, + 160, 161, 161, 161, 161, 161, 161, 161, 161, 162, + 163, 163, 164, 165, 165, 165, 165, 166, 166, 167, + 168, 169, 169, 170, 171, 172, 172, 173, 173, 173, + 174, 174, 174, 175, 175, 175, 176, 176, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 178, + 179, 179, 179, 180, 181, 181, 181, 181, 181, 182, + 183, 184, 184, 185, 186, 187, 188, 189, 189, 189, + 190, 191, 192, 192, 193, 193, 193, 193, 194, 195, + 195, 196, 197, 198, 199, 199, 200, 201, 202, 202, + 203, 204, 204, 205, 205, 205, 206, 207, 207, 207, + 207, 207, 207, 208, 208, 209, 210, 211, 212, 213, + 213, 214, 214, 215, 216, 216, 217, 218, 219, 219, + 220, 221, 222, 223, 223, 224, 224, 225, 226, 226, + 227, 227, 227, 227, 228, 228, 229, 229, 229, 231, + 230, 233, 232, 234, 234, 235, 236, 236, 236, 236, + 236, 236, 237, 238, 238, 238, 239, 239, 239, 240, + 240, 240, 241, 241, 241, 242, 242, 243, 243, 244, + 244, 245, 246, 247, 248 +}; + +/* 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, 4, 4, 4, 6, 6, 8, 8, + 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6, 3, 3, 2, 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, 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, + 3, 0, 3, 3, 1, 4, 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 +}; + +/* 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, 0, + 0, 231, 0, 0, 0, 0, 229, 2, 0, 0, + 0, 0, 0, 0, 0, 228, 0, 8, 0, 12, + 13, 14, 15, 16, 17, 18, 19, 21, 22, 20, + 0, 82, 83, 107, 108, 84, 85, 86, 87, 7, + 0, 0, 0, 0, 0, 0, 0, 58, 0, 81, + 57, 0, 0, 0, 0, 0, 69, 0, 0, 226, + 227, 30, 0, 0, 10, 11, 234, 232, 0, 0, + 0, 111, 228, 109, 230, 243, 241, 237, 239, 236, + 255, 238, 228, 77, 78, 79, 80, 47, 228, 228, + 228, 228, 228, 228, 71, 48, 219, 218, 0, 0, + 0, 0, 53, 228, 76, 0, 54, 56, 120, 121, + 199, 200, 122, 215, 216, 0, 0, 264, 88, 235, + 112, 0, 113, 117, 118, 119, 213, 214, 217, 0, + 245, 244, 246, 0, 240, 0, 0, 0, 0, 25, + 0, 24, 23, 252, 105, 103, 255, 90, 0, 0, + 0, 0, 0, 0, 249, 0, 249, 0, 0, 259, + 255, 128, 129, 130, 131, 133, 132, 134, 135, 136, + 137, 0, 138, 252, 95, 0, 93, 91, 255, 0, + 100, 89, 0, 74, 73, 75, 46, 0, 0, 233, + 0, 225, 224, 247, 248, 242, 261, 0, 228, 228, + 0, 0, 228, 253, 254, 104, 106, 0, 0, 0, + 198, 169, 170, 168, 0, 151, 251, 250, 150, 0, + 0, 0, 0, 193, 189, 0, 188, 255, 181, 175, + 174, 173, 0, 0, 0, 0, 94, 0, 96, 0, + 0, 92, 228, 220, 62, 0, 60, 61, 0, 228, + 0, 110, 256, 27, 26, 72, 45, 257, 0, 0, + 211, 0, 212, 0, 172, 0, 160, 0, 152, 0, + 157, 158, 141, 142, 159, 139, 140, 0, 0, 187, + 0, 190, 183, 185, 184, 180, 182, 263, 0, 156, + 155, 162, 163, 0, 0, 102, 0, 99, 0, 0, + 0, 55, 70, 64, 44, 0, 0, 228, 0, 31, + 0, 228, 206, 210, 0, 0, 249, 197, 0, 195, + 0, 196, 0, 260, 167, 166, 164, 165, 161, 186, + 0, 97, 98, 101, 228, 221, 0, 0, 63, 228, + 51, 52, 50, 0, 0, 0, 115, 123, 126, 124, + 201, 202, 125, 262, 0, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 29, 28, 171, + 146, 148, 145, 0, 143, 144, 0, 192, 194, 191, + 176, 0, 67, 65, 68, 66, 0, 0, 0, 127, + 178, 228, 114, 258, 149, 147, 153, 154, 228, 222, + 228, 0, 0, 0, 177, 116, 0, 0, 0, 204, + 0, 208, 0, 223, 228, 203, 0, 207, 0, 0, + 49, 205, 209, 0, 0, 179 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 3, 4, 6, 8, 9, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 268, 377, + 39, 146, 71, 58, 67, 314, 315, 352, 114, 59, + 115, 255, 256, 257, 348, 393, 395, 68, 313, 105, + 266, 196, 97, 40, 41, 116, 191, 308, 251, 306, + 157, 42, 43, 44, 131, 83, 261, 355, 132, 117, + 356, 357, 118, 171, 285, 172, 384, 405, 173, 228, + 174, 406, 175, 300, 286, 277, 176, 303, 338, 177, + 223, 178, 275, 179, 241, 180, 399, 414, 181, 295, + 296, 340, 238, 289, 330, 332, 328, 182, 119, 359, + 360, 418, 120, 361, 420, 121, 271, 273, 362, 122, + 136, 123, 124, 138, 72, 45, 55, 46, 50, 77, + 47, 60, 91, 142, 205, 229, 215, 144, 319, 243, + 207, 364, 298, 48 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -369 +static const yytype_int16 yypact[] = +{ + 143, -369, -369, 36, -369, -369, 45, -39, -369, 169, + -33, -369, -19, -6, -4, 12, -369, -369, -34, -34, + -34, -34, -34, -34, 15, 62, -34, -369, 26, -369, + -369, -369, -369, -369, -369, -369, -369, -369, -369, -369, + 60, -369, -369, -369, -369, -369, -369, -369, -369, -369, + 20, 56, 107, 110, 37, 20, -3, -369, 111, 109, + -369, 113, 114, 116, 117, 118, -369, 119, 125, -369, + -369, -369, -15, 121, -369, -369, -369, 122, 132, -18, + 167, 210, -11, -369, 122, 63, -369, -369, -369, -369, + 130, -369, 62, -369, -369, -369, -369, -369, 62, 62, + 62, 62, 62, 62, -369, -369, -369, -369, 9, 72, + 87, -1, 131, 62, 104, 134, -369, -369, -369, -369, + -369, -369, -369, -369, -369, -15, 142, -369, -369, -369, + -369, 135, -369, -369, -369, -369, -369, -369, -369, 182, + -369, -369, 52, 219, -369, 138, 139, -15, 140, -369, + 141, -369, -369, 61, -369, -369, 130, -369, 144, 145, + 146, 180, 11, 147, 85, 148, 99, 89, -2, 149, + 130, -369, -369, -369, -369, -369, -369, -369, -369, -369, + -369, 184, -369, 61, -369, 150, -369, -369, 130, 151, + 152, -369, 27, -369, -369, -369, -369, -10, 154, -369, + 153, -369, -369, -369, -369, -369, -369, 155, 62, 62, + 161, 168, 62, -369, -369, -369, -369, 229, 244, 246, + -369, -369, -369, -369, 247, -369, -369, -369, -369, 204, + 247, 17, 163, 164, -369, 165, -369, 130, 67, -369, + -369, -369, 252, 248, 18, 170, -369, 253, -369, 255, + 253, -369, 62, -369, -369, 171, -369, -369, 177, 62, + 172, -369, -369, -369, -369, -369, -369, 173, 175, 176, + -369, 178, -369, 179, -369, 181, -369, 183, -369, 185, + -369, -369, -369, -369, -369, -369, -369, 262, 264, -369, + 267, -369, -369, -369, -369, -369, -369, -369, 186, -369, + -369, -369, -369, 136, 269, -369, 187, -369, 188, 190, + 43, -369, -369, 106, -369, 193, -5, -7, 271, -369, + 108, 62, -369, -369, 245, 4, 99, -369, 194, -369, + 195, -369, 196, -369, -369, -369, -369, -369, -369, -369, + 197, -369, -369, -369, 62, -369, 280, 285, -369, 62, + -369, -369, -369, 93, 87, 53, -369, -369, -369, -369, + -369, -369, -369, -369, 199, -369, -369, -369, -369, -369, + -369, -369, -369, -369, -369, -369, -369, -369, -369, -369, + -369, -369, -369, 278, -369, -369, 8, -369, -369, -369, + -369, 57, -369, -369, -369, -369, 203, 205, 206, -369, + 250, -7, -369, -369, -369, -369, -369, -369, 62, -369, + 62, 229, 244, 208, -369, -369, 198, 211, 202, 213, + 214, 218, 269, -369, 62, -369, 229, -369, 244, 54, + -369, -369, -369, 269, 215, -369 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -369, -369, -369, -369, -369, -369, -369, -369, -369, -369, + -369, -369, -369, -369, -369, -369, -369, -369, -369, -369, + -369, -94, -88, 133, -369, -369, -334, -369, -85, -369, + -369, -369, -369, -369, -369, -369, -369, 128, -369, -369, + -369, -369, -369, -369, -369, 251, -369, -369, -369, 77, + -369, -369, -369, -369, -369, -369, -369, -369, -369, -369, + -72, -369, -81, -369, -369, -369, -369, -369, -369, -369, + -369, -369, -369, -369, -305, 101, -369, -369, -369, -369, + -369, -369, -369, -369, -369, -369, -369, -369, -22, -369, + -369, -336, -369, -369, -369, -369, -369, -369, 254, -369, + -369, -369, -369, -369, -369, -369, -342, -368, 256, -369, + -369, -369, -80, -110, -82, -369, -369, -369, -369, 279, + -369, 257, -369, -369, -369, -161, 156, -146, -369, -369, + -369, -369, -369, -369 +}; + +/* 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 -60 +static const yytype_int16 yytable[] = +{ + 139, 133, 137, 192, 145, 231, 149, 106, 107, 152, + 216, 148, 254, 150, 151, 396, 147, 350, 147, 108, + 385, 147, 108, 239, 244, 85, 86, 183, 280, 380, + 56, 139, 280, 87, 281, 184, 5, 153, 281, 221, + 198, 280, 248, 381, 421, 154, 109, 281, 185, 282, + 109, 186, 301, 7, 353, 88, 89, 110, 187, 10, + 432, 110, 210, 382, 57, 354, 222, 240, 155, 419, + 90, 302, 188, 49, 284, 383, 417, 111, 284, 51, + 111, 407, 156, 112, 431, 283, 429, 284, 66, 140, + 430, 291, 52, 351, 53, 189, 190, 434, 113, 69, + 70, 141, 113, 69, 70, 158, 113, 292, 293, 225, + 54, 226, 203, 66, 160, 264, 161, 159, 76, 204, + 263, 213, 162, 227, 269, 226, 397, 147, 214, 163, + 164, 165, 74, 166, 252, 167, 232, 227, 398, 233, + 234, 253, 310, 235, 168, 81, 1, 2, 294, 82, + 344, 236, 61, 62, 63, 64, 65, 345, 433, 73, + 401, 169, 170, 390, 408, 386, 75, 402, 78, 237, + 139, 409, 69, 70, 11, 12, 13, 316, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 193, 201, 202, 194, 195, 93, 94, + 95, 96, 334, 335, 336, 337, 346, 347, 92, 79, + 98, 99, 80, 100, 101, 102, 103, 104, 125, 126, + 127, 56, 130, 378, 391, 139, 358, 137, 143, -59, + 199, 206, 197, 220, 200, 208, 209, 211, 212, 245, + 267, 270, 217, 218, 219, 224, 230, 242, 247, 249, + 250, 259, 139, 265, 262, 260, 272, 316, 274, 276, + 278, 287, 288, 290, 297, 305, 299, 307, 304, 312, + 311, 318, 320, 321, 327, 317, 329, 322, 323, 331, + 324, 339, 325, 363, 326, 333, 341, 342, 416, 343, + 349, 379, 392, 387, 388, 389, 390, 394, 403, 404, + 410, 425, 423, 411, 412, 413, 422, 426, 424, 139, + 358, 137, 428, 427, 435, 258, 139, 309, 316, 415, + 128, 279, 400, 0, 84, 0, 134, 129, 135, 246, + 0, 0, 316 +}; + +static const yytype_int16 yycheck[] = +{ + 82, 82, 82, 113, 92, 166, 100, 22, 23, 103, + 156, 99, 22, 101, 102, 349, 98, 22, 100, 37, + 325, 103, 37, 25, 170, 28, 29, 28, 24, 25, + 64, 113, 24, 36, 30, 36, 0, 28, 30, 28, + 125, 24, 188, 39, 412, 36, 61, 30, 49, 32, + 61, 52, 34, 8, 61, 58, 59, 72, 59, 98, + 428, 72, 147, 59, 98, 72, 55, 69, 59, 411, + 73, 53, 73, 106, 70, 71, 410, 95, 70, 98, + 95, 386, 73, 98, 426, 68, 422, 70, 98, 26, + 424, 237, 98, 98, 98, 96, 97, 433, 113, 110, + 111, 38, 113, 110, 111, 33, 113, 40, 41, 24, + 98, 26, 60, 98, 27, 209, 29, 45, 98, 67, + 208, 60, 35, 38, 212, 26, 33, 209, 67, 42, + 43, 44, 106, 46, 107, 48, 47, 38, 45, 50, + 51, 114, 252, 54, 57, 108, 3, 4, 81, 112, + 107, 62, 19, 20, 21, 22, 23, 114, 104, 26, + 107, 74, 75, 109, 107, 326, 106, 114, 112, 80, + 252, 114, 110, 111, 5, 6, 7, 259, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 99, 22, 23, 102, 103, 99, 100, + 101, 102, 76, 77, 78, 79, 110, 111, 107, 112, + 107, 107, 112, 107, 107, 107, 107, 102, 107, 107, + 98, 64, 22, 321, 344, 317, 317, 317, 108, 108, + 98, 22, 108, 63, 109, 107, 107, 107, 107, 65, + 82, 22, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 107, 344, 102, 109, 112, 22, 349, 22, 22, + 66, 108, 108, 108, 22, 22, 28, 22, 108, 102, + 109, 108, 107, 107, 22, 113, 22, 109, 109, 22, + 109, 22, 109, 22, 109, 109, 109, 109, 408, 109, + 107, 56, 22, 109, 109, 109, 109, 22, 109, 31, + 107, 109, 114, 108, 108, 65, 108, 104, 107, 401, + 401, 401, 104, 109, 109, 197, 408, 250, 410, 401, + 79, 230, 354, -1, 55, -1, 82, 80, 82, 183, + -1, -1, 424 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 4, 116, 117, 0, 118, 8, 119, 120, + 98, 5, 6, 7, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 135, + 158, 159, 166, 167, 168, 230, 232, 235, 248, 106, + 233, 98, 98, 98, 98, 231, 64, 98, 138, 144, + 236, 138, 138, 138, 138, 138, 98, 139, 152, 110, + 111, 137, 229, 138, 106, 106, 98, 234, 112, 112, + 112, 108, 112, 170, 234, 28, 29, 36, 58, 59, + 73, 237, 107, 99, 100, 101, 102, 157, 107, 107, + 107, 107, 107, 107, 102, 154, 22, 23, 37, 61, + 72, 95, 98, 113, 143, 145, 160, 174, 177, 213, + 217, 220, 224, 226, 227, 107, 107, 98, 160, 236, + 22, 169, 173, 177, 213, 223, 225, 227, 228, 229, + 26, 38, 238, 108, 242, 137, 136, 229, 137, 136, + 137, 137, 136, 28, 36, 59, 73, 165, 33, 45, + 27, 29, 35, 42, 43, 44, 46, 48, 57, 74, + 75, 178, 180, 183, 185, 187, 191, 194, 196, 198, + 200, 203, 212, 28, 36, 49, 52, 59, 73, 96, + 97, 161, 228, 99, 102, 103, 156, 108, 143, 98, + 109, 22, 23, 60, 67, 239, 22, 245, 107, 107, + 143, 107, 107, 60, 67, 241, 242, 108, 108, 108, + 63, 28, 55, 195, 108, 24, 26, 38, 184, 240, + 108, 240, 47, 50, 51, 54, 62, 80, 207, 25, + 69, 199, 108, 244, 242, 65, 241, 108, 242, 108, + 108, 163, 107, 114, 22, 146, 147, 148, 152, 107, + 112, 171, 109, 137, 136, 102, 155, 82, 133, 137, + 22, 221, 22, 222, 22, 197, 22, 190, 66, 190, + 24, 30, 32, 68, 70, 179, 189, 108, 108, 208, + 108, 242, 40, 41, 81, 204, 205, 22, 247, 28, + 188, 34, 53, 192, 108, 22, 164, 22, 162, 164, + 228, 109, 102, 153, 140, 141, 229, 113, 108, 243, + 107, 107, 109, 109, 109, 109, 109, 22, 211, 22, + 209, 22, 210, 109, 76, 77, 78, 79, 193, 22, + 206, 109, 109, 109, 107, 114, 110, 111, 149, 107, + 22, 98, 142, 61, 72, 172, 175, 176, 177, 214, + 215, 218, 223, 22, 246, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 134, 137, 56, + 25, 39, 59, 71, 181, 189, 240, 109, 109, 109, + 109, 228, 22, 150, 22, 151, 141, 33, 45, 201, + 203, 107, 114, 109, 31, 182, 186, 189, 107, 114, + 107, 108, 108, 65, 202, 175, 228, 141, 216, 221, + 219, 222, 108, 114, 107, 109, 104, 109, 104, 206, + 141, 221, 222, 104, 206, 109 +}; + +#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 260 "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 268 "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 284 "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)); + } + + + 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 310 "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 328 "program_parse.y" + { + (yyval.inst) = (yyvsp[(1) - (1)].inst); + state->prog->NumAluInstructions++; + ;} + break; + + case 13: + +/* Line 1455 of yacc.c */ +#line 333 "program_parse.y" + { + (yyval.inst) = (yyvsp[(1) - (1)].inst); + state->prog->NumTexInstructions++; + ;} + break; + + case 23: + +/* Line 1455 of yacc.c */ +#line 353 "program_parse.y" + { + (yyval.inst) = asm_instruction_ctor(OPCODE_ARL, & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL); + ;} + break; + + case 24: + +/* Line 1455 of yacc.c */ +#line 359 "program_parse.y" + { + (yyval.inst) = asm_instruction_ctor((yyvsp[(1) - (4)].temp_inst).Opcode, & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL); + (yyval.inst)->Base.SaturateMode = (yyvsp[(1) - (4)].temp_inst).SaturateMode; + ;} + break; + + case 25: + +/* Line 1455 of yacc.c */ +#line 366 "program_parse.y" + { + (yyval.inst) = asm_instruction_ctor((yyvsp[(1) - (4)].temp_inst).Opcode, & (yyvsp[(2) - (4)].dst_reg), & (yyvsp[(4) - (4)].src_reg), NULL, NULL); + (yyval.inst)->Base.SaturateMode = (yyvsp[(1) - (4)].temp_inst).SaturateMode; + ;} + break; + + case 26: + +/* Line 1455 of yacc.c */ +#line 373 "program_parse.y" + { + (yyval.inst) = asm_instruction_ctor((yyvsp[(1) - (6)].temp_inst).Opcode, & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), & (yyvsp[(6) - (6)].src_reg), NULL); + (yyval.inst)->Base.SaturateMode = (yyvsp[(1) - (6)].temp_inst).SaturateMode; + ;} + break; + + case 27: + +/* Line 1455 of yacc.c */ +#line 381 "program_parse.y" + { + (yyval.inst) = asm_instruction_ctor((yyvsp[(1) - (6)].temp_inst).Opcode, & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), & (yyvsp[(6) - (6)].src_reg), NULL); + (yyval.inst)->Base.SaturateMode = (yyvsp[(1) - (6)].temp_inst).SaturateMode; + ;} + break; + + case 28: + +/* Line 1455 of yacc.c */ +#line 389 "program_parse.y" + { + (yyval.inst) = asm_instruction_ctor((yyvsp[(1) - (8)].temp_inst).Opcode, & (yyvsp[(2) - (8)].dst_reg), & (yyvsp[(4) - (8)].src_reg), & (yyvsp[(6) - (8)].src_reg), & (yyvsp[(8) - (8)].src_reg)); + (yyval.inst)->Base.SaturateMode = (yyvsp[(1) - (8)].temp_inst).SaturateMode; + ;} + break; + + case 29: + +/* Line 1455 of yacc.c */ +#line 396 "program_parse.y" + { + (yyval.inst) = asm_instruction_ctor((yyvsp[(1) - (8)].temp_inst).Opcode, & (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.SaturateMode = (yyvsp[(1) - (8)].temp_inst).SaturateMode; + (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 30: + +/* Line 1455 of yacc.c */ +#line 441 "program_parse.y" + { + (yyval.inst) = asm_instruction_ctor(OPCODE_KIL, NULL, & (yyvsp[(2) - (2)].src_reg), NULL, NULL); + state->fragment.UsesKill = 1; + ;} + break; + + case 31: + +/* Line 1455 of yacc.c */ +#line 448 "program_parse.y" + { + (yyval.integer) = (yyvsp[(2) - (2)].integer); + ;} + break; + + case 32: + +/* Line 1455 of yacc.c */ +#line 453 "program_parse.y" + { (yyval.integer) = TEXTURE_1D_INDEX; ;} + break; + + case 33: + +/* Line 1455 of yacc.c */ +#line 454 "program_parse.y" + { (yyval.integer) = TEXTURE_2D_INDEX; ;} + break; + + case 34: + +/* Line 1455 of yacc.c */ +#line 455 "program_parse.y" + { (yyval.integer) = TEXTURE_3D_INDEX; ;} + break; + + case 35: + +/* Line 1455 of yacc.c */ +#line 456 "program_parse.y" + { (yyval.integer) = TEXTURE_CUBE_INDEX; ;} + break; + + case 36: + +/* Line 1455 of yacc.c */ +#line 457 "program_parse.y" + { (yyval.integer) = TEXTURE_RECT_INDEX; ;} + break; + + case 37: + +/* Line 1455 of yacc.c */ +#line 458 "program_parse.y" + { (yyval.integer) = -TEXTURE_1D_INDEX; ;} + break; + + case 38: + +/* Line 1455 of yacc.c */ +#line 459 "program_parse.y" + { (yyval.integer) = -TEXTURE_2D_INDEX; ;} + break; + + case 39: + +/* Line 1455 of yacc.c */ +#line 460 "program_parse.y" + { (yyval.integer) = -TEXTURE_RECT_INDEX; ;} + break; + + case 40: + +/* Line 1455 of yacc.c */ +#line 461 "program_parse.y" + { (yyval.integer) = TEXTURE_1D_ARRAY_INDEX; ;} + break; + + case 41: + +/* Line 1455 of yacc.c */ +#line 462 "program_parse.y" + { (yyval.integer) = TEXTURE_2D_ARRAY_INDEX; ;} + break; + + case 42: + +/* Line 1455 of yacc.c */ +#line 463 "program_parse.y" + { (yyval.integer) = -TEXTURE_1D_ARRAY_INDEX; ;} + break; + + case 43: + +/* Line 1455 of yacc.c */ +#line 464 "program_parse.y" + { (yyval.integer) = -TEXTURE_2D_ARRAY_INDEX; ;} + break; + + case 44: + +/* Line 1455 of yacc.c */ +#line 468 "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_ctor(OPCODE_SWZ, & (yyvsp[(2) - (6)].dst_reg), & (yyvsp[(4) - (6)].src_reg), NULL, NULL); + (yyval.inst)->Base.SaturateMode = (yyvsp[(1) - (6)].temp_inst).SaturateMode; + ;} + break; + + case 45: + +/* Line 1455 of yacc.c */ +#line 481 "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 46: + +/* Line 1455 of yacc.c */ +#line 494 "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 47: + +/* Line 1455 of yacc.c */ +#line 507 "program_parse.y" + { + (yyval.dst_reg) = (yyvsp[(1) - (2)].dst_reg); + (yyval.dst_reg).WriteMask = (yyvsp[(2) - (2)].swiz_mask).mask; + + 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) - (2)]), state, "position-invariant programs cannot " + "write position"); + YYERROR; + } + + state->prog->OutputsWritten |= (1U << (yyval.dst_reg).Index); + } + ;} + break; + + case 48: + +/* Line 1455 of yacc.c */ +#line 529 "program_parse.y" + { + init_dst_reg(& (yyval.dst_reg)); + (yyval.dst_reg).File = PROGRAM_ADDRESS; + (yyval.dst_reg).Index = 0; + (yyval.dst_reg).WriteMask = (yyvsp[(2) - (2)].swiz_mask).mask; + ;} + break; + + case 49: + +/* Line 1455 of yacc.c */ +#line 538 "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 50: + +/* Line 1455 of yacc.c */ +#line 571 "program_parse.y" + { + (yyval.ext_swizzle) = (yyvsp[(2) - (2)].ext_swizzle); + (yyval.ext_swizzle).negate = ((yyvsp[(1) - (2)].negate)) ? 1 : 0; + ;} + break; + + case 51: + +/* Line 1455 of yacc.c */ +#line 578 "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 52: + +/* Line 1455 of yacc.c */ +#line 593 "program_parse.y" + { + if (strlen((yyvsp[(1) - (1)].string)) > 1) { + yyerror(& (yylsp[(1) - (1)]), state, "invalid extended swizzle selector"); + YYERROR; + } + + switch ((yyvsp[(1) - (1)].string)[0]) { + 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 53: + +/* Line 1455 of yacc.c */ +#line 643 "program_parse.y" + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, (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: + (yyval.src_reg).Base.File = PROGRAM_TEMPORARY; + (yyval.src_reg).Base.Index = s->temp_binding; + break; + case at_param: + (yyval.src_reg).Base.File = s->param_binding_type; + (yyval.src_reg).Base.Index = s->param_binding_begin; + break; + case at_attrib: + (yyval.src_reg).Base.File = PROGRAM_INPUT; + (yyval.src_reg).Base.Index = 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 54: + +/* Line 1455 of yacc.c */ +#line 685 "program_parse.y" + { + init_src_reg(& (yyval.src_reg)); + (yyval.src_reg).Base.File = PROGRAM_INPUT; + (yyval.src_reg).Base.Index = (yyvsp[(1) - (1)].attrib); + state->prog->InputsRead |= (1U << (yyval.src_reg).Base.Index); + + if (!validate_inputs(& (yylsp[(1) - (1)]), state)) { + YYERROR; + } + ;} + break; + + case 55: + +/* Line 1455 of yacc.c */ +#line 696 "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) { + (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 56: + +/* Line 1455 of yacc.c */ +#line 717 "program_parse.y" + { + init_src_reg(& (yyval.src_reg)); + (yyval.src_reg).Base.File = ((yyvsp[(1) - (1)].temp_sym).name != NULL) + ? (yyvsp[(1) - (1)].temp_sym).param_binding_type + : PROGRAM_CONSTANT; + (yyval.src_reg).Base.Index = (yyvsp[(1) - (1)].temp_sym).param_binding_begin; + ;} + break; + + case 57: + +/* Line 1455 of yacc.c */ +#line 727 "program_parse.y" + { + init_dst_reg(& (yyval.dst_reg)); + (yyval.dst_reg).File = PROGRAM_OUTPUT; + (yyval.dst_reg).Index = (yyvsp[(1) - (1)].result); + ;} + break; + + case 58: + +/* Line 1455 of yacc.c */ +#line 733 "program_parse.y" + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, (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; + } + + init_dst_reg(& (yyval.dst_reg)); + switch (s->type) { + case at_temp: + (yyval.dst_reg).File = PROGRAM_TEMPORARY; + (yyval.dst_reg).Index = s->temp_binding; + break; + case at_output: + (yyval.dst_reg).File = PROGRAM_OUTPUT; + (yyval.dst_reg).Index = s->output_binding; + break; + default: + (yyval.dst_reg).File = s->param_binding_type; + (yyval.dst_reg).Index = s->param_binding_begin; + break; + } + ;} + break; + + case 59: + +/* Line 1455 of yacc.c */ +#line 764 "program_parse.y" + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, (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 62: + +/* Line 1455 of yacc.c */ +#line 783 "program_parse.y" + { + init_src_reg(& (yyval.src_reg)); + (yyval.src_reg).Base.Index = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 63: + +/* Line 1455 of yacc.c */ +#line 790 "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 64: + +/* Line 1455 of yacc.c */ +#line 801 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 65: + +/* Line 1455 of yacc.c */ +#line 802 "program_parse.y" + { (yyval.integer) = (yyvsp[(2) - (2)].integer); ;} + break; + + case 66: + +/* Line 1455 of yacc.c */ +#line 803 "program_parse.y" + { (yyval.integer) = -(yyvsp[(2) - (2)].integer); ;} + break; + + case 67: + +/* Line 1455 of yacc.c */ +#line 807 "program_parse.y" + { + if (((yyvsp[(1) - (1)].integer) < 0) || ((yyvsp[(1) - (1)].integer) > 63)) { + yyerror(& (yylsp[(1) - (1)]), state, + "relative address offset too large (positive)"); + YYERROR; + } else { + (yyval.integer) = (yyvsp[(1) - (1)].integer); + } + ;} + break; + + case 68: + +/* Line 1455 of yacc.c */ +#line 819 "program_parse.y" + { + if (((yyvsp[(1) - (1)].integer) < 0) || ((yyvsp[(1) - (1)].integer) > 64)) { + yyerror(& (yylsp[(1) - (1)]), state, + "relative address offset too large (negative)"); + YYERROR; + } else { + (yyval.integer) = (yyvsp[(1) - (1)].integer); + } + ;} + break; + + case 69: + +/* Line 1455 of yacc.c */ +#line 831 "program_parse.y" + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, (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 70: + +/* Line 1455 of yacc.c */ +#line 849 "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 71: + +/* Line 1455 of yacc.c */ +#line 860 "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 76: + +/* Line 1455 of yacc.c */ +#line 876 "program_parse.y" + { (yyval.swiz_mask).swizzle = SWIZZLE_NOOP; (yyval.swiz_mask).mask = WRITEMASK_XYZW; ;} + break; + + case 81: + +/* Line 1455 of yacc.c */ +#line 880 "program_parse.y" + { (yyval.swiz_mask).swizzle = SWIZZLE_NOOP; (yyval.swiz_mask).mask = WRITEMASK_XYZW; ;} + break; + + case 88: + +/* Line 1455 of yacc.c */ +#line 892 "program_parse.y" + { + struct asm_symbol *const s = + declare_variable(state, (yyvsp[(2) - (4)].string), at_attrib, & (yylsp[(2) - (4)])); + + if (s == NULL) { + 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 89: + +/* Line 1455 of yacc.c */ +#line 910 "program_parse.y" + { + (yyval.attrib) = (yyvsp[(2) - (2)].attrib); + ;} + break; + + case 90: + +/* Line 1455 of yacc.c */ +#line 914 "program_parse.y" + { + (yyval.attrib) = (yyvsp[(2) - (2)].attrib); + ;} + break; + + case 91: + +/* Line 1455 of yacc.c */ +#line 920 "program_parse.y" + { + (yyval.attrib) = VERT_ATTRIB_POS; + ;} + break; + + case 92: + +/* Line 1455 of yacc.c */ +#line 924 "program_parse.y" + { + (yyval.attrib) = VERT_ATTRIB_WEIGHT; + ;} + break; + + case 93: + +/* Line 1455 of yacc.c */ +#line 928 "program_parse.y" + { + (yyval.attrib) = VERT_ATTRIB_NORMAL; + ;} + break; + + case 94: + +/* Line 1455 of yacc.c */ +#line 932 "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 95: + +/* Line 1455 of yacc.c */ +#line 941 "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 96: + +/* Line 1455 of yacc.c */ +#line 950 "program_parse.y" + { + (yyval.attrib) = VERT_ATTRIB_TEX0 + (yyvsp[(2) - (2)].integer); + ;} + break; + + case 97: + +/* Line 1455 of yacc.c */ +#line 954 "program_parse.y" + { + yyerror(& (yylsp[(1) - (4)]), state, "GL_ARB_matrix_palette not supported"); + YYERROR; + ;} + break; + + case 98: + +/* Line 1455 of yacc.c */ +#line 959 "program_parse.y" + { + (yyval.attrib) = VERT_ATTRIB_GENERIC0 + (yyvsp[(3) - (4)].integer); + ;} + break; + + case 99: + +/* Line 1455 of yacc.c */ +#line 965 "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 103: + +/* Line 1455 of yacc.c */ +#line 979 "program_parse.y" + { + (yyval.attrib) = FRAG_ATTRIB_WPOS; + ;} + break; + + case 104: + +/* Line 1455 of yacc.c */ +#line 983 "program_parse.y" + { + (yyval.attrib) = FRAG_ATTRIB_COL0 + (yyvsp[(2) - (2)].integer); + ;} + break; + + case 105: + +/* Line 1455 of yacc.c */ +#line 987 "program_parse.y" + { + (yyval.attrib) = FRAG_ATTRIB_FOGC; + ;} + break; + + case 106: + +/* Line 1455 of yacc.c */ +#line 991 "program_parse.y" + { + (yyval.attrib) = FRAG_ATTRIB_TEX0 + (yyvsp[(2) - (2)].integer); + ;} + break; + + case 109: + +/* Line 1455 of yacc.c */ +#line 999 "program_parse.y" + { + struct asm_symbol *const s = + declare_variable(state, (yyvsp[(2) - (3)].string), at_param, & (yylsp[(2) - (3)])); + + if (s == NULL) { + 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_is_array = 0; + } + ;} + break; + + case 110: + +/* Line 1455 of yacc.c */ +#line 1015 "program_parse.y" + { + if (((yyvsp[(4) - (6)].integer) != 0) && ((unsigned) (yyvsp[(4) - (6)].integer) != (yyvsp[(6) - (6)].temp_sym).param_binding_length)) { + 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) { + 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_is_array = 1; + } + } + ;} + break; + + case 111: + +/* Line 1455 of yacc.c */ +#line 1037 "program_parse.y" + { + (yyval.integer) = 0; + ;} + break; + + case 112: + +/* Line 1455 of yacc.c */ +#line 1041 "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 113: + +/* Line 1455 of yacc.c */ +#line 1052 "program_parse.y" + { + (yyval.temp_sym) = (yyvsp[(2) - (2)].temp_sym); + ;} + break; + + case 114: + +/* Line 1455 of yacc.c */ +#line 1058 "program_parse.y" + { + (yyval.temp_sym) = (yyvsp[(3) - (4)].temp_sym); + ;} + break; + + case 116: + +/* Line 1455 of yacc.c */ +#line 1065 "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 117: + +/* Line 1455 of yacc.c */ +#line 1072 "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 118: + +/* Line 1455 of yacc.c */ +#line 1078 "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 119: + +/* Line 1455 of yacc.c */ +#line 1084 "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)); + ;} + break; + + case 120: + +/* Line 1455 of yacc.c */ +#line 1092 "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 121: + +/* Line 1455 of yacc.c */ +#line 1098 "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 122: + +/* Line 1455 of yacc.c */ +#line 1104 "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)); + ;} + break; + + case 123: + +/* Line 1455 of yacc.c */ +#line 1112 "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 124: + +/* Line 1455 of yacc.c */ +#line 1118 "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 125: + +/* Line 1455 of yacc.c */ +#line 1124 "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)); + ;} + break; + + case 126: + +/* Line 1455 of yacc.c */ +#line 1131 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(1) - (1)].state), sizeof((yyval.state))); ;} + break; + + case 127: + +/* Line 1455 of yacc.c */ +#line 1132 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 128: + +/* Line 1455 of yacc.c */ +#line 1135 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 129: + +/* Line 1455 of yacc.c */ +#line 1136 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 130: + +/* Line 1455 of yacc.c */ +#line 1137 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 131: + +/* Line 1455 of yacc.c */ +#line 1138 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 132: + +/* Line 1455 of yacc.c */ +#line 1139 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 133: + +/* Line 1455 of yacc.c */ +#line 1140 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 134: + +/* Line 1455 of yacc.c */ +#line 1141 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 135: + +/* Line 1455 of yacc.c */ +#line 1142 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 136: + +/* Line 1455 of yacc.c */ +#line 1143 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 137: + +/* Line 1455 of yacc.c */ +#line 1144 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 138: + +/* Line 1455 of yacc.c */ +#line 1145 "program_parse.y" + { memcpy((yyval.state), (yyvsp[(2) - (2)].state), sizeof((yyval.state))); ;} + break; + + case 139: + +/* Line 1455 of yacc.c */ +#line 1149 "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 140: + +/* Line 1455 of yacc.c */ +#line 1158 "program_parse.y" + { + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 141: + +/* Line 1455 of yacc.c */ +#line 1162 "program_parse.y" + { + (yyval.integer) = STATE_EMISSION; + ;} + break; + + case 142: + +/* Line 1455 of yacc.c */ +#line 1166 "program_parse.y" + { + (yyval.integer) = STATE_SHININESS; + ;} + break; + + case 143: + +/* Line 1455 of yacc.c */ +#line 1172 "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 144: + +/* Line 1455 of yacc.c */ +#line 1181 "program_parse.y" + { + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 145: + +/* Line 1455 of yacc.c */ +#line 1185 "program_parse.y" + { + (yyval.integer) = STATE_POSITION; + ;} + break; + + case 146: + +/* Line 1455 of yacc.c */ +#line 1189 "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 147: + +/* Line 1455 of yacc.c */ +#line 1198 "program_parse.y" + { + (yyval.integer) = (yyvsp[(2) - (2)].integer); + ;} + break; + + case 148: + +/* Line 1455 of yacc.c */ +#line 1202 "program_parse.y" + { + (yyval.integer) = STATE_HALF_VECTOR; + ;} + break; + + case 149: + +/* Line 1455 of yacc.c */ +#line 1208 "program_parse.y" + { + (yyval.integer) = STATE_SPOT_DIRECTION; + ;} + break; + + case 150: + +/* Line 1455 of yacc.c */ +#line 1214 "program_parse.y" + { + (yyval.state)[0] = (yyvsp[(2) - (2)].state)[0]; + (yyval.state)[1] = (yyvsp[(2) - (2)].state)[1]; + ;} + break; + + case 151: + +/* Line 1455 of yacc.c */ +#line 1221 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = STATE_LIGHTMODEL_AMBIENT; + ;} + break; + + case 152: + +/* Line 1455 of yacc.c */ +#line 1226 "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 153: + +/* Line 1455 of yacc.c */ +#line 1234 "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 155: + +/* Line 1455 of yacc.c */ +#line 1246 "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 156: + +/* Line 1455 of yacc.c */ +#line 1254 "program_parse.y" + { + (yyval.integer) = STATE_TEXENV_COLOR; + ;} + break; + + case 157: + +/* Line 1455 of yacc.c */ +#line 1260 "program_parse.y" + { + (yyval.integer) = STATE_AMBIENT; + ;} + break; + + case 158: + +/* Line 1455 of yacc.c */ +#line 1264 "program_parse.y" + { + (yyval.integer) = STATE_DIFFUSE; + ;} + break; + + case 159: + +/* Line 1455 of yacc.c */ +#line 1268 "program_parse.y" + { + (yyval.integer) = STATE_SPECULAR; + ;} + break; + + case 160: + +/* Line 1455 of yacc.c */ +#line 1274 "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 161: + +/* Line 1455 of yacc.c */ +#line 1285 "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 162: + +/* Line 1455 of yacc.c */ +#line 1294 "program_parse.y" + { + (yyval.integer) = STATE_TEXGEN_EYE_S; + ;} + break; + + case 163: + +/* Line 1455 of yacc.c */ +#line 1298 "program_parse.y" + { + (yyval.integer) = STATE_TEXGEN_OBJECT_S; + ;} + break; + + case 164: + +/* Line 1455 of yacc.c */ +#line 1303 "program_parse.y" + { + (yyval.integer) = STATE_TEXGEN_EYE_S - STATE_TEXGEN_EYE_S; + ;} + break; + + case 165: + +/* Line 1455 of yacc.c */ +#line 1307 "program_parse.y" + { + (yyval.integer) = STATE_TEXGEN_EYE_T - STATE_TEXGEN_EYE_S; + ;} + break; + + case 166: + +/* Line 1455 of yacc.c */ +#line 1311 "program_parse.y" + { + (yyval.integer) = STATE_TEXGEN_EYE_R - STATE_TEXGEN_EYE_S; + ;} + break; + + case 167: + +/* Line 1455 of yacc.c */ +#line 1315 "program_parse.y" + { + (yyval.integer) = STATE_TEXGEN_EYE_Q - STATE_TEXGEN_EYE_S; + ;} + break; + + case 168: + +/* Line 1455 of yacc.c */ +#line 1321 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = (yyvsp[(2) - (2)].integer); + ;} + break; + + case 169: + +/* Line 1455 of yacc.c */ +#line 1328 "program_parse.y" + { + (yyval.integer) = STATE_FOG_COLOR; + ;} + break; + + case 170: + +/* Line 1455 of yacc.c */ +#line 1332 "program_parse.y" + { + (yyval.integer) = STATE_FOG_PARAMS; + ;} + break; + + case 171: + +/* Line 1455 of yacc.c */ +#line 1338 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = STATE_CLIPPLANE; + (yyval.state)[1] = (yyvsp[(3) - (5)].integer); + ;} + break; + + case 172: + +/* Line 1455 of yacc.c */ +#line 1346 "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 173: + +/* Line 1455 of yacc.c */ +#line 1357 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = (yyvsp[(2) - (2)].integer); + ;} + break; + + case 174: + +/* Line 1455 of yacc.c */ +#line 1364 "program_parse.y" + { + (yyval.integer) = STATE_POINT_SIZE; + ;} + break; + + case 175: + +/* Line 1455 of yacc.c */ +#line 1368 "program_parse.y" + { + (yyval.integer) = STATE_POINT_ATTENUATION; + ;} + break; + + case 176: + +/* Line 1455 of yacc.c */ +#line 1374 "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 177: + +/* Line 1455 of yacc.c */ +#line 1384 "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 178: + +/* Line 1455 of yacc.c */ +#line 1394 "program_parse.y" + { + (yyval.state)[2] = 0; + (yyval.state)[3] = 3; + ;} + break; + + case 179: + +/* Line 1455 of yacc.c */ +#line 1399 "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 180: + +/* Line 1455 of yacc.c */ +#line 1417 "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 181: + +/* Line 1455 of yacc.c */ +#line 1425 "program_parse.y" + { + (yyval.integer) = 0; + ;} + break; + + case 182: + +/* Line 1455 of yacc.c */ +#line 1429 "program_parse.y" + { + (yyval.integer) = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 183: + +/* Line 1455 of yacc.c */ +#line 1435 "program_parse.y" + { + (yyval.integer) = STATE_MATRIX_INVERSE; + ;} + break; + + case 184: + +/* Line 1455 of yacc.c */ +#line 1439 "program_parse.y" + { + (yyval.integer) = STATE_MATRIX_TRANSPOSE; + ;} + break; + + case 185: + +/* Line 1455 of yacc.c */ +#line 1443 "program_parse.y" + { + (yyval.integer) = STATE_MATRIX_INVTRANS; + ;} + break; + + case 186: + +/* Line 1455 of yacc.c */ +#line 1449 "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 187: + +/* Line 1455 of yacc.c */ +#line 1460 "program_parse.y" + { + (yyval.state)[0] = STATE_MODELVIEW_MATRIX; + (yyval.state)[1] = (yyvsp[(2) - (2)].integer); + ;} + break; + + case 188: + +/* Line 1455 of yacc.c */ +#line 1465 "program_parse.y" + { + (yyval.state)[0] = STATE_PROJECTION_MATRIX; + (yyval.state)[1] = 0; + ;} + break; + + case 189: + +/* Line 1455 of yacc.c */ +#line 1470 "program_parse.y" + { + (yyval.state)[0] = STATE_MVP_MATRIX; + (yyval.state)[1] = 0; + ;} + break; + + case 190: + +/* Line 1455 of yacc.c */ +#line 1475 "program_parse.y" + { + (yyval.state)[0] = STATE_TEXTURE_MATRIX; + (yyval.state)[1] = (yyvsp[(2) - (2)].integer); + ;} + break; + + case 191: + +/* Line 1455 of yacc.c */ +#line 1480 "program_parse.y" + { + yyerror(& (yylsp[(1) - (4)]), state, "GL_ARB_matrix_palette not supported"); + YYERROR; + ;} + break; + + case 192: + +/* Line 1455 of yacc.c */ +#line 1485 "program_parse.y" + { + (yyval.state)[0] = STATE_PROGRAM_MATRIX; + (yyval.state)[1] = (yyvsp[(3) - (4)].integer); + ;} + break; + + case 193: + +/* Line 1455 of yacc.c */ +#line 1492 "program_parse.y" + { + (yyval.integer) = 0; + ;} + break; + + case 194: + +/* Line 1455 of yacc.c */ +#line 1496 "program_parse.y" + { + (yyval.integer) = (yyvsp[(2) - (3)].integer); + ;} + break; + + case 195: + +/* Line 1455 of yacc.c */ +#line 1501 "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 196: + +/* Line 1455 of yacc.c */ +#line 1514 "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 197: + +/* Line 1455 of yacc.c */ +#line 1522 "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 198: + +/* Line 1455 of yacc.c */ +#line 1533 "program_parse.y" + { + memset((yyval.state), 0, sizeof((yyval.state))); + (yyval.state)[0] = STATE_DEPTH_RANGE; + ;} + break; + + case 203: + +/* Line 1455 of yacc.c */ +#line 1545 "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 204: + +/* Line 1455 of yacc.c */ +#line 1555 "program_parse.y" + { + (yyval.state)[0] = (yyvsp[(1) - (1)].integer); + (yyval.state)[1] = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 205: + +/* Line 1455 of yacc.c */ +#line 1560 "program_parse.y" + { + (yyval.state)[0] = (yyvsp[(1) - (3)].integer); + (yyval.state)[1] = (yyvsp[(3) - (3)].integer); + ;} + break; + + case 206: + +/* Line 1455 of yacc.c */ +#line 1567 "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 207: + +/* Line 1455 of yacc.c */ +#line 1577 "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 208: + +/* Line 1455 of yacc.c */ +#line 1586 "program_parse.y" + { + (yyval.state)[0] = (yyvsp[(1) - (1)].integer); + (yyval.state)[1] = (yyvsp[(1) - (1)].integer); + ;} + break; + + case 209: + +/* Line 1455 of yacc.c */ +#line 1591 "program_parse.y" + { + (yyval.state)[0] = (yyvsp[(1) - (3)].integer); + (yyval.state)[1] = (yyvsp[(3) - (3)].integer); + ;} + break; + + case 210: + +/* Line 1455 of yacc.c */ +#line 1598 "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 211: + +/* Line 1455 of yacc.c */ +#line 1608 "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 212: + +/* Line 1455 of yacc.c */ +#line 1618 "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 217: + +/* Line 1455 of yacc.c */ +#line 1633 "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 218: + +/* Line 1455 of yacc.c */ +#line 1643 "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 219: + +/* Line 1455 of yacc.c */ +#line 1651 "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 220: + +/* Line 1455 of yacc.c */ +#line 1661 "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 221: + +/* Line 1455 of yacc.c */ +#line 1669 "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 222: + +/* Line 1455 of yacc.c */ +#line 1678 "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 223: + +/* Line 1455 of yacc.c */ +#line 1687 "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 224: + +/* Line 1455 of yacc.c */ +#line 1697 "program_parse.y" + { + (yyval.real) = ((yyvsp[(1) - (2)].negate)) ? -(yyvsp[(2) - (2)].real) : (yyvsp[(2) - (2)].real); + ;} + break; + + case 225: + +/* Line 1455 of yacc.c */ +#line 1701 "program_parse.y" + { + (yyval.real) = (float)(((yyvsp[(1) - (2)].negate)) ? -(yyvsp[(2) - (2)].integer) : (yyvsp[(2) - (2)].integer)); + ;} + break; + + case 226: + +/* Line 1455 of yacc.c */ +#line 1706 "program_parse.y" + { (yyval.negate) = FALSE; ;} + break; + + case 227: + +/* Line 1455 of yacc.c */ +#line 1707 "program_parse.y" + { (yyval.negate) = TRUE; ;} + break; + + case 228: + +/* Line 1455 of yacc.c */ +#line 1708 "program_parse.y" + { (yyval.negate) = FALSE; ;} + break; + + case 229: + +/* Line 1455 of yacc.c */ +#line 1711 "program_parse.y" + { (yyval.integer) = (yyvsp[(1) - (1)].integer); ;} + break; + + case 231: + +/* Line 1455 of yacc.c */ +#line 1714 "program_parse.y" + { (yyval.integer) = (yyvsp[(1) - (1)].integer); ;} + break; + + case 233: + +/* Line 1455 of yacc.c */ +#line 1718 "program_parse.y" + { + if (!declare_variable(state, (yyvsp[(3) - (3)].string), (yyvsp[(0) - (3)].integer), & (yylsp[(3) - (3)]))) { + YYERROR; + } + ;} + break; + + case 234: + +/* Line 1455 of yacc.c */ +#line 1724 "program_parse.y" + { + if (!declare_variable(state, (yyvsp[(1) - (1)].string), (yyvsp[(0) - (1)].integer), & (yylsp[(1) - (1)]))) { + YYERROR; + } + ;} + break; + + case 235: + +/* Line 1455 of yacc.c */ +#line 1732 "program_parse.y" + { + struct asm_symbol *const s = + declare_variable(state, (yyvsp[(2) - (4)].string), at_output, & (yylsp[(2) - (4)])); + + if (s == NULL) { + YYERROR; + } else { + s->output_binding = (yyvsp[(4) - (4)].result); + } + ;} + break; + + case 236: + +/* Line 1455 of yacc.c */ +#line 1745 "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 237: + +/* Line 1455 of yacc.c */ +#line 1754 "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 238: + +/* Line 1455 of yacc.c */ +#line 1763 "program_parse.y" + { + (yyval.result) = (yyvsp[(2) - (2)].result); + ;} + break; + + case 239: + +/* Line 1455 of yacc.c */ +#line 1767 "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 240: + +/* Line 1455 of yacc.c */ +#line 1776 "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 241: + +/* Line 1455 of yacc.c */ +#line 1785 "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 242: + +/* Line 1455 of yacc.c */ +#line 1796 "program_parse.y" + { + (yyval.result) = (yyvsp[(2) - (3)].integer) + (yyvsp[(3) - (3)].integer); + ;} + break; + + case 243: + +/* Line 1455 of yacc.c */ +#line 1802 "program_parse.y" + { + (yyval.integer) = (state->mode == ARB_vertex) + ? VERT_RESULT_COL0 + : FRAG_RESULT_COLOR; + ;} + break; + + case 244: + +/* Line 1455 of yacc.c */ +#line 1808 "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 245: + +/* Line 1455 of yacc.c */ +#line 1817 "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 246: + +/* Line 1455 of yacc.c */ +#line 1828 "program_parse.y" + { + (yyval.integer) = 0; + ;} + break; + + case 247: + +/* Line 1455 of yacc.c */ +#line 1832 "program_parse.y" + { + if (state->mode == ARB_vertex) { + (yyval.integer) = 0; + } else { + yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name"); + YYERROR; + } + ;} + break; + + case 248: + +/* Line 1455 of yacc.c */ +#line 1841 "program_parse.y" + { + if (state->mode == ARB_vertex) { + (yyval.integer) = 1; + } else { + yyerror(& (yylsp[(1) - (1)]), state, "invalid program result name"); + YYERROR; + } + ;} + break; + + case 249: + +/* Line 1455 of yacc.c */ +#line 1851 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 250: + +/* Line 1455 of yacc.c */ +#line 1852 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 251: + +/* Line 1455 of yacc.c */ +#line 1853 "program_parse.y" + { (yyval.integer) = 1; ;} + break; + + case 252: + +/* Line 1455 of yacc.c */ +#line 1856 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 253: + +/* Line 1455 of yacc.c */ +#line 1857 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 254: + +/* Line 1455 of yacc.c */ +#line 1858 "program_parse.y" + { (yyval.integer) = 1; ;} + break; + + case 255: + +/* Line 1455 of yacc.c */ +#line 1861 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 256: + +/* Line 1455 of yacc.c */ +#line 1862 "program_parse.y" + { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;} + break; + + case 257: + +/* Line 1455 of yacc.c */ +#line 1865 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 258: + +/* Line 1455 of yacc.c */ +#line 1866 "program_parse.y" + { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;} + break; + + case 259: + +/* Line 1455 of yacc.c */ +#line 1869 "program_parse.y" + { (yyval.integer) = 0; ;} + break; + + case 260: + +/* Line 1455 of yacc.c */ +#line 1870 "program_parse.y" + { (yyval.integer) = (yyvsp[(2) - (3)].integer); ;} + break; + + case 261: + +/* Line 1455 of yacc.c */ +#line 1874 "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 262: + +/* Line 1455 of yacc.c */ +#line 1885 "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 263: + +/* Line 1455 of yacc.c */ +#line 1896 "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 264: + +/* Line 1455 of yacc.c */ +#line 1907 "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)); + + + if (exist != NULL) { + yyerror(& (yylsp[(2) - (4)]), state, "redeclared identifier"); + YYERROR; + } else if (target == NULL) { + 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 4577 "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 1927 "program_parse.y" + + +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(1, sizeof(struct asm_instruction)); + + if (inst) { + _mesa_init_instructions(& inst->Base, 1); + inst->Base.Opcode = op; + + /* 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; + } + + inst->Base.SrcReg[0] = src0->Base; + inst->SrcReg[0] = *src0; + + 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]); + } + } + + 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; +} + + +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; +} + + +/** + * 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() */ + _mesa_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_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_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)); + + param_var->type = at_param; + param_var->param_binding_type = (state_tokens[1] == STATE_ENV) + ? PROGRAM_ENV_PARAM : PROGRAM_LOCAL_PARAM; + + /* 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_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_length++; + } + + return idx; +} + + +int +initialize_symbol_from_const(struct gl_program *prog, + struct asm_symbol *param_var, + const struct asm_vector *vec) +{ + const int idx = _mesa_add_parameter(prog->Parameters, PROGRAM_CONSTANT, + NULL, vec->count, GL_NONE, vec->data, + NULL, 0x0); + + 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_length++; + + return idx; +} + + +char * +make_error_string(const char *fmt, ...) +{ + int length; + char *str; + va_list args; + + va_start(args, fmt); + + /* 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). + */ + length = 1 + vsnprintf(NULL, 0, fmt, args); + + str = _mesa_malloc(length); + if (str) { + 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, err_str); + _mesa_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) { + _mesa_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 *) _mesa_malloc(len + 1); + if (strz == NULL) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glProgramStringARB"); + return GL_FALSE; + } + _mesa_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; + _mesa_free(inst); + } + + state->inst_head = NULL; + state->inst_tail = NULL; + + for (sym = state->sym; sym != NULL; sym = temp) { + temp = sym->next; + + _mesa_free((void *) sym->name); + _mesa_free(sym); + } + state->sym = NULL; + + _mesa_symbol_table_dtor(state->st); + state->st = NULL; + + return result; +} + diff --git a/mesalib/src/mesa/shader/program_parse.tab.h b/mesalib/src/mesa/shader/program_parse.tab.h new file mode 100644 index 000000000..dabb3bf1a --- /dev/null +++ b/mesalib/src/mesa/shader/program_parse.tab.h @@ -0,0 +1,207 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton interface 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. */ + + +/* 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, + INTEGER = 277, + REAL = 278, + AMBIENT = 279, + ATTENUATION = 280, + BACK = 281, + CLIP = 282, + COLOR = 283, + DEPTH = 284, + DIFFUSE = 285, + DIRECTION = 286, + EMISSION = 287, + ENV = 288, + EYE = 289, + FOG = 290, + FOGCOORD = 291, + FRAGMENT = 292, + FRONT = 293, + HALF = 294, + INVERSE = 295, + INVTRANS = 296, + LIGHT = 297, + LIGHTMODEL = 298, + LIGHTPROD = 299, + LOCAL = 300, + MATERIAL = 301, + MAT_PROGRAM = 302, + MATRIX = 303, + MATRIXINDEX = 304, + MODELVIEW = 305, + MVP = 306, + NORMAL = 307, + OBJECT = 308, + PALETTE = 309, + PARAMS = 310, + PLANE = 311, + POINT_TOK = 312, + POINTSIZE = 313, + POSITION = 314, + PRIMARY = 315, + PROGRAM = 316, + PROJECTION = 317, + RANGE = 318, + RESULT = 319, + ROW = 320, + SCENECOLOR = 321, + SECONDARY = 322, + SHININESS = 323, + SIZE_TOK = 324, + SPECULAR = 325, + SPOT = 326, + STATE = 327, + TEXCOORD = 328, + TEXENV = 329, + TEXGEN = 330, + TEXGEN_Q = 331, + TEXGEN_R = 332, + TEXGEN_S = 333, + TEXGEN_T = 334, + TEXTURE = 335, + TRANSPOSE = 336, + TEXTURE_UNIT = 337, + TEX_1D = 338, + TEX_2D = 339, + TEX_3D = 340, + TEX_CUBE = 341, + TEX_RECT = 342, + TEX_SHADOW1D = 343, + TEX_SHADOW2D = 344, + TEX_SHADOWRECT = 345, + TEX_ARRAY1D = 346, + TEX_ARRAY2D = 347, + TEX_ARRAYSHADOW1D = 348, + TEX_ARRAYSHADOW2D = 349, + VERTEX = 350, + VTXATTRIB = 351, + WEIGHT = 352, + IDENTIFIER = 353, + MASK4 = 354, + MASK3 = 355, + MASK2 = 356, + MASK1 = 357, + SWIZZLE = 358, + DOT_DOT = 359, + DOT = 360 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 1676 of yacc.c */ +#line 107 "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 1676 of yacc.c */ +#line 185 "program_parse.tab.h" +} 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 + + + diff --git a/mesalib/src/mesa/shader/program_parse.y b/mesalib/src/mesa/shader/program_parse.y new file mode 100644 index 000000000..06c1915fb --- /dev/null +++ b/mesalib/src/mesa/shader/program_parse.y @@ -0,0 +1,2379 @@ +%{ +/* + * 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.h" +#include "prog_parameter.h" +#include "prog_parameter_layout.h" +#include "prog_statevars.h" +#include "prog_instruction.h" + +#include "symbol_table.h" +#include "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); + +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 init_src_reg(struct asm_src_register *r); + +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); + +#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 + +%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 +%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 SWZ_instruction SAMPLE_instruction +%type <inst> KIL_instruction + +%type <dst_reg> dstReg maskedDstReg maskedAddrReg +%type <src_reg> srcReg 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 <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 IDENTIFIER ';' + { + 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); + } + + + 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 + ; + +ARL_instruction: ARL maskedAddrReg ',' scalarSrcReg + { + $$ = asm_instruction_ctor(OPCODE_ARL, & $2, & $4, NULL, NULL); + } + ; + +VECTORop_instruction: VECTOR_OP maskedDstReg ',' swizzleSrcReg + { + $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, NULL, NULL); + $$->Base.SaturateMode = $1.SaturateMode; + } + ; + +SCALARop_instruction: SCALAR_OP maskedDstReg ',' scalarSrcReg + { + $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, NULL, NULL); + $$->Base.SaturateMode = $1.SaturateMode; + } + ; + +BINSCop_instruction: BINSC_OP maskedDstReg ',' scalarSrcReg ',' scalarSrcReg + { + $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, & $6, NULL); + $$->Base.SaturateMode = $1.SaturateMode; + } + ; + + +BINop_instruction: BIN_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg + { + $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, & $6, NULL); + $$->Base.SaturateMode = $1.SaturateMode; + } + ; + +TRIop_instruction: TRI_OP maskedDstReg ',' + swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg + { + $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, & $6, & $8); + $$->Base.SaturateMode = $1.SaturateMode; + } + ; + +SAMPLE_instruction: SAMPLE_OP maskedDstReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget + { + $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, NULL, NULL); + if ($$ != NULL) { + const GLbitfield tex_mask = (1U << $6); + GLbitfield shadow_tex = 0; + GLbitfield target_mask = 0; + + + $$->Base.SaturateMode = $1.SaturateMode; + $$->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; + } + ; + +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_ctor(OPCODE_SWZ, & $2, & $4, NULL, NULL); + $$->Base.SaturateMode = $1.SaturateMode; + } + ; + +scalarSrcReg: optionalSign srcReg scalarSuffix + { + $$ = $2; + + if ($1) { + $$.Base.Negate = ~$$.Base.Negate; + } + + $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle, + $3.swizzle); + } + ; + +swizzleSrcReg: optionalSign srcReg swizzleSuffix + { + $$ = $2; + + if ($1) { + $$.Base.Negate = ~$$.Base.Negate; + } + + $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle, + $3.swizzle); + } + ; + +maskedDstReg: dstReg optionalMask + { + $$ = $1; + $$.WriteMask = $2.mask; + + 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 |= (1U << $$.Index); + } + } + ; + +maskedAddrReg: addrReg addrWriteMask + { + init_dst_reg(& $$); + $$.File = PROGRAM_ADDRESS; + $$.Index = 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; + } + | IDENTIFIER + { + if (strlen($1) > 1) { + yyerror(& @1, state, "invalid extended swizzle selector"); + YYERROR; + } + + switch ($1[0]) { + 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: IDENTIFIER /* temporaryReg | progParamSingle */ + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, $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: + $$.Base.File = PROGRAM_TEMPORARY; + $$.Base.Index = s->temp_binding; + break; + case at_param: + $$.Base.File = s->param_binding_type; + $$.Base.Index = s->param_binding_begin; + break; + case at_attrib: + $$.Base.File = PROGRAM_INPUT; + $$.Base.Index = s->attrib_binding; + state->prog->InputsRead |= (1U << $$.Base.Index); + + if (!validate_inputs(& @1, state)) { + YYERROR; + } + break; + + default: + YYERROR; + break; + } + } + | attribBinding + { + init_src_reg(& $$); + $$.Base.File = PROGRAM_INPUT; + $$.Base.Index = $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) { + $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 + { + init_src_reg(& $$); + $$.Base.File = ($1.name != NULL) + ? $1.param_binding_type + : PROGRAM_CONSTANT; + $$.Base.Index = $1.param_binding_begin; + } + ; + +dstReg: resultBinding + { + init_dst_reg(& $$); + $$.File = PROGRAM_OUTPUT; + $$.Index = $1; + } + | IDENTIFIER /* temporaryReg | vertexResultReg */ + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, $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; + } + + init_dst_reg(& $$); + switch (s->type) { + case at_temp: + $$.File = PROGRAM_TEMPORARY; + $$.Index = s->temp_binding; + break; + case at_output: + $$.File = PROGRAM_OUTPUT; + $$.Index = s->output_binding; + break; + default: + $$.File = s->param_binding_type; + $$.Index = s->param_binding_begin; + break; + } + } + ; + +progParamArray: IDENTIFIER + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, $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 > 63)) { + yyerror(& @1, state, + "relative address offset too large (positive)"); + YYERROR; + } else { + $$ = $1; + } + } + ; + +addrRegNegOffset: INTEGER + { + if (($1 < 0) || ($1 > 64)) { + yyerror(& @1, state, + "relative address offset too large (negative)"); + YYERROR; + } else { + $$ = $1; + } + } + ; + +addrReg: IDENTIFIER + { + struct asm_symbol *const s = (struct asm_symbol *) + _mesa_symbol_table_find_symbol(state->st, 0, $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; } + ; + +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) { + 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) { + 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_is_array = 0; + } + } + ; + +PARAM_multipleStmt: PARAM IDENTIFIER '[' optArraySize ']' paramMultipleInit + { + if (($4 != 0) && ((unsigned) $4 != $6.param_binding_length)) { + 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) { + 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_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); + } + ; + +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); + } + ; + +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); + } + ; + +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: TEMP { $<integer>$ = $1; } varNameList + ; + +ADDRESS_statement: ADDRESS { $<integer>$ = $1; } varNameList + ; + +varNameList: varNameList ',' IDENTIFIER + { + if (!declare_variable(state, $3, $<integer>0, & @3)) { + YYERROR; + } + } + | IDENTIFIER + { + if (!declare_variable(state, $1, $<integer>0, & @1)) { + YYERROR; + } + } + ; + +OUTPUT_statement: OUTPUT IDENTIFIER '=' resultBinding + { + struct asm_symbol *const s = + declare_variable(state, $2, at_output, & @2); + + if (s == NULL) { + YYERROR; + } else { + s->output_binding = $4; + } + } + ; + +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 '=' 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); + + + if (exist != NULL) { + yyerror(& @2, state, "redeclared identifier"); + YYERROR; + } else if (target == NULL) { + yyerror(& @4, state, + "undefined variable binding in ALIAS statement"); + YYERROR; + } else { + _mesa_symbol_table_add_symbol(state->st, 0, $2, target); + } + } + ; + +%% + +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(1, sizeof(struct asm_instruction)); + + if (inst) { + _mesa_init_instructions(& inst->Base, 1); + inst->Base.Opcode = op; + + /* 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; + } + + inst->Base.SrcReg[0] = src0->Base; + inst->SrcReg[0] = *src0; + + 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]); + } + } + + 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; +} + + +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; +} + + +/** + * 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() */ + _mesa_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_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_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)); + + param_var->type = at_param; + param_var->param_binding_type = (state_tokens[1] == STATE_ENV) + ? PROGRAM_ENV_PARAM : PROGRAM_LOCAL_PARAM; + + /* 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_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_length++; + } + + return idx; +} + + +int +initialize_symbol_from_const(struct gl_program *prog, + struct asm_symbol *param_var, + const struct asm_vector *vec) +{ + const int idx = _mesa_add_parameter(prog->Parameters, PROGRAM_CONSTANT, + NULL, vec->count, GL_NONE, vec->data, + NULL, 0x0); + + 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_length++; + + return idx; +} + + +char * +make_error_string(const char *fmt, ...) +{ + int length; + char *str; + va_list args; + + va_start(args, fmt); + + /* 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). + */ + length = 1 + vsnprintf(NULL, 0, fmt, args); + + str = _mesa_malloc(length); + if (str) { + 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, err_str); + _mesa_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) { + _mesa_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 *) _mesa_malloc(len + 1); + if (strz == NULL) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glProgramStringARB"); + return GL_FALSE; + } + _mesa_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; + _mesa_free(inst); + } + + state->inst_head = NULL; + state->inst_tail = NULL; + + for (sym = state->sym; sym != NULL; sym = temp) { + temp = sym->next; + + _mesa_free((void *) sym->name); + _mesa_free(sym); + } + state->sym = NULL; + + _mesa_symbol_table_dtor(state->st); + state->st = NULL; + + return result; +} diff --git a/mesalib/src/mesa/shader/program_parse_extra.c b/mesalib/src/mesa/shader/program_parse_extra.c new file mode 100644 index 000000000..8e4be606f --- /dev/null +++ b/mesalib/src/mesa/shader/program_parse_extra.c @@ -0,0 +1,117 @@ +/* + * 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 <string.h> +#include "main/mtypes.h" +#include "prog_instruction.h" +#include "program_parser.h" + + +/** + * Extra assembly-level parser routines + * + * \author Ian Romanick <ian.d.romanick@intel.com> + */ + +int +_mesa_ARBvp_parse_option(struct asm_parser_state *state, const char *option) +{ + if (strcmp(option, "ARB_position_invariant") == 0) { + state->option.PositionInvariant = 1; + return 1; + } + + return 0; +} + + +int +_mesa_ARBfp_parse_option(struct asm_parser_state *state, const char *option) +{ + /* All of the options currently supported start with "ARB_". The code is + * currently structured with nested if-statements because eventually options + * that start with "NV_" will be supported. This structure will result in + * less churn when those options are added. + */ + if (strncmp(option, "ARB_", 4) == 0) { + /* Advance the pointer past the "ARB_" prefix. + */ + option += 4; + + + if (strncmp(option, "fog_", 4) == 0) { + option += 4; + + if (state->option.Fog == OPTION_NONE) { + if (strcmp(option, "exp") == 0) { + state->option.Fog = OPTION_FOG_EXP; + return 1; + } else if (strcmp(option, "exp2") == 0) { + state->option.Fog = OPTION_FOG_EXP2; + return 1; + } else if (strcmp(option, "linear") == 0) { + state->option.Fog = OPTION_FOG_LINEAR; + return 1; + } + } + + return 0; + } else if (strncmp(option, "precision_hint_", 15) == 0) { + option += 15; + + if (state->option.PrecisionHint == OPTION_NONE) { + if (strcmp(option, "nicest") == 0) { + state->option.PrecisionHint = OPTION_NICEST; + return 1; + } else if (strcmp(option, "fastest") == 0) { + state->option.PrecisionHint = OPTION_FASTEST; + return 1; + } + } + + return 0; + } else if (strcmp(option, "draw_buffers") == 0) { + /* Don't need to check extension availability because all Mesa-based + * drivers support GL_ARB_draw_buffers. + */ + state->option.DrawBuffers = 1; + return 1; + } else if (strcmp(option, "fragment_program_shadow") == 0) { + if (state->ctx->Extensions.ARB_fragment_program_shadow) { + state->option.Shadow = 1; + return 1; + } + } + } else if (strncmp(option, "MESA_", 5) == 0) { + option += 5; + + if (strcmp(option, "texture_array") == 0) { + if (state->ctx->Extensions.MESA_texture_array) { + state->option.TexArray = 1; + return 1; + } + } + } + + return 0; +} diff --git a/mesalib/src/mesa/shader/program_parser.h b/mesalib/src/mesa/shader/program_parser.h new file mode 100644 index 000000000..fa47d8456 --- /dev/null +++ b/mesalib/src/mesa/shader/program_parser.h @@ -0,0 +1,266 @@ +/* + * 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; + + /* This is how many entries in the the program_parameter_list we take up + * with our state tokens or constants. Note that this is _not_ the same as + * the number of param registers we eventually use. + */ + 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; + } 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); + +/*@}*/ diff --git a/mesalib/src/mesa/shader/programopt.c b/mesalib/src/mesa/shader/programopt.c new file mode 100644 index 000000000..f70c75cec --- /dev/null +++ b/mesalib/src/mesa/shader/programopt.c @@ -0,0 +1,575 @@ +/* + * 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 |= (1 << 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 |= (1 << 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; + + 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(prog, + PROGRAM_TEMPORARY); + } + 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; + const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); + GLuint j; + for (j = 0; j < numSrc; j++) { + 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++; + } + } + } +} diff --git a/mesalib/src/mesa/shader/programopt.h b/mesalib/src/mesa/shader/programopt.h new file mode 100644 index 000000000..96acaf956 --- /dev/null +++ b/mesalib/src/mesa/shader/programopt.h @@ -0,0 +1,45 @@ +/* + * 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 + + +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); + +#endif /* PROGRAMOPT_H */ diff --git a/mesalib/src/mesa/shader/shader_api.c b/mesalib/src/mesa/shader/shader_api.c new file mode 100644 index 000000000..178b7d0db --- /dev/null +++ b/mesalib/src/mesa/shader/shader_api.c @@ -0,0 +1,2154 @@ +/* + * Mesa 3-D graphics library + * Version: 7.6 + * + * Copyright (C) 2004-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 shader_api.c + * Implementation of GLSL-related API functions + * \author Brian Paul + */ + +/** + * XXX things to do: + * 1. Check that the right error code is generated for all _mesa_error() calls. + * 2. Insert FLUSH_VERTICES calls in various places + */ + + +#include "main/glheader.h" +#include "main/context.h" +#include "main/hash.h" +#include "main/macros.h" +#include "shader/program.h" +#include "shader/prog_parameter.h" +#include "shader/prog_print.h" +#include "shader/prog_statevars.h" +#include "shader/prog_uniform.h" +#include "shader/shader_api.h" +#include "shader/slang/slang_compile.h" +#include "shader/slang/slang_link.h" +#include "glapi/dispatch.h" + + +/** + * Allocate a new gl_shader_program object, initialize it. + */ +static struct gl_shader_program * +_mesa_new_shader_program(GLcontext *ctx, GLuint name) +{ + struct gl_shader_program *shProg; + shProg = CALLOC_STRUCT(gl_shader_program); + if (shProg) { + shProg->Type = GL_SHADER_PROGRAM_MESA; + shProg->Name = name; + shProg->RefCount = 1; + shProg->Attributes = _mesa_new_parameter_list(); + } + return shProg; +} + + +/** + * Clear (free) the shader program state that gets produced by linking. + */ +void +_mesa_clear_shader_program_data(GLcontext *ctx, + struct gl_shader_program *shProg) +{ + _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL); + _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL); + + if (shProg->Uniforms) { + _mesa_free_uniform_list(shProg->Uniforms); + shProg->Uniforms = NULL; + } + + if (shProg->Varying) { + _mesa_free_parameter_list(shProg->Varying); + shProg->Varying = NULL; + } +} + + +/** + * Free all the data that hangs off a shader program object, but not the + * object itself. + */ +void +_mesa_free_shader_program_data(GLcontext *ctx, + struct gl_shader_program *shProg) +{ + GLuint i; + + assert(shProg->Type == GL_SHADER_PROGRAM_MESA); + + _mesa_clear_shader_program_data(ctx, shProg); + + if (shProg->Attributes) { + _mesa_free_parameter_list(shProg->Attributes); + shProg->Attributes = NULL; + } + + /* detach shaders */ + for (i = 0; i < shProg->NumShaders; i++) { + _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); + } + shProg->NumShaders = 0; + + if (shProg->Shaders) { + _mesa_free(shProg->Shaders); + shProg->Shaders = NULL; + } + + if (shProg->InfoLog) { + _mesa_free(shProg->InfoLog); + shProg->InfoLog = NULL; + } +} + + +/** + * Free/delete a shader program object. + */ +void +_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg) +{ + _mesa_free_shader_program_data(ctx, shProg); + + _mesa_free(shProg); +} + + +/** + * Set ptr to point to shProg. + * If ptr is pointing to another object, decrement its refcount (and delete + * if refcount hits zero). + * Then set ptr to point to shProg, incrementing its refcount. + */ +/* XXX this could be static */ +void +_mesa_reference_shader_program(GLcontext *ctx, + struct gl_shader_program **ptr, + struct gl_shader_program *shProg) +{ + assert(ptr); + if (*ptr == shProg) { + /* no-op */ + return; + } + if (*ptr) { + /* Unreference the old shader program */ + GLboolean deleteFlag = GL_FALSE; + struct gl_shader_program *old = *ptr; + + ASSERT(old->RefCount > 0); + old->RefCount--; +#if 0 + printf("ShaderProgram %p ID=%u RefCount-- to %d\n", + (void *) old, old->Name, old->RefCount); +#endif + deleteFlag = (old->RefCount == 0); + + if (deleteFlag) { + _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name); + _mesa_free_shader_program(ctx, old); + } + + *ptr = NULL; + } + assert(!*ptr); + + if (shProg) { + shProg->RefCount++; +#if 0 + printf("ShaderProgram %p ID=%u RefCount++ to %d\n", + (void *) shProg, shProg->Name, shProg->RefCount); +#endif + *ptr = shProg; + } +} + + +/** + * Lookup a GLSL program object. + */ +struct gl_shader_program * +_mesa_lookup_shader_program(GLcontext *ctx, GLuint name) +{ + struct gl_shader_program *shProg; + if (name) { + shProg = (struct gl_shader_program *) + _mesa_HashLookup(ctx->Shared->ShaderObjects, name); + /* Note that both gl_shader and gl_shader_program objects are kept + * in the same hash table. Check the object's type to be sure it's + * what we're expecting. + */ + if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) { + return NULL; + } + return shProg; + } + return NULL; +} + + +/** + * As above, but record an error if program is not found. + */ +static struct gl_shader_program * +_mesa_lookup_shader_program_err(GLcontext *ctx, GLuint name, + const char *caller) +{ + if (!name) { + _mesa_error(ctx, GL_INVALID_VALUE, caller); + return NULL; + } + else { + struct gl_shader_program *shProg = (struct gl_shader_program *) + _mesa_HashLookup(ctx->Shared->ShaderObjects, name); + if (!shProg) { + _mesa_error(ctx, GL_INVALID_VALUE, caller); + return NULL; + } + if (shProg->Type != GL_SHADER_PROGRAM_MESA) { + _mesa_error(ctx, GL_INVALID_OPERATION, caller); + return NULL; + } + return shProg; + } +} + + + + +/** + * Allocate a new gl_shader object, initialize it. + */ +struct gl_shader * +_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type) +{ + struct gl_shader *shader; + assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER); + shader = CALLOC_STRUCT(gl_shader); + if (shader) { + shader->Type = type; + shader->Name = name; + shader->RefCount = 1; + } + return shader; +} + + +void +_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh) +{ + if (sh->Source) + _mesa_free((void *) sh->Source); + if (sh->InfoLog) + _mesa_free(sh->InfoLog); + _mesa_reference_program(ctx, &sh->Program, NULL); + _mesa_free(sh); +} + + +/** + * Set ptr to point to sh. + * If ptr is pointing to another shader, decrement its refcount (and delete + * if refcount hits zero). + * Then set ptr to point to sh, incrementing its refcount. + */ +/* XXX this could be static */ +void +_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr, + struct gl_shader *sh) +{ + assert(ptr); + if (*ptr == sh) { + /* no-op */ + return; + } + if (*ptr) { + /* Unreference the old shader */ + GLboolean deleteFlag = GL_FALSE; + struct gl_shader *old = *ptr; + + ASSERT(old->RefCount > 0); + old->RefCount--; + /*printf("SHADER DECR %p (%d) to %d\n", + (void*) old, old->Name, old->RefCount);*/ + deleteFlag = (old->RefCount == 0); + + if (deleteFlag) { + _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name); + _mesa_free_shader(ctx, old); + } + + *ptr = NULL; + } + assert(!*ptr); + + if (sh) { + /* reference new */ + sh->RefCount++; + /*printf("SHADER INCR %p (%d) to %d\n", + (void*) sh, sh->Name, sh->RefCount);*/ + *ptr = sh; + } +} + + +/** + * Lookup a GLSL shader object. + */ +struct gl_shader * +_mesa_lookup_shader(GLcontext *ctx, GLuint name) +{ + if (name) { + struct gl_shader *sh = (struct gl_shader *) + _mesa_HashLookup(ctx->Shared->ShaderObjects, name); + /* Note that both gl_shader and gl_shader_program objects are kept + * in the same hash table. Check the object's type to be sure it's + * what we're expecting. + */ + if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) { + return NULL; + } + return sh; + } + return NULL; +} + + +/** + * As above, but record an error if shader is not found. + */ +static struct gl_shader * +_mesa_lookup_shader_err(GLcontext *ctx, GLuint name, const char *caller) +{ + if (!name) { + _mesa_error(ctx, GL_INVALID_VALUE, caller); + return NULL; + } + else { + struct gl_shader *sh = (struct gl_shader *) + _mesa_HashLookup(ctx->Shared->ShaderObjects, name); + if (!sh) { + _mesa_error(ctx, GL_INVALID_VALUE, caller); + return NULL; + } + if (sh->Type == GL_SHADER_PROGRAM_MESA) { + _mesa_error(ctx, GL_INVALID_OPERATION, caller); + return NULL; + } + return sh; + } +} + + +/** + * Return mask of GLSL_x flags by examining the MESA_GLSL env var. + */ +static GLbitfield +get_shader_flags(void) +{ + GLbitfield flags = 0x0; + const char *env = _mesa_getenv("MESA_GLSL"); + + if (env) { + if (_mesa_strstr(env, "dump")) + flags |= GLSL_DUMP; + if (_mesa_strstr(env, "log")) + flags |= GLSL_LOG; + if (_mesa_strstr(env, "nopt")) + flags |= GLSL_NO_OPT; + else if (_mesa_strstr(env, "opt")) + flags |= GLSL_OPT; + if (_mesa_strstr(env, "uniform")) + flags |= GLSL_UNIFORMS; + } + + return flags; +} + + +/** + * Initialize context's shader state. + */ +void +_mesa_init_shader_state(GLcontext * ctx) +{ + /* Device drivers may override these to control what kind of instructions + * are generated by the GLSL compiler. + */ + ctx->Shader.EmitHighLevelInstructions = GL_TRUE; + ctx->Shader.EmitContReturn = GL_TRUE; + ctx->Shader.EmitCondCodes = GL_FALSE; + ctx->Shader.EmitComments = GL_FALSE; + ctx->Shader.Flags = get_shader_flags(); + + /* Default pragma settings */ + ctx->Shader.DefaultPragmas.IgnoreOptimize = GL_FALSE; + ctx->Shader.DefaultPragmas.IgnoreDebug = GL_FALSE; + ctx->Shader.DefaultPragmas.Optimize = GL_TRUE; + ctx->Shader.DefaultPragmas.Debug = GL_FALSE; +} + + +/** + * Free the per-context shader-related state. + */ +void +_mesa_free_shader_state(GLcontext *ctx) +{ + _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL); +} + + +/** + * Copy string from <src> to <dst>, up to maxLength characters, returning + * length of <dst> in <length>. + * \param src the strings source + * \param maxLength max chars to copy + * \param length returns number of chars copied + * \param dst the string destination + */ +static void +copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src) +{ + GLsizei len; + for (len = 0; len < maxLength - 1 && src && src[len]; len++) + dst[len] = src[len]; + if (maxLength > 0) + dst[len] = 0; + if (length) + *length = len; +} + + +static GLboolean +_mesa_is_program(GLcontext *ctx, GLuint name) +{ + struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name); + return shProg ? GL_TRUE : GL_FALSE; +} + + +static GLboolean +_mesa_is_shader(GLcontext *ctx, GLuint name) +{ + struct gl_shader *shader = _mesa_lookup_shader(ctx, name); + return shader ? GL_TRUE : GL_FALSE; +} + + +/** + * Called via ctx->Driver.AttachShader() + */ +static void +_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader) +{ + struct gl_shader_program *shProg; + struct gl_shader *sh; + GLuint i, n; + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader"); + if (!shProg) + return; + + sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader"); + if (!sh) { + return; + } + + n = shProg->NumShaders; + for (i = 0; i < n; i++) { + if (shProg->Shaders[i] == sh) { + /* The shader is already attched to this program. The + * GL_ARB_shader_objects spec says: + * + * "The error INVALID_OPERATION is generated by AttachObjectARB + * if <obj> is already attached to <containerObj>." + */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader"); + return; + } + } + + /* grow list */ + shProg->Shaders = (struct gl_shader **) + _mesa_realloc(shProg->Shaders, + n * sizeof(struct gl_shader *), + (n + 1) * sizeof(struct gl_shader *)); + if (!shProg->Shaders) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader"); + return; + } + + /* append */ + shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */ + _mesa_reference_shader(ctx, &shProg->Shaders[n], sh); + shProg->NumShaders++; +} + + +static GLint +_mesa_get_attrib_location(GLcontext *ctx, GLuint program, + const GLchar *name) +{ + struct gl_shader_program *shProg + = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation"); + + if (!shProg) { + return -1; + } + + if (!shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetAttribLocation(program not linked)"); + return -1; + } + + if (!name) + return -1; + + if (shProg->VertexProgram) { + const struct gl_program_parameter_list *attribs = + shProg->VertexProgram->Base.Attributes; + if (attribs) { + GLint i = _mesa_lookup_parameter_index(attribs, -1, name); + if (i >= 0) { + return attribs->Parameters[i].StateIndexes[0]; + } + } + } + return -1; +} + + +static void +_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index, + const GLchar *name) +{ + struct gl_shader_program *shProg; + const GLint size = -1; /* unknown size */ + GLint i, oldIndex; + GLenum datatype = GL_FLOAT_VEC4; + + shProg = _mesa_lookup_shader_program_err(ctx, program, + "glBindAttribLocation"); + if (!shProg) { + return; + } + + if (!name) + return; + + if (strncmp(name, "gl_", 3) == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindAttribLocation(illegal name)"); + return; + } + + if (index >= ctx->Const.VertexProgram.MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)"); + return; + } + + if (shProg->LinkStatus) { + /* get current index/location for the attribute */ + oldIndex = _mesa_get_attrib_location(ctx, program, name); + } + else { + oldIndex = -1; + } + + /* this will replace the current value if it's already in the list */ + i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index); + if (i < 0) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation"); + return; + } + + /* + * Note that this attribute binding won't go into effect until + * glLinkProgram is called again. + */ +} + + +static GLuint +_mesa_create_shader(GLcontext *ctx, GLenum type) +{ + struct gl_shader *sh; + GLuint name; + + name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); + + switch (type) { + case GL_FRAGMENT_SHADER: + case GL_VERTEX_SHADER: + sh = _mesa_new_shader(ctx, name, type); + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)"); + return 0; + } + + _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh); + + return name; +} + + +static GLuint +_mesa_create_program(GLcontext *ctx) +{ + GLuint name; + struct gl_shader_program *shProg; + + name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); + shProg = _mesa_new_shader_program(ctx, name); + + _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg); + + assert(shProg->RefCount == 1); + + return name; +} + + +/** + * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's + * DeleteProgramARB. + */ +static void +_mesa_delete_program2(GLcontext *ctx, GLuint name) +{ + /* + * NOTE: deleting shaders/programs works a bit differently than + * texture objects (and buffer objects, etc). Shader/program + * handles/IDs exist in the hash table until the object is really + * deleted (refcount==0). With texture objects, the handle/ID is + * removed from the hash table in glDeleteTextures() while the tex + * object itself might linger until its refcount goes to zero. + */ + struct gl_shader_program *shProg; + + shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram"); + if (!shProg) + return; + + shProg->DeletePending = GL_TRUE; + + /* effectively, decr shProg's refcount */ + _mesa_reference_shader_program(ctx, &shProg, NULL); +} + + +static void +_mesa_delete_shader(GLcontext *ctx, GLuint shader) +{ + struct gl_shader *sh; + + sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader"); + if (!sh) + return; + + sh->DeletePending = GL_TRUE; + + /* effectively, decr sh's refcount */ + _mesa_reference_shader(ctx, &sh, NULL); +} + + +static void +_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader) +{ + struct gl_shader_program *shProg; + GLuint n; + GLuint i, j; + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader"); + if (!shProg) + return; + + n = shProg->NumShaders; + + for (i = 0; i < n; i++) { + if (shProg->Shaders[i]->Name == shader) { + /* found it */ + struct gl_shader **newList; + + /* release */ + _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); + + /* alloc new, smaller array */ + newList = (struct gl_shader **) + _mesa_malloc((n - 1) * sizeof(struct gl_shader *)); + if (!newList) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader"); + return; + } + for (j = 0; j < i; j++) { + newList[j] = shProg->Shaders[j]; + } + while (++i < n) + newList[j++] = shProg->Shaders[i]; + _mesa_free(shProg->Shaders); + + shProg->Shaders = newList; + shProg->NumShaders = n - 1; + +#ifdef DEBUG + /* sanity check */ + { + for (j = 0; j < shProg->NumShaders; j++) { + assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER || + shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER); + assert(shProg->Shaders[j]->RefCount > 0); + } + } +#endif + + return; + } + } + + /* not found */ + { + GLenum err; + if (_mesa_is_shader(ctx, shader)) + err = GL_INVALID_OPERATION; + else if (_mesa_is_program(ctx, shader)) + err = GL_INVALID_OPERATION; + else + err = GL_INVALID_VALUE; + _mesa_error(ctx, err, "glDetachProgram(shader)"); + return; + } +} + + +static GLint +sizeof_glsl_type(GLenum type) +{ + switch (type) { + case GL_FLOAT: + case GL_INT: + case GL_BOOL: + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_2D_RECT_ARB: + case GL_SAMPLER_2D_RECT_SHADOW_ARB: + case GL_SAMPLER_1D_ARRAY_SHADOW_EXT: + case GL_SAMPLER_2D_ARRAY_SHADOW_EXT: + case GL_SAMPLER_CUBE_SHADOW_EXT: + return 1; + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_BOOL_VEC2: + return 2; + case GL_FLOAT_VEC3: + case GL_INT_VEC3: + case GL_BOOL_VEC3: + return 3; + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_BOOL_VEC4: + return 4; + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT2x4: + return 8; /* two float[4] vectors */ + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT3x2: + case GL_FLOAT_MAT3x4: + return 12; /* three float[4] vectors */ + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT4x2: + case GL_FLOAT_MAT4x3: + return 16; /* four float[4] vectors */ + default: + _mesa_problem(NULL, "Invalid type in sizeof_glsl_type()"); + return 1; + } +} + + +static GLboolean +is_boolean_type(GLenum type) +{ + switch (type) { + case GL_BOOL: + case GL_BOOL_VEC2: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +static GLboolean +is_integer_type(GLenum type) +{ + switch (type) { + case GL_INT: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_INT_VEC4: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +static GLboolean +is_sampler_type(GLenum type) +{ + switch (type) { + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_2D_RECT_ARB: + case GL_SAMPLER_2D_RECT_SHADOW_ARB: + case GL_SAMPLER_1D_ARRAY_EXT: + case GL_SAMPLER_2D_ARRAY_EXT: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +static void +_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index, + GLsizei maxLength, GLsizei *length, GLint *size, + GLenum *type, GLchar *nameOut) +{ + const struct gl_program_parameter_list *attribs = NULL; + struct gl_shader_program *shProg; + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib"); + if (!shProg) + return; + + if (shProg->VertexProgram) + attribs = shProg->VertexProgram->Base.Attributes; + + if (!attribs || index >= attribs->NumParameters) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)"); + return; + } + + copy_string(nameOut, maxLength, length, attribs->Parameters[index].Name); + + if (size) + *size = attribs->Parameters[index].Size + / sizeof_glsl_type(attribs->Parameters[index].DataType); + + if (type) + *type = attribs->Parameters[index].DataType; +} + + +static struct gl_program_parameter * +get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index) +{ + const struct gl_program *prog = NULL; + GLint progPos; + + progPos = shProg->Uniforms->Uniforms[index].VertPos; + if (progPos >= 0) { + prog = &shProg->VertexProgram->Base; + } + else { + progPos = shProg->Uniforms->Uniforms[index].FragPos; + if (progPos >= 0) { + prog = &shProg->FragmentProgram->Base; + } + } + + if (!prog || progPos < 0) + return NULL; /* should never happen */ + + return &prog->Parameters->Parameters[progPos]; +} + + +/** + * Called via ctx->Driver.GetActiveUniform(). + */ +static void +_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index, + GLsizei maxLength, GLsizei *length, GLint *size, + GLenum *type, GLchar *nameOut) +{ + const struct gl_shader_program *shProg; + const struct gl_program *prog = NULL; + const struct gl_program_parameter *param; + GLint progPos; + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform"); + if (!shProg) + return; + + if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)"); + return; + } + + progPos = shProg->Uniforms->Uniforms[index].VertPos; + if (progPos >= 0) { + prog = &shProg->VertexProgram->Base; + } + else { + progPos = shProg->Uniforms->Uniforms[index].FragPos; + if (progPos >= 0) { + prog = &shProg->FragmentProgram->Base; + } + } + + if (!prog || progPos < 0) + return; /* should never happen */ + + ASSERT(progPos < prog->Parameters->NumParameters); + param = &prog->Parameters->Parameters[progPos]; + + if (nameOut) { + copy_string(nameOut, maxLength, length, param->Name); + } + + if (size) { + GLint typeSize = sizeof_glsl_type(param->DataType); + if (param->Size > typeSize) { + /* This is an array. + * Array elements are placed on vector[4] boundaries so they're + * a multiple of four floats. We round typeSize up to next multiple + * of four to get the right size below. + */ + typeSize = (typeSize + 3) & ~3; + } + /* Note that the returned size is in units of the <type>, not bytes */ + *size = param->Size / typeSize; + } + + if (type) { + *type = param->DataType; + } +} + + +/** + * Called via ctx->Driver.GetAttachedShaders(). + */ +static void +_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount, + GLsizei *count, GLuint *obj) +{ + struct gl_shader_program *shProg = + _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders"); + if (shProg) { + GLuint i; + for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) { + obj[i] = shProg->Shaders[i]->Name; + } + if (count) + *count = i; + } +} + + +static GLuint +_mesa_get_handle(GLcontext *ctx, GLenum pname) +{ + GLint handle = 0; + + if (pname == GL_PROGRAM_OBJECT_ARB) { + CALL_GetIntegerv(ctx->Exec, (GL_CURRENT_PROGRAM, &handle)); + } else { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB"); + } + + return handle; +} + + +static void +_mesa_get_programiv(GLcontext *ctx, GLuint program, + GLenum pname, GLint *params) +{ + const struct gl_program_parameter_list *attribs; + struct gl_shader_program *shProg + = _mesa_lookup_shader_program(ctx, program); + + if (!shProg) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)"); + return; + } + + if (shProg->VertexProgram) + attribs = shProg->VertexProgram->Base.Attributes; + else + attribs = NULL; + + switch (pname) { + case GL_DELETE_STATUS: + *params = shProg->DeletePending; + break; + case GL_LINK_STATUS: + *params = shProg->LinkStatus; + break; + case GL_VALIDATE_STATUS: + *params = shProg->Validated; + break; + case GL_INFO_LOG_LENGTH: + *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0; + break; + case GL_ATTACHED_SHADERS: + *params = shProg->NumShaders; + break; + case GL_ACTIVE_ATTRIBUTES: + *params = attribs ? attribs->NumParameters : 0; + break; + case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: + *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1; + break; + case GL_ACTIVE_UNIFORMS: + *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0; + break; + case GL_ACTIVE_UNIFORM_MAX_LENGTH: + *params = _mesa_longest_uniform_name(shProg->Uniforms); + if (*params > 0) + (*params)++; /* add one for terminating zero */ + break; + case GL_PROGRAM_BINARY_LENGTH_OES: + *params = 0; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)"); + return; + } +} + + +static void +_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params) +{ + struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv"); + + if (!shader) { + return; + } + + switch (pname) { + case GL_SHADER_TYPE: + *params = shader->Type; + break; + case GL_DELETE_STATUS: + *params = shader->DeletePending; + break; + case GL_COMPILE_STATUS: + *params = shader->CompileStatus; + break; + case GL_INFO_LOG_LENGTH: + *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0; + break; + case GL_SHADER_SOURCE_LENGTH: + *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)"); + return; + } +} + + +static void +_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize, + GLsizei *length, GLchar *infoLog) +{ + struct gl_shader_program *shProg + = _mesa_lookup_shader_program(ctx, program); + if (!shProg) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)"); + return; + } + copy_string(infoLog, bufSize, length, shProg->InfoLog); +} + + +static void +_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize, + GLsizei *length, GLchar *infoLog) +{ + struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); + if (!sh) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)"); + return; + } + copy_string(infoLog, bufSize, length, sh->InfoLog); +} + + +/** + * Called via ctx->Driver.GetShaderSource(). + */ +static void +_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength, + GLsizei *length, GLchar *sourceOut) +{ + struct gl_shader *sh; + sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource"); + if (!sh) { + return; + } + copy_string(sourceOut, maxLength, length, sh->Source); +} + + +static void +get_matrix_dims(GLenum type, GLint *rows, GLint *cols) +{ + switch (type) { + case GL_FLOAT_MAT2: + *rows = *cols = 2; + break; + case GL_FLOAT_MAT2x3: + *rows = 3; + *cols = 2; + break; + case GL_FLOAT_MAT2x4: + *rows = 4; + *cols = 2; + break; + case GL_FLOAT_MAT3: + *rows = 3; + *cols = 3; + break; + case GL_FLOAT_MAT3x2: + *rows = 2; + *cols = 3; + break; + case GL_FLOAT_MAT3x4: + *rows = 4; + *cols = 3; + break; + case GL_FLOAT_MAT4: + *rows = 4; + *cols = 4; + break; + case GL_FLOAT_MAT4x2: + *rows = 2; + *cols = 4; + break; + case GL_FLOAT_MAT4x3: + *rows = 3; + *cols = 4; + break; + default: + *rows = *cols = 0; + } +} + + +/** + * Determine the number of rows and columns occupied by a uniform + * according to its datatype. For non-matrix types (such as GL_FLOAT_VEC4), + * the number of rows = 1 and cols = number of elements in the vector. + */ +static void +get_uniform_rows_cols(const struct gl_program_parameter *p, + GLint *rows, GLint *cols) +{ + get_matrix_dims(p->DataType, rows, cols); + if (*rows == 0 && *cols == 0) { + /* not a matrix type, probably a float or vector */ + if (p->Size <= 4) { + *rows = 1; + *cols = p->Size; + } + else { + *rows = p->Size / 4 + 1; + if (p->Size % 4 == 0) + *cols = 4; + else + *cols = p->Size % 4; + } + } +} + + +/** + * Helper for get_uniform[fi]v() functions. + * Given a shader program name and uniform location, return a pointer + * to the shader program and return the program parameter position. + */ +static void +lookup_uniform_parameter(GLcontext *ctx, GLuint program, GLint location, + struct gl_program **progOut, GLint *paramPosOut) +{ + struct gl_shader_program *shProg + = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v"); + struct gl_program *prog = NULL; + GLint progPos = -1; + + /* if shProg is NULL, we'll have already recorded an error */ + + if (shProg) { + if (!shProg->Uniforms || + location < 0 || + location >= (GLint) shProg->Uniforms->NumUniforms) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)"); + } + else { + /* OK, find the gl_program and program parameter location */ + progPos = shProg->Uniforms->Uniforms[location].VertPos; + if (progPos >= 0) { + prog = &shProg->VertexProgram->Base; + } + else { + progPos = shProg->Uniforms->Uniforms[location].FragPos; + if (progPos >= 0) { + prog = &shProg->FragmentProgram->Base; + } + } + } + } + + *progOut = prog; + *paramPosOut = progPos; +} + + +/** + * Called via ctx->Driver.GetUniformfv(). + */ +static void +_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location, + GLfloat *params) +{ + struct gl_program *prog; + GLint paramPos; + + lookup_uniform_parameter(ctx, program, location, &prog, ¶mPos); + + if (prog) { + const struct gl_program_parameter *p = + &prog->Parameters->Parameters[paramPos]; + GLint rows, cols, i, j, k; + + get_uniform_rows_cols(p, &rows, &cols); + + k = 0; + for (i = 0; i < rows; i++) { + for (j = 0; j < cols; j++ ) { + params[k++] = prog->Parameters->ParameterValues[paramPos+i][j]; + } + } + } +} + + +/** + * Called via ctx->Driver.GetUniformiv(). + * \sa _mesa_get_uniformfv, only difference is a cast. + */ +static void +_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location, + GLint *params) +{ + struct gl_program *prog; + GLint paramPos; + + lookup_uniform_parameter(ctx, program, location, &prog, ¶mPos); + + if (prog) { + const struct gl_program_parameter *p = + &prog->Parameters->Parameters[paramPos]; + GLint rows, cols, i, j, k; + + get_uniform_rows_cols(p, &rows, &cols); + + k = 0; + for (i = 0; i < rows; i++) { + for (j = 0; j < cols; j++ ) { + params[k++] = (GLint) prog->Parameters->ParameterValues[paramPos+i][j]; + } + } + } +} + + +/** + * The value returned by GetUniformLocation actually encodes two things: + * 1. the index into the prog->Uniforms[] array for the uniform + * 2. an offset in the prog->ParameterValues[] array for specifying array + * elements or structure fields. + * This function merges those two values. + */ +static void +merge_location_offset(GLint *location, GLint offset) +{ + *location = *location | (offset << 16); +} + + +/** + * Seperate the uniform location and parameter offset. See above. + */ +static void +split_location_offset(GLint *location, GLint *offset) +{ + *offset = (*location >> 16); + *location = *location & 0xffff; +} + + +/** + * Called via ctx->Driver.GetUniformLocation(). + * + * The return value will encode two values, the uniform location and an + * offset (used for arrays, structs). + */ +static GLint +_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name) +{ + GLint offset = 0, location = -1; + + struct gl_shader_program *shProg = + _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation"); + + if (!shProg) + return -1; + + if (shProg->LinkStatus == GL_FALSE) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)"); + return -1; + } + + /* XXX we should return -1 if the uniform was declared, but not + * actually used. + */ + + /* XXX we need to be able to parse uniform names for structs and arrays + * such as: + * mymatrix[1] + * mystruct.field1 + */ + + { + /* handle 1-dimension arrays here... */ + char *c = strchr(name, '['); + if (c) { + /* truncate name at [ */ + const GLint len = c - name; + GLchar *newName = _mesa_malloc(len + 1); + if (!newName) + return -1; /* out of mem */ + _mesa_memcpy(newName, name, len); + newName[len] = 0; + + location = _mesa_lookup_uniform(shProg->Uniforms, newName); + if (location >= 0) { + const GLint element = _mesa_atoi(c + 1); + if (element > 0) { + /* get type of the uniform array element */ + struct gl_program_parameter *p; + p = get_uniform_parameter(shProg, location); + if (p) { + GLint rows, cols; + get_matrix_dims(p->DataType, &rows, &cols); + if (rows < 1) + rows = 1; + offset = element * rows; + } + } + } + + _mesa_free(newName); + } + } + + if (location < 0) { + location = _mesa_lookup_uniform(shProg->Uniforms, name); + } + + if (location >= 0) { + merge_location_offset(&location, offset); + } + + return location; +} + + + +/** + * Called via ctx->Driver.ShaderSource() + */ +static void +_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source) +{ + struct gl_shader *sh; + + sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource"); + if (!sh) + return; + + /* free old shader source string and install new one */ + if (sh->Source) { + _mesa_free((void *) sh->Source); + } + sh->Source = source; + sh->CompileStatus = GL_FALSE; +#ifdef DEBUG + sh->SourceChecksum = _mesa_str_checksum(sh->Source); +#endif +} + + +/** + * Called via ctx->Driver.CompileShader() + */ +static void +_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj) +{ + struct gl_shader *sh; + + sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader"); + if (!sh) + return; + + /* set default pragma state for shader */ + sh->Pragmas = ctx->Shader.DefaultPragmas; + + /* this call will set the sh->CompileStatus field to indicate if + * compilation was successful. + */ + (void) _slang_compile(ctx, sh); +} + + +/** + * Called via ctx->Driver.LinkProgram() + */ +static void +_mesa_link_program(GLcontext *ctx, GLuint program) +{ + struct gl_shader_program *shProg; + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram"); + if (!shProg) + return; + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + _slang_link(ctx, program, shProg); + + /* debug code */ + if (0) { + GLuint i; + + _mesa_printf("Link %u shaders in program %u: %s\n", + shProg->NumShaders, shProg->Name, + shProg->LinkStatus ? "Success" : "Failed"); + + for (i = 0; i < shProg->NumShaders; i++) { + _mesa_printf(" shader %u, type 0x%x\n", + shProg->Shaders[i]->Name, + shProg->Shaders[i]->Type); + } + } +} + + +/** + * Called via ctx->Driver.UseProgram() + */ +void +_mesa_use_program(GLcontext *ctx, GLuint program) +{ + struct gl_shader_program *shProg; + + if (ctx->Shader.CurrentProgram && + ctx->Shader.CurrentProgram->Name == program) { + /* no-op */ + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + + if (program) { + shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram"); + if (!shProg) { + return; + } + if (!shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUseProgram(program %u not linked)", program); + return; + } + + /* debug code */ + if (0) { + GLuint i; + _mesa_printf("Use Shader %u\n", shProg->Name); + for (i = 0; i < shProg->NumShaders; i++) { + _mesa_printf(" shader %u, type 0x%x, checksum %u\n", + shProg->Shaders[i]->Name, + shProg->Shaders[i]->Type, + shProg->Shaders[i]->SourceChecksum); + } + if (shProg->VertexProgram) + printf(" vert prog %u\n", shProg->VertexProgram->Base.Id); + if (shProg->FragmentProgram) + printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id); + } + } + else { + shProg = NULL; + } + + _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg); +} + + + +/** + * Update the vertex/fragment program's TexturesUsed array. + * + * This needs to be called after glUniform(set sampler var) is called. + * A call to glUniform(samplerVar, value) causes a sampler to point to a + * particular texture unit. We know the sampler's texture target + * (1D/2D/3D/etc) from compile time but the sampler's texture unit is + * set by glUniform() calls. + * + * So, scan the program->SamplerUnits[] and program->SamplerTargets[] + * information to update the prog->TexturesUsed[] values. + * Each value of TexturesUsed[unit] is one of zero, TEXTURE_1D_INDEX, + * TEXTURE_2D_INDEX, TEXTURE_3D_INDEX, etc. + * We'll use that info for state validation before rendering. + */ +void +_mesa_update_shader_textures_used(struct gl_program *prog) +{ + GLuint s; + + memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed)); + + for (s = 0; s < MAX_SAMPLERS; s++) { + if (prog->SamplersUsed & (1 << s)) { + GLuint unit = prog->SamplerUnits[s]; + GLuint tgt = prog->SamplerTargets[s]; + assert(unit < MAX_TEXTURE_IMAGE_UNITS); + assert(tgt < NUM_TEXTURE_TARGETS); + prog->TexturesUsed[unit] |= (1 << tgt); + } + } +} + + +/** + * Check if the type given by userType is allowed to set a uniform of the + * target type. Generally, equivalence is required, but setting Boolean + * uniforms can be done with glUniformiv or glUniformfv. + */ +static GLboolean +compatible_types(GLenum userType, GLenum targetType) +{ + if (userType == targetType) + return GL_TRUE; + + if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT)) + return GL_TRUE; + + if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 || + userType == GL_INT_VEC2)) + return GL_TRUE; + + if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 || + userType == GL_INT_VEC3)) + return GL_TRUE; + + if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 || + userType == GL_INT_VEC4)) + return GL_TRUE; + + if (is_sampler_type(targetType) && userType == GL_INT) + return GL_TRUE; + + return GL_FALSE; +} + + +/** + * Set the value of a program's uniform variable. + * \param program the program whose uniform to update + * \param index the index of the program parameter for the uniform + * \param offset additional parameter slot offset (for arrays) + * \param type the incoming datatype of 'values' + * \param count the number of uniforms to set + * \param elems number of elements per uniform (1, 2, 3 or 4) + * \param values the new values, of datatype 'type' + */ +static void +set_program_uniform(GLcontext *ctx, struct gl_program *program, + GLint index, GLint offset, + GLenum type, GLsizei count, GLint elems, + const void *values) +{ + const struct gl_program_parameter *param = + &program->Parameters->Parameters[index]; + + assert(offset >= 0); + assert(elems >= 1); + assert(elems <= 4); + + if (!compatible_types(type, param->DataType)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)"); + return; + } + + if (index + offset > (GLint) program->Parameters->Size) { + /* out of bounds! */ + return; + } + + if (param->Type == PROGRAM_SAMPLER) { + /* This controls which texture unit which is used by a sampler */ + GLboolean changed = GL_FALSE; + GLint i; + + /* this should have been caught by the compatible_types() check */ + ASSERT(type == GL_INT); + + /* loop over number of samplers to change */ + for (i = 0; i < count; i++) { + GLuint sampler = + (GLuint) program->Parameters->ParameterValues[index + offset + i][0]; + GLuint texUnit = ((GLuint *) values)[i]; + + /* check that the sampler (tex unit index) is legal */ + if (texUnit >= ctx->Const.MaxTextureImageUnits) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glUniform1(invalid sampler/tex unit index)"); + return; + } + + /* This maps a sampler to a texture unit: */ + if (sampler < MAX_SAMPLERS) { +#if 0 + _mesa_printf("Set program %p sampler %d '%s' to unit %u\n", + program, sampler, param->Name, texUnit); +#endif + if (program->SamplerUnits[sampler] != texUnit) { + program->SamplerUnits[sampler] = texUnit; + changed = GL_TRUE; + } + } + } + + if (changed) { + /* When a sampler's value changes it usually requires rewriting + * a GPU program's TEX instructions since there may not be a + * sampler->texture lookup table. We signal this with the + * ProgramStringNotify() callback. + */ + FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM); + _mesa_update_shader_textures_used(program); + ctx->Driver.ProgramStringNotify(ctx, program->Target, program); + } + } + else { + /* ordinary uniform variable */ + const GLboolean isUniformBool = is_boolean_type(param->DataType); + const GLboolean areIntValues = is_integer_type(type); + const GLint slots = (param->Size + 3) / 4; + const GLint typeSize = sizeof_glsl_type(param->DataType); + GLsizei k, i; + + if (param->Size > typeSize) { + /* an array */ + /* we'll ignore extra data below */ + } + else { + /* non-array: count must be one */ + if (count != 1) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniform(uniform is not an array)"); + return; + } + } + + /* loop over number of array elements */ + for (k = 0; k < count; k++) { + GLfloat *uniformVal; + + if (offset + k >= slots) { + /* Extra array data is ignored */ + break; + } + + /* uniformVal (the destination) is always float[4] */ + uniformVal = program->Parameters->ParameterValues[index + offset + k]; + + if (areIntValues) { + /* convert user's ints to floats */ + const GLint *iValues = ((const GLint *) values) + k * elems; + for (i = 0; i < elems; i++) { + uniformVal[i] = (GLfloat) iValues[i]; + } + } + else { + const GLfloat *fValues = ((const GLfloat *) values) + k * elems; + for (i = 0; i < elems; i++) { + uniformVal[i] = fValues[i]; + } + } + + /* if the uniform is bool-valued, convert to 1.0 or 0.0 */ + if (isUniformBool) { + for (i = 0; i < elems; i++) { + uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f; + } + } + } + } +} + + +/** + * Called via ctx->Driver.Uniform(). + */ +static void +_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count, + const GLvoid *values, GLenum type) +{ + struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; + struct gl_uniform *uniform; + GLint elems, offset; + GLenum basicType; + + if (!shProg || !shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)"); + return; + } + + if (location == -1) + return; /* The standard specifies this as a no-op */ + + if (location < -1) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location)"); + return; + } + + split_location_offset(&location, &offset); + + if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) { + _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)"); + return; + } + + if (count < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)"); + return; + } + + switch (type) { + case GL_FLOAT: + basicType = GL_FLOAT; + elems = 1; + break; + case GL_INT: + basicType = GL_INT; + elems = 1; + break; + case GL_FLOAT_VEC2: + basicType = GL_FLOAT; + elems = 2; + break; + case GL_INT_VEC2: + basicType = GL_INT; + elems = 2; + break; + case GL_FLOAT_VEC3: + basicType = GL_FLOAT; + elems = 3; + break; + case GL_INT_VEC3: + basicType = GL_INT; + elems = 3; + break; + case GL_FLOAT_VEC4: + basicType = GL_FLOAT; + elems = 4; + break; + case GL_INT_VEC4: + basicType = GL_INT; + elems = 4; + break; + default: + _mesa_problem(ctx, "Invalid type in _mesa_uniform"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + uniform = &shProg->Uniforms->Uniforms[location]; + + if (ctx->Shader.Flags & GLSL_UNIFORMS) { + GLint i; + _mesa_printf("Mesa: set program %u uniform %s (loc %d) to: ", + shProg->Name, uniform->Name, location); + if (basicType == GL_INT) { + const GLint *v = (const GLint *) values; + for (i = 0; i < count * elems; i++) { + _mesa_printf("%d ", v[i]); + } + } + else { + const GLfloat *v = (const GLfloat *) values; + for (i = 0; i < count * elems; i++) { + _mesa_printf("%g ", v[i]); + } + } + _mesa_printf("\n"); + } + + /* A uniform var may be used by both a vertex shader and a fragment + * shader. We may need to update one or both shader's uniform here: + */ + if (shProg->VertexProgram) { + /* convert uniform location to program parameter index */ + GLint index = uniform->VertPos; + if (index >= 0) { + set_program_uniform(ctx, &shProg->VertexProgram->Base, + index, offset, type, count, elems, values); + } + } + + if (shProg->FragmentProgram) { + /* convert uniform location to program parameter index */ + GLint index = uniform->FragPos; + if (index >= 0) { + set_program_uniform(ctx, &shProg->FragmentProgram->Base, + index, offset, type, count, elems, values); + } + } + + uniform->Initialized = GL_TRUE; +} + + +/** + * Set a matrix-valued program parameter. + */ +static void +set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program, + GLuint index, GLuint offset, + GLuint count, GLuint rows, GLuint cols, + GLboolean transpose, const GLfloat *values) +{ + GLuint mat, row, col; + GLuint dst = index + offset, src = 0; + GLint nr, nc; + + /* check that the number of rows, columns is correct */ + get_matrix_dims(program->Parameters->Parameters[index].DataType, &nr, &nc); + if (rows != nr || cols != nc) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniformMatrix(matrix size mismatch)"); + return; + } + + if (index + offset > program->Parameters->Size) { + /* out of bounds! */ + return; + } + + /* + * Note: the _columns_ of a matrix are stored in program registers, not + * the rows. So, the loops below look a little funny. + * XXX could optimize this a bit... + */ + + /* loop over matrices */ + for (mat = 0; mat < count; mat++) { + + /* each matrix: */ + for (col = 0; col < cols; col++) { + GLfloat *v = program->Parameters->ParameterValues[dst]; + for (row = 0; row < rows; row++) { + if (transpose) { + v[row] = values[src + row * cols + col]; + } + else { + v[row] = values[src + col * rows + row]; + } + } + dst++; + } + + src += rows * cols; /* next matrix */ + } +} + + +/** + * Called by ctx->Driver.UniformMatrix(). + * Note: cols=2, rows=4 ==> array[2] of vec4 + */ +static void +_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows, + GLint location, GLsizei count, + GLboolean transpose, const GLfloat *values) +{ + struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; + struct gl_uniform *uniform; + GLint offset; + + if (!shProg || !shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUniformMatrix(program not linked)"); + return; + } + + if (location == -1) + return; /* The standard specifies this as a no-op */ + + if (location < -1) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)"); + return; + } + + split_location_offset(&location, &offset); + + if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) { + _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)"); + return; + } + if (values == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); + + uniform = &shProg->Uniforms->Uniforms[location]; + + if (shProg->VertexProgram) { + /* convert uniform location to program parameter index */ + GLint index = uniform->VertPos; + if (index >= 0) { + set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base, + index, offset, + count, rows, cols, transpose, values); + } + } + + if (shProg->FragmentProgram) { + /* convert uniform location to program parameter index */ + GLint index = uniform->FragPos; + if (index >= 0) { + set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base, + index, offset, + count, rows, cols, transpose, values); + } + } + + uniform->Initialized = GL_TRUE; +} + + +/** + * Validate a program's samplers. + * Specifically, check that there aren't two samplers of different types + * pointing to the same texture unit. + * \return GL_TRUE if valid, GL_FALSE if invalid + */ +static GLboolean +validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg) +{ + static const char *targetName[] = { + "TEXTURE_2D_ARRAY", + "TEXTURE_1D_ARRAY", + "TEXTURE_CUBE", + "TEXTURE_3D", + "TEXTURE_RECT", + "TEXTURE_2D", + "TEXTURE_1D", + }; + GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS]; + GLbitfield samplersUsed = prog->SamplersUsed; + GLuint i; + + assert(Elements(targetName) == NUM_TEXTURE_TARGETS); + + if (samplersUsed == 0x0) + return GL_TRUE; + + for (i = 0; i < Elements(targetUsed); i++) + targetUsed[i] = -1; + + /* walk over bits which are set in 'samplers' */ + while (samplersUsed) { + GLuint unit; + gl_texture_index target; + GLint sampler = _mesa_ffs(samplersUsed) - 1; + assert(sampler >= 0); + assert(sampler < MAX_TEXTURE_IMAGE_UNITS); + unit = prog->SamplerUnits[sampler]; + target = prog->SamplerTargets[sampler]; + if (targetUsed[unit] != -1 && targetUsed[unit] != target) { + _mesa_snprintf(errMsg, 100, + "Texture unit %d is accessed both as %s and %s", + unit, targetName[targetUsed[unit]], targetName[target]); + return GL_FALSE; + } + targetUsed[unit] = target; + samplersUsed ^= (1 << sampler); + } + + return GL_TRUE; +} + + +/** + * Do validation of the given shader program. + * \param errMsg returns error message if validation fails. + * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg) + */ +GLboolean +_mesa_validate_shader_program(GLcontext *ctx, + const struct gl_shader_program *shProg, + char *errMsg) +{ + const struct gl_vertex_program *vp = shProg->VertexProgram; + const struct gl_fragment_program *fp = shProg->FragmentProgram; + + if (!shProg->LinkStatus) { + return GL_FALSE; + } + + /* From the GL spec, a program is invalid if any of these are true: + + any two active samplers in the current program object are of + different types, but refer to the same texture image unit, + + any active sampler in the current program object refers to a texture + image unit where fixed-function fragment processing accesses a + texture target that does not match the sampler type, or + + the sum of the number of active samplers in the program and the + number of texture image units enabled for fixed-function fragment + processing exceeds the combined limit on the total number of texture + image units allowed. + */ + + + /* + * Check: any two active samplers in the current program object are of + * different types, but refer to the same texture image unit, + */ + if (vp && !validate_samplers(ctx, &vp->Base, errMsg)) { + return GL_FALSE; + } + if (fp && !validate_samplers(ctx, &fp->Base, errMsg)) { + return GL_FALSE; + } + + return GL_TRUE; +} + + +/** + * Called via glValidateProgram() + */ +static void +_mesa_validate_program(GLcontext *ctx, GLuint program) +{ + struct gl_shader_program *shProg; + char errMsg[100]; + + shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram"); + if (!shProg) { + return; + } + + shProg->Validated = _mesa_validate_shader_program(ctx, shProg, errMsg); + if (!shProg->Validated) { + /* update info log */ + if (shProg->InfoLog) { + _mesa_free(shProg->InfoLog); + } + shProg->InfoLog = _mesa_strdup(errMsg); + } +} + + +/** + * Plug in Mesa's GLSL functions into the device driver function table. + */ +void +_mesa_init_glsl_driver_functions(struct dd_function_table *driver) +{ + driver->AttachShader = _mesa_attach_shader; + driver->BindAttribLocation = _mesa_bind_attrib_location; + driver->CompileShader = _mesa_compile_shader; + driver->CreateProgram = _mesa_create_program; + driver->CreateShader = _mesa_create_shader; + driver->DeleteProgram2 = _mesa_delete_program2; + driver->DeleteShader = _mesa_delete_shader; + driver->DetachShader = _mesa_detach_shader; + driver->GetActiveAttrib = _mesa_get_active_attrib; + driver->GetActiveUniform = _mesa_get_active_uniform; + driver->GetAttachedShaders = _mesa_get_attached_shaders; + driver->GetAttribLocation = _mesa_get_attrib_location; + driver->GetHandle = _mesa_get_handle; + driver->GetProgramiv = _mesa_get_programiv; + driver->GetProgramInfoLog = _mesa_get_program_info_log; + driver->GetShaderiv = _mesa_get_shaderiv; + driver->GetShaderInfoLog = _mesa_get_shader_info_log; + driver->GetShaderSource = _mesa_get_shader_source; + driver->GetUniformfv = _mesa_get_uniformfv; + driver->GetUniformiv = _mesa_get_uniformiv; + driver->GetUniformLocation = _mesa_get_uniform_location; + driver->IsProgram = _mesa_is_program; + driver->IsShader = _mesa_is_shader; + driver->LinkProgram = _mesa_link_program; + driver->ShaderSource = _mesa_shader_source; + driver->Uniform = _mesa_uniform; + driver->UniformMatrix = _mesa_uniform_matrix; + driver->UseProgram = _mesa_use_program; + driver->ValidateProgram = _mesa_validate_program; +} diff --git a/mesalib/src/mesa/shader/shader_api.h b/mesalib/src/mesa/shader/shader_api.h new file mode 100644 index 000000000..d08d47373 --- /dev/null +++ b/mesalib/src/mesa/shader/shader_api.h @@ -0,0 +1,100 @@ +/* + * Mesa 3-D graphics library + * Version: 7.6 + * + * Copyright (C) 2004-2006 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. + */ + + +#ifndef SHADER_API_H +#define SHADER_API_H + + +#include "main/glheader.h" +#include "main/mtypes.h" + + +/** + * Internal functions + */ + +extern void +_mesa_init_shader_state(GLcontext * ctx); + +extern void +_mesa_free_shader_state(GLcontext *ctx); + +/* +extern struct gl_shader_program * +_mesa_new_shader_program(GLcontext *ctx, GLuint name); +*/ +extern void +_mesa_clear_shader_program_data(GLcontext *ctx, + struct gl_shader_program *shProg); + +extern void +_mesa_free_shader_program_data(GLcontext *ctx, + struct gl_shader_program *shProg); + +extern void +_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg); + +extern void +_mesa_reference_shader_program(GLcontext *ctx, + struct gl_shader_program **ptr, + struct gl_shader_program *shProg); + +extern struct gl_shader_program * +_mesa_lookup_shader_program(GLcontext *ctx, GLuint name); + + +extern struct gl_shader * +_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type); + +extern void +_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh); + +extern void +_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr, + struct gl_shader *sh); + +extern struct gl_shader * +_mesa_lookup_shader(GLcontext *ctx, GLuint name); + + +extern void +_mesa_update_shader_textures_used(struct gl_program *prog); + + +extern void +_mesa_use_program(GLcontext *ctx, GLuint program); + + +extern GLboolean +_mesa_validate_shader_program(GLcontext *ctx, + const struct gl_shader_program *shProg, + char *errMsg); + +extern void +_mesa_init_glsl_driver_functions(struct dd_function_table *driver); + + +#endif /* SHADER_API_H */ diff --git a/mesalib/src/mesa/shader/slang/descrip.mms b/mesalib/src/mesa/shader/slang/descrip.mms new file mode 100644 index 000000000..6eefbcf5b --- /dev/null +++ b/mesalib/src/mesa/shader/slang/descrip.mms @@ -0,0 +1,68 @@ +# Makefile for core library for VMS +# contributed by Jouk Jansen joukj@hrem.nano.tudelft.nl +# Last revision : 3 October 2007 + +.first + define gl [----.include.gl] + define math [--.math] + define swrast [--.swrast] + define array_cache [--.array_cache] + define main [--.main] + define glapi [--.glapi] + define shader [--.shader] + +.include [----]mms-config. + +##### MACROS ##### + +VPATH = RCS + +INCDIR = [----.include],[--.main],[--.glapi],[-.slang],[-.grammar],[-] +LIBDIR = [----.lib] +CFLAGS = /include=($(INCDIR),[])/define=(PTHREADS=1)/name=(as_is,short)/float=ieee/ieee=denorm + +SOURCES = \ + slang_compile.c,slang_preprocess.c + +OBJECTS = slang_builtin.obj,slang_codegen.obj,slang_compile.obj,\ + slang_compile_function.obj,slang_compile_operation.obj,\ + slang_compile_struct.obj,slang_compile_variable.obj,slang_emit.obj,\ + slang_ir.obj,slang_label.obj,slang_library_noise.obj,slang_link.obj,\ + slang_log.obj,slang_mem.obj,slang_preprocess.obj,slang_print.obj,\ + slang_simplify.obj,slang_storage.obj,slang_typeinfo.obj,\ + slang_utility.obj,slang_vartable.obj + +##### RULES ##### + +VERSION=Mesa V3.4 + +##### TARGETS ##### +# Make the library +$(LIBDIR)$(GL_LIB) : $(OBJECTS) + @ library $(LIBDIR)$(GL_LIB) $(OBJECTS) + +clean : + purge + delete *.obj;* + +slang_builtin.obj : slang_builtin.c +slang_codegen.obj : slang_codegen.c +slang_compile.obj : slang_compile.c +slang_compile_function.obj : slang_compile_function.c +slang_compile_operation.obj : slang_compile_operation.c +slang_compile_struct.obj : slang_compile_struct.c +slang_compile_variable.obj : slang_compile_variable.c +slang_emit.obj : slang_emit.c +slang_ir.obj : slang_ir.c +slang_label.obj : slang_label.c +slang_library_noise.obj : slang_library_noise.c +slang_link.obj : slang_link.c +slang_log.obj : slang_log.c +slang_mem.obj : slang_mem.c +slang_preprocess.obj : slang_preprocess.c +slang_print.obj : slang_print.c +slang_simplify.obj : slang_simplify.c +slang_storage.obj : slang_storage.c +slang_typeinfo.obj : slang_typeinfo.c +slang_utility.obj : slang_utility.c +slang_vartable.obj : slang_vartable.c diff --git a/mesalib/src/mesa/shader/slang/library/Makefile b/mesalib/src/mesa/shader/slang/library/Makefile new file mode 100644 index 000000000..0e03fac2e --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/Makefile @@ -0,0 +1,81 @@ +# src/mesa/shader/slang/library/Makefile + +TOP = ../../../../.. + +include $(TOP)/configs/current + +INCDIR = $(TOP)/include + +LIB_DEP = $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME) + +# +# targets +# + +.PHONY: default clean + +default: syntax builtin + +clean: + -rm -f syn_to_c gc_to_bin *_syn.h *_gc.h + +syntax: slang_pp_directives_syn.h slang_pp_expression_syn.h slang_shader_syn.h slang_pp_version_syn.h + +builtin: builtin_110 builtin_120 + +# +# executables +# + +syn_to_c: syn_to_c.c + $(CC) syn_to_c.c -o syn_to_c + +gc_to_bin: gc_to_bin.c slang_shader_syn.h + $(CC) gc_to_bin.c -o gc_to_bin + +# +# syntax scripts +# + +slang_pp_directives_syn.h: syn_to_c slang_pp_directives.syn + ./syn_to_c slang_pp_directives.syn > slang_pp_directives_syn.h + +slang_pp_expression_syn.h: syn_to_c slang_pp_expression.syn + ./syn_to_c slang_pp_expression.syn > slang_pp_expression_syn.h + +slang_shader_syn.h: syn_to_c slang_shader.syn + ./syn_to_c slang_shader.syn > slang_shader_syn.h + +slang_pp_version_syn.h: syn_to_c slang_pp_version.syn + ./syn_to_c slang_pp_version.syn > slang_pp_version_syn.h + +# +# builtin library sources +# + +builtin_110: slang_common_builtin_gc.h slang_core_gc.h slang_fragment_builtin_gc.h slang_vertex_builtin_gc.h + +builtin_120: slang_120_core_gc.h slang_builtin_120_common_gc.h slang_builtin_120_fragment_gc.h + + +slang_120_core_gc.h: gc_to_bin slang_120_core.gc + ./gc_to_bin 1 slang_120_core.gc slang_120_core_gc.h + +slang_builtin_120_common_gc.h: gc_to_bin slang_builtin_120_common.gc + ./gc_to_bin 1 slang_builtin_120_common.gc slang_builtin_120_common_gc.h + +slang_builtin_120_fragment_gc.h: gc_to_bin slang_builtin_120_fragment.gc + ./gc_to_bin 1 slang_builtin_120_fragment.gc slang_builtin_120_fragment_gc.h + +slang_common_builtin_gc.h: gc_to_bin slang_common_builtin.gc + ./gc_to_bin 1 slang_common_builtin.gc slang_common_builtin_gc.h + +slang_core_gc.h: gc_to_bin slang_core.gc + ./gc_to_bin 1 slang_core.gc slang_core_gc.h + +slang_fragment_builtin_gc.h: gc_to_bin slang_fragment_builtin.gc + ./gc_to_bin 1 slang_fragment_builtin.gc slang_fragment_builtin_gc.h + +slang_vertex_builtin_gc.h: gc_to_bin slang_vertex_builtin.gc + ./gc_to_bin 2 slang_vertex_builtin.gc slang_vertex_builtin_gc.h + diff --git a/mesalib/src/mesa/shader/slang/library/gc_to_bin.c b/mesalib/src/mesa/shader/slang/library/gc_to_bin.c new file mode 100644 index 000000000..8aef7b541 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/gc_to_bin.c @@ -0,0 +1,85 @@ +#include "../../grammar/grammar_crt.h" +#include "../../grammar/grammar_crt.c" +#include <stdlib.h> +#include <stdio.h> + +static const char *slang_shader_syn = +#include "slang_shader_syn.h" +; + +static int gc_to_bin (grammar id, const char *in, const char *out) +{ + FILE *f; + byte *source, *prod; + unsigned int size, i, line = 0; + + printf ("Precompiling %s\n", in); + + f = fopen (in, "r"); + if (f == NULL) + return 1; + fseek (f, 0, SEEK_END); + size = ftell (f); + fseek (f, 0, SEEK_SET); + source = (byte *) grammar_alloc_malloc (size + 1); + source[fread (source, 1, size, f)] = '\0'; + fclose (f); + + if (!grammar_fast_check (id, source, &prod, &size, 65536)) + { + grammar_alloc_free (source); + return 1; + } + + f = fopen (out, "w"); + fprintf (f, "\n"); + fprintf (f, "/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */\n"); + fprintf (f, "/* %s */\n", in); + fprintf (f, "\n"); + for (i = 0; i < size; i++) + { + unsigned int a; + if (prod[i] < 10) + a = 1; + else if (prod[i] < 100) + a = 2; + else + a = 3; + if (i < size - 1) + a++; + if (line + a >= 100) + { + fprintf (f, "\n"); + line = 0; + } + line += a; + fprintf (f, "%d", prod[i]); + if (i < size - 1) + fprintf (f, ","); + } + fprintf (f, "\n"); + fclose (f); + grammar_alloc_free (prod); + return 0; +} + +int main (int argc, char *argv[]) +{ + grammar id; + + id = grammar_load_from_text ((const byte *) slang_shader_syn); + if (id == 0) { + fprintf(stderr, "Error loading grammar from text\n"); + return 1; + } + grammar_set_reg8 (id, (const byte *) "parsing_builtin", 1); + grammar_set_reg8 (id, (const byte *) "shader_type", atoi (argv[1])); + if (gc_to_bin (id, argv[2], argv[3])) { + fprintf(stderr, "Error in gc_to_bin %s %s\n", argv[2], argv[3]); + grammar_destroy (id); + return 1; + } + grammar_destroy (id); + return 0; +} + diff --git a/mesalib/src/mesa/shader/slang/library/slang_120_core.gc b/mesalib/src/mesa/shader/slang/library/slang_120_core.gc new file mode 100644 index 000000000..04c5ec2ec --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_120_core.gc @@ -0,0 +1,1978 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// +// Constructors and operators introduced in GLSL 1.20 - mostly on new +// (non-square) types of matrices. +// +// One important change in the language is that when a matrix is used +// as an argument to a matrix constructor, it must be the only argument +// for the constructor. The compiler takes care of it by itself and +// here we only care to re-introduce constructors for old (square) +// types of matrices. +// + +// +// From Shader Spec, ver. 1.20, rev. 6 +// + +//// mat2x3: 2 columns of vec3 + +mat2x3 __constructor(const float f00, const float f10, const float f20, + const float f01, const float f11, const float f21) +{ + __retVal[0].x = f00; + __retVal[0].y = f10; + __retVal[0].z = f20; + __retVal[1].x = f01; + __retVal[1].y = f11; + __retVal[1].z = f21; +} + +mat2x3 __constructor(const float f) +{ + __retVal = mat2x3( f, 0.0, 0.0, + 0.0, f, 0.0); +} + +mat2x3 __constructor(const int i) +{ + const float f = float(i); + __retVal = mat2x3(f); +} + +mat2x3 __constructor(const bool b) +{ + const float f = float(b); + __retVal = mat2x3(f); +} + +mat2x3 __constructor(const vec3 c0, const vec3 c1) +{ + __retVal[0] = c0; + __retVal[1] = c1; +} + + + +//// mat2x4: 2 columns of vec4 + +mat2x4 __constructor(const float f00, const float f10, const float f20, const float f30, + const float f01, const float f11, const float f21, const float f31) +{ + __retVal[0].x = f00; + __retVal[0].y = f10; + __retVal[0].z = f20; + __retVal[0].w = f30; + __retVal[1].x = f01; + __retVal[1].y = f11; + __retVal[1].z = f21; + __retVal[1].w = f31; +} + +mat2x4 __constructor(const float f) +{ + __retVal = mat2x4( f, 0.0, 0.0, 0.0, + 0.0, f, 0.0, 0.0); +} + +mat2x4 __constructor(const int i) +{ + const float f = float(i); + __retVal = mat2x4(f); +} + +mat2x4 __constructor(const bool b) +{ + const float f = float(b); + __retVal = mat2x4(f); +} + +mat2x4 __constructor(const vec4 c0, const vec4 c1) +{ + __retVal[0] = c0; + __retVal[1] = c1; +} + + + +//// mat3x2: 3 columns of vec2 + +mat3x2 __constructor(const float f00, const float f10, + const float f01, const float f11, + const float f02, const float f12) +{ + __retVal[0].x = f00; + __retVal[0].y = f10; + __retVal[1].x = f01; + __retVal[1].y = f11; + __retVal[2].x = f02; + __retVal[2].y = f12; +} + +mat3x2 __constructor(const float f) +{ + __retVal = mat3x2( f, 0.0, + 0.0, f, + 0.0, 0.0); +} + +mat3x2 __constructor(const int i) +{ + const float f = float(i); + __retVal = mat3x2(f); +} + +mat3x2 __constructor(const bool b) +{ + const float f = float(b); + __retVal = mat3x2(f); +} + +mat3x2 __constructor(const vec2 c0, const vec2 c1, const vec2 c2) +{ + __retVal[0] = c0; + __retVal[1] = c1; + __retVal[2] = c2; +} + + + +//// mat3x4: 3 columns of vec4 + +mat3x4 __constructor(const float f00, const float f10, const float f20, const float f30, + const float f01, const float f11, const float f21, const float f31, + const float f02, const float f12, const float f22, const float f32) +{ + __retVal[0].x = f00; + __retVal[0].y = f10; + __retVal[0].z = f20; + __retVal[0].w = f30; + __retVal[1].x = f01; + __retVal[1].y = f11; + __retVal[1].z = f21; + __retVal[1].w = f31; + __retVal[2].x = f02; + __retVal[2].y = f12; + __retVal[2].z = f22; + __retVal[2].w = f32; +} + +mat3x4 __constructor(const float f) +{ + __retVal = mat3x4( f, 0.0, 0.0, 0.0, + 0.0, f, 0.0, 0.0, + 0.0, 0.0, f, 0.0); +} + +mat3x4 __constructor(const int i) +{ + const float f = float(i); + __retVal = mat3x4(f); +} + +mat3x4 __constructor(const bool b) +{ + const float f = float(b); + __retVal = mat3x4(f); +} + +mat3x4 __constructor(const vec4 c0, const vec4 c1, const vec4 c2) +{ + __retVal[0] = c0; + __retVal[1] = c1; + __retVal[2] = c2; +} + + + +//// mat4x2: 4 columns of vec2 + +mat4x2 __constructor(const float f00, const float f10, + const float f01, const float f11, + const float f02, const float f12, + const float f03, const float f13) +{ + __retVal[0].x = f00; + __retVal[0].y = f10; + __retVal[1].x = f01; + __retVal[1].y = f11; + __retVal[2].x = f02; + __retVal[2].y = f12; + __retVal[3].x = f03; + __retVal[3].y = f13; +} + +mat4x2 __constructor(const float f) +{ + __retVal = mat4x2( f, 0.0, + 0.0, 4, + 0.0, 0.0, + 0.0, 0.0); +} + +mat4x2 __constructor(const int i) +{ + const float f = float(i); + __retVal = mat4x2(f); +} + +mat4x2 __constructor(const bool b) +{ + const float f = float(b); + __retVal = mat4x2(f); +} + +mat4x2 __constructor(const vec2 c0, const vec2 c1, const vec2 c2, const vec2 c3) +{ + __retVal[0] = c0; + __retVal[1] = c1; + __retVal[2] = c2; + __retVal[3] = c3; +} + + + +//// mat4x3: 4 columns of vec3 + +mat4x3 __constructor(const float f00, const float f10, const float f20, + const float f01, const float f11, const float f21, + const float f02, const float f12, const float f22, + const float f03, const float f13, const float f23) +{ + __retVal[0].x = f00; + __retVal[0].y = f10; + __retVal[0].z = f20; + __retVal[1].x = f01; + __retVal[1].y = f11; + __retVal[1].z = f21; + __retVal[2].x = f02; + __retVal[2].y = f12; + __retVal[2].z = f22; + __retVal[3].x = f03; + __retVal[3].y = f13; + __retVal[3].z = f23; +} + +mat4x3 __constructor(const float f) +{ + __retVal = mat4x3( f, 0.0, 0.0, + 0.0, f, 0.0, + 0.0, 0.0, f, + 0.0, 0.0, 0.0); +} + +mat4x3 __constructor(const int i) +{ + const float f = float(i); + __retVal = mat4x3(f); +} + +mat4x3 __constructor(const bool b) +{ + const float f = float(b); + __retVal = mat4x3(f); +} + +mat4x3 __constructor(const vec3 c0, const vec3 c1, const vec3 c2, const vec3 c3) +{ + __retVal[0] = c0; + __retVal[1] = c1; + __retVal[2] = c2; + __retVal[3] = c3; +} + + + +//// misc assorted matrix constructors + +mat2 __constructor(const mat2 m) +{ + __retVal = m; +} + +mat2 __constructor(const mat3x2 m) +{ + __retVal = mat2(m[0], m[1]); +} + +mat2 __constructor(const mat4x2 m) +{ + __retVal = mat2(m[0], m[1]); +} + +mat2 __constructor(const mat2x3 m) +{ + __retVal = mat2(m[0].xy, m[1].xy); +} + +mat2 __constructor(const mat2x4 m) +{ + __retVal = mat2(m[0].xy, m[1].xy); +} + +mat2 __constructor(const mat3 m) +{ + __retVal = mat2(m[0].xy, m[1].xy); +} + +mat2 __constructor(const mat3x4 m) +{ + __retVal = mat2(m[0].xy, m[1].xy); +} + +mat2 __constructor(const mat4x3 m) +{ + __retVal = mat2(m[0].xy, m[1].xy); +} + +mat2 __constructor(const mat4 m) +{ + __retVal = mat2(m[0].xy, m[1].xy); +} + + + +mat2x3 __constructor(const mat2x3 m) +{ + __retVal = m; +} + +mat2x3 __constructor(const mat3 m) +{ + __retVal = mat2x3(m[0], m[1]); +} + +mat2x3 __constructor(const mat4x3 m) +{ + __retVal = mat2x3(m[0], m[1]); +} + +mat2x3 __constructor(const mat2x4 m) +{ + __retVal = mat2x3(m[0].xyz, m[1].xyz); +} + +mat2x3 __constructor(const mat3x4 m) +{ + __retVal = mat2x3(m[0].xyz, m[1].xyz); +} + +mat2x3 __constructor(const mat4 m) +{ + __retVal = mat2x3(m[0].xyz, m[1].xyz); +} + +mat2x3 __constructor(const mat2 m) +{ + __retVal = mat2x3(m[0].x, m[0].y, 0.0, + m[1].x, m[1].y, 0.0); +} + +mat2x3 __constructor(const mat3x2 m) +{ + __retVal = mat2x3(m[0].x, m[0].y, 0.0, + m[1].x, m[1].y, 0.0); +} + +mat2x3 __constructor(const mat4x2 m) +{ + __retVal = mat2x3(m[0].x, m[0].y, 0.0, + m[1].x, m[1].y, 0.0); +} + + + +mat2x4 __constructor(const mat2x4 m) +{ + __retVal = m; +} + +mat2x4 __constructor(const mat3x4 m) +{ + __retVal = mat2x4(m[0], m[1]); +} + +mat2x4 __constructor(const mat4 m) +{ + __retVal = mat2x4(m[0], m[1]); +} + +mat2x4 __constructor(const mat2x3 m) +{ + __retVal = mat2x4(m[0].x, m[0].y, m[0].z, 0.0, + m[1].x, m[1].y, m[1].z, 0.0); +} + +mat2x4 __constructor(const mat3 m) +{ + __retVal = mat2x4(m[0].x, m[0].y, m[0].z, 0.0, + m[1].x, m[1].y, m[1].z, 0.0); +} + +mat2x4 __constructor(const mat4x3 m) +{ + __retVal = mat2x4(m[0].x, m[0].y, m[0].z, 0.0, + m[1].x, m[1].y, m[1].z, 0.0); +} + +mat2x4 __constructor(const mat2 m) +{ + __retVal = mat2x4(m[0].x, m[1].y, 0.0, 0.0, + m[1].x, m[1].y, 0.0, 0.0); +} + +mat2x4 __constructor(const mat3x2 m) +{ + __retVal = mat2x4(m[0].x, m[0].y, 0.0, 0.0, + m[1].x, m[1].y, 0.0, 0.0); +} + +mat2x4 __constructor(const mat4x2 m) +{ + __retVal = mat2x4(m[0].x, m[0].y, 0.0, 0.0, + m[1].x, m[1].y, 0.0, 0.0); +} + + + +mat3x2 __constructor(const mat3x2 m) +{ + __retVal = m; +} + +mat3x2 __constructor(const mat4x2 m) +{ + __retVal = mat3x2(m[0], m[1], m[2]); +} + +mat3x2 __constructor(const mat3 m) +{ + __retVal = mat3x2(m[0], m[1], m[2]); +} + +mat3x2 __constructor(const mat3x4 m) +{ + __retVal = mat3x2(m[0].x, m[0].y, + m[1].x, m[1].y, + m[2].x, m[2].y); +} + +mat3x2 __constructor(const mat4x3 m) +{ + __retVal = mat3x2(m[0].x, m[0].y, + m[1].x, m[1].y, + m[2].x, m[2].y); +} + +mat3x2 __constructor(const mat4 m) +{ + __retVal = mat3x2(m[0].x, m[0].y, + m[1].x, m[1].y, + 0.0, 0.0); +} + +mat3x2 __constructor(const mat2 m) +{ + __retVal = mat3x2(m[0], m[1], vec2(0.0)); +} + +mat3x2 __constructor(const mat2x3 m) +{ + __retVal = mat3x2(m[0].x, m[0].y, + m[1].x, m[1].y, + 0.0, 0.0); +} + +mat3x2 __constructor(const mat2x4 m) +{ + __retVal = mat3x2(m[0].x, m[0].y, + m[1].x, m[1].y, + 0.0, 0.0); +} + + + + +mat3 __constructor(const mat3 m) +{ + __retVal = m; +} + +mat3 __constructor(const mat4x3 m) +{ + __retVal = mat3 ( + m[0], + m[1], + m[2] + ); +} + +mat3 __constructor(const mat3x4 m) +{ + __retVal = mat3 ( + m[0].xyz, + m[1].xyz, + m[2].xyz + ); +} + +mat3 __constructor(const mat4 m) +{ + __retVal = mat3 ( + m[0].xyz, + m[1].xyz, + m[2].xyz + ); +} + +mat3 __constructor(const mat2x3 m) +{ + __retVal = mat3 ( + m[0], + m[1], + 0., 0., 1. + ); +} + +mat3 __constructor(const mat2x4 m) +{ + __retVal = mat3 ( + m[0].xyz, + m[1].xyz, + 0., 0., 1. + ); +} + +mat3 __constructor(const mat3x2 m) +{ + __retVal = mat3 ( + m[0], 0., + m[1], 0., + m[2], 1. + ); +} + +mat3 __constructor(const mat4x2 m) +{ + __retVal = mat3 ( + m[0], 0., + m[1], 0., + m[2], 1. + ); +} + +mat3 __constructor(const mat2 m) +{ + __retVal = mat3 ( + m[0], 0., + m[1], 0., + 0., 0., 1. + ); +} + + +mat3x4 __constructor(const mat3x4 m) +{ + __retVal = m; +} + +mat3x4 __constructor(const mat4 m) +{ + __retVal = mat3x4 ( + m[0], + m[1], + m[2] + ); +} + +mat3x4 __constructor(const mat3 m) +{ + __retVal = mat3x4 ( + m[0], 0., + m[1], 0., + m[2], 0. + ); +} + +mat3x4 __constructor(const mat4x3 m) +{ + __retVal = mat3x4 ( + m[0], 0., + m[1], 0., + m[2], 0. + ); +} + +mat3x4 __constructor(const mat2x4 m) +{ + __retVal = mat3x4 ( + m[0], + m[1], + 0., 0., 1., 0. + ); +} + +mat3x4 __constructor(const mat2x3 m) +{ + __retVal = mat3x4 ( + m[0], 0., + m[1], 0., + 0., 0., 1., 0. + ); +} + +mat3x4 __constructor(const mat3x2 m) +{ + __retVal = mat3x4 ( + m[0], 0., 0., + m[1], 0., 0., + m[2], 1., 0. + ); +} + +mat3x4 __constructor(const mat4x2 m) +{ + __retVal = mat3x4 ( + m[0], 0., 0., + m[1], 0., 0., + m[2], 1., 0. + ); +} + +mat3x4 __constructor(const mat2 m) +{ + __retVal = mat3x4 ( + m[0], 0., 0., + m[1], 0., 0., + 0., 0., 1., 0. + ); +} + + +mat4x2 __constructor(const mat4x2 m) +{ + __retVal = m; +} + +mat4x2 __constructor(const mat4x3 m) +{ + __retVal = mat4x2 ( + m[0].xy, + m[1].xy, + m[2].xy, + m[3].xy + ); +} + +mat4x2 __constructor(const mat4 m) +{ + __retVal = mat4x2 ( + m[0].xy, + m[1].xy, + m[2].xy, + m[3].xy + ); +} + +mat4x2 __constructor(const mat3x2 m) +{ + __retVal = mat4x2 ( + m[0], + m[1], + 0., 0. + ); +} + +mat4x2 __constructor(const mat3 m) +{ + __retVal = mat4x2 ( + m[0].xy, + m[1].xy, + m[2].xy, + 0., 0. + ); +} + +mat4x2 __constructor(const mat3x4 m) +{ + __retVal = mat4x2 ( + m[0].xy, + m[1].xy, + m[2].xy, + 0., 0. + ); +} + +mat4x2 __constructor(const mat2 m) +{ + __retVal = mat4x2 ( + m[0], + m[1], + 0., 0., + 0., 0. + ); +} + +mat4x2 __constructor(const mat2x3 m) +{ + __retVal = mat4x2 ( + m[0].xy, + m[1].xy, + 0., 0., + 0., 0. + ); +} + +mat4x2 __constructor(const mat2x4 m) +{ + __retVal = mat4x2 ( + m[0].xy, + m[1].xy, + 0., 0., + 0., 0. + ); +} + + +mat4x3 __constructor(const mat4x3 m) +{ + __retVal = m; +} + +mat4x3 __constructor(const mat4 m) +{ + __retVal = mat4x3 ( + m[0].xyz, + m[1].xyz, + m[2].xyz, + m[3].xyz + ); +} + +mat4x3 __constructor(const mat3 m) +{ + __retVal = mat4x3 ( + m[0], + m[1], + m[2], + 0., 0., 0. + ); +} + +mat4x3 __constructor(const mat3x4 m) +{ + __retVal = mat4x3 ( + m[0].xyz, + m[1].xyz, + m[2].xyz, + 0., 0., 0. + ); +} + +mat4x3 __constructor(const mat4x2 m) +{ + __retVal = mat4x3 ( + m[0], 0., + m[1], 0., + m[2], 1., + m[3], 0. + ); +} + +mat4x3 __constructor(const mat2x3 m) +{ + __retVal = mat4x3 ( + m[0], + m[1], + 0., 0., 1., + 0., 0., 0. + ); +} + +mat4x3 __constructor(const mat3x2 m) +{ + __retVal = mat4x3 ( + m[0], 0., + m[1], 0., + m[2], 1., + 0., 0., 0. + ); +} + +mat4x3 __constructor(const mat2x4 m) +{ + __retVal = mat4x3 ( + m[0].xyz, + m[1].xyz, + 0., 0., 1., + 0., 0., 0. + ); +} + +mat4x3 __constructor(const mat2 m) +{ + __retVal = mat4x3 ( + m[0], 0., + m[1], 0., + 0., 0., 1., + 0., 0., 0. + ); +} + + +mat4 __constructor(const mat4 m) +{ + __retVal = m; +} + +mat4 __constructor(const mat3x4 m) +{ + __retVal = mat4 ( + m[0], + m[1], + m[2], + 0., 0., 0., 1. + ); +} + +mat4 __constructor(const mat4x3 m) +{ + __retVal = mat4 ( + m[0], 0., + m[1], 0., + m[2], 0., + m[3], 1. + ); +} + +mat4 __constructor(const mat2x4 m) +{ + __retVal = mat4 ( + m[0], + m[1], + 0., 0., 1., 0., + 0., 0., 0., 1. + ); +} + +mat4 __constructor(const mat4x2 m) +{ + __retVal = mat4 ( + m[0], 0., 0., + m[1], 0., 0., + m[2], 1., 0., + m[3], 0., 1. + ); +} + +mat4 __constructor(const mat3 m) +{ + __retVal = mat4 ( + m[0], 0., + m[1], 0., + m[2], 0., + 0., 0., 0., 1. + ); +} + +mat4 __constructor(const mat2x3 m) +{ + __retVal = mat4 ( + m[0], 0., + m[1], 0., + 0., 0., 1., 0., + 0., 0., 0., 1. + ); +} + +mat4 __constructor(const mat3x2 m) +{ + __retVal = mat4 ( + m[0], 0., 0., + m[1], 0., 0., + m[2], 1., 0., + 0., 0., 0., 1. + ); +} + +mat4 __constructor(const mat2 m) +{ + __retVal = mat4 ( + m[0], 0., 0., + m[1], 0., 0., + 0., 0., 1., 0., + 0., 0., 0., 1. + ); +} + + +void __operator += (inout mat2x3 m, const mat2x3 n) { + m[0] += n[0]; + m[1] += n[1]; +} + +void __operator += (inout mat2x4 m, const mat2x4 n) { + m[0] += n[0]; + m[1] += n[1]; +} + +void __operator += (inout mat3x2 m, const mat3x2 n) { + m[0] += n[0]; + m[1] += n[1]; + m[2] += n[2]; +} + +void __operator += (inout mat3x4 m, const mat3x4 n) { + m[0] += n[0]; + m[1] += n[1]; + m[2] += n[2]; +} + +void __operator += (inout mat4x2 m, const mat4x2 n) { + m[0] += n[0]; + m[1] += n[1]; + m[2] += n[2]; + m[3] += n[3]; +} + +void __operator += (inout mat4x3 m, const mat4x3 n) { + m[0] += n[0]; + m[1] += n[1]; + m[2] += n[2]; + m[3] += n[3]; +} + + +void __operator -= (inout mat2x3 m, const mat2x3 n) { + m[0] -= n[0]; + m[1] -= n[1]; +} + +void __operator -= (inout mat2x4 m, const mat2x4 n) { + m[0] -= n[0]; + m[1] -= n[1]; +} + +void __operator -= (inout mat3x2 m, const mat3x2 n) { + m[0] -= n[0]; + m[1] -= n[1]; + m[2] -= n[2]; +} + +void __operator -= (inout mat3x4 m, const mat3x4 n) { + m[0] -= n[0]; + m[1] -= n[1]; + m[2] -= n[2]; +} + +void __operator -= (inout mat4x2 m, const mat4x2 n) { + m[0] -= n[0]; + m[1] -= n[1]; + m[2] -= n[2]; + m[3] -= n[3]; +} + +void __operator -= (inout mat4x3 m, const mat4x3 n) { + m[0] -= n[0]; + m[1] -= n[1]; + m[2] -= n[2]; + m[3] -= n[3]; +} + + +void __operator /= (inout mat2x3 m, const mat2x3 n) { + m[0] /= n[0]; + m[1] /= n[1]; +} + +void __operator /= (inout mat2x4 m, const mat2x4 n) { + m[0] /= n[0]; + m[1] /= n[1]; +} + +void __operator /= (inout mat3x2 m, const mat3x2 n) { + m[0] /= n[0]; + m[1] /= n[1]; + m[2] /= n[2]; +} + +void __operator /= (inout mat3x4 m, const mat3x4 n) { + m[0] /= n[0]; + m[1] /= n[1]; + m[2] /= n[2]; +} + +void __operator /= (inout mat4x2 m, const mat4x2 n) { + m[0] /= n[0]; + m[1] /= n[1]; + m[2] /= n[2]; + m[3] /= n[3]; +} + +void __operator /= (inout mat4x3 m, const mat4x3 n) { + m[0] /= n[0]; + m[1] /= n[1]; + m[2] /= n[2]; + m[3] /= n[3]; +} + + +vec3 __operator * (const mat2x3 m, const vec2 v) +{ + __retVal.x = v.x * m[0].x + v.y * m[1].x; + __retVal.y = v.x * m[0].y + v.y * m[1].y; + __retVal.z = v.x * m[0].z + v.y * m[1].z; +} + +vec4 __operator * (const mat2x4 m, const vec2 v) +{ + __retVal.x = v.x * m[0].x + v.y * m[1].x; + __retVal.y = v.x * m[0].y + v.y * m[1].y; + __retVal.z = v.x * m[0].z + v.y * m[1].z; + __retVal.w = v.x * m[0].w + v.y * m[1].w; +} + +vec2 __operator * (const mat3x2 m, const vec3 v) +{ + __retVal.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x; + __retVal.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y; +} + +vec4 __operator * (const mat3x4 m, const vec3 v) +{ + __retVal.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x; + __retVal.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y; + __retVal.z = v.x * m[0].z + v.y * m[1].z + v.z * m[2].z; + __retVal.w = v.x * m[0].w + v.y * m[1].w + v.z * m[2].w; +} + +vec2 __operator * (const mat4x2 m, const vec4 v) +{ + __retVal.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x + v.w * m[3].x; + __retVal.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y + v.w * m[3].y; +} + +vec3 __operator * (const mat4x3 m, const vec4 v) +{ + __retVal.x = v.x * m[0].x + v.y * m[1].x + v.z * m[2].x + v.w * m[3].x; + __retVal.y = v.x * m[0].y + v.y * m[1].y + v.z * m[2].y + v.w * m[3].y; + __retVal.z = v.x * m[0].z + v.y * m[1].z + v.z * m[2].z + v.w * m[3].z; +} + + +mat3x2 __operator * (const mat2 m, const mat3x2 n) +{ + //return mat3x2 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + +mat4x2 __operator * (const mat2 m, const mat4x2 n) +{ + //return mat4x2 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2x3 __operator * (const mat2x3 m, const mat2 n) +{ + //return mat2x3 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat3 __operator * (const mat2x3 m, const mat3x2 n) +{ + //return mat3 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + +mat4x3 __operator * (const mat2x3 m, const mat4x2 n) +{ + //return mat4x3 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2x4 __operator * (const mat2x4 m, const mat2 n) +{ + //return mat2x4 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat3x4 __operator * (const mat2x4 m, const mat3x2 n) +{ + //return mat3x4 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + +mat4 __operator * (const mat2x4 m, const mat4x2 n) +{ + //return mat4 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2 __operator * (const mat3x2 m, const mat2x3 n) +{ + //return mat2 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat3x2 __operator * (const mat3x2 m, const mat3 n) +{ + //return mat3x2 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + +mat4x2 __operator * (const mat3x2 m, const mat4x3 n) +{ + //return mat4x2 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2x3 __operator * (const mat3 m, const mat2x3 n) +{ + //return mat2x3 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat4x3 __operator * (const mat3 m, const mat4x3 n) +{ + //return mat4x3 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2x4 __operator * (const mat3x4 m, const mat2x3 n) +{ + //return mat2x4 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat3x4 __operator * (const mat3x4 m, const mat3 n) +{ + //return mat3x4 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + +mat4 __operator * (const mat3x4 m, const mat4x3 n) +{ + //return mat4 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2 __operator * (const mat4x2 m, const mat2x4 n) +{ + //return = mat2 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat3x2 __operator * (const mat4x2 m, const mat3x4 n) +{ + //return mat3x2 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + +mat4x2 __operator * (const mat4x2 m, const mat4 n) +{ + //return mat4x2 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2x3 __operator * (const mat4x3 m, const mat2x4 n) +{ + //return mat2x3 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat3 __operator * (const mat4x3 m, const mat3x4 n) +{ + //return mat3 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + +mat4x3 __operator * (const mat4x3 m, const mat4 n) +{ + //return mat4x3 (m * n[0], m * n[1], m * n[2], m * n[3]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; + __retVal[3] = m * n[3]; +} + + +mat2x4 __operator * (const mat4 m, const mat2x4 n) +{ + //return mat2x4 (m * n[0], m * n[1]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; +} + +mat3x4 __operator * (const mat4 m, const mat3x4 n) +{ + //return mat3x4 (m * n[0], m * n[1], m * n[2]); + __retVal[0] = m * n[0]; + __retVal[1] = m * n[1]; + __retVal[2] = m * n[2]; +} + + +void __operator *= (inout mat2x3 m, const mat2 n) { + m = m * n; +} + +void __operator *= (inout mat2x4 m, const mat2 n) { + m = m * n; +} + +void __operator *= (inout mat3x2 m, const mat3 n) { + m = m * n; +} + +void __operator *= (inout mat3x4 m, const mat3 n) { + m = m * n; +} + +void __operator *= (inout mat4x2 m, const mat4 n) { + m = m * n; +} + +void __operator *= (inout mat4x3 m, const mat4 n) { + m = m * n; +} + + +vec3 __operator * (const vec2 v, const mat3x2 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); + __retVal.z = dot(v, m[2]); +} + +vec4 __operator * (const vec2 v, const mat4x2 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); + __retVal.z = dot(v, m[2]); + __retVal.w = dot(v, m[3]); +} + +vec2 __operator * (const vec3 v, const mat2x3 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); +} + +vec4 __operator * (const vec3 v, const mat4x3 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); + __retVal.z = dot(v, m[2]); + __retVal.w = dot(v, m[3]); +} + +vec2 __operator * (const vec4 v, const mat2x4 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); +} + +vec3 __operator * (const vec4 v, const mat3x4 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); + __retVal.z = dot(v, m[2]); +} + + +void __operator += (inout mat2x3 m, const float a) { + m[0] += a; + m[1] += a; +} + +void __operator += (inout mat2x4 m, const float a) { + m[0] += a; + m[1] += a; +} + +void __operator += (inout mat3x2 m, const float a) { + m[0] += a; + m[1] += a; + m[2] += a; +} + +void __operator += (inout mat3x4 m, const float a) { + m[0] += a; + m[1] += a; + m[2] += a; +} + +void __operator += (inout mat4x2 m, const float a) { + m[0] += a; + m[1] += a; + m[2] += a; + m[3] += a; +} + +void __operator += (inout mat4x3 m, const float a) { + m[0] += a; + m[1] += a; + m[2] += a; + m[3] += a; +} + + +void __operator -= (inout mat2x3 m, const float a) { + m[0] -= a; + m[1] -= a; +} + +void __operator -= (inout mat2x4 m, const float a) { + m[0] -= a; + m[1] -= a; +} + +void __operator -= (inout mat3x2 m, const float a) { + m[0] -= a; + m[1] -= a; + m[2] -= a; +} + +void __operator -= (inout mat3x4 m, const float a) { + m[0] -= a; + m[1] -= a; + m[2] -= a; +} + +void __operator -= (inout mat4x2 m, const float a) { + m[0] -= a; + m[1] -= a; + m[2] -= a; + m[3] -= a; +} + +void __operator -= (inout mat4x3 m, const float a) { + m[0] -= a; + m[1] -= a; + m[2] -= a; + m[3] -= a; +} + + +void __operator *= (inout mat2x3 m, const float a) { + m[0] *= a; + m[1] *= a; +} + +void __operator *= (inout mat2x4 m, const float a) { + m[0] *= a; + m[1] *= a; +} + +void __operator *= (inout mat3x2 m, const float a) { + m[0] *= a; + m[1] *= a; + m[2] *= a; +} + +void __operator *= (inout mat3x4 m, const float a) { + m[0] *= a; + m[1] *= a; + m[2] *= a; +} + +void __operator *= (inout mat4x2 m, const float a) { + m[0] *= a; + m[1] *= a; + m[2] *= a; + m[3] *= a; +} + +void __operator *= (inout mat4x3 m, const float a) { + m[0] *= a; + m[1] *= a; + m[2] *= a; + m[3] *= a; +} + + +void __operator /= (inout mat2x3 m, const float a) { + m[0] /= a; + m[1] /= a; +} + +void __operator /= (inout mat2x4 m, const float a) { + m[0] /= a; + m[1] /= a; +} + +void __operator /= (inout mat3x2 m, const float a) { + m[0] /= a; + m[1] /= a; + m[2] /= a; +} + +void __operator /= (inout mat3x4 m, const float a) { + m[0] /= a; + m[1] /= a; + m[2] /= a; +} + +void __operator /= (inout mat4x2 m, const float a) { + m[0] /= a; + m[1] /= a; + m[2] /= a; + m[3] /= a; +} + +void __operator /= (inout mat4x3 m, const float a) { + m[0] /= a; + m[1] /= a; + m[2] /= a; + m[3] /= a; +} + + +mat2x3 __operator + (const mat2x3 m, const mat2x3 n) { + return mat2x3 (m[0] + n[0], m[1] + n[1]); +} + +mat2x4 __operator + (const mat2x4 m, const mat2x4 n) { + return mat2x4 (m[0] + n[0], m[1] + n[1]); +} + +mat3x2 __operator + (const mat3x2 m, const mat3x2 n) { + return mat3x2 (m[0] + n[0], m[1] + n[1], m[2] + n[2]); +} + +mat3x4 __operator + (const mat3x4 m, const mat3x4 n) { + return mat3x4 (m[0] + n[0], m[1] + n[1], m[2] + n[2]); +} + +mat4x2 __operator + (const mat4x2 m, const mat4x2 n) { + return mat4x2 (m[0] + n[0], m[1] + n[1], m[2] + n[2], m[3] + n[3]); +} + +mat4x3 __operator + (const mat4x3 m, const mat4x3 n) { + return mat4x3 (m[0] + n[0], m[1] + n[1], m[2] + n[2], m[3] + n[3]); +} + + +mat2x3 __operator - (const mat2x3 m, const mat2x3 n) { + return mat2x3 (m[0] - n[0], m[1] - n[1]); +} + +mat2x4 __operator - (const mat2x4 m, const mat2x4 n) { + return mat2x4 (m[0] - n[0], m[1] - n[1]); +} + +mat3x2 __operator - (const mat3x2 m, const mat3x2 n) { + return mat3x2 (m[0] - n[0], m[1] - n[1], m[2] - n[2]); +} + +mat3x4 __operator - (const mat3x4 m, const mat3x4 n) { + return mat3x4 (m[0] - n[0], m[1] - n[1], m[2] - n[2]); +} + +mat4x2 __operator - (const mat4x2 m, const mat4x2 n) { + return mat4x2 (m[0] - n[0], m[1] - n[1], m[2] - n[2], m[3] - n[3]); +} + +mat4x3 __operator - (const mat4x3 m, const mat4x3 n) { + return mat4x3 (m[0] - n[0], m[1] - n[1], m[2] - n[2], m[3] - n[3]); +} + + +mat2x3 __operator / (const mat2x3 m, const mat2x3 n) { + return mat2x3 (m[0] / n[0], m[1] / n[1]); +} + +mat2x4 __operator / (const mat2x4 m, const mat2x4 n) { + return mat2x4 (m[0] / n[0], m[1] / n[1]); +} + +mat3x2 __operator / (const mat3x2 m, const mat3x2 n) { + return mat3x2 (m[0] / n[0], m[1] / n[1], m[2] / n[2]); +} + +mat3x4 __operator / (const mat3x4 m, const mat3x4 n) { + return mat3x4 (m[0] / n[0], m[1] / n[1], m[2] / n[2]); +} + +mat4x2 __operator / (const mat4x2 m, const mat4x2 n) { + return mat4x2 (m[0] / n[0], m[1] / n[1], m[2] / n[2], m[3] / n[3]); +} + +mat4x3 __operator / (const mat4x3 m, const mat4x3 n) { + return mat4x3 (m[0] / n[0], m[1] / n[1], m[2] / n[2], m[3] / n[3]); +} + + +mat2x3 __operator + (const float a, const mat2x3 n) { + return mat2x3 (a + n[0], a + n[1]); +} + +mat2x3 __operator + (const mat2x3 m, const float b) { + return mat2x3 (m[0] + b, m[1] + b); +} + +mat2x4 __operator + (const float a, const mat2x4 n) { + return mat2x4 (a + n[0], a + n[1]); +} + +mat2x4 __operator + (const mat2x4 m, const float b) { + return mat2x4 (m[0] + b, m[1] + b); +} + +mat3x2 __operator + (const float a, const mat3x2 n) { + return mat3x2 (a + n[0], a + n[1], a + n[2]); +} + +mat3x2 __operator + (const mat3x2 m, const float b) { + return mat3x2 (m[0] + b, m[1] + b, m[2] + b); +} + +mat3x4 __operator + (const float a, const mat3x4 n) { + return mat3x4 (a + n[0], a + n[1], a + n[2]); +} + +mat3x4 __operator + (const mat3x4 m, const float b) { + return mat3x4 (m[0] + b, m[1] + b, m[2] + b); +} + +mat4x2 __operator + (const mat4x2 m, const float b) { + return mat4x2 (m[0] + b, m[1] + b, m[2] + b, m[3] + b); +} + +mat4x2 __operator + (const float a, const mat4x2 n) { + return mat4x2 (a + n[0], a + n[1], a + n[2], a + n[3]); +} + +mat4x3 __operator + (const mat4x3 m, const float b) { + return mat4x3 (m[0] + b, m[1] + b, m[2] + b, m[3] + b); +} + +mat4x3 __operator + (const float a, const mat4x3 n) { + return mat4x3 (a + n[0], a + n[1], a + n[2], a + n[3]); +} + + +mat2x3 __operator - (const float a, const mat2x3 n) { + return mat2x3 (a - n[0], a - n[1]); +} + +mat2x3 __operator - (const mat2x3 m, const float b) { + return mat2x3 (m[0] - b, m[1] - b); +} + +mat2x4 __operator - (const float a, const mat2x4 n) { + return mat2x4 (a - n[0], a - n[1]); +} + +mat2x4 __operator - (const mat2x4 m, const float b) { + return mat2x4 (m[0] - b, m[1] - b); +} + +mat3x2 __operator - (const float a, const mat3x2 n) { + return mat3x2 (a - n[0], a - n[1], a - n[2]); +} + +mat3x2 __operator - (const mat3x2 m, const float b) { + return mat3x2 (m[0] - b, m[1] - b, m[2] - b); +} + +mat3x4 __operator - (const float a, const mat3x4 n) { + return mat3x4 (a - n[0], a - n[1], a - n[2]); +} + +mat3x4 __operator - (const mat3x4 m, const float b) { + return mat3x4 (m[0] - b, m[1] - b, m[2] - b); +} + +mat4x2 __operator - (const mat4x2 m, const float b) { + return mat4x2 (m[0] - b, m[1] - b, m[2] - b, m[3] - b); +} + +mat4x2 __operator - (const float a, const mat4x2 n) { + return mat4x2 (a - n[0], a - n[1], a - n[2], a - n[3]); +} + +mat4x3 __operator - (const mat4x3 m, const float b) { + return mat4x3 (m[0] - b, m[1] - b, m[2] - b, m[3] - b); +} + +mat4x3 __operator - (const float a, const mat4x3 n) { + return mat4x3 (a - n[0], a - n[1], a - n[2], a - n[3]); +} + + +mat2x3 __operator * (const float a, const mat2x3 n) +{ + //return mat2x3 (a * n[0], a * n[1]); + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; +} + +mat2x3 __operator * (const mat2x3 m, const float b) +{ + //return mat2x3 (m[0] * b, m[1] * b); + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; +} + +mat2x4 __operator * (const float a, const mat2x4 n) +{ + //return mat2x4 (a * n[0], a * n[1]); + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; +} + +mat2x4 __operator * (const mat2x4 m, const float b) +{ + //return mat2x4 (m[0] * b, m[1] * b); + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; +} + +mat3x2 __operator * (const float a, const mat3x2 n) +{ + //return mat3x2 (a * n[0], a * n[1], a * n[2]); + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; + __retVal[2] = a * n[2]; +} + +mat3x2 __operator * (const mat3x2 m, const float b) +{ + //return mat3x2 (m[0] * b, m[1] * b, m[2] * b); + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; + __retVal[2] = m[2] * b; +} + +mat3x4 __operator * (const float a, const mat3x4 n) +{ + //return mat3x4 (a * n[0], a * n[1], a * n[2]); + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; + __retVal[2] = a * n[2]; +} + +mat3x4 __operator * (const mat3x4 m, const float b) +{ + //return mat3x4 (m[0] * b, m[1] * b, m[2] * b); + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; + __retVal[2] = m[2] * b; +} + +mat4x2 __operator * (const mat4x2 m, const float b) +{ + //return mat4x2 (m[0] * b, m[1] * b, m[2] * b, m[3] * b); + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; + __retVal[2] = m[2] * b; + __retVal[3] = m[3] * b; +} + +mat4x2 __operator * (const float a, const mat4x2 n) +{ + //return mat4x2 (a * n[0], a * n[1], a * n[2], a * n[3]); + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; + __retVal[2] = a * n[2]; + __retVal[3] = a * n[3]; +} + +mat4x3 __operator * (const mat4x3 m, const float b) +{ + //return mat4x3 (m[0] * b, m[1] * b, m[2] * b, m[3] * b); + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; + __retVal[2] = m[2] * b; + __retVal[3] = m[3] * b; +} + +mat4x3 __operator * (const float a, const mat4x3 n) +{ + //return mat4x3 (a * n[0], a * n[1], a * n[2], a * n[3]); + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; + __retVal[2] = a * n[2]; + __retVal[3] = a * n[3]; +} + + +mat2x3 __operator / (const float a, const mat2x3 n) +{ + //return mat2x3 (a / n[0], a / n[1]); + const float inv = 1.0 / a; + __retVal[0] = inv * n[0]; + __retVal[1] = inv * n[1]; +} + +mat2x3 __operator / (const mat2x3 m, const float b) +{ + //return mat2x3 (m[0] / b, m[1] / b); + const float inv = 1.0 / b; + __retVal[0] = m[0] * inv; + __retVal[1] = m[1] * inv; +} + +mat2x4 __operator / (const float a, const mat2x4 n) +{ + //return mat2x4 (a / n[0], a / n[1]); + const float inv = 1.0 / a; + __retVal[0] = inv * n[0]; + __retVal[1] = inv * n[1]; +} + +mat2x4 __operator / (const mat2x4 m, const float b) +{ + //return mat2x4 (m[0] / b, m[1] / b); + const float inv = 1.0 / b; + __retVal[0] = m[0] * inv; + __retVal[1] = m[1] * inv; +} + +mat3x2 __operator / (const float a, const mat3x2 n) +{ + //return mat3x2 (a / n[0], a / n[1], a / n[2]); + const float inv = 1.0 / a; + __retVal[0] = inv * n[0]; + __retVal[1] = inv * n[1]; + __retVal[2] = inv * n[2]; +} + +mat3x2 __operator / (const mat3x2 m, const float b) +{ + //return mat3x2 (m[0] / b, m[1] / b, m[2] / b); + const float inv = 1.0 / b; + __retVal[0] = m[0] * inv; + __retVal[1] = m[1] * inv; + __retVal[2] = m[2] * inv; +} + +mat3x4 __operator / (const float a, const mat3x4 n) +{ + //return mat3x4 (a / n[0], a / n[1], a / n[2]); + const float inv = 1.0 / a; + __retVal[0] = inv * n[0]; + __retVal[1] = inv * n[1]; + __retVal[2] = inv * n[2]; +} + +mat3x4 __operator / (const mat3x4 m, const float b) +{ + //return mat3x4 (m[0] / b, m[1] / b, m[2] / b); + const float inv = 1.0 / b; + __retVal[0] = m[0] * inv; + __retVal[1] = m[1] * inv; + __retVal[2] = m[2] * inv; +} + +mat4x2 __operator / (const mat4x2 m, const float b) +{ + //return mat4x2 (m[0] / b, m[1] / b, m[2] / b, m[3] / b); + const float inv = 1.0 / b; + __retVal[0] = m[0] * inv; + __retVal[1] = m[1] * inv; + __retVal[2] = m[2] * inv; + __retVal[3] = m[3] * inv; +} + +mat4x2 __operator / (const float a, const mat4x2 n) +{ + //return mat4x2 (a / n[0], a / n[1], a / n[2], a / n[3]); + const float inv = 1.0 / a; + __retVal[0] = inv * n[0]; + __retVal[1] = inv * n[1]; + __retVal[2] = inv * n[2]; + __retVal[3] = inv * n[3]; +} + +mat4x3 __operator / (const mat4x3 m, const float b) +{ + //return mat4x3 (m[0] / b, m[1] / b, m[2] / b, m[3] / b); + const float inv = 1.0 / b; + __retVal[0] = m[0] * inv; + __retVal[1] = m[1] * inv; + __retVal[2] = m[2] * inv; + __retVal[3] = m[3] * inv; +} + +mat4x3 __operator / (const float a, const mat4x3 n) +{ + //return mat4x3 (a / n[0], a / n[1], a / n[2], a / n[3]); + const float inv = 1.0 / a; + __retVal[0] = inv * n[0]; + __retVal[1] = inv * n[1]; + __retVal[2] = inv * n[2]; + __retVal[3] = inv * n[3]; +} + + +mat2x3 __operator - (const mat2x3 m) { + return mat2x3 (-m[0], -m[1]); +} + +mat2x4 __operator - (const mat2x4 m) { + return mat2x4 (-m[0], -m[1]); +} + +mat3x2 __operator - (const mat3x2 m) { + return mat3x2 (-m[0], -m[1], -m[2]); +} + +mat3x4 __operator - (const mat3x4 m) { + return mat3x4 (-m[0], -m[1], -m[2]); +} + +mat4x2 __operator - (const mat4x2 m) { + return mat4x2 (-m[0], -m[1], -m[2], -m[3]); +} + +mat4x3 __operator - (const mat4x3 m) { + return mat4x3 (-m[0], -m[1], -m[2], -m[3]); +} + + +void __operator -- (inout mat2x3 m) { + --m[0]; + --m[1]; +} + +void __operator -- (inout mat2x4 m) { + --m[0]; + --m[1]; +} + +void __operator -- (inout mat3x2 m) { + --m[0]; + --m[1]; + --m[2]; +} + +void __operator -- (inout mat3x4 m) { + --m[0]; + --m[1]; + --m[2]; +} + +void __operator -- (inout mat4x2 m) { + --m[0]; + --m[1]; + --m[2]; + --m[3]; +} + +void __operator -- (inout mat4x3 m) { + --m[0]; + --m[1]; + --m[2]; + --m[3]; +} + + +void __operator ++ (inout mat2x3 m) { + ++m[0]; + ++m[1]; +} + +void __operator ++ (inout mat2x4 m) { + ++m[0]; + ++m[1]; +} + +void __operator ++ (inout mat3x2 m) { + ++m[0]; + ++m[1]; + ++m[2]; +} + +void __operator ++ (inout mat3x4 m) { + ++m[0]; + ++m[1]; + ++m[2]; +} + +void __operator ++ (inout mat4x2 m) { + ++m[0]; + ++m[1]; + ++m[2]; + ++m[3]; +} + +void __operator ++ (inout mat4x3 m) { + ++m[0]; + ++m[1]; + ++m[2]; + ++m[3]; +} + diff --git a/mesalib/src/mesa/shader/slang/library/slang_120_core_gc.h b/mesalib/src/mesa/shader/slang/library/slang_120_core_gc.h new file mode 100644 index 000000000..1fdbddf7c --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_120_core_gc.h @@ -0,0 +1,764 @@ + +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */ +/* slang_120_core.gc */ + +5,1,90,95,0,0,26,0,1,1,1,0,0,9,0,102,48,48,0,0,1,1,0,0,9,0,102,49,48,0,0,1,1,0,0,9,0,102,50,48,0,0, +1,1,0,0,9,0,102,48,49,0,0,1,1,0,0,9,0,102,49,49,0,0,1,1,0,0,9,0,102,50,49,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,16,8,48,0,57,59,120,0,18,102,48,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0, +16,8,48,0,57,59,121,0,18,102,49,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,59,122,0, +18,102,50,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,120,0,18,102,48,49,0,20,0, +9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,121,0,18,102,49,49,0,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,49,0,57,59,122,0,18,102,50,49,0,20,0,0,1,90,95,0,0,26,0,1,1,1,0,0,9,0,102,0, +0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,50,120,51,0,0,18,102,0,0,17,48,0,48,0,0,0, +17,48,0,48,0,0,0,17,48,0,48,0,0,0,18,102,0,0,17,48,0,48,0,0,0,0,20,0,0,1,90,95,0,0,26,0,1,1,1,0,0, +5,0,105,0,0,0,1,3,2,90,95,1,0,9,0,1,102,0,2,58,102,108,111,97,116,0,0,18,105,0,0,0,0,0,9,18,95,95, +114,101,116,86,97,108,0,58,109,97,116,50,120,51,0,0,18,102,0,0,0,20,0,0,1,90,95,0,0,26,0,1,1,1,0,0, +1,0,98,0,0,0,1,3,2,90,95,1,0,9,0,1,102,0,2,58,102,108,111,97,116,0,0,18,98,0,0,0,0,0,9,18,95,95, +114,101,116,86,97,108,0,58,109,97,116,50,120,51,0,0,18,102,0,0,0,20,0,0,1,90,95,0,0,26,0,1,1,1,0,0, +11,0,99,48,0,0,1,1,0,0,11,0,99,49,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,99,48, +0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,99,49,0,20,0,0,1,90,95,0,0,28,0,1,1,1,0, +0,9,0,102,48,48,0,0,1,1,0,0,9,0,102,49,48,0,0,1,1,0,0,9,0,102,50,48,0,0,1,1,0,0,9,0,102,51,48,0,0, +1,1,0,0,9,0,102,48,49,0,0,1,1,0,0,9,0,102,49,49,0,0,1,1,0,0,9,0,102,50,49,0,0,1,1,0,0,9,0,102,51, +49,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,59,120,0,18,102,48,48,0,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,8,48,0,57,59,121,0,18,102,49,48,0,20,0,9,18,95,95,114,101,116,86,97,108, +0,16,8,48,0,57,59,122,0,18,102,50,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,59,119, +0,18,102,51,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,120,0,18,102,48,49,0,20, +0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,121,0,18,102,49,49,0,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,49,0,57,59,122,0,18,102,50,49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16, +10,49,0,57,59,119,0,18,102,51,49,0,20,0,0,1,90,95,0,0,28,0,1,1,1,0,0,9,0,102,0,0,0,1,9,18,95,95, +114,101,116,86,97,108,0,58,109,97,116,50,120,52,0,0,18,102,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0, +17,48,0,48,0,0,0,17,48,0,48,0,0,0,18,102,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,0,20,0,0,1,90,95,0, +0,28,0,1,1,1,0,0,5,0,105,0,0,0,1,3,2,90,95,1,0,9,0,1,102,0,2,58,102,108,111,97,116,0,0,18,105,0,0, +0,0,0,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,50,120,52,0,0,18,102,0,0,0,20,0,0,1,90,95,0, +0,28,0,1,1,1,0,0,1,0,98,0,0,0,1,3,2,90,95,1,0,9,0,1,102,0,2,58,102,108,111,97,116,0,0,18,98,0,0,0, +0,0,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,50,120,52,0,0,18,102,0,0,0,20,0,0,1,90,95,0,0, +28,0,1,1,1,0,0,12,0,99,48,0,0,1,1,0,0,12,0,99,49,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8, +48,0,57,18,99,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,99,49,0,20,0,0,1,90,95, +0,0,27,0,1,1,1,0,0,9,0,102,48,48,0,0,1,1,0,0,9,0,102,49,48,0,0,1,1,0,0,9,0,102,48,49,0,0,1,1,0,0,9, +0,102,49,49,0,0,1,1,0,0,9,0,102,48,50,0,0,1,1,0,0,9,0,102,49,50,0,0,0,1,9,18,95,95,114,101,116,86, +97,108,0,16,8,48,0,57,59,120,0,18,102,48,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57, +59,121,0,18,102,49,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,120,0,18,102,48, +49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,121,0,18,102,49,49,0,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,50,0,57,59,120,0,18,102,48,50,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,10,50,0,57,59,121,0,18,102,49,50,0,20,0,0,1,90,95,0,0,27,0,1,1,1,0,0,9,0,102,0,0,0,1,9,18, +95,95,114,101,116,86,97,108,0,58,109,97,116,51,120,50,0,0,18,102,0,0,17,48,0,48,0,0,0,17,48,0,48,0, +0,0,18,102,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,0,20,0,0,1,90,95,0,0,27,0,1,1,1,0,0,5,0,105,0,0,0, +1,3,2,90,95,1,0,9,0,1,102,0,2,58,102,108,111,97,116,0,0,18,105,0,0,0,0,0,9,18,95,95,114,101,116,86, +97,108,0,58,109,97,116,51,120,50,0,0,18,102,0,0,0,20,0,0,1,90,95,0,0,27,0,1,1,1,0,0,1,0,98,0,0,0,1, +3,2,90,95,1,0,9,0,1,102,0,2,58,102,108,111,97,116,0,0,18,98,0,0,0,0,0,9,18,95,95,114,101,116,86,97, +108,0,58,109,97,116,51,120,50,0,0,18,102,0,0,0,20,0,0,1,90,95,0,0,27,0,1,1,1,0,0,10,0,99,48,0,0,1, +1,0,0,10,0,99,49,0,0,1,1,0,0,10,0,99,50,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18, +99,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,99,49,0,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,50,0,57,18,99,50,0,20,0,0,1,90,95,0,0,30,0,1,1,1,0,0,9,0,102,48,48,0,0,1,1,0, +0,9,0,102,49,48,0,0,1,1,0,0,9,0,102,50,48,0,0,1,1,0,0,9,0,102,51,48,0,0,1,1,0,0,9,0,102,48,49,0,0, +1,1,0,0,9,0,102,49,49,0,0,1,1,0,0,9,0,102,50,49,0,0,1,1,0,0,9,0,102,51,49,0,0,1,1,0,0,9,0,102,48, +50,0,0,1,1,0,0,9,0,102,49,50,0,0,1,1,0,0,9,0,102,50,50,0,0,1,1,0,0,9,0,102,51,50,0,0,0,1,9,18,95, +95,114,101,116,86,97,108,0,16,8,48,0,57,59,120,0,18,102,48,48,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,8,48,0,57,59,121,0,18,102,49,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,59, +122,0,18,102,50,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,59,119,0,18,102,51,48,0, +20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,120,0,18,102,48,49,0,20,0,9,18,95,95,114, +101,116,86,97,108,0,16,10,49,0,57,59,121,0,18,102,49,49,0,20,0,9,18,95,95,114,101,116,86,97,108,0, +16,10,49,0,57,59,122,0,18,102,50,49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,119, +0,18,102,51,49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,59,120,0,18,102,48,50,0,20, +0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,59,121,0,18,102,49,50,0,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,50,0,57,59,122,0,18,102,50,50,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16, +10,50,0,57,59,119,0,18,102,51,50,0,20,0,0,1,90,95,0,0,30,0,1,1,1,0,0,9,0,102,0,0,0,1,9,18,95,95, +114,101,116,86,97,108,0,58,109,97,116,51,120,52,0,0,18,102,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0, +17,48,0,48,0,0,0,17,48,0,48,0,0,0,18,102,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,17, +48,0,48,0,0,0,18,102,0,0,17,48,0,48,0,0,0,0,20,0,0,1,90,95,0,0,30,0,1,1,1,0,0,5,0,105,0,0,0,1,3,2, +90,95,1,0,9,0,1,102,0,2,58,102,108,111,97,116,0,0,18,105,0,0,0,0,0,9,18,95,95,114,101,116,86,97, +108,0,58,109,97,116,51,120,52,0,0,18,102,0,0,0,20,0,0,1,90,95,0,0,30,0,1,1,1,0,0,1,0,98,0,0,0,1,3, +2,90,95,1,0,9,0,1,102,0,2,58,102,108,111,97,116,0,0,18,98,0,0,0,0,0,9,18,95,95,114,101,116,86,97, +108,0,58,109,97,116,51,120,52,0,0,18,102,0,0,0,20,0,0,1,90,95,0,0,30,0,1,1,1,0,0,12,0,99,48,0,0,1, +1,0,0,12,0,99,49,0,0,1,1,0,0,12,0,99,50,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18, +99,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,99,49,0,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,50,0,57,18,99,50,0,20,0,0,1,90,95,0,0,29,0,1,1,1,0,0,9,0,102,48,48,0,0,1,1,0, +0,9,0,102,49,48,0,0,1,1,0,0,9,0,102,48,49,0,0,1,1,0,0,9,0,102,49,49,0,0,1,1,0,0,9,0,102,48,50,0,0, +1,1,0,0,9,0,102,49,50,0,0,1,1,0,0,9,0,102,48,51,0,0,1,1,0,0,9,0,102,49,51,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,16,8,48,0,57,59,120,0,18,102,48,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0, +16,8,48,0,57,59,121,0,18,102,49,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,120, +0,18,102,48,49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,121,0,18,102,49,49,0,20, +0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,59,120,0,18,102,48,50,0,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,50,0,57,59,121,0,18,102,49,50,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16, +10,51,0,57,59,120,0,18,102,48,51,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,59,121,0, +18,102,49,51,0,20,0,0,1,90,95,0,0,29,0,1,1,1,0,0,9,0,102,0,0,0,1,9,18,95,95,114,101,116,86,97,108, +0,58,109,97,116,52,120,50,0,0,18,102,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,16,10,52,0,0,17,48,0,48, +0,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,0,20,0,0,1,90,95,0,0,29,0,1,1,1,0,0,5,0, +105,0,0,0,1,3,2,90,95,1,0,9,0,1,102,0,2,58,102,108,111,97,116,0,0,18,105,0,0,0,0,0,9,18,95,95,114, +101,116,86,97,108,0,58,109,97,116,52,120,50,0,0,18,102,0,0,0,20,0,0,1,90,95,0,0,29,0,1,1,1,0,0,1,0, +98,0,0,0,1,3,2,90,95,1,0,9,0,1,102,0,2,58,102,108,111,97,116,0,0,18,98,0,0,0,0,0,9,18,95,95,114, +101,116,86,97,108,0,58,109,97,116,52,120,50,0,0,18,102,0,0,0,20,0,0,1,90,95,0,0,29,0,1,1,1,0,0,10, +0,99,48,0,0,1,1,0,0,10,0,99,49,0,0,1,1,0,0,10,0,99,50,0,0,1,1,0,0,10,0,99,51,0,0,0,1,9,18,95,95, +114,101,116,86,97,108,0,16,8,48,0,57,18,99,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0, +57,18,99,49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,99,50,0,20,0,9,18,95,95,114, +101,116,86,97,108,0,16,10,51,0,57,18,99,51,0,20,0,0,1,90,95,0,0,31,0,1,1,1,0,0,9,0,102,48,48,0,0,1, +1,0,0,9,0,102,49,48,0,0,1,1,0,0,9,0,102,50,48,0,0,1,1,0,0,9,0,102,48,49,0,0,1,1,0,0,9,0,102,49,49, +0,0,1,1,0,0,9,0,102,50,49,0,0,1,1,0,0,9,0,102,48,50,0,0,1,1,0,0,9,0,102,49,50,0,0,1,1,0,0,9,0,102, +50,50,0,0,1,1,0,0,9,0,102,48,51,0,0,1,1,0,0,9,0,102,49,51,0,0,1,1,0,0,9,0,102,50,51,0,0,0,1,9,18, +95,95,114,101,116,86,97,108,0,16,8,48,0,57,59,120,0,18,102,48,48,0,20,0,9,18,95,95,114,101,116,86, +97,108,0,16,8,48,0,57,59,121,0,18,102,49,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57, +59,122,0,18,102,50,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,120,0,18,102,48, +49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,121,0,18,102,49,49,0,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,49,0,57,59,122,0,18,102,50,49,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,10,50,0,57,59,120,0,18,102,48,50,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57, +59,121,0,18,102,49,50,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,59,122,0,18,102,50, +50,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,59,120,0,18,102,48,51,0,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,51,0,57,59,121,0,18,102,49,51,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,10,51,0,57,59,122,0,18,102,50,51,0,20,0,0,1,90,95,0,0,31,0,1,1,1,0,0,9,0,102,0,0,0,1,9,18, +95,95,114,101,116,86,97,108,0,58,109,97,116,52,120,51,0,0,18,102,0,0,17,48,0,48,0,0,0,17,48,0,48,0, +0,0,17,48,0,48,0,0,0,18,102,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,18,102,0,0,17, +48,0,48,0,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,0,20,0,0,1,90,95,0,0,31,0,1,1,1,0,0,5,0,105,0,0,0, +1,3,2,90,95,1,0,9,0,1,102,0,2,58,102,108,111,97,116,0,0,18,105,0,0,0,0,0,9,18,95,95,114,101,116,86, +97,108,0,58,109,97,116,52,120,51,0,0,18,102,0,0,0,20,0,0,1,90,95,0,0,31,0,1,1,1,0,0,1,0,98,0,0,0,1, +3,2,90,95,1,0,9,0,1,102,0,2,58,102,108,111,97,116,0,0,18,98,0,0,0,0,0,9,18,95,95,114,101,116,86,97, +108,0,58,109,97,116,52,120,51,0,0,18,102,0,0,0,20,0,0,1,90,95,0,0,31,0,1,1,1,0,0,11,0,99,48,0,0,1, +1,0,0,11,0,99,49,0,0,1,1,0,0,11,0,99,50,0,0,1,1,0,0,11,0,99,51,0,0,0,1,9,18,95,95,114,101,116,86, +97,108,0,16,8,48,0,57,18,99,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,99,49,0, +20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,99,50,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,10,51,0,57,18,99,51,0,20,0,0,1,90,95,0,0,13,0,1,1,1,0,0,13,0,109,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,18,109,0,20,0,0,1,90,95,0,0,13,0,1,1,1,0,0,27,0,109,0,0,0,1,9,18,95,95,114,101, +116,86,97,108,0,58,109,97,116,50,0,0,18,109,0,16,8,48,0,57,0,18,109,0,16,10,49,0,57,0,0,20,0,0,1, +90,95,0,0,13,0,1,1,1,0,0,29,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,50,0,0, +18,109,0,16,8,48,0,57,0,18,109,0,16,10,49,0,57,0,0,20,0,0,1,90,95,0,0,13,0,1,1,1,0,0,26,0,109,0,0, +0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,50,0,0,18,109,0,16,8,48,0,57,59,120,121,0,0, +18,109,0,16,10,49,0,57,59,120,121,0,0,0,20,0,0,1,90,95,0,0,13,0,1,1,1,0,0,28,0,109,0,0,0,1,9,18,95, +95,114,101,116,86,97,108,0,58,109,97,116,50,0,0,18,109,0,16,8,48,0,57,59,120,121,0,0,18,109,0,16, +10,49,0,57,59,120,121,0,0,0,20,0,0,1,90,95,0,0,13,0,1,1,1,0,0,14,0,109,0,0,0,1,9,18,95,95,114,101, +116,86,97,108,0,58,109,97,116,50,0,0,18,109,0,16,8,48,0,57,59,120,121,0,0,18,109,0,16,10,49,0,57, +59,120,121,0,0,0,20,0,0,1,90,95,0,0,13,0,1,1,1,0,0,30,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97, +108,0,58,109,97,116,50,0,0,18,109,0,16,8,48,0,57,59,120,121,0,0,18,109,0,16,10,49,0,57,59,120,121, +0,0,0,20,0,0,1,90,95,0,0,13,0,1,1,1,0,0,31,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109, +97,116,50,0,0,18,109,0,16,8,48,0,57,59,120,121,0,0,18,109,0,16,10,49,0,57,59,120,121,0,0,0,20,0,0, +1,90,95,0,0,13,0,1,1,1,0,0,15,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,50,0, +0,18,109,0,16,8,48,0,57,59,120,121,0,0,18,109,0,16,10,49,0,57,59,120,121,0,0,0,20,0,0,1,90,95,0,0, +26,0,1,1,1,0,0,26,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,0,1,90,95,0,0,26, +0,1,1,1,0,0,14,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,50,120,51,0,0,18,109, +0,16,8,48,0,57,0,18,109,0,16,10,49,0,57,0,0,20,0,0,1,90,95,0,0,26,0,1,1,1,0,0,31,0,109,0,0,0,1,9, +18,95,95,114,101,116,86,97,108,0,58,109,97,116,50,120,51,0,0,18,109,0,16,8,48,0,57,0,18,109,0,16, +10,49,0,57,0,0,20,0,0,1,90,95,0,0,26,0,1,1,1,0,0,28,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108, +0,58,109,97,116,50,120,51,0,0,18,109,0,16,8,48,0,57,59,120,121,122,0,0,18,109,0,16,10,49,0,57,59, +120,121,122,0,0,0,20,0,0,1,90,95,0,0,26,0,1,1,1,0,0,30,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97, +108,0,58,109,97,116,50,120,51,0,0,18,109,0,16,8,48,0,57,59,120,121,122,0,0,18,109,0,16,10,49,0,57, +59,120,121,122,0,0,0,20,0,0,1,90,95,0,0,26,0,1,1,1,0,0,15,0,109,0,0,0,1,9,18,95,95,114,101,116,86, +97,108,0,58,109,97,116,50,120,51,0,0,18,109,0,16,8,48,0,57,59,120,121,122,0,0,18,109,0,16,10,49,0, +57,59,120,121,122,0,0,0,20,0,0,1,90,95,0,0,26,0,1,1,1,0,0,13,0,109,0,0,0,1,9,18,95,95,114,101,116, +86,97,108,0,58,109,97,116,50,120,51,0,0,18,109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59, +121,0,0,17,48,0,48,0,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,121,0,0,17,48, +0,48,0,0,0,0,20,0,0,1,90,95,0,0,26,0,1,1,1,0,0,27,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0, +58,109,97,116,50,120,51,0,0,18,109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59,121,0,0,17, +48,0,48,0,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,121,0,0,17,48,0,48,0,0,0, +0,20,0,0,1,90,95,0,0,26,0,1,1,1,0,0,29,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97, +116,50,120,51,0,0,18,109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59,121,0,0,17,48,0,48,0,0, +0,18,109,0,16,10,49,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,121,0,0,17,48,0,48,0,0,0,0,20,0,0,1, +90,95,0,0,28,0,1,1,1,0,0,28,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,0,1,90, +95,0,0,28,0,1,1,1,0,0,30,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,50,120,52, +0,0,18,109,0,16,8,48,0,57,0,18,109,0,16,10,49,0,57,0,0,20,0,0,1,90,95,0,0,28,0,1,1,1,0,0,15,0,109, +0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,50,120,52,0,0,18,109,0,16,8,48,0,57,0,18, +109,0,16,10,49,0,57,0,0,20,0,0,1,90,95,0,0,28,0,1,1,1,0,0,26,0,109,0,0,0,1,9,18,95,95,114,101,116, +86,97,108,0,58,109,97,116,50,120,52,0,0,18,109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59, +121,0,0,18,109,0,16,8,48,0,57,59,122,0,0,17,48,0,48,0,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18,109, +0,16,10,49,0,57,59,121,0,0,18,109,0,16,10,49,0,57,59,122,0,0,17,48,0,48,0,0,0,0,20,0,0,1,90,95,0,0, +28,0,1,1,1,0,0,14,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,50,120,52,0,0,18, +109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59,121,0,0,18,109,0,16,8,48,0,57,59,122,0,0,17, +48,0,48,0,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,121,0,0,18,109,0,16,10, +49,0,57,59,122,0,0,17,48,0,48,0,0,0,0,20,0,0,1,90,95,0,0,28,0,1,1,1,0,0,31,0,109,0,0,0,1,9,18,95, +95,114,101,116,86,97,108,0,58,109,97,116,50,120,52,0,0,18,109,0,16,8,48,0,57,59,120,0,0,18,109,0, +16,8,48,0,57,59,121,0,0,18,109,0,16,8,48,0,57,59,122,0,0,17,48,0,48,0,0,0,18,109,0,16,10,49,0,57, +59,120,0,0,18,109,0,16,10,49,0,57,59,121,0,0,18,109,0,16,10,49,0,57,59,122,0,0,17,48,0,48,0,0,0,0, +20,0,0,1,90,95,0,0,28,0,1,1,1,0,0,13,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97, +116,50,120,52,0,0,18,109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,121,0,0,17,48,0,48,0, +0,0,17,48,0,48,0,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,121,0,0,17,48,0, +48,0,0,0,17,48,0,48,0,0,0,0,20,0,0,1,90,95,0,0,28,0,1,1,1,0,0,27,0,109,0,0,0,1,9,18,95,95,114,101, +116,86,97,108,0,58,109,97,116,50,120,52,0,0,18,109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,8,48,0,57, +59,121,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18,109,0,16,10,49,0, +57,59,121,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,0,20,0,0,1,90,95,0,0,28,0,1,1,1,0,0,29,0,109,0,0,0, +1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,50,120,52,0,0,18,109,0,16,8,48,0,57,59,120,0,0, +18,109,0,16,8,48,0,57,59,121,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,18,109,0,16,10,49,0,57,59,120,0, +0,18,109,0,16,10,49,0,57,59,121,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,0,20,0,0,1,90,95,0,0,27,0,1, +1,1,0,0,27,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,0,1,90,95,0,0,27,0,1,1,1, +0,0,29,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51,120,50,0,0,18,109,0,16,8, +48,0,57,0,18,109,0,16,10,49,0,57,0,18,109,0,16,10,50,0,57,0,0,20,0,0,1,90,95,0,0,27,0,1,1,1,0,0,14, +0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51,120,50,0,0,18,109,0,16,8,48,0,57, +0,18,109,0,16,10,49,0,57,0,18,109,0,16,10,50,0,57,0,0,20,0,0,1,90,95,0,0,27,0,1,1,1,0,0,30,0,109,0, +0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51,120,50,0,0,18,109,0,16,8,48,0,57,59,120, +0,0,18,109,0,16,8,48,0,57,59,121,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59, +121,0,0,18,109,0,16,10,50,0,57,59,120,0,0,18,109,0,16,10,50,0,57,59,121,0,0,0,20,0,0,1,90,95,0,0, +27,0,1,1,1,0,0,31,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51,120,50,0,0,18, +109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59,121,0,0,18,109,0,16,10,49,0,57,59,120,0,0, +18,109,0,16,10,49,0,57,59,121,0,0,18,109,0,16,10,50,0,57,59,120,0,0,18,109,0,16,10,50,0,57,59,121, +0,0,0,20,0,0,1,90,95,0,0,27,0,1,1,1,0,0,15,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109, +97,116,51,120,50,0,0,18,109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59,121,0,0,18,109,0,16, +10,49,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,121,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,0,20,0,0, +1,90,95,0,0,27,0,1,1,1,0,0,13,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51, +120,50,0,0,18,109,0,16,8,48,0,57,0,18,109,0,16,10,49,0,57,0,58,118,101,99,50,0,0,17,48,0,48,0,0,0, +0,0,0,20,0,0,1,90,95,0,0,27,0,1,1,1,0,0,26,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109, +97,116,51,120,50,0,0,18,109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59,121,0,0,18,109,0,16, +10,49,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,121,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,0,20,0,0, +1,90,95,0,0,27,0,1,1,1,0,0,28,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51, +120,50,0,0,18,109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59,121,0,0,18,109,0,16,10,49,0, +57,59,120,0,0,18,109,0,16,10,49,0,57,59,121,0,0,17,48,0,48,0,0,0,17,48,0,48,0,0,0,0,20,0,0,1,90,95, +0,0,14,0,1,1,1,0,0,14,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,0,1,90,95,0,0, +14,0,1,1,1,0,0,31,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51,0,0,18,109,0, +16,8,48,0,57,0,18,109,0,16,10,49,0,57,0,18,109,0,16,10,50,0,57,0,0,20,0,0,1,90,95,0,0,14,0,1,1,1,0, +0,30,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51,0,0,18,109,0,16,8,48,0,57, +59,120,121,122,0,0,18,109,0,16,10,49,0,57,59,120,121,122,0,0,18,109,0,16,10,50,0,57,59,120,121,122, +0,0,0,20,0,0,1,90,95,0,0,14,0,1,1,1,0,0,15,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109, +97,116,51,0,0,18,109,0,16,8,48,0,57,59,120,121,122,0,0,18,109,0,16,10,49,0,57,59,120,121,122,0,0, +18,109,0,16,10,50,0,57,59,120,121,122,0,0,0,20,0,0,1,90,95,0,0,14,0,1,1,1,0,0,26,0,109,0,0,0,1,9, +18,95,95,114,101,116,86,97,108,0,58,109,97,116,51,0,0,18,109,0,16,8,48,0,57,0,18,109,0,16,10,49,0, +57,0,17,48,0,0,0,0,17,48,0,0,0,0,17,49,0,0,0,0,0,20,0,0,1,90,95,0,0,14,0,1,1,1,0,0,28,0,109,0,0,0, +1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51,0,0,18,109,0,16,8,48,0,57,59,120,121,122,0,0, +18,109,0,16,10,49,0,57,59,120,121,122,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,49,0,0,0,0,0,20,0,0,1,90, +95,0,0,14,0,1,1,1,0,0,27,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51,0,0,18, +109,0,16,8,48,0,57,0,17,48,0,0,0,0,18,109,0,16,10,49,0,57,0,17,48,0,0,0,0,18,109,0,16,10,50,0,57,0, +17,49,0,0,0,0,0,20,0,0,1,90,95,0,0,14,0,1,1,1,0,0,29,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97, +108,0,58,109,97,116,51,0,0,18,109,0,16,8,48,0,57,0,17,48,0,0,0,0,18,109,0,16,10,49,0,57,0,17,48,0, +0,0,0,18,109,0,16,10,50,0,57,0,17,49,0,0,0,0,0,20,0,0,1,90,95,0,0,14,0,1,1,1,0,0,13,0,109,0,0,0,1, +9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51,0,0,18,109,0,16,8,48,0,57,0,17,48,0,0,0,0,18, +109,0,16,10,49,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,49,0,0,0,0,0,20,0,0,1,90,95,0,0, +30,0,1,1,1,0,0,30,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,0,1,90,95,0,0,30, +0,1,1,1,0,0,15,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51,120,52,0,0,18,109, +0,16,8,48,0,57,0,18,109,0,16,10,49,0,57,0,18,109,0,16,10,50,0,57,0,0,20,0,0,1,90,95,0,0,30,0,1,1,1, +0,0,14,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51,120,52,0,0,18,109,0,16,8, +48,0,57,0,17,48,0,0,0,0,18,109,0,16,10,49,0,57,0,17,48,0,0,0,0,18,109,0,16,10,50,0,57,0,17,48,0,0, +0,0,0,20,0,0,1,90,95,0,0,30,0,1,1,1,0,0,31,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109, +97,116,51,120,52,0,0,18,109,0,16,8,48,0,57,0,17,48,0,0,0,0,18,109,0,16,10,49,0,57,0,17,48,0,0,0,0, +18,109,0,16,10,50,0,57,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0,30,0,1,1,1,0,0,28,0,109,0,0,0,1,9,18, +95,95,114,101,116,86,97,108,0,58,109,97,116,51,120,52,0,0,18,109,0,16,8,48,0,57,0,18,109,0,16,10, +49,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,17,49,0,0,0,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0,30,0,1,1,1, +0,0,26,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51,120,52,0,0,18,109,0,16,8, +48,0,57,0,17,48,0,0,0,0,18,109,0,16,10,49,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,49,0, +0,0,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0,30,0,1,1,1,0,0,27,0,109,0,0,0,1,9,18,95,95,114,101,116,86, +97,108,0,58,109,97,116,51,120,52,0,0,18,109,0,16,8,48,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,18,109,0, +16,10,49,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,18,109,0,16,10,50,0,57,0,17,49,0,0,0,0,17,48,0,0,0,0,0, +20,0,0,1,90,95,0,0,30,0,1,1,1,0,0,29,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97, +116,51,120,52,0,0,18,109,0,16,8,48,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,18,109,0,16,10,49,0,57,0,17, +48,0,0,0,0,17,48,0,0,0,0,18,109,0,16,10,50,0,57,0,17,49,0,0,0,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0, +30,0,1,1,1,0,0,13,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,51,120,52,0,0,18, +109,0,16,8,48,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,18,109,0,16,10,49,0,57,0,17,48,0,0,0,0,17,48,0,0, +0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,49,0,0,0,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0,29,0,1,1,1,0,0,29, +0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,0,1,90,95,0,0,29,0,1,1,1,0,0,31,0, +109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,120,50,0,0,18,109,0,16,8,48,0,57, +59,120,121,0,0,18,109,0,16,10,49,0,57,59,120,121,0,0,18,109,0,16,10,50,0,57,59,120,121,0,0,18,109, +0,16,10,51,0,57,59,120,121,0,0,0,20,0,0,1,90,95,0,0,29,0,1,1,1,0,0,15,0,109,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,58,109,97,116,52,120,50,0,0,18,109,0,16,8,48,0,57,59,120,121,0,0,18,109,0,16, +10,49,0,57,59,120,121,0,0,18,109,0,16,10,50,0,57,59,120,121,0,0,18,109,0,16,10,51,0,57,59,120,121, +0,0,0,20,0,0,1,90,95,0,0,29,0,1,1,1,0,0,27,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109, +97,116,52,120,50,0,0,18,109,0,16,8,48,0,57,0,18,109,0,16,10,49,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0, +0,20,0,0,1,90,95,0,0,29,0,1,1,1,0,0,14,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97, +116,52,120,50,0,0,18,109,0,16,8,48,0,57,59,120,121,0,0,18,109,0,16,10,49,0,57,59,120,121,0,0,18, +109,0,16,10,50,0,57,59,120,121,0,0,17,48,0,0,0,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0,29,0,1,1,1,0,0, +30,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,120,50,0,0,18,109,0,16,8,48,0, +57,59,120,121,0,0,18,109,0,16,10,49,0,57,59,120,121,0,0,18,109,0,16,10,50,0,57,59,120,121,0,0,17, +48,0,0,0,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0,29,0,1,1,1,0,0,13,0,109,0,0,0,1,9,18,95,95,114,101, +116,86,97,108,0,58,109,97,116,52,120,50,0,0,18,109,0,16,8,48,0,57,0,18,109,0,16,10,49,0,57,0,17,48, +0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0,29,0,1,1,1,0,0,26,0,109,0,0, +0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,120,50,0,0,18,109,0,16,8,48,0,57,59,120, +121,0,0,18,109,0,16,10,49,0,57,59,120,121,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0, +0,0,0,20,0,0,1,90,95,0,0,29,0,1,1,1,0,0,28,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109, +97,116,52,120,50,0,0,18,109,0,16,8,48,0,57,59,120,121,0,0,18,109,0,16,10,49,0,57,59,120,121,0,0,17, +48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0,31,0,1,1,1,0,0,31,0,109, +0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,0,1,90,95,0,0,31,0,1,1,1,0,0,15,0,109,0,0, +0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,120,51,0,0,18,109,0,16,8,48,0,57,59,120, +121,122,0,0,18,109,0,16,10,49,0,57,59,120,121,122,0,0,18,109,0,16,10,50,0,57,59,120,121,122,0,0,18, +109,0,16,10,51,0,57,59,120,121,122,0,0,0,20,0,0,1,90,95,0,0,31,0,1,1,1,0,0,14,0,109,0,0,0,1,9,18, +95,95,114,101,116,86,97,108,0,58,109,97,116,52,120,51,0,0,18,109,0,16,8,48,0,57,0,18,109,0,16,10, +49,0,57,0,18,109,0,16,10,50,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0, +31,0,1,1,1,0,0,30,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,120,51,0,0,18, +109,0,16,8,48,0,57,59,120,121,122,0,0,18,109,0,16,10,49,0,57,59,120,121,122,0,0,18,109,0,16,10,50, +0,57,59,120,121,122,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0,31,0,1,1,1, +0,0,29,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,120,51,0,0,18,109,0,16,8, +48,0,57,0,17,48,0,0,0,0,18,109,0,16,10,49,0,57,0,17,48,0,0,0,0,18,109,0,16,10,50,0,57,0,17,49,0,0, +0,0,18,109,0,16,10,51,0,57,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0,31,0,1,1,1,0,0,26,0,109,0,0,0,1,9, +18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,120,51,0,0,18,109,0,16,8,48,0,57,0,18,109,0,16, +10,49,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,17,49,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,0, +20,0,0,1,90,95,0,0,31,0,1,1,1,0,0,27,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97, +116,52,120,51,0,0,18,109,0,16,8,48,0,57,0,17,48,0,0,0,0,18,109,0,16,10,49,0,57,0,17,48,0,0,0,0,18, +109,0,16,10,50,0,57,0,17,49,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0, +31,0,1,1,1,0,0,28,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,120,51,0,0,18, +109,0,16,8,48,0,57,59,120,121,122,0,0,18,109,0,16,10,49,0,57,59,120,121,122,0,0,17,48,0,0,0,0,17, +48,0,0,0,0,17,49,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0,31,0,1,1,1, +0,0,13,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,120,51,0,0,18,109,0,16,8, +48,0,57,0,17,48,0,0,0,0,18,109,0,16,10,49,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,49,0, +0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,0,20,0,0,1,90,95,0,0,15,0,1,1,1,0,0,15,0,109,0,0,0, +1,9,18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,0,1,90,95,0,0,15,0,1,1,1,0,0,30,0,109,0,0,0,1,9, +18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,0,0,18,109,0,16,8,48,0,57,0,18,109,0,16,10,49,0, +57,0,18,109,0,16,10,50,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,49,0,0,0,0,0,20,0,0,1, +90,95,0,0,15,0,1,1,1,0,0,31,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,0,0, +18,109,0,16,8,48,0,57,0,17,48,0,0,0,0,18,109,0,16,10,49,0,57,0,17,48,0,0,0,0,18,109,0,16,10,50,0, +57,0,17,48,0,0,0,0,18,109,0,16,10,51,0,57,0,17,49,0,0,0,0,0,20,0,0,1,90,95,0,0,15,0,1,1,1,0,0,28,0, +109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,0,0,18,109,0,16,8,48,0,57,0,18,109, +0,16,10,49,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,17,49,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0, +0,0,17,48,0,0,0,0,17,49,0,0,0,0,0,20,0,0,1,90,95,0,0,15,0,1,1,1,0,0,29,0,109,0,0,0,1,9,18,95,95, +114,101,116,86,97,108,0,58,109,97,116,52,0,0,18,109,0,16,8,48,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0, +18,109,0,16,10,49,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,18,109,0,16,10,50,0,57,0,17,49,0,0,0,0,17,48, +0,0,0,0,18,109,0,16,10,51,0,57,0,17,48,0,0,0,0,17,49,0,0,0,0,0,20,0,0,1,90,95,0,0,15,0,1,1,1,0,0, +14,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,0,0,18,109,0,16,8,48,0,57,0, +17,48,0,0,0,0,18,109,0,16,10,49,0,57,0,17,48,0,0,0,0,18,109,0,16,10,50,0,57,0,17,48,0,0,0,0,17,48, +0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,49,0,0,0,0,0,20,0,0,1,90,95,0,0,15,0,1,1,1,0,0,26,0,109,0,0, +0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,0,0,18,109,0,16,8,48,0,57,0,17,48,0,0,0,0, +18,109,0,16,10,49,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,49,0,0,0,0,17,48,0,0,0,0,17, +48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,49,0,0,0,0,0,20,0,0,1,90,95,0,0,15,0,1,1,1,0,0,27,0,109, +0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,0,0,18,109,0,16,8,48,0,57,0,17,48,0,0, +0,0,17,48,0,0,0,0,18,109,0,16,10,49,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,18,109,0,16,10,50,0,57,0,17, +49,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,49,0,0,0,0,0,20,0,0,1,90,95, +0,0,15,0,1,1,1,0,0,13,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,109,97,116,52,0,0,18,109, +0,16,8,48,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0,18,109,0,16,10,49,0,57,0,17,48,0,0,0,0,17,48,0,0,0,0, +17,48,0,0,0,0,17,48,0,0,0,0,17,49,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0,17,48,0,0,0,0, +17,49,0,0,0,0,0,20,0,0,1,90,95,0,0,0,0,2,1,1,0,2,0,26,0,109,0,0,1,1,0,0,26,0,110,0,0,0,1,9,18,109, +0,16,8,48,0,57,18,110,0,16,8,48,0,57,21,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,21,0,0,1, +90,95,0,0,0,0,2,1,1,0,2,0,28,0,109,0,0,1,1,0,0,28,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0, +16,8,48,0,57,21,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,21,0,0,1,90,95,0,0,0,0,2,1,1,0,2, +0,27,0,109,0,0,1,1,0,0,27,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,21,0,9,18, +109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,21,0,9,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,21, +0,0,1,90,95,0,0,0,0,2,1,1,0,2,0,30,0,109,0,0,1,1,0,0,30,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18, +110,0,16,8,48,0,57,21,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,21,0,9,18,109,0,16,10,50,0, +57,18,110,0,16,10,50,0,57,21,0,0,1,90,95,0,0,0,0,2,1,1,0,2,0,29,0,109,0,0,1,1,0,0,29,0,110,0,0,0,1, +9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,21,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57, +21,0,9,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,21,0,9,18,109,0,16,10,51,0,57,18,110,0,16,10, +51,0,57,21,0,0,1,90,95,0,0,0,0,2,1,1,0,2,0,31,0,109,0,0,1,1,0,0,31,0,110,0,0,0,1,9,18,109,0,16,8, +48,0,57,18,110,0,16,8,48,0,57,21,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,21,0,9,18,109,0, +16,10,50,0,57,18,110,0,16,10,50,0,57,21,0,9,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,21,0,0,1, +90,95,0,0,0,0,2,2,1,0,2,0,26,0,109,0,0,1,1,0,0,26,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0, +16,8,48,0,57,22,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,22,0,0,1,90,95,0,0,0,0,2,2,1,0,2, +0,28,0,109,0,0,1,1,0,0,28,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,22,0,9,18, +109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,22,0,0,1,90,95,0,0,0,0,2,2,1,0,2,0,27,0,109,0,0,1,1,0,0, +27,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,22,0,9,18,109,0,16,10,49,0,57,18, +110,0,16,10,49,0,57,22,0,9,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,22,0,0,1,90,95,0,0,0,0,2, +2,1,0,2,0,30,0,109,0,0,1,1,0,0,30,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,22,0, +9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,22,0,9,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0, +57,22,0,0,1,90,95,0,0,0,0,2,2,1,0,2,0,29,0,109,0,0,1,1,0,0,29,0,110,0,0,0,1,9,18,109,0,16,8,48,0, +57,18,110,0,16,8,48,0,57,22,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,22,0,9,18,109,0,16, +10,50,0,57,18,110,0,16,10,50,0,57,22,0,9,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,22,0,0,1,90, +95,0,0,0,0,2,2,1,0,2,0,31,0,109,0,0,1,1,0,0,31,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,8, +48,0,57,22,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,22,0,9,18,109,0,16,10,50,0,57,18,110, +0,16,10,50,0,57,22,0,9,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,22,0,0,1,90,95,0,0,0,0,2,4,1, +0,2,0,26,0,109,0,0,1,1,0,0,26,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,24,0,9, +18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,24,0,0,1,90,95,0,0,0,0,2,4,1,0,2,0,28,0,109,0,0,1,1, +0,0,28,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,24,0,9,18,109,0,16,10,49,0,57, +18,110,0,16,10,49,0,57,24,0,0,1,90,95,0,0,0,0,2,4,1,0,2,0,27,0,109,0,0,1,1,0,0,27,0,110,0,0,0,1,9, +18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,24,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57, +24,0,9,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,24,0,0,1,90,95,0,0,0,0,2,4,1,0,2,0,30,0,109,0, +0,1,1,0,0,30,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,24,0,9,18,109,0,16,10,49, +0,57,18,110,0,16,10,49,0,57,24,0,9,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,24,0,0,1,90,95,0, +0,0,0,2,4,1,0,2,0,29,0,109,0,0,1,1,0,0,29,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0, +57,24,0,9,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,24,0,9,18,109,0,16,10,50,0,57,18,110,0,16, +10,50,0,57,24,0,9,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,24,0,0,1,90,95,0,0,0,0,2,4,1,0,2,0, +31,0,109,0,0,1,1,0,0,31,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,24,0,9,18,109, +0,16,10,49,0,57,18,110,0,16,10,49,0,57,24,0,9,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,24,0,9, +18,109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,24,0,0,1,90,95,0,0,11,0,2,21,1,1,0,0,26,0,109,0,0,1, +1,0,0,10,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,18,118,0,59,120,0,18,109,0,16,8, +48,0,57,59,120,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,120,0,48,46,20,0,9,18,95,95,114, +101,116,86,97,108,0,59,121,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,121,0,48,18,118,0,59,121,0, +18,109,0,16,10,49,0,57,59,121,0,48,46,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,18,118,0,59, +120,0,18,109,0,16,8,48,0,57,59,122,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,122,0,48,46,20, +0,0,1,90,95,0,0,12,0,2,21,1,1,0,0,28,0,109,0,0,1,1,0,0,10,0,118,0,0,0,1,9,18,95,95,114,101,116,86, +97,108,0,59,120,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,120,0,48,18,118,0,59,121,0,18,109,0, +16,10,49,0,57,59,120,0,48,46,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,18,118,0,59,120,0,18, +109,0,16,8,48,0,57,59,121,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,121,0,48,46,20,0,9,18, +95,95,114,101,116,86,97,108,0,59,122,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,122,0,48,18,118, +0,59,121,0,18,109,0,16,10,49,0,57,59,122,0,48,46,20,0,9,18,95,95,114,101,116,86,97,108,0,59,119,0, +18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,119,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59, +119,0,48,46,20,0,0,1,90,95,0,0,10,0,2,21,1,1,0,0,27,0,109,0,0,1,1,0,0,11,0,118,0,0,0,1,9,18,95,95, +114,101,116,86,97,108,0,59,120,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,120,0,48,18,118,0,59, +121,0,18,109,0,16,10,49,0,57,59,120,0,48,46,18,118,0,59,122,0,18,109,0,16,10,50,0,57,59,120,0,48, +46,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,121, +0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,121,0,48,46,18,118,0,59,122,0,18,109,0,16,10,50,0, +57,59,121,0,48,46,20,0,0,1,90,95,0,0,12,0,2,21,1,1,0,0,30,0,109,0,0,1,1,0,0,11,0,118,0,0,0,1,9,18, +95,95,114,101,116,86,97,108,0,59,120,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,120,0,48,18,118, +0,59,121,0,18,109,0,16,10,49,0,57,59,120,0,48,46,18,118,0,59,122,0,18,109,0,16,10,50,0,57,59,120,0, +48,46,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59, +121,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,121,0,48,46,18,118,0,59,122,0,18,109,0,16,10, +50,0,57,59,121,0,48,46,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,18,118,0,59,120,0,18,109,0, +16,8,48,0,57,59,122,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,122,0,48,46,18,118,0,59,122,0, +18,109,0,16,10,50,0,57,59,122,0,48,46,20,0,9,18,95,95,114,101,116,86,97,108,0,59,119,0,18,118,0,59, +120,0,18,109,0,16,8,48,0,57,59,119,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,119,0,48,46,18, +118,0,59,122,0,18,109,0,16,10,50,0,57,59,119,0,48,46,20,0,0,1,90,95,0,0,10,0,2,21,1,1,0,0,29,0,109, +0,0,1,1,0,0,12,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,18,118,0,59,120,0,18,109, +0,16,8,48,0,57,59,120,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,120,0,48,46,18,118,0,59,122, +0,18,109,0,16,10,50,0,57,59,120,0,48,46,18,118,0,59,119,0,18,109,0,16,10,51,0,57,59,120,0,48,46,20, +0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,121,0,48, +18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,121,0,48,46,18,118,0,59,122,0,18,109,0,16,10,50,0,57, +59,121,0,48,46,18,118,0,59,119,0,18,109,0,16,10,51,0,57,59,121,0,48,46,20,0,0,1,90,95,0,0,11,0,2, +21,1,1,0,0,31,0,109,0,0,1,1,0,0,12,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,18, +118,0,59,120,0,18,109,0,16,8,48,0,57,59,120,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,120,0, +48,46,18,118,0,59,122,0,18,109,0,16,10,50,0,57,59,120,0,48,46,18,118,0,59,119,0,18,109,0,16,10,51, +0,57,59,120,0,48,46,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,18,118,0,59,120,0,18,109,0,16, +8,48,0,57,59,121,0,48,18,118,0,59,121,0,18,109,0,16,10,49,0,57,59,121,0,48,46,18,118,0,59,122,0,18, +109,0,16,10,50,0,57,59,121,0,48,46,18,118,0,59,119,0,18,109,0,16,10,51,0,57,59,121,0,48,46,20,0,9, +18,95,95,114,101,116,86,97,108,0,59,122,0,18,118,0,59,120,0,18,109,0,16,8,48,0,57,59,122,0,48,18, +118,0,59,121,0,18,109,0,16,10,49,0,57,59,122,0,48,46,18,118,0,59,122,0,18,109,0,16,10,50,0,57,59, +122,0,48,46,18,118,0,59,119,0,18,109,0,16,10,51,0,57,59,122,0,48,46,20,0,0,1,90,95,0,0,27,0,2,21,1, +1,0,0,13,0,109,0,0,1,1,0,0,27,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109, +0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,18,110,0, +16,10,49,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,18,110,0,16,10,50, +0,57,48,20,0,0,1,90,95,0,0,29,0,2,21,1,1,0,0,13,0,109,0,0,1,1,0,0,29,0,110,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,16,8,48,0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86, +97,108,0,16,10,49,0,57,18,109,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0, +16,10,50,0,57,18,109,0,18,110,0,16,10,50,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51, +0,57,18,109,0,18,110,0,16,10,51,0,57,48,20,0,0,1,90,95,0,0,26,0,2,21,1,1,0,0,26,0,109,0,0,1,1,0,0, +13,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,18,110,0,16,8,48,0,57,48, +20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,18,110,0,16,10,49,0,57,48,20,0,0,1, +90,95,0,0,14,0,2,21,1,1,0,0,26,0,109,0,0,1,1,0,0,27,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108, +0,16,8,48,0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49, +0,57,18,109,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18, +109,0,18,110,0,16,10,50,0,57,48,20,0,0,1,90,95,0,0,31,0,2,21,1,1,0,0,26,0,109,0,0,1,1,0,0,29,0,110, +0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9, +18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,18,110,0,16,10,50,0,57,48,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,51,0,57,18,109,0,18,110,0,16,10,51,0,57,48,20,0,0,1,90,95,0,0,28,0,2,21,1,1, +0,0,28,0,109,0,0,1,1,0,0,13,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0, +18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,18,110,0, +16,10,49,0,57,48,20,0,0,1,90,95,0,0,30,0,2,21,1,1,0,0,28,0,109,0,0,1,1,0,0,27,0,110,0,0,0,1,9,18, +95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114, +101,116,86,97,108,0,16,10,49,0,57,18,109,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101,116, +86,97,108,0,16,10,50,0,57,18,109,0,18,110,0,16,10,50,0,57,48,20,0,0,1,90,95,0,0,15,0,2,21,1,1,0,0, +28,0,109,0,0,1,1,0,0,29,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,18, +110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,18,110,0,16, +10,49,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,18,110,0,16,10,50,0, +57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,18,109,0,18,110,0,16,10,51,0,57,48,20, +0,0,1,90,95,0,0,13,0,2,21,1,1,0,0,27,0,109,0,0,1,1,0,0,26,0,110,0,0,0,1,9,18,95,95,114,101,116,86, +97,108,0,16,8,48,0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16, +10,49,0,57,18,109,0,18,110,0,16,10,49,0,57,48,20,0,0,1,90,95,0,0,27,0,2,21,1,1,0,0,27,0,109,0,0,1, +1,0,0,14,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,18,110,0,16,8,48,0, +57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,18,110,0,16,10,49,0,57,48,20, +0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,18,110,0,16,10,50,0,57,48,20,0,0,1,90, +95,0,0,29,0,2,21,1,1,0,0,27,0,109,0,0,1,1,0,0,31,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0, +16,8,48,0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0, +57,18,109,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109, +0,18,110,0,16,10,50,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,18,109,0,18,110, +0,16,10,51,0,57,48,20,0,0,1,90,95,0,0,26,0,2,21,1,1,0,0,14,0,109,0,0,1,1,0,0,26,0,110,0,0,0,1,9,18, +95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114, +101,116,86,97,108,0,16,10,49,0,57,18,109,0,18,110,0,16,10,49,0,57,48,20,0,0,1,90,95,0,0,31,0,2,21, +1,1,0,0,14,0,109,0,0,1,1,0,0,31,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18, +109,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,18, +110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,18,110,0,16, +10,50,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,18,109,0,18,110,0,16,10,51,0, +57,48,20,0,0,1,90,95,0,0,28,0,2,21,1,1,0,0,30,0,109,0,0,1,1,0,0,26,0,110,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,16,8,48,0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86, +97,108,0,16,10,49,0,57,18,109,0,18,110,0,16,10,49,0,57,48,20,0,0,1,90,95,0,0,30,0,2,21,1,1,0,0,30, +0,109,0,0,1,1,0,0,14,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,18,110, +0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,18,110,0,16,10,49, +0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,18,110,0,16,10,50,0,57,48, +20,0,0,1,90,95,0,0,15,0,2,21,1,1,0,0,30,0,109,0,0,1,1,0,0,31,0,110,0,0,0,1,9,18,95,95,114,101,116, +86,97,108,0,16,8,48,0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0, +16,10,49,0,57,18,109,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50, +0,57,18,109,0,18,110,0,16,10,50,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,18, +109,0,18,110,0,16,10,51,0,57,48,20,0,0,1,90,95,0,0,13,0,2,21,1,1,0,0,29,0,109,0,0,1,1,0,0,28,0,110, +0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9, +18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,18,110,0,16,10,49,0,57,48,20,0,0,1,90,95,0, +0,27,0,2,21,1,1,0,0,29,0,109,0,0,1,1,0,0,30,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8, +48,0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18, +109,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,18, +110,0,16,10,50,0,57,48,20,0,0,1,90,95,0,0,29,0,2,21,1,1,0,0,29,0,109,0,0,1,1,0,0,15,0,110,0,0,0,1, +9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,50,0,57,18,109,0,18,110,0,16,10,50,0,57,48,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,10,51,0,57,18,109,0,18,110,0,16,10,51,0,57,48,20,0,0,1,90,95,0,0,26,0,2,21,1,1,0,0,31,0, +109,0,0,1,1,0,0,28,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,18,110,0, +16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,18,110,0,16,10,49,0, +57,48,20,0,0,1,90,95,0,0,14,0,2,21,1,1,0,0,31,0,109,0,0,1,1,0,0,30,0,110,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,16,8,48,0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86, +97,108,0,16,10,49,0,57,18,109,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0, +16,10,50,0,57,18,109,0,18,110,0,16,10,50,0,57,48,20,0,0,1,90,95,0,0,31,0,2,21,1,1,0,0,31,0,109,0,0, +1,1,0,0,15,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,18,110,0,16,8,48, +0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,18,110,0,16,10,49,0,57,48, +20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,18,110,0,16,10,50,0,57,48,20,0,9,18, +95,95,114,101,116,86,97,108,0,16,10,51,0,57,18,109,0,18,110,0,16,10,51,0,57,48,20,0,0,1,90,95,0,0, +28,0,2,21,1,1,0,0,15,0,109,0,0,1,1,0,0,28,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48, +0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18, +109,0,18,110,0,16,10,49,0,57,48,20,0,0,1,90,95,0,0,30,0,2,21,1,1,0,0,15,0,109,0,0,1,1,0,0,30,0,110, +0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,18,110,0,16,8,48,0,57,48,20,0,9, +18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,18,110,0,16,10,50,0,57,48,20,0,0,1,90,95,0,0,0,0,2, +3,1,0,2,0,26,0,109,0,0,1,1,0,0,13,0,110,0,0,0,1,9,18,109,0,18,109,0,18,110,0,48,20,0,0,1,90,95,0,0, +0,0,2,3,1,0,2,0,28,0,109,0,0,1,1,0,0,13,0,110,0,0,0,1,9,18,109,0,18,109,0,18,110,0,48,20,0,0,1,90, +95,0,0,0,0,2,3,1,0,2,0,27,0,109,0,0,1,1,0,0,14,0,110,0,0,0,1,9,18,109,0,18,109,0,18,110,0,48,20,0, +0,1,90,95,0,0,0,0,2,3,1,0,2,0,30,0,109,0,0,1,1,0,0,14,0,110,0,0,0,1,9,18,109,0,18,109,0,18,110,0, +48,20,0,0,1,90,95,0,0,0,0,2,3,1,0,2,0,29,0,109,0,0,1,1,0,0,15,0,110,0,0,0,1,9,18,109,0,18,109,0,18, +110,0,48,20,0,0,1,90,95,0,0,0,0,2,3,1,0,2,0,31,0,109,0,0,1,1,0,0,15,0,110,0,0,0,1,9,18,109,0,18, +109,0,18,110,0,48,20,0,0,1,90,95,0,0,11,0,2,21,1,1,0,0,10,0,118,0,0,1,1,0,0,27,0,109,0,0,0,1,9,18, +95,95,114,101,116,86,97,108,0,59,120,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,8,48,0,57,0,0,20, +0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10,49,0,57, +0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10, +50,0,57,0,0,20,0,0,1,90,95,0,0,12,0,2,21,1,1,0,0,10,0,118,0,0,1,1,0,0,29,0,109,0,0,0,1,9,18,95,95, +114,101,116,86,97,108,0,59,120,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,8,48,0,57,0,0,20,0,9,18, +95,95,114,101,116,86,97,108,0,59,121,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10,49,0,57,0,0,20, +0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10,50,0,57, +0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,119,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10, +51,0,57,0,0,20,0,0,1,90,95,0,0,10,0,2,21,1,1,0,0,11,0,118,0,0,1,1,0,0,26,0,109,0,0,0,1,9,18,95,95, +114,101,116,86,97,108,0,59,120,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,8,48,0,57,0,0,20,0,9,18, +95,95,114,101,116,86,97,108,0,59,121,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10,49,0,57,0,0,20, +0,0,1,90,95,0,0,12,0,2,21,1,1,0,0,11,0,118,0,0,1,1,0,0,31,0,109,0,0,0,1,9,18,95,95,114,101,116,86, +97,108,0,59,120,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,8,48,0,57,0,0,20,0,9,18,95,95,114,101, +116,86,97,108,0,59,121,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10,49,0,57,0,0,20,0,9,18,95,95, +114,101,116,86,97,108,0,59,122,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10,50,0,57,0,0,20,0,9, +18,95,95,114,101,116,86,97,108,0,59,119,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10,51,0,57,0,0, +20,0,0,1,90,95,0,0,10,0,2,21,1,1,0,0,12,0,118,0,0,1,1,0,0,28,0,109,0,0,0,1,9,18,95,95,114,101,116, +86,97,108,0,59,120,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,8,48,0,57,0,0,20,0,9,18,95,95,114, +101,116,86,97,108,0,59,121,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10,49,0,57,0,0,20,0,0,1,90, +95,0,0,11,0,2,21,1,1,0,0,12,0,118,0,0,1,1,0,0,30,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0, +59,120,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,8,48,0,57,0,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,59,121,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10,49,0,57,0,0,20,0,9,18,95,95,114,101, +116,86,97,108,0,59,122,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10,50,0,57,0,0,20,0,0,1,90,95,0, +0,0,0,2,1,1,0,2,0,26,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,21,0,9,18, +109,0,16,10,49,0,57,18,97,0,21,0,0,1,90,95,0,0,0,0,2,1,1,0,2,0,28,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1, +9,18,109,0,16,8,48,0,57,18,97,0,21,0,9,18,109,0,16,10,49,0,57,18,97,0,21,0,0,1,90,95,0,0,0,0,2,1,1, +0,2,0,27,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,21,0,9,18,109,0,16,10,49, +0,57,18,97,0,21,0,9,18,109,0,16,10,50,0,57,18,97,0,21,0,0,1,90,95,0,0,0,0,2,1,1,0,2,0,30,0,109,0,0, +1,1,0,0,9,0,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,21,0,9,18,109,0,16,10,49,0,57,18,97,0,21,0, +9,18,109,0,16,10,50,0,57,18,97,0,21,0,0,1,90,95,0,0,0,0,2,1,1,0,2,0,29,0,109,0,0,1,1,0,0,9,0,97,0, +0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,21,0,9,18,109,0,16,10,49,0,57,18,97,0,21,0,9,18,109,0,16,10, +50,0,57,18,97,0,21,0,9,18,109,0,16,10,51,0,57,18,97,0,21,0,0,1,90,95,0,0,0,0,2,1,1,0,2,0,31,0,109, +0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,21,0,9,18,109,0,16,10,49,0,57,18,97,0, +21,0,9,18,109,0,16,10,50,0,57,18,97,0,21,0,9,18,109,0,16,10,51,0,57,18,97,0,21,0,0,1,90,95,0,0,0,0, +2,2,1,0,2,0,26,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,22,0,9,18,109,0,16, +10,49,0,57,18,97,0,22,0,0,1,90,95,0,0,0,0,2,2,1,0,2,0,28,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,109, +0,16,8,48,0,57,18,97,0,22,0,9,18,109,0,16,10,49,0,57,18,97,0,22,0,0,1,90,95,0,0,0,0,2,2,1,0,2,0,27, +0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,22,0,9,18,109,0,16,10,49,0,57,18, +97,0,22,0,9,18,109,0,16,10,50,0,57,18,97,0,22,0,0,1,90,95,0,0,0,0,2,2,1,0,2,0,30,0,109,0,0,1,1,0,0, +9,0,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,22,0,9,18,109,0,16,10,49,0,57,18,97,0,22,0,9,18,109, +0,16,10,50,0,57,18,97,0,22,0,0,1,90,95,0,0,0,0,2,2,1,0,2,0,29,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,9, +18,109,0,16,8,48,0,57,18,97,0,22,0,9,18,109,0,16,10,49,0,57,18,97,0,22,0,9,18,109,0,16,10,50,0,57, +18,97,0,22,0,9,18,109,0,16,10,51,0,57,18,97,0,22,0,0,1,90,95,0,0,0,0,2,2,1,0,2,0,31,0,109,0,0,1,1, +0,0,9,0,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,22,0,9,18,109,0,16,10,49,0,57,18,97,0,22,0,9,18, +109,0,16,10,50,0,57,18,97,0,22,0,9,18,109,0,16,10,51,0,57,18,97,0,22,0,0,1,90,95,0,0,0,0,2,3,1,0,2, +0,26,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,23,0,9,18,109,0,16,10,49,0, +57,18,97,0,23,0,0,1,90,95,0,0,0,0,2,3,1,0,2,0,28,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,109,0,16,8, +48,0,57,18,97,0,23,0,9,18,109,0,16,10,49,0,57,18,97,0,23,0,0,1,90,95,0,0,0,0,2,3,1,0,2,0,27,0,109, +0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,23,0,9,18,109,0,16,10,49,0,57,18,97,0, +23,0,9,18,109,0,16,10,50,0,57,18,97,0,23,0,0,1,90,95,0,0,0,0,2,3,1,0,2,0,30,0,109,0,0,1,1,0,0,9,0, +97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,23,0,9,18,109,0,16,10,49,0,57,18,97,0,23,0,9,18,109,0, +16,10,50,0,57,18,97,0,23,0,0,1,90,95,0,0,0,0,2,3,1,0,2,0,29,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18, +109,0,16,8,48,0,57,18,97,0,23,0,9,18,109,0,16,10,49,0,57,18,97,0,23,0,9,18,109,0,16,10,50,0,57,18, +97,0,23,0,9,18,109,0,16,10,51,0,57,18,97,0,23,0,0,1,90,95,0,0,0,0,2,3,1,0,2,0,31,0,109,0,0,1,1,0,0, +9,0,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,23,0,9,18,109,0,16,10,49,0,57,18,97,0,23,0,9,18,109, +0,16,10,50,0,57,18,97,0,23,0,9,18,109,0,16,10,51,0,57,18,97,0,23,0,0,1,90,95,0,0,0,0,2,4,1,0,2,0, +26,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,24,0,9,18,109,0,16,10,49,0,57, +18,97,0,24,0,0,1,90,95,0,0,0,0,2,4,1,0,2,0,28,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,109,0,16,8,48, +0,57,18,97,0,24,0,9,18,109,0,16,10,49,0,57,18,97,0,24,0,0,1,90,95,0,0,0,0,2,4,1,0,2,0,27,0,109,0,0, +1,1,0,0,9,0,97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,24,0,9,18,109,0,16,10,49,0,57,18,97,0,24,0, +9,18,109,0,16,10,50,0,57,18,97,0,24,0,0,1,90,95,0,0,0,0,2,4,1,0,2,0,30,0,109,0,0,1,1,0,0,9,0,97,0, +0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,24,0,9,18,109,0,16,10,49,0,57,18,97,0,24,0,9,18,109,0,16,10, +50,0,57,18,97,0,24,0,0,1,90,95,0,0,0,0,2,4,1,0,2,0,29,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,109,0, +16,8,48,0,57,18,97,0,24,0,9,18,109,0,16,10,49,0,57,18,97,0,24,0,9,18,109,0,16,10,50,0,57,18,97,0, +24,0,9,18,109,0,16,10,51,0,57,18,97,0,24,0,0,1,90,95,0,0,0,0,2,4,1,0,2,0,31,0,109,0,0,1,1,0,0,9,0, +97,0,0,0,1,9,18,109,0,16,8,48,0,57,18,97,0,24,0,9,18,109,0,16,10,49,0,57,18,97,0,24,0,9,18,109,0, +16,10,50,0,57,18,97,0,24,0,9,18,109,0,16,10,51,0,57,18,97,0,24,0,0,1,90,95,0,0,26,0,2,26,1,1,0,0, +26,0,109,0,0,1,1,0,0,26,0,110,0,0,0,1,8,58,109,97,116,50,120,51,0,0,18,109,0,16,8,48,0,57,18,110,0, +16,8,48,0,57,46,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,46,0,0,0,0,1,90,95,0,0,28,0,2,26,1, +1,0,0,28,0,109,0,0,1,1,0,0,28,0,110,0,0,0,1,8,58,109,97,116,50,120,52,0,0,18,109,0,16,8,48,0,57,18, +110,0,16,8,48,0,57,46,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,46,0,0,0,0,1,90,95,0,0,27,0, +2,26,1,1,0,0,27,0,109,0,0,1,1,0,0,27,0,110,0,0,0,1,8,58,109,97,116,51,120,50,0,0,18,109,0,16,8,48, +0,57,18,110,0,16,8,48,0,57,46,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,46,0,18,109,0,16,10, +50,0,57,18,110,0,16,10,50,0,57,46,0,0,0,0,1,90,95,0,0,30,0,2,26,1,1,0,0,30,0,109,0,0,1,1,0,0,30,0, +110,0,0,0,1,8,58,109,97,116,51,120,52,0,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,46,0,18,109, +0,16,10,49,0,57,18,110,0,16,10,49,0,57,46,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,46,0,0,0, +0,1,90,95,0,0,29,0,2,26,1,1,0,0,29,0,109,0,0,1,1,0,0,29,0,110,0,0,0,1,8,58,109,97,116,52,120,50,0, +0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,46,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57, +46,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,46,0,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0, +57,46,0,0,0,0,1,90,95,0,0,31,0,2,26,1,1,0,0,31,0,109,0,0,1,1,0,0,31,0,110,0,0,0,1,8,58,109,97,116, +52,120,51,0,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,46,0,18,109,0,16,10,49,0,57,18,110,0,16, +10,49,0,57,46,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,46,0,18,109,0,16,10,51,0,57,18,110,0, +16,10,51,0,57,46,0,0,0,0,1,90,95,0,0,26,0,2,27,1,1,0,0,26,0,109,0,0,1,1,0,0,26,0,110,0,0,0,1,8,58, +109,97,116,50,120,51,0,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,47,0,18,109,0,16,10,49,0,57, +18,110,0,16,10,49,0,57,47,0,0,0,0,1,90,95,0,0,28,0,2,27,1,1,0,0,28,0,109,0,0,1,1,0,0,28,0,110,0,0, +0,1,8,58,109,97,116,50,120,52,0,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,47,0,18,109,0,16,10, +49,0,57,18,110,0,16,10,49,0,57,47,0,0,0,0,1,90,95,0,0,27,0,2,27,1,1,0,0,27,0,109,0,0,1,1,0,0,27,0, +110,0,0,0,1,8,58,109,97,116,51,120,50,0,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,47,0,18,109, +0,16,10,49,0,57,18,110,0,16,10,49,0,57,47,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,47,0,0,0, +0,1,90,95,0,0,30,0,2,27,1,1,0,0,30,0,109,0,0,1,1,0,0,30,0,110,0,0,0,1,8,58,109,97,116,51,120,52,0, +0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,47,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57, +47,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,47,0,0,0,0,1,90,95,0,0,29,0,2,27,1,1,0,0,29,0, +109,0,0,1,1,0,0,29,0,110,0,0,0,1,8,58,109,97,116,52,120,50,0,0,18,109,0,16,8,48,0,57,18,110,0,16,8, +48,0,57,47,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,47,0,18,109,0,16,10,50,0,57,18,110,0,16, +10,50,0,57,47,0,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,47,0,0,0,0,1,90,95,0,0,31,0,2,27,1,1, +0,0,31,0,109,0,0,1,1,0,0,31,0,110,0,0,0,1,8,58,109,97,116,52,120,51,0,0,18,109,0,16,8,48,0,57,18, +110,0,16,8,48,0,57,47,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,47,0,18,109,0,16,10,50,0,57, +18,110,0,16,10,50,0,57,47,0,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,47,0,0,0,0,1,90,95,0,0, +26,0,2,22,1,1,0,0,26,0,109,0,0,1,1,0,0,26,0,110,0,0,0,1,8,58,109,97,116,50,120,51,0,0,18,109,0,16, +8,48,0,57,18,110,0,16,8,48,0,57,49,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,49,0,0,0,0,1,90, +95,0,0,28,0,2,22,1,1,0,0,28,0,109,0,0,1,1,0,0,28,0,110,0,0,0,1,8,58,109,97,116,50,120,52,0,0,18, +109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,49,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,49,0,0, +0,0,1,90,95,0,0,27,0,2,22,1,1,0,0,27,0,109,0,0,1,1,0,0,27,0,110,0,0,0,1,8,58,109,97,116,51,120,50, +0,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,49,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57, +49,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,49,0,0,0,0,1,90,95,0,0,30,0,2,22,1,1,0,0,30,0, +109,0,0,1,1,0,0,30,0,110,0,0,0,1,8,58,109,97,116,51,120,52,0,0,18,109,0,16,8,48,0,57,18,110,0,16,8, +48,0,57,49,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,49,0,18,109,0,16,10,50,0,57,18,110,0,16, +10,50,0,57,49,0,0,0,0,1,90,95,0,0,29,0,2,22,1,1,0,0,29,0,109,0,0,1,1,0,0,29,0,110,0,0,0,1,8,58,109, +97,116,52,120,50,0,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,49,0,18,109,0,16,10,49,0,57,18, +110,0,16,10,49,0,57,49,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,49,0,18,109,0,16,10,51,0,57, +18,110,0,16,10,51,0,57,49,0,0,0,0,1,90,95,0,0,31,0,2,22,1,1,0,0,31,0,109,0,0,1,1,0,0,31,0,110,0,0, +0,1,8,58,109,97,116,52,120,51,0,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,49,0,18,109,0,16,10, +49,0,57,18,110,0,16,10,49,0,57,49,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,49,0,18,109,0,16, +10,51,0,57,18,110,0,16,10,51,0,57,49,0,0,0,0,1,90,95,0,0,26,0,2,26,1,1,0,0,9,0,97,0,0,1,1,0,0,26,0, +110,0,0,0,1,8,58,109,97,116,50,120,51,0,0,18,97,0,18,110,0,16,8,48,0,57,46,0,18,97,0,18,110,0,16, +10,49,0,57,46,0,0,0,0,1,90,95,0,0,26,0,2,26,1,1,0,0,26,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,8,58,109, +97,116,50,120,51,0,0,18,109,0,16,8,48,0,57,18,98,0,46,0,18,109,0,16,10,49,0,57,18,98,0,46,0,0,0,0, +1,90,95,0,0,28,0,2,26,1,1,0,0,9,0,97,0,0,1,1,0,0,28,0,110,0,0,0,1,8,58,109,97,116,50,120,52,0,0,18, +97,0,18,110,0,16,8,48,0,57,46,0,18,97,0,18,110,0,16,10,49,0,57,46,0,0,0,0,1,90,95,0,0,28,0,2,26,1, +1,0,0,28,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,8,58,109,97,116,50,120,52,0,0,18,109,0,16,8,48,0,57,18, +98,0,46,0,18,109,0,16,10,49,0,57,18,98,0,46,0,0,0,0,1,90,95,0,0,27,0,2,26,1,1,0,0,9,0,97,0,0,1,1,0, +0,27,0,110,0,0,0,1,8,58,109,97,116,51,120,50,0,0,18,97,0,18,110,0,16,8,48,0,57,46,0,18,97,0,18,110, +0,16,10,49,0,57,46,0,18,97,0,18,110,0,16,10,50,0,57,46,0,0,0,0,1,90,95,0,0,27,0,2,26,1,1,0,0,27,0, +109,0,0,1,1,0,0,9,0,98,0,0,0,1,8,58,109,97,116,51,120,50,0,0,18,109,0,16,8,48,0,57,18,98,0,46,0,18, +109,0,16,10,49,0,57,18,98,0,46,0,18,109,0,16,10,50,0,57,18,98,0,46,0,0,0,0,1,90,95,0,0,30,0,2,26,1, +1,0,0,9,0,97,0,0,1,1,0,0,30,0,110,0,0,0,1,8,58,109,97,116,51,120,52,0,0,18,97,0,18,110,0,16,8,48,0, +57,46,0,18,97,0,18,110,0,16,10,49,0,57,46,0,18,97,0,18,110,0,16,10,50,0,57,46,0,0,0,0,1,90,95,0,0, +30,0,2,26,1,1,0,0,30,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,8,58,109,97,116,51,120,52,0,0,18,109,0,16,8, +48,0,57,18,98,0,46,0,18,109,0,16,10,49,0,57,18,98,0,46,0,18,109,0,16,10,50,0,57,18,98,0,46,0,0,0,0, +1,90,95,0,0,29,0,2,26,1,1,0,0,29,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,8,58,109,97,116,52,120,50,0,0,18, +109,0,16,8,48,0,57,18,98,0,46,0,18,109,0,16,10,49,0,57,18,98,0,46,0,18,109,0,16,10,50,0,57,18,98,0, +46,0,18,109,0,16,10,51,0,57,18,98,0,46,0,0,0,0,1,90,95,0,0,29,0,2,26,1,1,0,0,9,0,97,0,0,1,1,0,0,29, +0,110,0,0,0,1,8,58,109,97,116,52,120,50,0,0,18,97,0,18,110,0,16,8,48,0,57,46,0,18,97,0,18,110,0,16, +10,49,0,57,46,0,18,97,0,18,110,0,16,10,50,0,57,46,0,18,97,0,18,110,0,16,10,51,0,57,46,0,0,0,0,1,90, +95,0,0,31,0,2,26,1,1,0,0,31,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,8,58,109,97,116,52,120,51,0,0,18,109, +0,16,8,48,0,57,18,98,0,46,0,18,109,0,16,10,49,0,57,18,98,0,46,0,18,109,0,16,10,50,0,57,18,98,0,46, +0,18,109,0,16,10,51,0,57,18,98,0,46,0,0,0,0,1,90,95,0,0,31,0,2,26,1,1,0,0,9,0,97,0,0,1,1,0,0,31,0, +110,0,0,0,1,8,58,109,97,116,52,120,51,0,0,18,97,0,18,110,0,16,8,48,0,57,46,0,18,97,0,18,110,0,16, +10,49,0,57,46,0,18,97,0,18,110,0,16,10,50,0,57,46,0,18,97,0,18,110,0,16,10,51,0,57,46,0,0,0,0,1,90, +95,0,0,26,0,2,27,1,1,0,0,9,0,97,0,0,1,1,0,0,26,0,110,0,0,0,1,8,58,109,97,116,50,120,51,0,0,18,97,0, +18,110,0,16,8,48,0,57,47,0,18,97,0,18,110,0,16,10,49,0,57,47,0,0,0,0,1,90,95,0,0,26,0,2,27,1,1,0,0, +26,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,8,58,109,97,116,50,120,51,0,0,18,109,0,16,8,48,0,57,18,98,0,47, +0,18,109,0,16,10,49,0,57,18,98,0,47,0,0,0,0,1,90,95,0,0,28,0,2,27,1,1,0,0,9,0,97,0,0,1,1,0,0,28,0, +110,0,0,0,1,8,58,109,97,116,50,120,52,0,0,18,97,0,18,110,0,16,8,48,0,57,47,0,18,97,0,18,110,0,16, +10,49,0,57,47,0,0,0,0,1,90,95,0,0,28,0,2,27,1,1,0,0,28,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,8,58,109, +97,116,50,120,52,0,0,18,109,0,16,8,48,0,57,18,98,0,47,0,18,109,0,16,10,49,0,57,18,98,0,47,0,0,0,0, +1,90,95,0,0,27,0,2,27,1,1,0,0,9,0,97,0,0,1,1,0,0,27,0,110,0,0,0,1,8,58,109,97,116,51,120,50,0,0,18, +97,0,18,110,0,16,8,48,0,57,47,0,18,97,0,18,110,0,16,10,49,0,57,47,0,18,97,0,18,110,0,16,10,50,0,57, +47,0,0,0,0,1,90,95,0,0,27,0,2,27,1,1,0,0,27,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,8,58,109,97,116,51, +120,50,0,0,18,109,0,16,8,48,0,57,18,98,0,47,0,18,109,0,16,10,49,0,57,18,98,0,47,0,18,109,0,16,10, +50,0,57,18,98,0,47,0,0,0,0,1,90,95,0,0,30,0,2,27,1,1,0,0,9,0,97,0,0,1,1,0,0,30,0,110,0,0,0,1,8,58, +109,97,116,51,120,52,0,0,18,97,0,18,110,0,16,8,48,0,57,47,0,18,97,0,18,110,0,16,10,49,0,57,47,0,18, +97,0,18,110,0,16,10,50,0,57,47,0,0,0,0,1,90,95,0,0,30,0,2,27,1,1,0,0,30,0,109,0,0,1,1,0,0,9,0,98,0, +0,0,1,8,58,109,97,116,51,120,52,0,0,18,109,0,16,8,48,0,57,18,98,0,47,0,18,109,0,16,10,49,0,57,18, +98,0,47,0,18,109,0,16,10,50,0,57,18,98,0,47,0,0,0,0,1,90,95,0,0,29,0,2,27,1,1,0,0,29,0,109,0,0,1,1, +0,0,9,0,98,0,0,0,1,8,58,109,97,116,52,120,50,0,0,18,109,0,16,8,48,0,57,18,98,0,47,0,18,109,0,16,10, +49,0,57,18,98,0,47,0,18,109,0,16,10,50,0,57,18,98,0,47,0,18,109,0,16,10,51,0,57,18,98,0,47,0,0,0,0, +1,90,95,0,0,29,0,2,27,1,1,0,0,9,0,97,0,0,1,1,0,0,29,0,110,0,0,0,1,8,58,109,97,116,52,120,50,0,0,18, +97,0,18,110,0,16,8,48,0,57,47,0,18,97,0,18,110,0,16,10,49,0,57,47,0,18,97,0,18,110,0,16,10,50,0,57, +47,0,18,97,0,18,110,0,16,10,51,0,57,47,0,0,0,0,1,90,95,0,0,31,0,2,27,1,1,0,0,31,0,109,0,0,1,1,0,0, +9,0,98,0,0,0,1,8,58,109,97,116,52,120,51,0,0,18,109,0,16,8,48,0,57,18,98,0,47,0,18,109,0,16,10,49, +0,57,18,98,0,47,0,18,109,0,16,10,50,0,57,18,98,0,47,0,18,109,0,16,10,51,0,57,18,98,0,47,0,0,0,0,1, +90,95,0,0,31,0,2,27,1,1,0,0,9,0,97,0,0,1,1,0,0,31,0,110,0,0,0,1,8,58,109,97,116,52,120,51,0,0,18, +97,0,18,110,0,16,8,48,0,57,47,0,18,97,0,18,110,0,16,10,49,0,57,47,0,18,97,0,18,110,0,16,10,50,0,57, +47,0,18,97,0,18,110,0,16,10,51,0,57,47,0,0,0,0,1,90,95,0,0,26,0,2,21,1,1,0,0,9,0,97,0,0,1,1,0,0,26, +0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,97,0,18,110,0,16,8,48,0,57,48,20, +0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,97,0,18,110,0,16,10,49,0,57,48,20,0,0,1,90, +95,0,0,26,0,2,21,1,1,0,0,26,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16, +8,48,0,57,18,109,0,16,8,48,0,57,18,98,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57, +18,109,0,16,10,49,0,57,18,98,0,48,20,0,0,1,90,95,0,0,28,0,2,21,1,1,0,0,9,0,97,0,0,1,1,0,0,28,0,110, +0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,97,0,18,110,0,16,8,48,0,57,48,20,0,9,18, +95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,97,0,18,110,0,16,10,49,0,57,48,20,0,0,1,90,95,0,0, +28,0,2,21,1,1,0,0,28,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0, +57,18,109,0,16,8,48,0,57,18,98,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0, +16,10,49,0,57,18,98,0,48,20,0,0,1,90,95,0,0,27,0,2,21,1,1,0,0,9,0,97,0,0,1,1,0,0,27,0,110,0,0,0,1, +9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,97,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,49,0,57,18,97,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,50,0,57,18,97,0,18,110,0,16,10,50,0,57,48,20,0,0,1,90,95,0,0,27,0,2,21,1,1,0, +0,27,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16, +8,48,0,57,18,98,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57, +18,98,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,98,0,48, +20,0,0,1,90,95,0,0,30,0,2,21,1,1,0,0,9,0,97,0,0,1,1,0,0,30,0,110,0,0,0,1,9,18,95,95,114,101,116,86, +97,108,0,16,8,48,0,57,18,97,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16, +10,49,0,57,18,97,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57, +18,97,0,18,110,0,16,10,50,0,57,48,20,0,0,1,90,95,0,0,30,0,2,21,1,1,0,0,30,0,109,0,0,1,1,0,0,9,0,98, +0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,98,0,48,20,0,9,18, +95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,98,0,48,20,0,9,18,95,95,114, +101,116,86,97,108,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,98,0,48,20,0,0,1,90,95,0,0,29,0,2,21,1, +1,0,0,29,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0, +16,8,48,0,57,18,98,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0, +57,18,98,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,98,0, +48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,18,109,0,16,10,51,0,57,18,98,0,48,20,0,0, +1,90,95,0,0,29,0,2,21,1,1,0,0,9,0,97,0,0,1,1,0,0,29,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108, +0,16,8,48,0,57,18,97,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0, +57,18,97,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,97,0, +18,110,0,16,10,50,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,18,97,0,18,110,0, +16,10,51,0,57,48,20,0,0,1,90,95,0,0,31,0,2,21,1,1,0,0,31,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,9,18,95, +95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,98,0,48,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,98,0,48,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,98,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16, +10,51,0,57,18,109,0,16,10,51,0,57,18,98,0,48,20,0,0,1,90,95,0,0,31,0,2,21,1,1,0,0,9,0,97,0,0,1,1,0, +0,31,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,97,0,18,110,0,16,8,48,0,57, +48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,97,0,18,110,0,16,10,49,0,57,48,20,0,9, +18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,97,0,18,110,0,16,10,50,0,57,48,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,51,0,57,18,97,0,18,110,0,16,10,51,0,57,48,20,0,0,1,90,95,0,0,26,0,2, +22,1,1,0,0,9,0,97,0,0,1,1,0,0,26,0,110,0,0,0,1,3,2,90,95,1,0,9,0,1,105,110,118,0,2,17,49,0,48,0,0, +18,97,0,49,0,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,105,110,118,0,18,110,0,16,8,48,0, +57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,105,110,118,0,18,110,0,16,10,49,0, +57,48,20,0,0,1,90,95,0,0,26,0,2,22,1,1,0,0,26,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,3,2,90,95,1,0,9,0,1, +105,110,118,0,2,17,49,0,48,0,0,18,98,0,49,0,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18, +109,0,16,8,48,0,57,18,105,110,118,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18, +109,0,16,10,49,0,57,18,105,110,118,0,48,20,0,0,1,90,95,0,0,28,0,2,22,1,1,0,0,9,0,97,0,0,1,1,0,0,28, +0,110,0,0,0,1,3,2,90,95,1,0,9,0,1,105,110,118,0,2,17,49,0,48,0,0,18,97,0,49,0,0,9,18,95,95,114,101, +116,86,97,108,0,16,8,48,0,57,18,105,110,118,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116, +86,97,108,0,16,10,49,0,57,18,105,110,118,0,18,110,0,16,10,49,0,57,48,20,0,0,1,90,95,0,0,28,0,2,22, +1,1,0,0,28,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,3,2,90,95,1,0,9,0,1,105,110,118,0,2,17,49,0,48,0,0,18, +98,0,49,0,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,105,110,118,0, +48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,105,110,118,0, +48,20,0,0,1,90,95,0,0,27,0,2,22,1,1,0,0,9,0,97,0,0,1,1,0,0,27,0,110,0,0,0,1,3,2,90,95,1,0,9,0,1, +105,110,118,0,2,17,49,0,48,0,0,18,97,0,49,0,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18, +105,110,118,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18, +105,110,118,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18, +105,110,118,0,18,110,0,16,10,50,0,57,48,20,0,0,1,90,95,0,0,27,0,2,22,1,1,0,0,27,0,109,0,0,1,1,0,0, +9,0,98,0,0,0,1,3,2,90,95,1,0,9,0,1,105,110,118,0,2,17,49,0,48,0,0,18,98,0,49,0,0,9,18,95,95,114, +101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,105,110,118,0,48,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,105,110,118,0,48,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,105,110,118,0,48,20,0,0,1,90,95,0,0,30,0,2, +22,1,1,0,0,9,0,97,0,0,1,1,0,0,30,0,110,0,0,0,1,3,2,90,95,1,0,9,0,1,105,110,118,0,2,17,49,0,48,0,0, +18,97,0,49,0,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,105,110,118,0,18,110,0,16,8,48,0, +57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,105,110,118,0,18,110,0,16,10,49,0, +57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,105,110,118,0,18,110,0,16,10,50,0, +57,48,20,0,0,1,90,95,0,0,30,0,2,22,1,1,0,0,30,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,3,2,90,95,1,0,9,0,1, +105,110,118,0,2,17,49,0,48,0,0,18,98,0,49,0,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18, +109,0,16,8,48,0,57,18,105,110,118,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18, +109,0,16,10,49,0,57,18,105,110,118,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18, +109,0,16,10,50,0,57,18,105,110,118,0,48,20,0,0,1,90,95,0,0,29,0,2,22,1,1,0,0,29,0,109,0,0,1,1,0,0, +9,0,98,0,0,0,1,3,2,90,95,1,0,9,0,1,105,110,118,0,2,17,49,0,48,0,0,18,98,0,49,0,0,9,18,95,95,114, +101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,105,110,118,0,48,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,105,110,118,0,48,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,105,110,118,0,48,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,51,0,57,18,109,0,16,10,51,0,57,18,105,110,118,0,48,20,0,0,1,90,95,0,0,29,0,2, +22,1,1,0,0,9,0,97,0,0,1,1,0,0,29,0,110,0,0,0,1,3,2,90,95,1,0,9,0,1,105,110,118,0,2,17,49,0,48,0,0, +18,97,0,49,0,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,105,110,118,0,18,110,0,16,8,48,0, +57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,105,110,118,0,18,110,0,16,10,49,0, +57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,105,110,118,0,18,110,0,16,10,50,0, +57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,18,105,110,118,0,18,110,0,16,10,51,0, +57,48,20,0,0,1,90,95,0,0,31,0,2,22,1,1,0,0,31,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,3,2,90,95,1,0,9,0,1, +105,110,118,0,2,17,49,0,48,0,0,18,98,0,49,0,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18, +109,0,16,8,48,0,57,18,105,110,118,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18, +109,0,16,10,49,0,57,18,105,110,118,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18, +109,0,16,10,50,0,57,18,105,110,118,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,18, +109,0,16,10,51,0,57,18,105,110,118,0,48,20,0,0,1,90,95,0,0,31,0,2,22,1,1,0,0,9,0,97,0,0,1,1,0,0,31, +0,110,0,0,0,1,3,2,90,95,1,0,9,0,1,105,110,118,0,2,17,49,0,48,0,0,18,97,0,49,0,0,9,18,95,95,114,101, +116,86,97,108,0,16,8,48,0,57,18,105,110,118,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116, +86,97,108,0,16,10,49,0,57,18,105,110,118,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101,116, +86,97,108,0,16,10,50,0,57,18,105,110,118,0,18,110,0,16,10,50,0,57,48,20,0,9,18,95,95,114,101,116, +86,97,108,0,16,10,51,0,57,18,105,110,118,0,18,110,0,16,10,51,0,57,48,20,0,0,1,90,95,0,0,26,0,2,27, +1,1,0,0,26,0,109,0,0,0,1,8,58,109,97,116,50,120,51,0,0,18,109,0,16,8,48,0,57,54,0,18,109,0,16,10, +49,0,57,54,0,0,0,0,1,90,95,0,0,28,0,2,27,1,1,0,0,28,0,109,0,0,0,1,8,58,109,97,116,50,120,52,0,0,18, +109,0,16,8,48,0,57,54,0,18,109,0,16,10,49,0,57,54,0,0,0,0,1,90,95,0,0,27,0,2,27,1,1,0,0,27,0,109,0, +0,0,1,8,58,109,97,116,51,120,50,0,0,18,109,0,16,8,48,0,57,54,0,18,109,0,16,10,49,0,57,54,0,18,109, +0,16,10,50,0,57,54,0,0,0,0,1,90,95,0,0,30,0,2,27,1,1,0,0,30,0,109,0,0,0,1,8,58,109,97,116,51,120, +52,0,0,18,109,0,16,8,48,0,57,54,0,18,109,0,16,10,49,0,57,54,0,18,109,0,16,10,50,0,57,54,0,0,0,0,1, +90,95,0,0,29,0,2,27,1,1,0,0,29,0,109,0,0,0,1,8,58,109,97,116,52,120,50,0,0,18,109,0,16,8,48,0,57, +54,0,18,109,0,16,10,49,0,57,54,0,18,109,0,16,10,50,0,57,54,0,18,109,0,16,10,51,0,57,54,0,0,0,0,1, +90,95,0,0,31,0,2,27,1,1,0,0,31,0,109,0,0,0,1,8,58,109,97,116,52,120,51,0,0,18,109,0,16,8,48,0,57, +54,0,18,109,0,16,10,49,0,57,54,0,18,109,0,16,10,50,0,57,54,0,18,109,0,16,10,51,0,57,54,0,0,0,0,1, +90,95,0,0,0,0,2,25,1,0,2,0,26,0,109,0,0,0,1,9,18,109,0,16,8,48,0,57,52,0,9,18,109,0,16,10,49,0,57, +52,0,0,1,90,95,0,0,0,0,2,25,1,0,2,0,28,0,109,0,0,0,1,9,18,109,0,16,8,48,0,57,52,0,9,18,109,0,16,10, +49,0,57,52,0,0,1,90,95,0,0,0,0,2,25,1,0,2,0,27,0,109,0,0,0,1,9,18,109,0,16,8,48,0,57,52,0,9,18,109, +0,16,10,49,0,57,52,0,9,18,109,0,16,10,50,0,57,52,0,0,1,90,95,0,0,0,0,2,25,1,0,2,0,30,0,109,0,0,0,1, +9,18,109,0,16,8,48,0,57,52,0,9,18,109,0,16,10,49,0,57,52,0,9,18,109,0,16,10,50,0,57,52,0,0,1,90,95, +0,0,0,0,2,25,1,0,2,0,29,0,109,0,0,0,1,9,18,109,0,16,8,48,0,57,52,0,9,18,109,0,16,10,49,0,57,52,0,9, +18,109,0,16,10,50,0,57,52,0,9,18,109,0,16,10,51,0,57,52,0,0,1,90,95,0,0,0,0,2,25,1,0,2,0,31,0,109, +0,0,0,1,9,18,109,0,16,8,48,0,57,52,0,9,18,109,0,16,10,49,0,57,52,0,9,18,109,0,16,10,50,0,57,52,0,9, +18,109,0,16,10,51,0,57,52,0,0,1,90,95,0,0,0,0,2,24,1,0,2,0,26,0,109,0,0,0,1,9,18,109,0,16,8,48,0, +57,51,0,9,18,109,0,16,10,49,0,57,51,0,0,1,90,95,0,0,0,0,2,24,1,0,2,0,28,0,109,0,0,0,1,9,18,109,0, +16,8,48,0,57,51,0,9,18,109,0,16,10,49,0,57,51,0,0,1,90,95,0,0,0,0,2,24,1,0,2,0,27,0,109,0,0,0,1,9, +18,109,0,16,8,48,0,57,51,0,9,18,109,0,16,10,49,0,57,51,0,9,18,109,0,16,10,50,0,57,51,0,0,1,90,95,0, +0,0,0,2,24,1,0,2,0,30,0,109,0,0,0,1,9,18,109,0,16,8,48,0,57,51,0,9,18,109,0,16,10,49,0,57,51,0,9, +18,109,0,16,10,50,0,57,51,0,0,1,90,95,0,0,0,0,2,24,1,0,2,0,29,0,109,0,0,0,1,9,18,109,0,16,8,48,0, +57,51,0,9,18,109,0,16,10,49,0,57,51,0,9,18,109,0,16,10,50,0,57,51,0,9,18,109,0,16,10,51,0,57,51,0, +0,1,90,95,0,0,0,0,2,24,1,0,2,0,31,0,109,0,0,0,1,9,18,109,0,16,8,48,0,57,51,0,9,18,109,0,16,10,49,0, +57,51,0,9,18,109,0,16,10,50,0,57,51,0,9,18,109,0,16,10,51,0,57,51,0,0,0 diff --git a/mesalib/src/mesa/shader/slang/library/slang_builtin_120_common.gc b/mesalib/src/mesa/shader/slang/library/slang_builtin_120_common.gc new file mode 100644 index 000000000..c6264c3b4 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_builtin_120_common.gc @@ -0,0 +1,200 @@ +/* + * Mesa 3-D graphics library + * Version: 6.6 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// +// From Shader Spec, ver. 1.20, rev. 6 +// + +// +// 8.5 Matrix Functions +// + +mat2x3 matrixCompMult (mat2x3 m, mat2x3 n) { + return mat2x3 (m[0] * n[0], m[1] * n[1]); +} + +mat2x4 matrixCompMult (mat2x4 m, mat2x4 n) { + return mat2x4 (m[0] * n[0], m[1] * n[1]); +} + +mat3x2 matrixCompMult (mat3x2 m, mat3x2 n) { + return mat3x2 (m[0] * n[0], m[1] * n[1], m[2] * n[2]); +} + +mat3x4 matrixCompMult (mat3x4 m, mat3x4 n) { + return mat3x4 (m[0] * n[0], m[1] * n[1], m[2] * n[2]); +} + +mat4x2 matrixCompMult (mat4x2 m, mat4x2 n) { + return mat4x2 (m[0] * n[0], m[1] * n[1], m[2] * n[2], m[3] * n[3]); +} + +mat4x3 matrixCompMult (mat4x3 m, mat4x3 n) { + return mat4x3 (m[0] * n[0], m[1] * n[1], m[2] * n[2], m[3] * n[3]); +} + +mat2 outerProduct (vec2 c, vec2 r) { + return mat2 ( + c.x * r.x, c.y * r.x, + c.x * r.y, c.y * r.y + ); +} + +mat3 outerProduct (vec3 c, vec3 r) { + return mat3 ( + c.x * r.x, c.y * r.x, c.z * r.x, + c.x * r.y, c.y * r.y, c.z * r.y, + c.x * r.z, c.y * r.z, c.z * r.z + ); +} + +mat4 outerProduct (vec4 c, vec4 r) { + return mat4 ( + c.x * r.x, c.y * r.x, c.z * r.x, c.w * r.x, + c.x * r.y, c.y * r.y, c.z * r.y, c.w * r.y, + c.x * r.z, c.y * r.z, c.z * r.z, c.w * r.z, + c.x * r.w, c.y * r.w, c.z * r.w, c.w * r.w + ); +} + +mat2x3 outerProduct (vec3 c, vec2 r) { + return mat2x3 ( + c.x * r.x, c.y * r.x, c.z * r.x, + c.x * r.y, c.y * r.y, c.z * r.y + ); +} + +mat3x2 outerProduct (vec2 c, vec3 r) { + return mat3x2 ( + c.x * r.x, c.y * r.x, + c.x * r.y, c.y * r.y, + c.x * r.z, c.y * r.z + ); +} + +mat2x4 outerProduct (vec4 c, vec2 r) { + return mat2x4 ( + c.x * r.x, c.y * r.x, c.z * r.x, c.w * r.x, + c.x * r.y, c.y * r.y, c.z * r.y, c.w * r.y + ); +} + +mat4x2 outerProduct (vec2 c, vec4 r) { + return mat4x2 ( + c.x * r.x, c.y * r.x, + c.x * r.y, c.y * r.y, + c.x * r.z, c.y * r.z, + c.x * r.w, c.y * r.w + ); +} + +mat3x4 outerProduct (vec4 c, vec3 r) { + return mat3x4 ( + c.x * r.x, c.y * r.x, c.z * r.x, c.w * r.x, + c.x * r.y, c.y * r.y, c.z * r.y, c.w * r.y, + c.x * r.z, c.y * r.z, c.z * r.z, c.w * r.z + ); +} + +mat4x3 outerProduct (vec3 c, vec4 r) { + return mat4x3 ( + c.x * r.x, c.y * r.x, c.z * r.x, + c.x * r.y, c.y * r.y, c.z * r.y, + c.x * r.z, c.y * r.z, c.z * r.z, + c.x * r.w, c.y * r.w, c.z * r.w + ); +} + +mat2 transpose (mat2 m) { + return mat2 ( + m[0].x, m[1].x, + m[0].y, m[1].y + ); +} + +mat3 transpose (mat3 m) { + return mat3 ( + m[0].x, m[1].x, m[2].x, + m[0].y, m[1].y, m[2].y, + m[0].z, m[1].z, m[2].z + ); +} + +mat4 transpose (mat4 m) { + return mat4 ( + m[0].x, m[1].x, m[2].x, m[3].x, + m[0].y, m[1].y, m[2].y, m[3].y, + m[0].z, m[1].z, m[2].z, m[3].z, + m[0].w, m[1].w, m[2].w, m[3].w + ); +} + +mat2x3 transpose (mat3x2 m) { + return mat2x3 ( + m[0].x, m[1].x, m[2].x, + m[0].y, m[1].y, m[2].y + ); +} + +mat3x2 transpose (mat2x3 m) { + return mat3x2 ( + m[0].x, m[1].x, + m[0].y, m[1].y, + m[0].z, m[1].z + ); +} + +mat2x4 transpose (mat4x2 m) { + return mat2x4 ( + m[0].x, m[1].x, m[2].x, m[3].x, + m[0].y, m[1].y, m[2].y, m[3].y + ); +} + +mat4x2 transpose (mat2x4 m) { + return mat4x2 ( + m[0].x, m[1].x, + m[0].y, m[1].y, + m[0].z, m[1].z, + m[0].w, m[1].w + ); +} + +mat3x4 transpose (mat4x3 m) { + return mat3x4 ( + m[0].x, m[1].x, m[2].x, m[3].x, + m[0].y, m[1].y, m[2].y, m[3].y, + m[0].z, m[1].z, m[2].z, m[3].z + ); +} + +mat4x3 transpose (mat3x4 m) { + return mat4x3 ( + m[0].x, m[1].x, m[2].x, + m[0].y, m[1].y, m[2].y, + m[0].z, m[1].z, m[2].z, + m[0].w, m[1].w, m[2].w + ); +} + diff --git a/mesalib/src/mesa/shader/slang/library/slang_builtin_120_common_gc.h b/mesalib/src/mesa/shader/slang/library/slang_builtin_120_common_gc.h new file mode 100644 index 000000000..c397b9f0f --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_builtin_120_common_gc.h @@ -0,0 +1,108 @@ + +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */ +/* slang_builtin_120_common.gc */ + +5,1,90,95,0,0,26,0,0,109,97,116,114,105,120,67,111,109,112,77,117,108,116,0,1,0,0,0,26,0,109,0,0,1, +0,0,0,26,0,110,0,0,0,1,8,58,109,97,116,50,120,51,0,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57, +48,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,48,0,0,0,0,1,90,95,0,0,28,0,0,109,97,116,114, +105,120,67,111,109,112,77,117,108,116,0,1,0,0,0,28,0,109,0,0,1,0,0,0,28,0,110,0,0,0,1,8,58,109,97, +116,50,120,52,0,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,48,0,18,109,0,16,10,49,0,57,18,110,0, +16,10,49,0,57,48,0,0,0,0,1,90,95,0,0,27,0,0,109,97,116,114,105,120,67,111,109,112,77,117,108,116,0, +1,0,0,0,27,0,109,0,0,1,0,0,0,27,0,110,0,0,0,1,8,58,109,97,116,51,120,50,0,0,18,109,0,16,8,48,0,57, +18,110,0,16,8,48,0,57,48,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,48,0,18,109,0,16,10,50,0, +57,18,110,0,16,10,50,0,57,48,0,0,0,0,1,90,95,0,0,30,0,0,109,97,116,114,105,120,67,111,109,112,77, +117,108,116,0,1,0,0,0,30,0,109,0,0,1,0,0,0,30,0,110,0,0,0,1,8,58,109,97,116,51,120,52,0,0,18,109,0, +16,8,48,0,57,18,110,0,16,8,48,0,57,48,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,48,0,18,109, +0,16,10,50,0,57,18,110,0,16,10,50,0,57,48,0,0,0,0,1,90,95,0,0,29,0,0,109,97,116,114,105,120,67,111, +109,112,77,117,108,116,0,1,0,0,0,29,0,109,0,0,1,0,0,0,29,0,110,0,0,0,1,8,58,109,97,116,52,120,50,0, +0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,48,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57, +48,0,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,48,0,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0, +57,48,0,0,0,0,1,90,95,0,0,31,0,0,109,97,116,114,105,120,67,111,109,112,77,117,108,116,0,1,0,0,0,31, +0,109,0,0,1,0,0,0,31,0,110,0,0,0,1,8,58,109,97,116,52,120,51,0,0,18,109,0,16,8,48,0,57,18,110,0,16, +8,48,0,57,48,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,48,0,18,109,0,16,10,50,0,57,18,110,0, +16,10,50,0,57,48,0,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,48,0,0,0,0,1,90,95,0,0,13,0,0,111, +117,116,101,114,80,114,111,100,117,99,116,0,1,0,0,0,10,0,99,0,0,1,0,0,0,10,0,114,0,0,0,1,8,58,109, +97,116,50,0,0,18,99,0,59,120,0,18,114,0,59,120,0,48,0,18,99,0,59,121,0,18,114,0,59,120,0,48,0,18, +99,0,59,120,0,18,114,0,59,121,0,48,0,18,99,0,59,121,0,18,114,0,59,121,0,48,0,0,0,0,1,90,95,0,0,14, +0,0,111,117,116,101,114,80,114,111,100,117,99,116,0,1,0,0,0,11,0,99,0,0,1,0,0,0,11,0,114,0,0,0,1,8, +58,109,97,116,51,0,0,18,99,0,59,120,0,18,114,0,59,120,0,48,0,18,99,0,59,121,0,18,114,0,59,120,0,48, +0,18,99,0,59,122,0,18,114,0,59,120,0,48,0,18,99,0,59,120,0,18,114,0,59,121,0,48,0,18,99,0,59,121,0, +18,114,0,59,121,0,48,0,18,99,0,59,122,0,18,114,0,59,121,0,48,0,18,99,0,59,120,0,18,114,0,59,122,0, +48,0,18,99,0,59,121,0,18,114,0,59,122,0,48,0,18,99,0,59,122,0,18,114,0,59,122,0,48,0,0,0,0,1,90,95, +0,0,15,0,0,111,117,116,101,114,80,114,111,100,117,99,116,0,1,0,0,0,12,0,99,0,0,1,0,0,0,12,0,114,0, +0,0,1,8,58,109,97,116,52,0,0,18,99,0,59,120,0,18,114,0,59,120,0,48,0,18,99,0,59,121,0,18,114,0,59, +120,0,48,0,18,99,0,59,122,0,18,114,0,59,120,0,48,0,18,99,0,59,119,0,18,114,0,59,120,0,48,0,18,99,0, +59,120,0,18,114,0,59,121,0,48,0,18,99,0,59,121,0,18,114,0,59,121,0,48,0,18,99,0,59,122,0,18,114,0, +59,121,0,48,0,18,99,0,59,119,0,18,114,0,59,121,0,48,0,18,99,0,59,120,0,18,114,0,59,122,0,48,0,18, +99,0,59,121,0,18,114,0,59,122,0,48,0,18,99,0,59,122,0,18,114,0,59,122,0,48,0,18,99,0,59,119,0,18, +114,0,59,122,0,48,0,18,99,0,59,120,0,18,114,0,59,119,0,48,0,18,99,0,59,121,0,18,114,0,59,119,0,48, +0,18,99,0,59,122,0,18,114,0,59,119,0,48,0,18,99,0,59,119,0,18,114,0,59,119,0,48,0,0,0,0,1,90,95,0, +0,26,0,0,111,117,116,101,114,80,114,111,100,117,99,116,0,1,0,0,0,11,0,99,0,0,1,0,0,0,10,0,114,0,0, +0,1,8,58,109,97,116,50,120,51,0,0,18,99,0,59,120,0,18,114,0,59,120,0,48,0,18,99,0,59,121,0,18,114, +0,59,120,0,48,0,18,99,0,59,122,0,18,114,0,59,120,0,48,0,18,99,0,59,120,0,18,114,0,59,121,0,48,0,18, +99,0,59,121,0,18,114,0,59,121,0,48,0,18,99,0,59,122,0,18,114,0,59,121,0,48,0,0,0,0,1,90,95,0,0,27, +0,0,111,117,116,101,114,80,114,111,100,117,99,116,0,1,0,0,0,10,0,99,0,0,1,0,0,0,11,0,114,0,0,0,1,8, +58,109,97,116,51,120,50,0,0,18,99,0,59,120,0,18,114,0,59,120,0,48,0,18,99,0,59,121,0,18,114,0,59, +120,0,48,0,18,99,0,59,120,0,18,114,0,59,121,0,48,0,18,99,0,59,121,0,18,114,0,59,121,0,48,0,18,99,0, +59,120,0,18,114,0,59,122,0,48,0,18,99,0,59,121,0,18,114,0,59,122,0,48,0,0,0,0,1,90,95,0,0,28,0,0, +111,117,116,101,114,80,114,111,100,117,99,116,0,1,0,0,0,12,0,99,0,0,1,0,0,0,10,0,114,0,0,0,1,8,58, +109,97,116,50,120,52,0,0,18,99,0,59,120,0,18,114,0,59,120,0,48,0,18,99,0,59,121,0,18,114,0,59,120, +0,48,0,18,99,0,59,122,0,18,114,0,59,120,0,48,0,18,99,0,59,119,0,18,114,0,59,120,0,48,0,18,99,0,59, +120,0,18,114,0,59,121,0,48,0,18,99,0,59,121,0,18,114,0,59,121,0,48,0,18,99,0,59,122,0,18,114,0,59, +121,0,48,0,18,99,0,59,119,0,18,114,0,59,121,0,48,0,0,0,0,1,90,95,0,0,29,0,0,111,117,116,101,114,80, +114,111,100,117,99,116,0,1,0,0,0,10,0,99,0,0,1,0,0,0,12,0,114,0,0,0,1,8,58,109,97,116,52,120,50,0, +0,18,99,0,59,120,0,18,114,0,59,120,0,48,0,18,99,0,59,121,0,18,114,0,59,120,0,48,0,18,99,0,59,120,0, +18,114,0,59,121,0,48,0,18,99,0,59,121,0,18,114,0,59,121,0,48,0,18,99,0,59,120,0,18,114,0,59,122,0, +48,0,18,99,0,59,121,0,18,114,0,59,122,0,48,0,18,99,0,59,120,0,18,114,0,59,119,0,48,0,18,99,0,59, +121,0,18,114,0,59,119,0,48,0,0,0,0,1,90,95,0,0,30,0,0,111,117,116,101,114,80,114,111,100,117,99, +116,0,1,0,0,0,12,0,99,0,0,1,0,0,0,11,0,114,0,0,0,1,8,58,109,97,116,51,120,52,0,0,18,99,0,59,120,0, +18,114,0,59,120,0,48,0,18,99,0,59,121,0,18,114,0,59,120,0,48,0,18,99,0,59,122,0,18,114,0,59,120,0, +48,0,18,99,0,59,119,0,18,114,0,59,120,0,48,0,18,99,0,59,120,0,18,114,0,59,121,0,48,0,18,99,0,59, +121,0,18,114,0,59,121,0,48,0,18,99,0,59,122,0,18,114,0,59,121,0,48,0,18,99,0,59,119,0,18,114,0,59, +121,0,48,0,18,99,0,59,120,0,18,114,0,59,122,0,48,0,18,99,0,59,121,0,18,114,0,59,122,0,48,0,18,99,0, +59,122,0,18,114,0,59,122,0,48,0,18,99,0,59,119,0,18,114,0,59,122,0,48,0,0,0,0,1,90,95,0,0,31,0,0, +111,117,116,101,114,80,114,111,100,117,99,116,0,1,0,0,0,11,0,99,0,0,1,0,0,0,12,0,114,0,0,0,1,8,58, +109,97,116,52,120,51,0,0,18,99,0,59,120,0,18,114,0,59,120,0,48,0,18,99,0,59,121,0,18,114,0,59,120, +0,48,0,18,99,0,59,122,0,18,114,0,59,120,0,48,0,18,99,0,59,120,0,18,114,0,59,121,0,48,0,18,99,0,59, +121,0,18,114,0,59,121,0,48,0,18,99,0,59,122,0,18,114,0,59,121,0,48,0,18,99,0,59,120,0,18,114,0,59, +122,0,48,0,18,99,0,59,121,0,18,114,0,59,122,0,48,0,18,99,0,59,122,0,18,114,0,59,122,0,48,0,18,99,0, +59,120,0,18,114,0,59,119,0,48,0,18,99,0,59,121,0,18,114,0,59,119,0,48,0,18,99,0,59,122,0,18,114,0, +59,119,0,48,0,0,0,0,1,90,95,0,0,13,0,0,116,114,97,110,115,112,111,115,101,0,1,0,0,0,13,0,109,0,0,0, +1,8,58,109,97,116,50,0,0,18,109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18,109, +0,16,8,48,0,57,59,121,0,0,18,109,0,16,10,49,0,57,59,121,0,0,0,0,0,1,90,95,0,0,14,0,0,116,114,97, +110,115,112,111,115,101,0,1,0,0,0,14,0,109,0,0,0,1,8,58,109,97,116,51,0,0,18,109,0,16,8,48,0,57,59, +120,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18,109,0,16,10,50,0,57,59,120,0,0,18,109,0,16,8,48,0,57, +59,121,0,0,18,109,0,16,10,49,0,57,59,121,0,0,18,109,0,16,10,50,0,57,59,121,0,0,18,109,0,16,8,48,0, +57,59,122,0,0,18,109,0,16,10,49,0,57,59,122,0,0,18,109,0,16,10,50,0,57,59,122,0,0,0,0,0,1,90,95,0, +0,15,0,0,116,114,97,110,115,112,111,115,101,0,1,0,0,0,15,0,109,0,0,0,1,8,58,109,97,116,52,0,0,18, +109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18,109,0,16,10,50,0,57,59,120,0,0, +18,109,0,16,10,51,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59,121,0,0,18,109,0,16,10,49,0,57,59,121,0, +0,18,109,0,16,10,50,0,57,59,121,0,0,18,109,0,16,10,51,0,57,59,121,0,0,18,109,0,16,8,48,0,57,59,122, +0,0,18,109,0,16,10,49,0,57,59,122,0,0,18,109,0,16,10,50,0,57,59,122,0,0,18,109,0,16,10,51,0,57,59, +122,0,0,18,109,0,16,8,48,0,57,59,119,0,0,18,109,0,16,10,49,0,57,59,119,0,0,18,109,0,16,10,50,0,57, +59,119,0,0,18,109,0,16,10,51,0,57,59,119,0,0,0,0,0,1,90,95,0,0,26,0,0,116,114,97,110,115,112,111, +115,101,0,1,0,0,0,27,0,109,0,0,0,1,8,58,109,97,116,50,120,51,0,0,18,109,0,16,8,48,0,57,59,120,0,0, +18,109,0,16,10,49,0,57,59,120,0,0,18,109,0,16,10,50,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59,121,0, +0,18,109,0,16,10,49,0,57,59,121,0,0,18,109,0,16,10,50,0,57,59,121,0,0,0,0,0,1,90,95,0,0,27,0,0,116, +114,97,110,115,112,111,115,101,0,1,0,0,0,26,0,109,0,0,0,1,8,58,109,97,116,51,120,50,0,0,18,109,0, +16,8,48,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59,121,0,0,18,109, +0,16,10,49,0,57,59,121,0,0,18,109,0,16,8,48,0,57,59,122,0,0,18,109,0,16,10,49,0,57,59,122,0,0,0,0, +0,1,90,95,0,0,28,0,0,116,114,97,110,115,112,111,115,101,0,1,0,0,0,29,0,109,0,0,0,1,8,58,109,97,116, +50,120,52,0,0,18,109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18,109,0,16,10,50, +0,57,59,120,0,0,18,109,0,16,10,51,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59,121,0,0,18,109,0,16,10, +49,0,57,59,121,0,0,18,109,0,16,10,50,0,57,59,121,0,0,18,109,0,16,10,51,0,57,59,121,0,0,0,0,0,1,90, +95,0,0,29,0,0,116,114,97,110,115,112,111,115,101,0,1,0,0,0,28,0,109,0,0,0,1,8,58,109,97,116,52,120, +50,0,0,18,109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59, +121,0,0,18,109,0,16,10,49,0,57,59,121,0,0,18,109,0,16,8,48,0,57,59,122,0,0,18,109,0,16,10,49,0,57, +59,122,0,0,18,109,0,16,8,48,0,57,59,119,0,0,18,109,0,16,10,49,0,57,59,119,0,0,0,0,0,1,90,95,0,0,30, +0,0,116,114,97,110,115,112,111,115,101,0,1,0,0,0,31,0,109,0,0,0,1,8,58,109,97,116,51,120,52,0,0,18, +109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18,109,0,16,10,50,0,57,59,120,0,0, +18,109,0,16,10,51,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59,121,0,0,18,109,0,16,10,49,0,57,59,121,0, +0,18,109,0,16,10,50,0,57,59,121,0,0,18,109,0,16,10,51,0,57,59,121,0,0,18,109,0,16,8,48,0,57,59,122, +0,0,18,109,0,16,10,49,0,57,59,122,0,0,18,109,0,16,10,50,0,57,59,122,0,0,18,109,0,16,10,51,0,57,59, +122,0,0,0,0,0,1,90,95,0,0,31,0,0,116,114,97,110,115,112,111,115,101,0,1,0,0,0,30,0,109,0,0,0,1,8, +58,109,97,116,52,120,51,0,0,18,109,0,16,8,48,0,57,59,120,0,0,18,109,0,16,10,49,0,57,59,120,0,0,18, +109,0,16,10,50,0,57,59,120,0,0,18,109,0,16,8,48,0,57,59,121,0,0,18,109,0,16,10,49,0,57,59,121,0,0, +18,109,0,16,10,50,0,57,59,121,0,0,18,109,0,16,8,48,0,57,59,122,0,0,18,109,0,16,10,49,0,57,59,122,0, +0,18,109,0,16,10,50,0,57,59,122,0,0,18,109,0,16,8,48,0,57,59,119,0,0,18,109,0,16,10,49,0,57,59,119, +0,0,18,109,0,16,10,50,0,57,59,119,0,0,0,0,0,0 diff --git a/mesalib/src/mesa/shader/slang/library/slang_builtin_120_fragment.gc b/mesalib/src/mesa/shader/slang/library/slang_builtin_120_fragment.gc new file mode 100644 index 000000000..7d516046a --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_builtin_120_fragment.gc @@ -0,0 +1,30 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// +// From Shader Spec, ver. 1.20, rev. 6 +// + +varying vec2 gl_PointCoord; + diff --git a/mesalib/src/mesa/shader/slang/library/slang_builtin_120_fragment_gc.h b/mesalib/src/mesa/shader/slang/library/slang_builtin_120_fragment_gc.h new file mode 100644 index 000000000..add3b5aea --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_builtin_120_fragment_gc.h @@ -0,0 +1,5 @@ + +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */ +/* slang_builtin_120_fragment.gc */ + +5,2,2,90,95,3,0,10,0,1,103,108,95,80,111,105,110,116,67,111,111,114,100,0,0,0,0 diff --git a/mesalib/src/mesa/shader/slang/library/slang_common_builtin.gc b/mesalib/src/mesa/shader/slang/library/slang_common_builtin.gc new file mode 100644 index 000000000..9764fc25b --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_common_builtin.gc @@ -0,0 +1,1873 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * Copyright (C) 2008 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. + */ + +// +// From Shader Spec, ver. 1.10, rev. 59 +// + +// Note: the values assigned to these constants here aren't actually used. +// They're set by the compiler according to the GL context limits. +// See slang_simplify.c +const int gl_MaxLights = 8; +const int gl_MaxClipPlanes = 6; +const int gl_MaxTextureUnits = 8; +const int gl_MaxTextureCoords = 8; +const int gl_MaxVertexAttribs = 16; +const int gl_MaxVertexUniformComponents = 512; +const int gl_MaxVaryingFloats = 32; +const int gl_MaxVertexTextureImageUnits = 0; +const int gl_MaxCombinedTextureImageUnits = 2; +const int gl_MaxTextureImageUnits = 2; +const int gl_MaxFragmentUniformComponents = 64; +const int gl_MaxDrawBuffers = 1; + +uniform mat4 gl_ModelViewMatrix; +uniform mat4 gl_ProjectionMatrix; +uniform mat4 gl_ModelViewProjectionMatrix; +uniform mat4 gl_TextureMatrix[gl_MaxTextureCoords]; + +uniform mat3 gl_NormalMatrix; + +uniform mat4 gl_ModelViewMatrixInverse; +uniform mat4 gl_ProjectionMatrixInverse; +uniform mat4 gl_ModelViewProjectionMatrixInverse; +uniform mat4 gl_TextureMatrixInverse[gl_MaxTextureCoords]; + +uniform mat4 gl_ModelViewMatrixTranspose; +uniform mat4 gl_ProjectionMatrixTranspose; +uniform mat4 gl_ModelViewProjectionMatrixTranspose; +uniform mat4 gl_TextureMatrixTranspose[gl_MaxTextureCoords]; + +uniform mat4 gl_ModelViewMatrixInverseTranspose; +uniform mat4 gl_ProjectionMatrixInverseTranspose; +uniform mat4 gl_ModelViewProjectionMatrixInverseTranspose; +uniform mat4 gl_TextureMatrixInverseTranspose[gl_MaxTextureCoords]; + +uniform float gl_NormalScale; + +struct gl_DepthRangeParameters { + float near; + float far; + float diff; +}; + +uniform gl_DepthRangeParameters gl_DepthRange; + +uniform vec4 gl_ClipPlane[gl_MaxClipPlanes]; + +struct gl_PointParameters { + float size; + float sizeMin; + float sizeMax; + float fadeThresholdSize; + float distanceConstantAttenuation; + float distanceLinearAttenuation; + float distanceQuadraticAttenuation; +}; + +uniform gl_PointParameters gl_Point; + +struct gl_MaterialParameters { + vec4 emission; + vec4 ambient; + vec4 diffuse; + vec4 specular; + float shininess; +}; + +uniform gl_MaterialParameters gl_FrontMaterial; +uniform gl_MaterialParameters gl_BackMaterial; + +/* NOTE: the order of these fields is significant! + * See the definition of the lighting state vars such as STATE_SPOT_DIRECTION. + */ +struct gl_LightSourceParameters { + vec4 ambient; + vec4 diffuse; + vec4 specular; + vec4 position; + vec4 halfVector; + vec3 spotDirection; + float spotCosCutoff; + + float constantAttenuation; + float linearAttenuation; + float quadraticAttenuation; + float spotExponent; + + float spotCutoff; +}; + +uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights]; + +struct gl_LightModelParameters { + vec4 ambient; +}; + +uniform gl_LightModelParameters gl_LightModel; + +struct gl_LightModelProducts { + vec4 sceneColor; +}; + +uniform gl_LightModelProducts gl_FrontLightModelProduct; +uniform gl_LightModelProducts gl_BackLightModelProduct; + +struct gl_LightProducts { + vec4 ambient; + vec4 diffuse; + vec4 specular; +}; + +uniform gl_LightProducts gl_FrontLightProduct[gl_MaxLights]; +uniform gl_LightProducts gl_BackLightProduct[gl_MaxLights]; + +uniform vec4 gl_TextureEnvColor[gl_MaxTextureImageUnits]; +uniform vec4 gl_EyePlaneS[gl_MaxTextureCoords]; +uniform vec4 gl_EyePlaneT[gl_MaxTextureCoords]; +uniform vec4 gl_EyePlaneR[gl_MaxTextureCoords]; +uniform vec4 gl_EyePlaneQ[gl_MaxTextureCoords]; +uniform vec4 gl_ObjectPlaneS[gl_MaxTextureCoords]; +uniform vec4 gl_ObjectPlaneT[gl_MaxTextureCoords]; +uniform vec4 gl_ObjectPlaneR[gl_MaxTextureCoords]; +uniform vec4 gl_ObjectPlaneQ[gl_MaxTextureCoords]; + +struct gl_FogParameters { + vec4 color; + float density; + float start; + float end; + float scale; +}; + +uniform gl_FogParameters gl_Fog; + + + + + +// +// 8.1 Angle and Trigonometry Functions +// + +//// radians + +float radians(const float deg) +{ + const float c = 3.1415926 / 180.0; + __asm vec4_multiply __retVal, deg, c; +} + +vec2 radians(const vec2 deg) +{ + const float c = 3.1415926 / 180.0; + __asm vec4_multiply __retVal.xy, deg.xy, c.xx; +} + +vec3 radians(const vec3 deg) +{ + const float c = 3.1415926 / 180.0; + __asm vec4_multiply __retVal.xyz, deg.xyz, c.xxx; +} + +vec4 radians(const vec4 deg) +{ + const float c = 3.1415926 / 180.0; + __asm vec4_multiply __retVal, deg, c.xxxx; +} + + +//// degrees + +float degrees(const float rad) +{ + const float c = 180.0 / 3.1415926; + __asm vec4_multiply __retVal, rad, c; +} + +vec2 degrees(const vec2 rad) +{ + const float c = 180.0 / 3.1415926; + __asm vec4_multiply __retVal.xy, rad.xy, c.xx; +} + +vec3 degrees(const vec3 rad) +{ + const float c = 180.0 / 3.1415926; + __asm vec4_multiply __retVal.xyz, rad.xyz, c.xxx; +} + +vec4 degrees(const vec4 rad) +{ + const float c = 180.0 / 3.1415926; + __asm vec4_multiply __retVal, rad, c.xxxx; +} + + +//// sin + +float sin(const float radians) +{ + __asm float_sine __retVal, radians; +} + +vec2 sin(const vec2 radians) +{ + __asm float_sine __retVal.x, radians.x; + __asm float_sine __retVal.y, radians.y; +} + +vec3 sin(const vec3 radians) +{ + __asm float_sine __retVal.x, radians.x; + __asm float_sine __retVal.y, radians.y; + __asm float_sine __retVal.z, radians.z; +} + +vec4 sin(const vec4 radians) +{ + __asm float_sine __retVal.x, radians.x; + __asm float_sine __retVal.y, radians.y; + __asm float_sine __retVal.z, radians.z; + __asm float_sine __retVal.w, radians.w; +} + + +//// cos + +float cos(const float radians) +{ + __asm float_cosine __retVal, radians; +} + +vec2 cos(const vec2 radians) +{ + __asm float_cosine __retVal.x, radians.x; + __asm float_cosine __retVal.y, radians.y; +} + +vec3 cos(const vec3 radians) +{ + __asm float_cosine __retVal.x, radians.x; + __asm float_cosine __retVal.y, radians.y; + __asm float_cosine __retVal.z, radians.z; +} + +vec4 cos(const vec4 radians) +{ + __asm float_cosine __retVal.x, radians.x; + __asm float_cosine __retVal.y, radians.y; + __asm float_cosine __retVal.z, radians.z; + __asm float_cosine __retVal.w, radians.w; +} + + + +//// tan + +float tan(const float angle) +{ + const float s = sin(angle); + const float c = cos(angle); + return s / c; +} + +vec2 tan(const vec2 angle) +{ + const vec2 s = sin(angle); + const vec2 c = cos(angle); + return s / c; +} + +vec3 tan(const vec3 angle) +{ + const vec3 s = sin(angle); + const vec3 c = cos(angle); + return s / c; +} + +vec4 tan(const vec4 angle) +{ + const vec4 s = sin(angle); + const vec4 c = cos(angle); + return s / c; +} + + + +float asin(const float x) +{ + const float a0 = 1.5707288; // PI/2? + const float a1 = -0.2121144; + const float a2 = 0.0742610; + //const float a3 = -0.0187293; + const float halfPi = 3.1415926 * 0.5; + const float y = abs(x); + // three terms seem to be enough: + __retVal = (halfPi - sqrt(1.0 - y) * (a0 + y * (a1 + a2 * y))) * sign(x); + // otherwise, try four: + //__retVal = (halfPi - sqrt(1.0 - y) * (a0 + y * (a1 + y * (a2 + y * a3)))) * sign(x); +} + +vec2 asin(const vec2 v) +{ + __retVal.x = asin(v.x); + __retVal.y = asin(v.y); +} + +vec3 asin(const vec3 v) +{ + __retVal.x = asin(v.x); + __retVal.y = asin(v.y); + __retVal.z = asin(v.z); +} + +vec4 asin(const vec4 v) +{ + __retVal.x = asin(v.x); + __retVal.y = asin(v.y); + __retVal.z = asin(v.z); + __retVal.w = asin(v.w); +} + +float acos(const float x) +{ + const float halfPi = 3.1415926 * 0.5; + __retVal = halfPi - asin(x); +} + +vec2 acos(const vec2 v) +{ + __retVal.x = acos(v.x); + __retVal.y = acos(v.y); +} + +vec3 acos(const vec3 v) +{ + __retVal.x = acos(v.x); + __retVal.y = acos(v.y); + __retVal.z = acos(v.z); +} + +vec4 acos(const vec4 v) +{ + __retVal.x = acos(v.x); + __retVal.y = acos(v.y); + __retVal.z = acos(v.z); + __retVal.w = acos(v.w); +} + +float atan(const float x) +{ + __retVal = asin(x * inversesqrt(x * x + 1.0)); +} + +vec2 atan(const vec2 y_over_x) +{ + __retVal.x = atan(y_over_x.x); + __retVal.y = atan(y_over_x.y); +} + +vec3 atan(const vec3 y_over_x) +{ + __retVal.x = atan(y_over_x.x); + __retVal.y = atan(y_over_x.y); + __retVal.z = atan(y_over_x.z); +} + +vec4 atan(const vec4 y_over_x) +{ + __retVal.x = atan(y_over_x.x); + __retVal.y = atan(y_over_x.y); + __retVal.z = atan(y_over_x.z); + __retVal.w = atan(y_over_x.w); +} + +float atan(const float y, const float x) +{ + float r; + if (abs(x) > 1.0e-4) { + r = atan(y / x); + if (x < 0.0) { + r = r + sign(y) * 3.141593; + } + } + else { + r = sign(y) * 1.5707965; // pi/2 + } + return r; +} + +vec2 atan(const vec2 u, const vec2 v) +{ + __retVal.x = atan(u.x, v.x); + __retVal.y = atan(u.y, v.y); +} + +vec3 atan(const vec3 u, const vec3 v) +{ + __retVal.x = atan(u.x, v.x); + __retVal.y = atan(u.y, v.y); + __retVal.z = atan(u.z, v.z); +} + +vec4 atan(const vec4 u, const vec4 v) +{ + __retVal.x = atan(u.x, v.x); + __retVal.y = atan(u.y, v.y); + __retVal.z = atan(u.z, v.z); + __retVal.w = atan(u.w, v.w); +} + + +// +// 8.2 Exponential Functions +// + +//// pow + +float pow(const float a, const float b) +{ + __asm float_power __retVal, a, b; +} + +vec2 pow(const vec2 a, const vec2 b) +{ + __asm float_power __retVal.x, a.x, b.x; + __asm float_power __retVal.y, a.y, b.y; +} + +vec3 pow(const vec3 a, const vec3 b) +{ + __asm float_power __retVal.x, a.x, b.x; + __asm float_power __retVal.y, a.y, b.y; + __asm float_power __retVal.z, a.z, b.z; +} + +vec4 pow(const vec4 a, const vec4 b) +{ + __asm float_power __retVal.x, a.x, b.x; + __asm float_power __retVal.y, a.y, b.y; + __asm float_power __retVal.z, a.z, b.z; + __asm float_power __retVal.w, a.w, b.w; +} + + +//// exp + +float exp(const float a) +{ + // NOTE: log2(e) = 1.44269502 + float t = a * 1.44269502; + __asm float_exp2 __retVal, t; +} + +vec2 exp(const vec2 a) +{ + vec2 t = a * 1.44269502; + __asm float_exp2 __retVal.x, t.x; + __asm float_exp2 __retVal.y, t.y; +} + +vec3 exp(const vec3 a) +{ + vec3 t = a * 1.44269502; + __asm float_exp2 __retVal.x, t.x; + __asm float_exp2 __retVal.y, t.y; + __asm float_exp2 __retVal.z, t.z; +} + +vec4 exp(const vec4 a) +{ + vec4 t = a * 1.44269502; + __asm float_exp2 __retVal.x, t.x; + __asm float_exp2 __retVal.y, t.y; + __asm float_exp2 __retVal.z, t.z; + __asm float_exp2 __retVal.w, t.w; +} + + + +//// log2 + +float log2(const float x) +{ + __asm float_log2 __retVal, x; +} + +vec2 log2(const vec2 v) +{ + __asm float_log2 __retVal.x, v.x; + __asm float_log2 __retVal.y, v.y; +} + +vec3 log2(const vec3 v) +{ + __asm float_log2 __retVal.x, v.x; + __asm float_log2 __retVal.y, v.y; + __asm float_log2 __retVal.z, v.z; +} + +vec4 log2(const vec4 v) +{ + __asm float_log2 __retVal.x, v.x; + __asm float_log2 __retVal.y, v.y; + __asm float_log2 __retVal.z, v.z; + __asm float_log2 __retVal.w, v.w; +} + + +//// log (natural log) + +float log(const float x) +{ + // note: logBaseB(x) = logBaseN(x) / logBaseN(B) + // compute log(x) = log2(x) / log2(e) + // c = 1.0 / log2(e) = 0.693147181 + const float c = 0.693147181; + return log2(x) * c; +} + +vec2 log(const vec2 v) +{ + const float c = 0.693147181; + return log2(v) * c; +} + +vec3 log(const vec3 v) +{ + const float c = 0.693147181; + return log2(v) * c; +} + +vec4 log(const vec4 v) +{ + const float c = 0.693147181; + return log2(v) * c; +} + + +//// exp2 + +float exp2(const float a) +{ + __asm float_exp2 __retVal, a; +} + +vec2 exp2(const vec2 a) +{ + __asm float_exp2 __retVal.x, a.x; + __asm float_exp2 __retVal.y, a.y; +} + +vec3 exp2(const vec3 a) +{ + __asm float_exp2 __retVal.x, a.x; + __asm float_exp2 __retVal.y, a.y; + __asm float_exp2 __retVal.z, a.z; +} + +vec4 exp2(const vec4 a) +{ + __asm float_exp2 __retVal.x, a.x; + __asm float_exp2 __retVal.y, a.y; + __asm float_exp2 __retVal.z, a.z; + __asm float_exp2 __retVal.w, a.w; +} + + +//// sqrt + +float sqrt(const float x) +{ + float r; + __asm float_rsq r, x; + __asm float_rcp __retVal, r; +} + +vec2 sqrt(const vec2 v) +{ + float r; + __asm float_rsq r, v.x; + __asm float_rcp __retVal.x, r; + __asm float_rsq r, v.y; + __asm float_rcp __retVal.y, r; +} + +vec3 sqrt(const vec3 v) +{ + float r; + __asm float_rsq r, v.x; + __asm float_rcp __retVal.x, r; + __asm float_rsq r, v.y; + __asm float_rcp __retVal.y, r; + __asm float_rsq r, v.z; + __asm float_rcp __retVal.z, r; +} + +vec4 sqrt(const vec4 v) +{ + float r; + __asm float_rsq r, v.x; + __asm float_rcp __retVal.x, r; + __asm float_rsq r, v.y; + __asm float_rcp __retVal.y, r; + __asm float_rsq r, v.z; + __asm float_rcp __retVal.z, r; + __asm float_rsq r, v.w; + __asm float_rcp __retVal.w, r; +} + + +//// inversesqrt + +float inversesqrt(const float x) +{ + __asm float_rsq __retVal.x, x; +} + +vec2 inversesqrt(const vec2 v) +{ + __asm float_rsq __retVal.x, v.x; + __asm float_rsq __retVal.y, v.y; +} + +vec3 inversesqrt(const vec3 v) +{ + __asm float_rsq __retVal.x, v.x; + __asm float_rsq __retVal.y, v.y; + __asm float_rsq __retVal.z, v.z; +} + +vec4 inversesqrt(const vec4 v) +{ + __asm float_rsq __retVal.x, v.x; + __asm float_rsq __retVal.y, v.y; + __asm float_rsq __retVal.z, v.z; + __asm float_rsq __retVal.w, v.w; +} + + +//// normalize + +float normalize(const float x) +{ + __retVal = 1.0; +} + +vec2 normalize(const vec2 v) +{ + const float s = inversesqrt(dot(v, v)); + __asm vec4_multiply __retVal.xy, v, s; +} + +vec3 normalize(const vec3 v) +{ +// const float s = inversesqrt(dot(v, v)); +// __retVal = v * s; +// XXX note, we _could_ use __retVal.w instead of tmp and and save a +// register, but that's actually a compilation error because v is a vec3 +// and the .w suffix is illegal. Oh well. + float tmp; + __asm vec3_dot tmp, v, v; + __asm float_rsq tmp, tmp; + __asm vec4_multiply __retVal.xyz, v, tmp; +} + +vec4 normalize(const vec4 v) +{ + float tmp; + __asm vec4_dot tmp, v, v; + __asm float_rsq tmp, tmp; + __asm vec4_multiply __retVal.xyz, v, tmp; +} + + + +// +// 8.3 Common Functions +// + + +//// abs + +float abs(const float a) +{ + __asm vec4_abs __retVal, a; +} + +vec2 abs(const vec2 a) +{ + __asm vec4_abs __retVal.xy, a; +} + +vec3 abs(const vec3 a) +{ + __asm vec4_abs __retVal.xyz, a; +} + +vec4 abs(const vec4 a) +{ + __asm vec4_abs __retVal, a; +} + + +//// sign + +float sign(const float x) +{ + float p, n; + __asm vec4_sgt p, x, 0.0; // p = (x > 0) + __asm vec4_sgt n, 0.0, x; // n = (x < 0) + __asm vec4_subtract __retVal, p, n; // sign = p - n +} + +vec2 sign(const vec2 v) +{ + vec2 p, n; + __asm vec4_sgt p.xy, v, 0.0; + __asm vec4_sgt n.xy, 0.0, v; + __asm vec4_subtract __retVal.xy, p, n; +} + +vec3 sign(const vec3 v) +{ + vec3 p, n; + __asm vec4_sgt p.xyz, v, 0.0; + __asm vec4_sgt n.xyz, 0.0, v; + __asm vec4_subtract __retVal.xyz, p, n; +} + +vec4 sign(const vec4 v) +{ + vec4 p, n; + __asm vec4_sgt p, v, 0.0; + __asm vec4_sgt n, 0.0, v; + __asm vec4_subtract __retVal, p, n; +} + + +//// floor + +float floor(const float a) +{ + __asm vec4_floor __retVal, a; +} + +vec2 floor(const vec2 a) +{ + __asm vec4_floor __retVal.xy, a; +} + +vec3 floor(const vec3 a) +{ + __asm vec4_floor __retVal.xyz, a; +} + +vec4 floor(const vec4 a) +{ + __asm vec4_floor __retVal, a; +} + + +//// ceil + +float ceil(const float a) +{ + // XXX this could be improved + float b = -a; + __asm vec4_floor b, b; + __retVal = -b; +} + +vec2 ceil(const vec2 a) +{ + vec2 b = -a; + __asm vec4_floor b, b; + __retVal.xy = -b; +} + +vec3 ceil(const vec3 a) +{ + vec3 b = -a; + __asm vec4_floor b, b; + __retVal.xyz = -b; +} + +vec4 ceil(const vec4 a) +{ + vec4 b = -a; + __asm vec4_floor b, b; + __retVal = -b; +} + + +//// fract + +float fract(const float a) +{ + __asm vec4_frac __retVal, a; +} + +vec2 fract(const vec2 a) +{ + __asm vec4_frac __retVal.xy, a; +} + +vec3 fract(const vec3 a) +{ + __asm vec4_frac __retVal.xyz, a; +} + +vec4 fract(const vec4 a) +{ + __asm vec4_frac __retVal, a; +} + + +//// mod (very untested!) + +float mod(const float a, const float b) +{ + float oneOverB; + __asm float_rcp oneOverB, b; + __retVal = a - b * floor(a * oneOverB); +} + +vec2 mod(const vec2 a, const float b) +{ + float oneOverB; + __asm float_rcp oneOverB, b; + __retVal.xy = a - b * floor(a * oneOverB); +} + +vec3 mod(const vec3 a, const float b) +{ + float oneOverB; + __asm float_rcp oneOverB, b; + __retVal.xyz = a - b * floor(a * oneOverB); +} + +vec4 mod(const vec4 a, const float b) +{ + float oneOverB; + __asm float_rcp oneOverB, b; + __retVal = a - b * floor(a * oneOverB); +} + +vec2 mod(const vec2 a, const vec2 b) +{ + vec2 oneOverB; + __asm float_rcp oneOverB.x, b.x; + __asm float_rcp oneOverB.y, b.y; + __retVal = a - b * floor(a * oneOverB); +} + +vec3 mod(const vec3 a, const vec3 b) +{ + vec3 oneOverB; + __asm float_rcp oneOverB.x, b.x; + __asm float_rcp oneOverB.y, b.y; + __asm float_rcp oneOverB.z, b.z; + __retVal = a - b * floor(a * oneOverB); +} + +vec4 mod(const vec4 a, const vec4 b) +{ + vec4 oneOverB; + __asm float_rcp oneOverB.x, b.x; + __asm float_rcp oneOverB.y, b.y; + __asm float_rcp oneOverB.z, b.z; + __asm float_rcp oneOverB.w, b.w; + __retVal = a - b * floor(a * oneOverB); +} + + +//// min + +float min(const float a, const float b) +{ + __asm vec4_min __retVal, a, b; +} + +vec2 min(const vec2 a, const vec2 b) +{ + __asm vec4_min __retVal.xy, a.xy, b.xy; +} + +vec3 min(const vec3 a, const vec3 b) +{ + __asm vec4_min __retVal.xyz, a.xyz, b.xyz; +} + +vec4 min(const vec4 a, const vec4 b) +{ + __asm vec4_min __retVal, a, b; +} + +vec2 min(const vec2 a, const float b) +{ + __asm vec4_min __retVal, a.xy, b; +} + +vec3 min(const vec3 a, const float b) +{ + __asm vec4_min __retVal, a.xyz, b; +} + +vec4 min(const vec4 a, const float b) +{ + __asm vec4_min __retVal, a, b; +} + + +//// max + +float max(const float a, const float b) +{ + __asm vec4_max __retVal, a, b; +} + +vec2 max(const vec2 a, const vec2 b) +{ + __asm vec4_max __retVal.xy, a.xy, b.xy; +} + +vec3 max(const vec3 a, const vec3 b) +{ + __asm vec4_max __retVal.xyz, a.xyz, b.xyz; +} + +vec4 max(const vec4 a, const vec4 b) +{ + __asm vec4_max __retVal, a, b; +} + +vec2 max(const vec2 a, const float b) +{ + __asm vec4_max __retVal, a.xy, b; +} + +vec3 max(const vec3 a, const float b) +{ + __asm vec4_max __retVal, a.xyz, b; +} + +vec4 max(const vec4 a, const float b) +{ + __asm vec4_max __retVal, a, b; +} + + +//// clamp + +float clamp(const float val, const float minVal, const float maxVal) +{ + __asm vec4_clamp __retVal, val, minVal, maxVal; +} + +vec2 clamp(const vec2 val, const float minVal, const float maxVal) +{ + __asm vec4_clamp __retVal, val, minVal, maxVal; +} + +vec3 clamp(const vec3 val, const float minVal, const float maxVal) +{ + __asm vec4_clamp __retVal, val, minVal, maxVal; +} + +vec4 clamp(const vec4 val, const float minVal, const float maxVal) +{ + __asm vec4_clamp __retVal, val, minVal, maxVal; +} + +vec2 clamp(const vec2 val, const vec2 minVal, const vec2 maxVal) +{ + __asm vec4_clamp __retVal, val, minVal, maxVal; +} + +vec3 clamp(const vec3 val, const vec3 minVal, const vec3 maxVal) +{ + __asm vec4_clamp __retVal, val, minVal, maxVal; +} + +vec4 clamp(const vec4 val, const vec4 minVal, const vec4 maxVal) +{ + __asm vec4_clamp __retVal, val, minVal, maxVal; +} + + +//// mix + +float mix(const float x, const float y, const float a) +{ + __asm vec4_lrp __retVal, a, y, x; +} + +vec2 mix(const vec2 x, const vec2 y, const float a) +{ + __asm vec4_lrp __retVal, a, y, x; +} + +vec3 mix(const vec3 x, const vec3 y, const float a) +{ + __asm vec4_lrp __retVal, a, y, x; +} + +vec4 mix(const vec4 x, const vec4 y, const float a) +{ + __asm vec4_lrp __retVal, a, y, x; +} + +vec2 mix(const vec2 x, const vec2 y, const vec2 a) +{ + __asm vec4_lrp __retVal, a, y, x; +} + +vec3 mix(const vec3 x, const vec3 y, const vec3 a) +{ + __asm vec4_lrp __retVal, a, y, x; +} + +vec4 mix(const vec4 x, const vec4 y, const vec4 a) +{ + __asm vec4_lrp __retVal, a, y, x; +} + + +//// step + +float step(const float edge, const float x) +{ + __asm vec4_sge __retVal, x, edge; +} + +vec2 step(const vec2 edge, const vec2 x) +{ + __asm vec4_sge __retVal.xy, x, edge; +} + +vec3 step(const vec3 edge, const vec3 x) +{ + __asm vec4_sge __retVal.xyz, x, edge; +} + +vec4 step(const vec4 edge, const vec4 x) +{ + __asm vec4_sge __retVal, x, edge; +} + +vec2 step(const float edge, const vec2 v) +{ + __asm vec4_sge __retVal.xy, v, edge; +} + +vec3 step(const float edge, const vec3 v) +{ + __asm vec4_sge __retVal.xyz, v, edge; +} + +vec4 step(const float edge, const vec4 v) +{ + __asm vec4_sge __retVal, v, edge; +} + + +//// smoothstep + +float smoothstep(const float edge0, const float edge1, const float x) +{ + float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + +vec2 smoothstep(const vec2 edge0, const vec2 edge1, const vec2 v) +{ + vec2 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + +vec3 smoothstep(const vec3 edge0, const vec3 edge1, const vec3 v) +{ + vec3 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + +vec4 smoothstep(const vec4 edge0, const vec4 edge1, const vec4 v) +{ + vec4 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + +vec2 smoothstep(const float edge0, const float edge1, const vec2 v) +{ + vec2 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + +vec3 smoothstep(const float edge0, const float edge1, const vec3 v) +{ + vec3 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + +vec4 smoothstep(const float edge0, const float edge1, const vec4 v) +{ + vec4 t = clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t); +} + + + +// +// 8.4 Geometric Functions +// + + +//// length + +float length(const float x) +{ + return abs(x); +} + +float length(const vec2 v) +{ + float r; + const float p = dot(v, v); // p = v.x * v.x + v.y * v.y + __asm float_rsq r, p; // r = 1 / sqrt(p) + __asm float_rcp __retVal.x, r; // retVal = 1 / r +} + +float length(const vec3 v) +{ + float r; + const float p = dot(v, v); // p = v.x * v.x + v.y * v.y + v.z * v.z + __asm float_rsq r, p; // r = 1 / sqrt(p) + __asm float_rcp __retVal, r; // retVal = 1 / r +} + +float length(const vec4 v) +{ + float r; + const float p = dot(v, v); // p = v.x * v.x + v.y * v.y + ... + __asm float_rsq r, p; // r = 1 / sqrt(p) + __asm float_rcp __retVal, r; // retVal = 1 / r +} + + +//// distance + +float distance(const float x, const float y) +{ + const float d = x - y; + __retVal = length(d); +} + +float distance(const vec2 v, const vec2 u) +{ + const vec2 d2 = v - u; + __retVal = length(d2); +} + +float distance(const vec3 v, const vec3 u) +{ + const vec3 d3 = v - u; + __retVal = length(d3); +} + +float distance(const vec4 v, const vec4 u) +{ + const vec4 d4 = v - u; + __retVal = length(d4); +} + + +//// cross + +vec3 cross(const vec3 v, const vec3 u) +{ + __asm vec3_cross __retVal.xyz, v, u; +} + + +//// faceforward + +float faceforward(const float N, const float I, const float Nref) +{ + // this could probably be done better + const float d = dot(Nref, I); + float s; + __asm vec4_sgt s, 0.0, d; // s = (0.0 > d) ? 1 : 0 + return mix(-N, N, s); +} + +vec2 faceforward(const vec2 N, const vec2 I, const vec2 Nref) +{ + // this could probably be done better + const float d = dot(Nref, I); + float s; + __asm vec4_sgt s, 0.0, d; // s = (0.0 > d) ? 1 : 0 + return mix(-N, N, s); +} + +vec3 faceforward(const vec3 N, const vec3 I, const vec3 Nref) +{ + // this could probably be done better + const float d = dot(Nref, I); + float s; + __asm vec4_sgt s, 0.0, d; // s = (0.0 > d) ? 1 : 0 + return mix(-N, N, s); +} + +vec4 faceforward(const vec4 N, const vec4 I, const vec4 Nref) +{ + // this could probably be done better + const float d = dot(Nref, I); + float s; + __asm vec4_sgt s, 0.0, d; // s = (0.0 > d) ? 1 : 0 + return mix(-N, N, s); +} + + +//// reflect + +float reflect(const float I, const float N) +{ + return I - 2.0 * dot(N, I) * N; +} + +vec2 reflect(const vec2 I, const vec2 N) +{ + return I - 2.0 * dot(N, I) * N; +} + +vec3 reflect(const vec3 I, const vec3 N) +{ + return I - 2.0 * dot(N, I) * N; +} + +vec4 reflect(const vec4 I, const vec4 N) +{ + return I - 2.0 * dot(N, I) * N; +} + +//// refract + +float refract(const float I, const float N, const float eta) +{ + float n_dot_i = dot(N, I); + float k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i); + float retval; + if (k < 0.0) + retval = 0.0; + else + retval = eta * I - (eta * n_dot_i + sqrt(k)) * N; + return retval; +} + +vec2 refract(const vec2 I, const vec2 N, const float eta) +{ + float n_dot_i = dot(N, I); + float k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i); + vec2 retval; + if (k < 0.0) + retval = vec2(0.0); + else + retval = eta * I - (eta * n_dot_i + sqrt(k)) * N; + return retval; +} + +vec3 refract(const vec3 I, const vec3 N, const float eta) +{ + float n_dot_i = dot(N, I); + float k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i); + vec3 retval; + if (k < 0.0) + retval = vec3(0.0); + else + retval = eta * I - (eta * n_dot_i + sqrt(k)) * N; + return retval; +} + +vec4 refract(const vec4 I, const vec4 N, const float eta) +{ + float n_dot_i = dot(N, I); + float k = 1.0 - eta * eta * (1.0 - n_dot_i * n_dot_i); + vec4 retval; + if (k < 0.0) + retval = vec4(0.0); + else + retval = eta * I - (eta * n_dot_i + sqrt(k)) * N; + return retval; +} + + + + +// +// 8.5 Matrix Functions +// + +mat2 matrixCompMult (mat2 m, mat2 n) { + return mat2 (m[0] * n[0], m[1] * n[1]); +} + +mat3 matrixCompMult (mat3 m, mat3 n) { + return mat3 (m[0] * n[0], m[1] * n[1], m[2] * n[2]); +} + +mat4 matrixCompMult (mat4 m, mat4 n) { + return mat4 (m[0] * n[0], m[1] * n[1], m[2] * n[2], m[3] * n[3]); +} + + + + +// +// 8.6 Vector Relational Functions +// + +//// lessThan + +bvec2 lessThan(const vec2 u, const vec2 v) +{ + __asm vec4_slt __retVal.xy, u, v; +} + +bvec3 lessThan(const vec3 u, const vec3 v) +{ + __asm vec4_slt __retVal.xyz, u, v; +} + +bvec4 lessThan(const vec4 u, const vec4 v) +{ + __asm vec4_slt __retVal, u, v; +} + +bvec2 lessThan(const ivec2 u, const ivec2 v) +{ + __asm vec4_slt __retVal.xy, u, v; +} + +bvec3 lessThan(const ivec3 u, const ivec3 v) +{ + __asm vec4_slt __retVal.xyz, u, v; +} + +bvec4 lessThan(const ivec4 u, const ivec4 v) +{ + __asm vec4_slt __retVal, u, v; +} + + +//// lessThanEqual + +bvec2 lessThanEqual(const vec2 u, const vec2 v) +{ + __asm vec4_sle __retVal.xy, u, v; +} + +bvec3 lessThanEqual(const vec3 u, const vec3 v) +{ + __asm vec4_sle __retVal.xyz, u, v; +} + +bvec4 lessThanEqual(const vec4 u, const vec4 v) +{ + __asm vec4_sle __retVal, u, v; +} + +bvec2 lessThanEqual(const ivec2 u, const ivec2 v) +{ + __asm vec4_sle __retVal.xy, u, v; +} + +bvec3 lessThanEqual(const ivec3 u, const ivec3 v) +{ + __asm vec4_sle __retVal.xyz, u, v; +} + +bvec4 lessThanEqual(const ivec4 u, const ivec4 v) +{ + __asm vec4_sle __retVal, u, v; +} + + +//// greaterThan + +bvec2 greaterThan(const vec2 u, const vec2 v) +{ + __asm vec4_sgt __retVal.xy, u, v; +} + +bvec3 greaterThan(const vec3 u, const vec3 v) +{ + __asm vec4_sgt __retVal.xyz, u, v; +} + +bvec4 greaterThan(const vec4 u, const vec4 v) +{ + __asm vec4_sgt __retVal, u, v; +} + +bvec2 greaterThan(const ivec2 u, const ivec2 v) +{ + __asm vec4_sgt __retVal.xy, u.xy, v.xy; +} + +bvec3 greaterThan(const ivec3 u, const ivec3 v) +{ + __asm vec4_sgt __retVal.xyz, u, v; +} + +bvec4 greaterThan(const ivec4 u, const ivec4 v) +{ + __asm vec4_sgt __retVal, u, v; +} + + +//// greaterThanEqual + +bvec2 greaterThanEqual(const vec2 u, const vec2 v) +{ + __asm vec4_sge __retVal.xy, u, v; +} + +bvec3 greaterThanEqual(const vec3 u, const vec3 v) +{ + __asm vec4_sge __retVal.xyz, u, v; +} + +bvec4 greaterThanEqual(const vec4 u, const vec4 v) +{ + __asm vec4_sge __retVal, u, v; +} + +bvec2 greaterThanEqual(const ivec2 u, const ivec2 v) +{ + __asm vec4_sge __retVal.xy, u, v; +} + +bvec3 greaterThanEqual(const ivec3 u, const ivec3 v) +{ + __asm vec4_sge __retVal.xyz, u, v; +} + +bvec4 greaterThanEqual(const ivec4 u, const ivec4 v) +{ + __asm vec4_sge __retVal, u, v; +} + + +//// equal + +bvec2 equal(const vec2 u, const vec2 v) +{ + __asm vec4_seq __retVal.xy, u, v; +} + +bvec3 equal(const vec3 u, const vec3 v) +{ + __asm vec4_seq __retVal.xyz, u, v; +} + +bvec4 equal(const vec4 u, const vec4 v) +{ + __asm vec4_seq __retVal, u, v; +} + +bvec2 equal(const ivec2 u, const ivec2 v) +{ + __asm vec4_seq __retVal.xy, u, v; +} + +bvec3 equal(const ivec3 u, const ivec3 v) +{ + __asm vec4_seq __retVal.xyz, u, v; +} + +bvec4 equal(const ivec4 u, const ivec4 v) +{ + __asm vec4_seq __retVal, u, v; +} + +bvec2 equal(const bvec2 u, const bvec2 v) +{ + __asm vec4_seq __retVal.xy, u, v; +} + +bvec3 equal(const bvec3 u, const bvec3 v) +{ + __asm vec4_seq __retVal.xyz, u, v; +} + +bvec4 equal(const bvec4 u, const bvec4 v) +{ + __asm vec4_seq __retVal, u, v; +} + + + + +//// notEqual + +bvec2 notEqual(const vec2 u, const vec2 v) +{ + __asm vec4_sne __retVal.xy, u, v; +} + +bvec3 notEqual(const vec3 u, const vec3 v) +{ + __asm vec4_sne __retVal.xyz, u, v; +} + +bvec4 notEqual(const vec4 u, const vec4 v) +{ + __asm vec4_sne __retVal, u, v; +} + +bvec2 notEqual(const ivec2 u, const ivec2 v) +{ + __asm vec4_sne __retVal.xy, u, v; +} + +bvec3 notEqual(const ivec3 u, const ivec3 v) +{ + __asm vec4_sne __retVal.xyz, u, v; +} + +bvec4 notEqual(const ivec4 u, const ivec4 v) +{ + __asm vec4_sne __retVal, u, v; +} + +bvec2 notEqual(const bvec2 u, const bvec2 v) +{ + __asm vec4_sne __retVal.xy, u, v; +} + +bvec3 notEqual(const bvec3 u, const bvec3 v) +{ + __asm vec4_sne __retVal.xyz, u, v; +} + +bvec4 notEqual(const bvec4 u, const bvec4 v) +{ + __asm vec4_sne __retVal, u, v; +} + + + +//// any + +bool any(const bvec2 v) +{ + float sum; + __asm vec4_add sum.x, v.x, v.y; + __asm vec4_sne __retVal.x, sum.x, 0.0; +} + +bool any(const bvec3 v) +{ + float sum; + __asm vec4_add sum.x, v.x, v.y; + __asm vec4_add sum.x, sum.x, v.z; + __asm vec4_sne __retVal.x, sum.x, 0.0; +} + +bool any(const bvec4 v) +{ + float sum; + __asm vec4_add sum.x, v.x, v.y; + __asm vec4_add sum.x, sum.x, v.z; + __asm vec4_add sum.x, sum.x, v.w; + __asm vec4_sne __retVal.x, sum.x, 0.0; +} + + +//// all + +bool all (const bvec2 v) +{ + float prod; + __asm vec4_multiply prod, v.x, v.y; + __asm vec4_sne __retVal, prod, 0.0; +} + +bool all (const bvec3 v) +{ + float prod; + __asm vec4_multiply prod, v.x, v.y; + __asm vec4_multiply prod, prod, v.z; + __asm vec4_sne __retVal, prod, 0.0; +} + +bool all (const bvec4 v) +{ + float prod; + __asm vec4_multiply prod, v.x, v.y; + __asm vec4_multiply prod, prod, v.z; + __asm vec4_multiply prod, prod, v.w; + __asm vec4_sne __retVal, prod, 0.0; +} + + + +//// not + +bvec2 not (const bvec2 v) +{ + __asm vec4_seq __retVal.xy, v, 0.0; +} + +bvec3 not (const bvec3 v) +{ + __asm vec4_seq __retVal.xyz, v, 0.0; +} + +bvec4 not (const bvec4 v) +{ + __asm vec4_seq __retVal, v, 0.0; +} + + + +//// Texture Lookup Functions (for both fragment and vertex shaders) + +vec4 texture1D(const sampler1D sampler, const float coord) +{ + __asm vec4_tex_1d __retVal, sampler, coord; +} + +vec4 texture1DProj(const sampler1D sampler, const vec2 coord) +{ + // need to swizzle .y into .w + __asm vec4_tex_1d_proj __retVal, sampler, coord.xyyy; +} + +vec4 texture1DProj(const sampler1D sampler, const vec4 coord) +{ + __asm vec4_tex_1d_proj __retVal, sampler, coord; +} + + +vec4 texture2D(const sampler2D sampler, const vec2 coord) +{ + __asm vec4_tex_2d __retVal, sampler, coord; +} + +vec4 texture2DProj(const sampler2D sampler, const vec3 coord) +{ + // need to swizzle 'z' into 'w'. + __asm vec4_tex_2d_proj __retVal, sampler, coord.xyzz; +} + +vec4 texture2DProj(const sampler2D sampler, const vec4 coord) +{ + __asm vec4_tex_2d_proj __retVal, sampler, coord; +} + + +vec4 texture3D(const sampler3D sampler, const vec3 coord) +{ + __asm vec4_tex_3d __retVal, sampler, coord; +} + +vec4 texture3DProj(const sampler3D sampler, const vec4 coord) +{ + __asm vec4_tex_3d_proj __retVal, sampler, coord; +} + + +vec4 textureCube(const samplerCube sampler, const vec3 coord) +{ + __asm vec4_tex_cube __retVal, sampler, coord; +} + + + +vec4 shadow1D(const sampler1DShadow sampler, const vec3 coord) +{ + __asm vec4_tex_1d_shadow __retVal, sampler, coord; +} + +vec4 shadow1DProj(const sampler1DShadow sampler, const vec4 coord) +{ + // .s and .p will be divided by .q + __asm vec4_tex_1d_proj_shadow __retVal, sampler, coord; +} + +vec4 shadow2D(const sampler2DShadow sampler, const vec3 coord) +{ + __asm vec4_tex_2d_shadow __retVal, sampler, coord; +} + +vec4 shadow2DProj(const sampler2DShadow sampler, const vec4 coord) +{ + // .s, .t and .p will be divided by .q + __asm vec4_tex_2d_proj_shadow __retVal, sampler, coord; +} + + +//// GL_ARB_texture_rectangle: +vec4 texture2DRect(const sampler2DRect sampler, const vec2 coord) +{ + __asm vec4_tex_rect __retVal, sampler, coord; +} + +vec4 texture2DRectProj(const sampler2DRect sampler, const vec3 coord) +{ + // need to swizzle .y into .w + __asm vec4_tex_rect_proj __retVal, sampler, coord.xyzz; +} + +vec4 texture2DRectProj(const sampler2DRect sampler, const vec4 coord) +{ + __asm vec4_tex_rect_proj __retVal, sampler, ccoord; +} + +vec4 shadow2DRect(const sampler2DRectShadow sampler, const vec3 coord) +{ + __asm vec4_tex_rect_shadow __retVal, sampler, coord; +} + +vec4 shadow2DRectProj(const sampler2DRectShadow sampler, const vec4 coord) +{ + __asm vec4_tex_rect_proj_shadow __retVal, sampler, coord; +} + + + +// +// 8.9 Noise Functions +// +// AUTHOR: Stefan Gustavson (stegu@itn.liu.se), Nov 26, 2005 +// + +float noise1(const float x) +{ + __asm float_noise1 __retVal, x; +} + + +float noise1(const vec2 x) +{ + __asm float_noise2 __retVal, x; +} + +float noise1(const vec3 x) +{ + __asm float_noise3 __retVal, x; +} + +float noise1(const vec4 x) +{ + __asm float_noise4 __retVal, x; +} + +vec2 noise2(const float x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + 19.34); +} + +vec2 noise2(const vec2 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec2(19.34, 7.66)); +} + +vec2 noise2(const vec3 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec3(19.34, 7.66, 3.23)); +} + +vec2 noise2(const vec4 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec4(19.34, 7.66, 3.23, 2.77)); +} + +vec3 noise3(const float x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + 19.34); + __retVal.z = noise1(x + 5.47); +} + +vec3 noise3(const vec2 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec2(19.34, 7.66)); + __retVal.z = noise1(x + vec2(5.47, 17.85)); +} + +vec3 noise3(const vec3 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec3(19.34, 7.66, 3.23)); + __retVal.z = noise1(x + vec3(5.47, 17.85, 11.04)); +} + +vec3 noise3(const vec4 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec4(19.34, 7.66, 3.23, 2.77)); + __retVal.z = noise1(x + vec4(5.47, 17.85, 11.04, 13.19)); +} + +vec4 noise4(const float x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + 19.34); + __retVal.z = noise1(x + 5.47); + __retVal.w = noise1(x + 23.54); +} + +vec4 noise4(const vec2 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec2 (19.34, 7.66)); + __retVal.z = noise1(x + vec2 (5.47, 17.85)); + __retVal.w = noise1(x + vec2 (23.54, 29.11)); +} + +vec4 noise4(const vec3 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec3(19.34, 7.66, 3.23)); + __retVal.z = noise1(x + vec3(5.47, 17.85, 11.04)); + __retVal.w = noise1(x + vec3(23.54, 29.11, 31.91)); +} + +vec4 noise4(const vec4 x) +{ + __retVal.x = noise1(x); + __retVal.y = noise1(x + vec4(19.34, 7.66, 3.23, 2.77)); + __retVal.z = noise1(x + vec4(5.47, 17.85, 11.04, 13.19)); + __retVal.w = noise1(x + vec4(23.54, 29.11, 31.91, 37.48)); +} diff --git a/mesalib/src/mesa/shader/slang/library/slang_common_builtin_gc.h b/mesalib/src/mesa/shader/slang/library/slang_common_builtin_gc.h new file mode 100644 index 000000000..78a7b83ec --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_common_builtin_gc.h @@ -0,0 +1,872 @@ + +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */ +/* slang_common_builtin.gc */ + +5,2,2,90,95,1,0,5,0,1,103,108,95,77,97,120,76,105,103,104,116,115,0,2,16,10,56,0,0,0,2,2,90,95,1,0, +5,0,1,103,108,95,77,97,120,67,108,105,112,80,108,97,110,101,115,0,2,16,10,54,0,0,0,2,2,90,95,1,0,5, +0,1,103,108,95,77,97,120,84,101,120,116,117,114,101,85,110,105,116,115,0,2,16,10,56,0,0,0,2,2,90, +95,1,0,5,0,1,103,108,95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,2,16,10,56,0, +0,0,2,2,90,95,1,0,5,0,1,103,108,95,77,97,120,86,101,114,116,101,120,65,116,116,114,105,98,115,0,2, +16,10,49,54,0,0,0,2,2,90,95,1,0,5,0,1,103,108,95,77,97,120,86,101,114,116,101,120,85,110,105,102, +111,114,109,67,111,109,112,111,110,101,110,116,115,0,2,16,10,53,49,50,0,0,0,2,2,90,95,1,0,5,0,1, +103,108,95,77,97,120,86,97,114,121,105,110,103,70,108,111,97,116,115,0,2,16,10,51,50,0,0,0,2,2,90, +95,1,0,5,0,1,103,108,95,77,97,120,86,101,114,116,101,120,84,101,120,116,117,114,101,73,109,97,103, +101,85,110,105,116,115,0,2,16,8,48,0,0,0,2,2,90,95,1,0,5,0,1,103,108,95,77,97,120,67,111,109,98, +105,110,101,100,84,101,120,116,117,114,101,73,109,97,103,101,85,110,105,116,115,0,2,16,10,50,0,0,0, +2,2,90,95,1,0,5,0,1,103,108,95,77,97,120,84,101,120,116,117,114,101,73,109,97,103,101,85,110,105, +116,115,0,2,16,10,50,0,0,0,2,2,90,95,1,0,5,0,1,103,108,95,77,97,120,70,114,97,103,109,101,110,116, +85,110,105,102,111,114,109,67,111,109,112,111,110,101,110,116,115,0,2,16,10,54,52,0,0,0,2,2,90,95, +1,0,5,0,1,103,108,95,77,97,120,68,114,97,119,66,117,102,102,101,114,115,0,2,16,10,49,0,0,0,2,2,90, +95,4,0,15,0,1,103,108,95,77,111,100,101,108,86,105,101,119,77,97,116,114,105,120,0,0,0,2,2,90,95,4, +0,15,0,1,103,108,95,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,0,0,0,2,2,90,95,4, +0,15,0,1,103,108,95,77,111,100,101,108,86,105,101,119,80,114,111,106,101,99,116,105,111,110,77,97, +116,114,105,120,0,0,0,2,2,90,95,4,0,15,0,1,103,108,95,84,101,120,116,117,114,101,77,97,116,114,105, +120,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,90,95, +4,0,14,0,1,103,108,95,78,111,114,109,97,108,77,97,116,114,105,120,0,0,0,2,2,90,95,4,0,15,0,1,103, +108,95,77,111,100,101,108,86,105,101,119,77,97,116,114,105,120,73,110,118,101,114,115,101,0,0,0,2, +2,90,95,4,0,15,0,1,103,108,95,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,73,110, +118,101,114,115,101,0,0,0,2,2,90,95,4,0,15,0,1,103,108,95,77,111,100,101,108,86,105,101,119,80,114, +111,106,101,99,116,105,111,110,77,97,116,114,105,120,73,110,118,101,114,115,101,0,0,0,2,2,90,95,4, +0,15,0,1,103,108,95,84,101,120,116,117,114,101,77,97,116,114,105,120,73,110,118,101,114,115,101,0, +3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,90,95,4,0,15, +0,1,103,108,95,77,111,100,101,108,86,105,101,119,77,97,116,114,105,120,84,114,97,110,115,112,111, +115,101,0,0,0,2,2,90,95,4,0,15,0,1,103,108,95,80,114,111,106,101,99,116,105,111,110,77,97,116,114, +105,120,84,114,97,110,115,112,111,115,101,0,0,0,2,2,90,95,4,0,15,0,1,103,108,95,77,111,100,101,108, +86,105,101,119,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,84,114,97,110,115,112, +111,115,101,0,0,0,2,2,90,95,4,0,15,0,1,103,108,95,84,101,120,116,117,114,101,77,97,116,114,105,120, +84,114,97,110,115,112,111,115,101,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,67,111, +111,114,100,115,0,0,0,2,2,90,95,4,0,15,0,1,103,108,95,77,111,100,101,108,86,105,101,119,77,97,116, +114,105,120,73,110,118,101,114,115,101,84,114,97,110,115,112,111,115,101,0,0,0,2,2,90,95,4,0,15,0, +1,103,108,95,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,73,110,118,101,114,115, +101,84,114,97,110,115,112,111,115,101,0,0,0,2,2,90,95,4,0,15,0,1,103,108,95,77,111,100,101,108,86, +105,101,119,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,73,110,118,101,114,115,101, +84,114,97,110,115,112,111,115,101,0,0,0,2,2,90,95,4,0,15,0,1,103,108,95,84,101,120,116,117,114,101, +77,97,116,114,105,120,73,110,118,101,114,115,101,84,114,97,110,115,112,111,115,101,0,3,18,103,108, +95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,90,95,4,0,9,0,1,103,108, +95,78,111,114,109,97,108,83,99,97,108,101,0,0,0,2,2,90,95,0,0,24,103,108,95,68,101,112,116,104,82, +97,110,103,101,80,97,114,97,109,101,116,101,114,115,0,9,0,110,101,97,114,0,0,0,1,9,0,102,97,114,0, +0,0,1,9,0,100,105,102,102,0,0,0,0,0,0,0,2,2,90,95,4,0,25,103,108,95,68,101,112,116,104,82,97,110, +103,101,80,97,114,97,109,101,116,101,114,115,0,0,1,103,108,95,68,101,112,116,104,82,97,110,103,101, +0,0,0,2,2,90,95,4,0,12,0,1,103,108,95,67,108,105,112,80,108,97,110,101,0,3,18,103,108,95,77,97,120, +67,108,105,112,80,108,97,110,101,115,0,0,0,2,2,90,95,0,0,24,103,108,95,80,111,105,110,116,80,97, +114,97,109,101,116,101,114,115,0,9,0,115,105,122,101,0,0,0,1,9,0,115,105,122,101,77,105,110,0,0,0, +1,9,0,115,105,122,101,77,97,120,0,0,0,1,9,0,102,97,100,101,84,104,114,101,115,104,111,108,100,83, +105,122,101,0,0,0,1,9,0,100,105,115,116,97,110,99,101,67,111,110,115,116,97,110,116,65,116,116,101, +110,117,97,116,105,111,110,0,0,0,1,9,0,100,105,115,116,97,110,99,101,76,105,110,101,97,114,65,116, +116,101,110,117,97,116,105,111,110,0,0,0,1,9,0,100,105,115,116,97,110,99,101,81,117,97,100,114,97, +116,105,99,65,116,116,101,110,117,97,116,105,111,110,0,0,0,0,0,0,0,2,2,90,95,4,0,25,103,108,95,80, +111,105,110,116,80,97,114,97,109,101,116,101,114,115,0,0,1,103,108,95,80,111,105,110,116,0,0,0,2,2, +90,95,0,0,24,103,108,95,77,97,116,101,114,105,97,108,80,97,114,97,109,101,116,101,114,115,0,12,0, +101,109,105,115,115,105,111,110,0,0,0,1,12,0,97,109,98,105,101,110,116,0,0,0,1,12,0,100,105,102, +102,117,115,101,0,0,0,1,12,0,115,112,101,99,117,108,97,114,0,0,0,1,9,0,115,104,105,110,105,110,101, +115,115,0,0,0,0,0,0,0,2,2,90,95,4,0,25,103,108,95,77,97,116,101,114,105,97,108,80,97,114,97,109, +101,116,101,114,115,0,0,1,103,108,95,70,114,111,110,116,77,97,116,101,114,105,97,108,0,0,0,2,2,90, +95,4,0,25,103,108,95,77,97,116,101,114,105,97,108,80,97,114,97,109,101,116,101,114,115,0,0,1,103, +108,95,66,97,99,107,77,97,116,101,114,105,97,108,0,0,0,2,2,90,95,0,0,24,103,108,95,76,105,103,104, +116,83,111,117,114,99,101,80,97,114,97,109,101,116,101,114,115,0,12,0,97,109,98,105,101,110,116,0, +0,0,1,12,0,100,105,102,102,117,115,101,0,0,0,1,12,0,115,112,101,99,117,108,97,114,0,0,0,1,12,0,112, +111,115,105,116,105,111,110,0,0,0,1,12,0,104,97,108,102,86,101,99,116,111,114,0,0,0,1,11,0,115,112, +111,116,68,105,114,101,99,116,105,111,110,0,0,0,1,9,0,115,112,111,116,67,111,115,67,117,116,111, +102,102,0,0,0,1,9,0,99,111,110,115,116,97,110,116,65,116,116,101,110,117,97,116,105,111,110,0,0,0, +1,9,0,108,105,110,101,97,114,65,116,116,101,110,117,97,116,105,111,110,0,0,0,1,9,0,113,117,97,100, +114,97,116,105,99,65,116,116,101,110,117,97,116,105,111,110,0,0,0,1,9,0,115,112,111,116,69,120,112, +111,110,101,110,116,0,0,0,1,9,0,115,112,111,116,67,117,116,111,102,102,0,0,0,0,0,0,0,2,2,90,95,4,0, +25,103,108,95,76,105,103,104,116,83,111,117,114,99,101,80,97,114,97,109,101,116,101,114,115,0,0,1, +103,108,95,76,105,103,104,116,83,111,117,114,99,101,0,3,18,103,108,95,77,97,120,76,105,103,104,116, +115,0,0,0,2,2,90,95,0,0,24,103,108,95,76,105,103,104,116,77,111,100,101,108,80,97,114,97,109,101, +116,101,114,115,0,12,0,97,109,98,105,101,110,116,0,0,0,0,0,0,0,2,2,90,95,4,0,25,103,108,95,76,105, +103,104,116,77,111,100,101,108,80,97,114,97,109,101,116,101,114,115,0,0,1,103,108,95,76,105,103, +104,116,77,111,100,101,108,0,0,0,2,2,90,95,0,0,24,103,108,95,76,105,103,104,116,77,111,100,101,108, +80,114,111,100,117,99,116,115,0,12,0,115,99,101,110,101,67,111,108,111,114,0,0,0,0,0,0,0,2,2,90,95, +4,0,25,103,108,95,76,105,103,104,116,77,111,100,101,108,80,114,111,100,117,99,116,115,0,0,1,103, +108,95,70,114,111,110,116,76,105,103,104,116,77,111,100,101,108,80,114,111,100,117,99,116,0,0,0,2, +2,90,95,4,0,25,103,108,95,76,105,103,104,116,77,111,100,101,108,80,114,111,100,117,99,116,115,0,0, +1,103,108,95,66,97,99,107,76,105,103,104,116,77,111,100,101,108,80,114,111,100,117,99,116,0,0,0,2, +2,90,95,0,0,24,103,108,95,76,105,103,104,116,80,114,111,100,117,99,116,115,0,12,0,97,109,98,105, +101,110,116,0,0,0,1,12,0,100,105,102,102,117,115,101,0,0,0,1,12,0,115,112,101,99,117,108,97,114,0, +0,0,0,0,0,0,2,2,90,95,4,0,25,103,108,95,76,105,103,104,116,80,114,111,100,117,99,116,115,0,0,1,103, +108,95,70,114,111,110,116,76,105,103,104,116,80,114,111,100,117,99,116,0,3,18,103,108,95,77,97,120, +76,105,103,104,116,115,0,0,0,2,2,90,95,4,0,25,103,108,95,76,105,103,104,116,80,114,111,100,117,99, +116,115,0,0,1,103,108,95,66,97,99,107,76,105,103,104,116,80,114,111,100,117,99,116,0,3,18,103,108, +95,77,97,120,76,105,103,104,116,115,0,0,0,2,2,90,95,4,0,12,0,1,103,108,95,84,101,120,116,117,114, +101,69,110,118,67,111,108,111,114,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,73,109,97, +103,101,85,110,105,116,115,0,0,0,2,2,90,95,4,0,12,0,1,103,108,95,69,121,101,80,108,97,110,101,83,0, +3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,90,95,4,0,12, +0,1,103,108,95,69,121,101,80,108,97,110,101,84,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114, +101,67,111,111,114,100,115,0,0,0,2,2,90,95,4,0,12,0,1,103,108,95,69,121,101,80,108,97,110,101,82,0, +3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,90,95,4,0,12, +0,1,103,108,95,69,121,101,80,108,97,110,101,81,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114, +101,67,111,111,114,100,115,0,0,0,2,2,90,95,4,0,12,0,1,103,108,95,79,98,106,101,99,116,80,108,97, +110,101,83,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2, +90,95,4,0,12,0,1,103,108,95,79,98,106,101,99,116,80,108,97,110,101,84,0,3,18,103,108,95,77,97,120, +84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,90,95,4,0,12,0,1,103,108,95,79,98,106, +101,99,116,80,108,97,110,101,82,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,67,111,111, +114,100,115,0,0,0,2,2,90,95,4,0,12,0,1,103,108,95,79,98,106,101,99,116,80,108,97,110,101,81,0,3,18, +103,108,95,77,97,120,84,101,120,116,117,114,101,67,111,111,114,100,115,0,0,0,2,2,90,95,0,0,24,103, +108,95,70,111,103,80,97,114,97,109,101,116,101,114,115,0,12,0,99,111,108,111,114,0,0,0,1,9,0,100, +101,110,115,105,116,121,0,0,0,1,9,0,115,116,97,114,116,0,0,0,1,9,0,101,110,100,0,0,0,1,9,0,115,99, +97,108,101,0,0,0,0,0,0,0,2,2,90,95,4,0,25,103,108,95,70,111,103,80,97,114,97,109,101,116,101,114, +115,0,0,1,103,108,95,70,111,103,0,0,0,1,90,95,0,0,9,0,0,114,97,100,105,97,110,115,0,1,1,0,0,9,0, +100,101,103,0,0,0,1,3,2,90,95,1,0,9,0,1,99,0,2,17,51,0,49,52,49,53,57,50,54,0,0,17,49,56,48,0,48,0, +0,49,0,0,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,0, +18,100,101,103,0,0,18,99,0,0,0,0,1,90,95,0,0,10,0,0,114,97,100,105,97,110,115,0,1,1,0,0,10,0,100, +101,103,0,0,0,1,3,2,90,95,1,0,9,0,1,99,0,2,17,51,0,49,52,49,53,57,50,54,0,0,17,49,56,48,0,48,0,0, +49,0,0,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,59, +120,121,0,0,18,100,101,103,0,59,120,121,0,0,18,99,0,59,120,120,0,0,0,0,1,90,95,0,0,11,0,0,114,97, +100,105,97,110,115,0,1,1,0,0,11,0,100,101,103,0,0,0,1,3,2,90,95,1,0,9,0,1,99,0,2,17,51,0,49,52,49, +53,57,50,54,0,0,17,49,56,48,0,48,0,0,49,0,0,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0, +18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,100,101,103,0,59,120,121,122,0,0,18,99,0,59, +120,120,120,0,0,0,0,1,90,95,0,0,12,0,0,114,97,100,105,97,110,115,0,1,1,0,0,12,0,100,101,103,0,0,0, +1,3,2,90,95,1,0,9,0,1,99,0,2,17,51,0,49,52,49,53,57,50,54,0,0,17,49,56,48,0,48,0,0,49,0,0,4,118, +101,99,52,95,109,117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,0,18,100,101,103,0, +0,18,99,0,59,120,120,120,120,0,0,0,0,1,90,95,0,0,9,0,0,100,101,103,114,101,101,115,0,1,1,0,0,9,0, +114,97,100,0,0,0,1,3,2,90,95,1,0,9,0,1,99,0,2,17,49,56,48,0,48,0,0,17,51,0,49,52,49,53,57,50,54,0, +0,49,0,0,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,0, +18,114,97,100,0,0,18,99,0,0,0,0,1,90,95,0,0,10,0,0,100,101,103,114,101,101,115,0,1,1,0,0,10,0,114, +97,100,0,0,0,1,3,2,90,95,1,0,9,0,1,99,0,2,17,49,56,48,0,48,0,0,17,51,0,49,52,49,53,57,50,54,0,0,49, +0,0,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,59,120, +121,0,0,18,114,97,100,0,59,120,121,0,0,18,99,0,59,120,120,0,0,0,0,1,90,95,0,0,11,0,0,100,101,103, +114,101,101,115,0,1,1,0,0,11,0,114,97,100,0,0,0,1,3,2,90,95,1,0,9,0,1,99,0,2,17,49,56,48,0,48,0,0, +17,51,0,49,52,49,53,57,50,54,0,0,49,0,0,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,95, +95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,114,97,100,0,59,120,121,122,0,0,18,99,0,59,120, +120,120,0,0,0,0,1,90,95,0,0,12,0,0,100,101,103,114,101,101,115,0,1,1,0,0,12,0,114,97,100,0,0,0,1,3, +2,90,95,1,0,9,0,1,99,0,2,17,49,56,48,0,48,0,0,17,51,0,49,52,49,53,57,50,54,0,0,49,0,0,4,118,101,99, +52,95,109,117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,0,18,114,97,100,0,0,18,99, +0,59,120,120,120,120,0,0,0,0,1,90,95,0,0,9,0,0,115,105,110,0,1,1,0,0,9,0,114,97,100,105,97,110,115, +0,0,0,1,4,102,108,111,97,116,95,115,105,110,101,0,18,95,95,114,101,116,86,97,108,0,0,18,114,97,100, +105,97,110,115,0,0,0,0,1,90,95,0,0,10,0,0,115,105,110,0,1,1,0,0,10,0,114,97,100,105,97,110,115,0,0, +0,1,4,102,108,111,97,116,95,115,105,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,114, +97,100,105,97,110,115,0,59,120,0,0,0,4,102,108,111,97,116,95,115,105,110,101,0,18,95,95,114,101, +116,86,97,108,0,59,121,0,0,18,114,97,100,105,97,110,115,0,59,121,0,0,0,0,1,90,95,0,0,11,0,0,115, +105,110,0,1,1,0,0,11,0,114,97,100,105,97,110,115,0,0,0,1,4,102,108,111,97,116,95,115,105,110,101,0, +18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,114,97,100,105,97,110,115,0,59,120,0,0,0,4,102,108, +111,97,116,95,115,105,110,101,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18,114,97,100,105,97, +110,115,0,59,121,0,0,0,4,102,108,111,97,116,95,115,105,110,101,0,18,95,95,114,101,116,86,97,108,0, +59,122,0,0,18,114,97,100,105,97,110,115,0,59,122,0,0,0,0,1,90,95,0,0,12,0,0,115,105,110,0,1,1,0,0, +12,0,114,97,100,105,97,110,115,0,0,0,1,4,102,108,111,97,116,95,115,105,110,101,0,18,95,95,114,101, +116,86,97,108,0,59,120,0,0,18,114,97,100,105,97,110,115,0,59,120,0,0,0,4,102,108,111,97,116,95,115, +105,110,101,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18,114,97,100,105,97,110,115,0,59,121,0, +0,0,4,102,108,111,97,116,95,115,105,110,101,0,18,95,95,114,101,116,86,97,108,0,59,122,0,0,18,114, +97,100,105,97,110,115,0,59,122,0,0,0,4,102,108,111,97,116,95,115,105,110,101,0,18,95,95,114,101, +116,86,97,108,0,59,119,0,0,18,114,97,100,105,97,110,115,0,59,119,0,0,0,0,1,90,95,0,0,9,0,0,99,111, +115,0,1,1,0,0,9,0,114,97,100,105,97,110,115,0,0,0,1,4,102,108,111,97,116,95,99,111,115,105,110,101, +0,18,95,95,114,101,116,86,97,108,0,0,18,114,97,100,105,97,110,115,0,0,0,0,1,90,95,0,0,10,0,0,99, +111,115,0,1,1,0,0,10,0,114,97,100,105,97,110,115,0,0,0,1,4,102,108,111,97,116,95,99,111,115,105, +110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,114,97,100,105,97,110,115,0,59,120,0,0,0, +4,102,108,111,97,116,95,99,111,115,105,110,101,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18, +114,97,100,105,97,110,115,0,59,121,0,0,0,0,1,90,95,0,0,11,0,0,99,111,115,0,1,1,0,0,11,0,114,97,100, +105,97,110,115,0,0,0,1,4,102,108,111,97,116,95,99,111,115,105,110,101,0,18,95,95,114,101,116,86,97, +108,0,59,120,0,0,18,114,97,100,105,97,110,115,0,59,120,0,0,0,4,102,108,111,97,116,95,99,111,115, +105,110,101,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18,114,97,100,105,97,110,115,0,59,121,0, +0,0,4,102,108,111,97,116,95,99,111,115,105,110,101,0,18,95,95,114,101,116,86,97,108,0,59,122,0,0, +18,114,97,100,105,97,110,115,0,59,122,0,0,0,0,1,90,95,0,0,12,0,0,99,111,115,0,1,1,0,0,12,0,114,97, +100,105,97,110,115,0,0,0,1,4,102,108,111,97,116,95,99,111,115,105,110,101,0,18,95,95,114,101,116, +86,97,108,0,59,120,0,0,18,114,97,100,105,97,110,115,0,59,120,0,0,0,4,102,108,111,97,116,95,99,111, +115,105,110,101,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18,114,97,100,105,97,110,115,0,59, +121,0,0,0,4,102,108,111,97,116,95,99,111,115,105,110,101,0,18,95,95,114,101,116,86,97,108,0,59,122, +0,0,18,114,97,100,105,97,110,115,0,59,122,0,0,0,4,102,108,111,97,116,95,99,111,115,105,110,101,0, +18,95,95,114,101,116,86,97,108,0,59,119,0,0,18,114,97,100,105,97,110,115,0,59,119,0,0,0,0,1,90,95, +0,0,9,0,0,116,97,110,0,1,1,0,0,9,0,97,110,103,108,101,0,0,0,1,3,2,90,95,1,0,9,0,1,115,0,2,58,115, +105,110,0,0,18,97,110,103,108,101,0,0,0,0,0,3,2,90,95,1,0,9,0,1,99,0,2,58,99,111,115,0,0,18,97,110, +103,108,101,0,0,0,0,0,8,18,115,0,18,99,0,49,0,0,1,90,95,0,0,10,0,0,116,97,110,0,1,1,0,0,10,0,97, +110,103,108,101,0,0,0,1,3,2,90,95,1,0,10,0,1,115,0,2,58,115,105,110,0,0,18,97,110,103,108,101,0,0, +0,0,0,3,2,90,95,1,0,10,0,1,99,0,2,58,99,111,115,0,0,18,97,110,103,108,101,0,0,0,0,0,8,18,115,0,18, +99,0,49,0,0,1,90,95,0,0,11,0,0,116,97,110,0,1,1,0,0,11,0,97,110,103,108,101,0,0,0,1,3,2,90,95,1,0, +11,0,1,115,0,2,58,115,105,110,0,0,18,97,110,103,108,101,0,0,0,0,0,3,2,90,95,1,0,11,0,1,99,0,2,58, +99,111,115,0,0,18,97,110,103,108,101,0,0,0,0,0,8,18,115,0,18,99,0,49,0,0,1,90,95,0,0,12,0,0,116,97, +110,0,1,1,0,0,12,0,97,110,103,108,101,0,0,0,1,3,2,90,95,1,0,12,0,1,115,0,2,58,115,105,110,0,0,18, +97,110,103,108,101,0,0,0,0,0,3,2,90,95,1,0,12,0,1,99,0,2,58,99,111,115,0,0,18,97,110,103,108,101,0, +0,0,0,0,8,18,115,0,18,99,0,49,0,0,1,90,95,0,0,9,0,0,97,115,105,110,0,1,1,0,0,9,0,120,0,0,0,1,3,2, +90,95,1,0,9,0,1,97,48,0,2,17,49,0,53,55,48,55,50,56,56,0,0,0,0,3,2,90,95,1,0,9,0,1,97,49,0,2,17,48, +0,50,49,50,49,49,52,52,0,0,54,0,0,3,2,90,95,1,0,9,0,1,97,50,0,2,17,48,0,48,55,52,50,54,49,48,0,0,0, +0,3,2,90,95,1,0,9,0,1,104,97,108,102,80,105,0,2,17,51,0,49,52,49,53,57,50,54,0,0,17,48,0,53,0,0,48, +0,0,3,2,90,95,1,0,9,0,1,121,0,2,58,97,98,115,0,0,18,120,0,0,0,0,0,9,18,95,95,114,101,116,86,97,108, +0,18,104,97,108,102,80,105,0,58,115,113,114,116,0,0,17,49,0,48,0,0,18,121,0,47,0,0,18,97,48,0,18, +121,0,18,97,49,0,18,97,50,0,18,121,0,48,46,48,46,48,47,58,115,105,103,110,0,0,18,120,0,0,0,48,20,0, +0,1,90,95,0,0,10,0,0,97,115,105,110,0,1,1,0,0,10,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0, +59,120,0,58,97,115,105,110,0,0,18,118,0,59,120,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59, +121,0,58,97,115,105,110,0,0,18,118,0,59,121,0,0,0,20,0,0,1,90,95,0,0,11,0,0,97,115,105,110,0,1,1,0, +0,11,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,58,97,115,105,110,0,0,18,118,0,59, +120,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,58,97,115,105,110,0,0,18,118,0,59,121,0, +0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,58,97,115,105,110,0,0,18,118,0,59,122,0,0,0, +20,0,0,1,90,95,0,0,12,0,0,97,115,105,110,0,1,1,0,0,12,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97, +108,0,59,120,0,58,97,115,105,110,0,0,18,118,0,59,120,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0, +59,121,0,58,97,115,105,110,0,0,18,118,0,59,121,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59, +122,0,58,97,115,105,110,0,0,18,118,0,59,122,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,119,0, +58,97,115,105,110,0,0,18,118,0,59,119,0,0,0,20,0,0,1,90,95,0,0,9,0,0,97,99,111,115,0,1,1,0,0,9,0, +120,0,0,0,1,3,2,90,95,1,0,9,0,1,104,97,108,102,80,105,0,2,17,51,0,49,52,49,53,57,50,54,0,0,17,48,0, +53,0,0,48,0,0,9,18,95,95,114,101,116,86,97,108,0,18,104,97,108,102,80,105,0,58,97,115,105,110,0,0, +18,120,0,0,0,47,20,0,0,1,90,95,0,0,10,0,0,97,99,111,115,0,1,1,0,0,10,0,118,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,59,120,0,58,97,99,111,115,0,0,18,118,0,59,120,0,0,0,20,0,9,18,95,95,114,101, +116,86,97,108,0,59,121,0,58,97,99,111,115,0,0,18,118,0,59,121,0,0,0,20,0,0,1,90,95,0,0,11,0,0,97, +99,111,115,0,1,1,0,0,11,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,58,97,99,111,115, +0,0,18,118,0,59,120,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,58,97,99,111,115,0,0,18, +118,0,59,121,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,58,97,99,111,115,0,0,18,118,0, +59,122,0,0,0,20,0,0,1,90,95,0,0,12,0,0,97,99,111,115,0,1,1,0,0,12,0,118,0,0,0,1,9,18,95,95,114,101, +116,86,97,108,0,59,120,0,58,97,99,111,115,0,0,18,118,0,59,120,0,0,0,20,0,9,18,95,95,114,101,116,86, +97,108,0,59,121,0,58,97,99,111,115,0,0,18,118,0,59,121,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108, +0,59,122,0,58,97,99,111,115,0,0,18,118,0,59,122,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59, +119,0,58,97,99,111,115,0,0,18,118,0,59,119,0,0,0,20,0,0,1,90,95,0,0,9,0,0,97,116,97,110,0,1,1,0,0, +9,0,120,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,97,115,105,110,0,0,18,120,0,58,105,110,118, +101,114,115,101,115,113,114,116,0,0,18,120,0,18,120,0,48,17,49,0,48,0,0,46,0,0,48,0,0,20,0,0,1,90, +95,0,0,10,0,0,97,116,97,110,0,1,1,0,0,10,0,121,95,111,118,101,114,95,120,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,59,120,0,58,97,116,97,110,0,0,18,121,95,111,118,101,114,95,120,0,59,120,0,0,0, +20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,58,97,116,97,110,0,0,18,121,95,111,118,101,114,95, +120,0,59,121,0,0,0,20,0,0,1,90,95,0,0,11,0,0,97,116,97,110,0,1,1,0,0,11,0,121,95,111,118,101,114, +95,120,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,58,97,116,97,110,0,0,18,121,95,111,118, +101,114,95,120,0,59,120,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,58,97,116,97,110,0, +0,18,121,95,111,118,101,114,95,120,0,59,121,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0, +58,97,116,97,110,0,0,18,121,95,111,118,101,114,95,120,0,59,122,0,0,0,20,0,0,1,90,95,0,0,12,0,0,97, +116,97,110,0,1,1,0,0,12,0,121,95,111,118,101,114,95,120,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0, +59,120,0,58,97,116,97,110,0,0,18,121,95,111,118,101,114,95,120,0,59,120,0,0,0,20,0,9,18,95,95,114, +101,116,86,97,108,0,59,121,0,58,97,116,97,110,0,0,18,121,95,111,118,101,114,95,120,0,59,121,0,0,0, +20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,58,97,116,97,110,0,0,18,121,95,111,118,101,114,95, +120,0,59,122,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,119,0,58,97,116,97,110,0,0,18,121,95, +111,118,101,114,95,120,0,59,119,0,0,0,20,0,0,1,90,95,0,0,9,0,0,97,116,97,110,0,1,1,0,0,9,0,121,0,0, +1,1,0,0,9,0,120,0,0,0,1,3,2,90,95,0,0,9,0,1,114,0,0,0,10,58,97,98,115,0,0,18,120,0,0,0,17,49,0,48, +0,45,52,0,41,0,2,9,18,114,0,58,97,116,97,110,0,0,18,121,0,18,120,0,49,0,0,20,0,10,18,120,0,17,48,0, +48,0,0,40,0,2,9,18,114,0,18,114,0,58,115,105,103,110,0,0,18,121,0,0,0,17,51,0,49,52,49,53,57,51,0, +0,48,46,20,0,0,9,14,0,0,2,9,18,114,0,58,115,105,103,110,0,0,18,121,0,0,0,17,49,0,53,55,48,55,57,54, +53,0,0,48,20,0,0,8,18,114,0,0,0,1,90,95,0,0,10,0,0,97,116,97,110,0,1,1,0,0,10,0,117,0,0,1,1,0,0,10, +0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,58,97,116,97,110,0,0,18,117,0,59,120,0,0, +18,118,0,59,120,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,58,97,116,97,110,0,0,18,117, +0,59,121,0,0,18,118,0,59,121,0,0,0,20,0,0,1,90,95,0,0,11,0,0,97,116,97,110,0,1,1,0,0,11,0,117,0,0, +1,1,0,0,11,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,58,97,116,97,110,0,0,18,117,0, +59,120,0,0,18,118,0,59,120,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,58,97,116,97,110, +0,0,18,117,0,59,121,0,0,18,118,0,59,121,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,58, +97,116,97,110,0,0,18,117,0,59,122,0,0,18,118,0,59,122,0,0,0,20,0,0,1,90,95,0,0,12,0,0,97,116,97, +110,0,1,1,0,0,12,0,117,0,0,1,1,0,0,12,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,58, +97,116,97,110,0,0,18,117,0,59,120,0,0,18,118,0,59,120,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108, +0,59,121,0,58,97,116,97,110,0,0,18,117,0,59,121,0,0,18,118,0,59,121,0,0,0,20,0,9,18,95,95,114,101, +116,86,97,108,0,59,122,0,58,97,116,97,110,0,0,18,117,0,59,122,0,0,18,118,0,59,122,0,0,0,20,0,9,18, +95,95,114,101,116,86,97,108,0,59,119,0,58,97,116,97,110,0,0,18,117,0,59,119,0,0,18,118,0,59,119,0, +0,0,20,0,0,1,90,95,0,0,9,0,0,112,111,119,0,1,1,0,0,9,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,4,102,108,111, +97,116,95,112,111,119,101,114,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1,90,95, +0,0,10,0,0,112,111,119,0,1,1,0,0,10,0,97,0,0,1,1,0,0,10,0,98,0,0,0,1,4,102,108,111,97,116,95,112, +111,119,101,114,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,97,0,59,120,0,0,18,98,0,59,120,0, +0,0,4,102,108,111,97,116,95,112,111,119,101,114,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18, +97,0,59,121,0,0,18,98,0,59,121,0,0,0,0,1,90,95,0,0,11,0,0,112,111,119,0,1,1,0,0,11,0,97,0,0,1,1,0, +0,11,0,98,0,0,0,1,4,102,108,111,97,116,95,112,111,119,101,114,0,18,95,95,114,101,116,86,97,108,0, +59,120,0,0,18,97,0,59,120,0,0,18,98,0,59,120,0,0,0,4,102,108,111,97,116,95,112,111,119,101,114,0, +18,95,95,114,101,116,86,97,108,0,59,121,0,0,18,97,0,59,121,0,0,18,98,0,59,121,0,0,0,4,102,108,111, +97,116,95,112,111,119,101,114,0,18,95,95,114,101,116,86,97,108,0,59,122,0,0,18,97,0,59,122,0,0,18, +98,0,59,122,0,0,0,0,1,90,95,0,0,12,0,0,112,111,119,0,1,1,0,0,12,0,97,0,0,1,1,0,0,12,0,98,0,0,0,1,4, +102,108,111,97,116,95,112,111,119,101,114,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,97,0,59, +120,0,0,18,98,0,59,120,0,0,0,4,102,108,111,97,116,95,112,111,119,101,114,0,18,95,95,114,101,116,86, +97,108,0,59,121,0,0,18,97,0,59,121,0,0,18,98,0,59,121,0,0,0,4,102,108,111,97,116,95,112,111,119, +101,114,0,18,95,95,114,101,116,86,97,108,0,59,122,0,0,18,97,0,59,122,0,0,18,98,0,59,122,0,0,0,4, +102,108,111,97,116,95,112,111,119,101,114,0,18,95,95,114,101,116,86,97,108,0,59,119,0,0,18,97,0,59, +119,0,0,18,98,0,59,119,0,0,0,0,1,90,95,0,0,9,0,0,101,120,112,0,1,1,0,0,9,0,97,0,0,0,1,3,2,90,95,0, +0,9,0,1,116,0,2,18,97,0,17,49,0,52,52,50,54,57,53,48,50,0,0,48,0,0,4,102,108,111,97,116,95,101,120, +112,50,0,18,95,95,114,101,116,86,97,108,0,0,18,116,0,0,0,0,1,90,95,0,0,10,0,0,101,120,112,0,1,1,0, +0,10,0,97,0,0,0,1,3,2,90,95,0,0,10,0,1,116,0,2,18,97,0,17,49,0,52,52,50,54,57,53,48,50,0,0,48,0,0, +4,102,108,111,97,116,95,101,120,112,50,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,116,0,59, +120,0,0,0,4,102,108,111,97,116,95,101,120,112,50,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18, +116,0,59,121,0,0,0,0,1,90,95,0,0,11,0,0,101,120,112,0,1,1,0,0,11,0,97,0,0,0,1,3,2,90,95,0,0,11,0,1, +116,0,2,18,97,0,17,49,0,52,52,50,54,57,53,48,50,0,0,48,0,0,4,102,108,111,97,116,95,101,120,112,50, +0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,116,0,59,120,0,0,0,4,102,108,111,97,116,95,101, +120,112,50,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18,116,0,59,121,0,0,0,4,102,108,111,97, +116,95,101,120,112,50,0,18,95,95,114,101,116,86,97,108,0,59,122,0,0,18,116,0,59,122,0,0,0,0,1,90, +95,0,0,12,0,0,101,120,112,0,1,1,0,0,12,0,97,0,0,0,1,3,2,90,95,0,0,12,0,1,116,0,2,18,97,0,17,49,0, +52,52,50,54,57,53,48,50,0,0,48,0,0,4,102,108,111,97,116,95,101,120,112,50,0,18,95,95,114,101,116, +86,97,108,0,59,120,0,0,18,116,0,59,120,0,0,0,4,102,108,111,97,116,95,101,120,112,50,0,18,95,95,114, +101,116,86,97,108,0,59,121,0,0,18,116,0,59,121,0,0,0,4,102,108,111,97,116,95,101,120,112,50,0,18, +95,95,114,101,116,86,97,108,0,59,122,0,0,18,116,0,59,122,0,0,0,4,102,108,111,97,116,95,101,120,112, +50,0,18,95,95,114,101,116,86,97,108,0,59,119,0,0,18,116,0,59,119,0,0,0,0,1,90,95,0,0,9,0,0,108,111, +103,50,0,1,1,0,0,9,0,120,0,0,0,1,4,102,108,111,97,116,95,108,111,103,50,0,18,95,95,114,101,116,86, +97,108,0,0,18,120,0,0,0,0,1,90,95,0,0,10,0,0,108,111,103,50,0,1,1,0,0,10,0,118,0,0,0,1,4,102,108, +111,97,116,95,108,111,103,50,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,118,0,59,120,0,0,0,4, +102,108,111,97,116,95,108,111,103,50,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18,118,0,59,121, +0,0,0,0,1,90,95,0,0,11,0,0,108,111,103,50,0,1,1,0,0,11,0,118,0,0,0,1,4,102,108,111,97,116,95,108, +111,103,50,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,118,0,59,120,0,0,0,4,102,108,111,97, +116,95,108,111,103,50,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18,118,0,59,121,0,0,0,4,102, +108,111,97,116,95,108,111,103,50,0,18,95,95,114,101,116,86,97,108,0,59,122,0,0,18,118,0,59,122,0,0, +0,0,1,90,95,0,0,12,0,0,108,111,103,50,0,1,1,0,0,12,0,118,0,0,0,1,4,102,108,111,97,116,95,108,111, +103,50,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,118,0,59,120,0,0,0,4,102,108,111,97,116,95, +108,111,103,50,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18,118,0,59,121,0,0,0,4,102,108,111, +97,116,95,108,111,103,50,0,18,95,95,114,101,116,86,97,108,0,59,122,0,0,18,118,0,59,122,0,0,0,4,102, +108,111,97,116,95,108,111,103,50,0,18,95,95,114,101,116,86,97,108,0,59,119,0,0,18,118,0,59,119,0,0, +0,0,1,90,95,0,0,9,0,0,108,111,103,0,1,1,0,0,9,0,120,0,0,0,1,3,2,90,95,1,0,9,0,1,99,0,2,17,48,0,54, +57,51,49,52,55,49,56,49,0,0,0,0,8,58,108,111,103,50,0,0,18,120,0,0,0,18,99,0,48,0,0,1,90,95,0,0,10, +0,0,108,111,103,0,1,1,0,0,10,0,118,0,0,0,1,3,2,90,95,1,0,9,0,1,99,0,2,17,48,0,54,57,51,49,52,55,49, +56,49,0,0,0,0,8,58,108,111,103,50,0,0,18,118,0,0,0,18,99,0,48,0,0,1,90,95,0,0,11,0,0,108,111,103,0, +1,1,0,0,11,0,118,0,0,0,1,3,2,90,95,1,0,9,0,1,99,0,2,17,48,0,54,57,51,49,52,55,49,56,49,0,0,0,0,8, +58,108,111,103,50,0,0,18,118,0,0,0,18,99,0,48,0,0,1,90,95,0,0,12,0,0,108,111,103,0,1,1,0,0,12,0, +118,0,0,0,1,3,2,90,95,1,0,9,0,1,99,0,2,17,48,0,54,57,51,49,52,55,49,56,49,0,0,0,0,8,58,108,111,103, +50,0,0,18,118,0,0,0,18,99,0,48,0,0,1,90,95,0,0,9,0,0,101,120,112,50,0,1,1,0,0,9,0,97,0,0,0,1,4,102, +108,111,97,116,95,101,120,112,50,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,0,0,1,90,95,0,0,10, +0,0,101,120,112,50,0,1,1,0,0,10,0,97,0,0,0,1,4,102,108,111,97,116,95,101,120,112,50,0,18,95,95,114, +101,116,86,97,108,0,59,120,0,0,18,97,0,59,120,0,0,0,4,102,108,111,97,116,95,101,120,112,50,0,18,95, +95,114,101,116,86,97,108,0,59,121,0,0,18,97,0,59,121,0,0,0,0,1,90,95,0,0,11,0,0,101,120,112,50,0,1, +1,0,0,11,0,97,0,0,0,1,4,102,108,111,97,116,95,101,120,112,50,0,18,95,95,114,101,116,86,97,108,0,59, +120,0,0,18,97,0,59,120,0,0,0,4,102,108,111,97,116,95,101,120,112,50,0,18,95,95,114,101,116,86,97, +108,0,59,121,0,0,18,97,0,59,121,0,0,0,4,102,108,111,97,116,95,101,120,112,50,0,18,95,95,114,101, +116,86,97,108,0,59,122,0,0,18,97,0,59,122,0,0,0,0,1,90,95,0,0,12,0,0,101,120,112,50,0,1,1,0,0,12,0, +97,0,0,0,1,4,102,108,111,97,116,95,101,120,112,50,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18, +97,0,59,120,0,0,0,4,102,108,111,97,116,95,101,120,112,50,0,18,95,95,114,101,116,86,97,108,0,59,121, +0,0,18,97,0,59,121,0,0,0,4,102,108,111,97,116,95,101,120,112,50,0,18,95,95,114,101,116,86,97,108,0, +59,122,0,0,18,97,0,59,122,0,0,0,4,102,108,111,97,116,95,101,120,112,50,0,18,95,95,114,101,116,86, +97,108,0,59,119,0,0,18,97,0,59,119,0,0,0,0,1,90,95,0,0,9,0,0,115,113,114,116,0,1,1,0,0,9,0,120,0,0, +0,1,3,2,90,95,0,0,9,0,1,114,0,0,0,4,102,108,111,97,116,95,114,115,113,0,18,114,0,0,18,120,0,0,0,4, +102,108,111,97,116,95,114,99,112,0,18,95,95,114,101,116,86,97,108,0,0,18,114,0,0,0,0,1,90,95,0,0, +10,0,0,115,113,114,116,0,1,1,0,0,10,0,118,0,0,0,1,3,2,90,95,0,0,9,0,1,114,0,0,0,4,102,108,111,97, +116,95,114,115,113,0,18,114,0,0,18,118,0,59,120,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,95, +95,114,101,116,86,97,108,0,59,120,0,0,18,114,0,0,0,4,102,108,111,97,116,95,114,115,113,0,18,114,0, +0,18,118,0,59,121,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,95,95,114,101,116,86,97,108,0,59, +121,0,0,18,114,0,0,0,0,1,90,95,0,0,11,0,0,115,113,114,116,0,1,1,0,0,11,0,118,0,0,0,1,3,2,90,95,0,0, +9,0,1,114,0,0,0,4,102,108,111,97,116,95,114,115,113,0,18,114,0,0,18,118,0,59,120,0,0,0,4,102,108, +111,97,116,95,114,99,112,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,114,0,0,0,4,102,108,111, +97,116,95,114,115,113,0,18,114,0,0,18,118,0,59,121,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18, +95,95,114,101,116,86,97,108,0,59,121,0,0,18,114,0,0,0,4,102,108,111,97,116,95,114,115,113,0,18,114, +0,0,18,118,0,59,122,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,95,95,114,101,116,86,97,108,0,59, +122,0,0,18,114,0,0,0,0,1,90,95,0,0,12,0,0,115,113,114,116,0,1,1,0,0,12,0,118,0,0,0,1,3,2,90,95,0,0, +9,0,1,114,0,0,0,4,102,108,111,97,116,95,114,115,113,0,18,114,0,0,18,118,0,59,120,0,0,0,4,102,108, +111,97,116,95,114,99,112,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,114,0,0,0,4,102,108,111, +97,116,95,114,115,113,0,18,114,0,0,18,118,0,59,121,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18, +95,95,114,101,116,86,97,108,0,59,121,0,0,18,114,0,0,0,4,102,108,111,97,116,95,114,115,113,0,18,114, +0,0,18,118,0,59,122,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,95,95,114,101,116,86,97,108,0,59, +122,0,0,18,114,0,0,0,4,102,108,111,97,116,95,114,115,113,0,18,114,0,0,18,118,0,59,119,0,0,0,4,102, +108,111,97,116,95,114,99,112,0,18,95,95,114,101,116,86,97,108,0,59,119,0,0,18,114,0,0,0,0,1,90,95, +0,0,9,0,0,105,110,118,101,114,115,101,115,113,114,116,0,1,1,0,0,9,0,120,0,0,0,1,4,102,108,111,97, +116,95,114,115,113,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,120,0,0,0,0,1,90,95,0,0,10,0,0, +105,110,118,101,114,115,101,115,113,114,116,0,1,1,0,0,10,0,118,0,0,0,1,4,102,108,111,97,116,95,114, +115,113,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,118,0,59,120,0,0,0,4,102,108,111,97,116, +95,114,115,113,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18,118,0,59,121,0,0,0,0,1,90,95,0,0, +11,0,0,105,110,118,101,114,115,101,115,113,114,116,0,1,1,0,0,11,0,118,0,0,0,1,4,102,108,111,97,116, +95,114,115,113,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,118,0,59,120,0,0,0,4,102,108,111, +97,116,95,114,115,113,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18,118,0,59,121,0,0,0,4,102, +108,111,97,116,95,114,115,113,0,18,95,95,114,101,116,86,97,108,0,59,122,0,0,18,118,0,59,122,0,0,0, +0,1,90,95,0,0,12,0,0,105,110,118,101,114,115,101,115,113,114,116,0,1,1,0,0,12,0,118,0,0,0,1,4,102, +108,111,97,116,95,114,115,113,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,118,0,59,120,0,0,0, +4,102,108,111,97,116,95,114,115,113,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18,118,0,59,121, +0,0,0,4,102,108,111,97,116,95,114,115,113,0,18,95,95,114,101,116,86,97,108,0,59,122,0,0,18,118,0, +59,122,0,0,0,4,102,108,111,97,116,95,114,115,113,0,18,95,95,114,101,116,86,97,108,0,59,119,0,0,18, +118,0,59,119,0,0,0,0,1,90,95,0,0,9,0,0,110,111,114,109,97,108,105,122,101,0,1,1,0,0,9,0,120,0,0,0, +1,9,18,95,95,114,101,116,86,97,108,0,17,49,0,48,0,0,20,0,0,1,90,95,0,0,10,0,0,110,111,114,109,97, +108,105,122,101,0,1,1,0,0,10,0,118,0,0,0,1,3,2,90,95,1,0,9,0,1,115,0,2,58,105,110,118,101,114,115, +101,115,113,114,116,0,0,58,100,111,116,0,0,18,118,0,0,18,118,0,0,0,0,0,0,0,4,118,101,99,52,95,109, +117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,118,0,0,18,115,0, +0,0,0,1,90,95,0,0,11,0,0,110,111,114,109,97,108,105,122,101,0,1,1,0,0,11,0,118,0,0,0,1,3,2,90,95,0, +0,9,0,1,116,109,112,0,0,0,4,118,101,99,51,95,100,111,116,0,18,116,109,112,0,0,18,118,0,0,18,118,0, +0,0,4,102,108,111,97,116,95,114,115,113,0,18,116,109,112,0,0,18,116,109,112,0,0,0,4,118,101,99,52, +95,109,117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,118,0, +0,18,116,109,112,0,0,0,0,1,90,95,0,0,12,0,0,110,111,114,109,97,108,105,122,101,0,1,1,0,0,12,0,118, +0,0,0,1,3,2,90,95,0,0,9,0,1,116,109,112,0,0,0,4,118,101,99,52,95,100,111,116,0,18,116,109,112,0,0, +18,118,0,0,18,118,0,0,0,4,102,108,111,97,116,95,114,115,113,0,18,116,109,112,0,0,18,116,109,112,0, +0,0,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,59,120, +121,122,0,0,18,118,0,0,18,116,109,112,0,0,0,0,1,90,95,0,0,9,0,0,97,98,115,0,1,1,0,0,9,0,97,0,0,0,1, +4,118,101,99,52,95,97,98,115,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,0,0,1,90,95,0,0,10,0,0, +97,98,115,0,1,1,0,0,10,0,97,0,0,0,1,4,118,101,99,52,95,97,98,115,0,18,95,95,114,101,116,86,97,108, +0,59,120,121,0,0,18,97,0,0,0,0,1,90,95,0,0,11,0,0,97,98,115,0,1,1,0,0,11,0,97,0,0,0,1,4,118,101,99, +52,95,97,98,115,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,97,0,0,0,0,1,90,95,0,0,12, +0,0,97,98,115,0,1,1,0,0,12,0,97,0,0,0,1,4,118,101,99,52,95,97,98,115,0,18,95,95,114,101,116,86,97, +108,0,0,18,97,0,0,0,0,1,90,95,0,0,9,0,0,115,105,103,110,0,1,1,0,0,9,0,120,0,0,0,1,3,2,90,95,0,0,9, +0,1,112,0,0,1,1,110,0,0,0,4,118,101,99,52,95,115,103,116,0,18,112,0,0,18,120,0,0,17,48,0,48,0,0,0, +0,4,118,101,99,52,95,115,103,116,0,18,110,0,0,17,48,0,48,0,0,0,18,120,0,0,0,4,118,101,99,52,95,115, +117,98,116,114,97,99,116,0,18,95,95,114,101,116,86,97,108,0,0,18,112,0,0,18,110,0,0,0,0,1,90,95,0, +0,10,0,0,115,105,103,110,0,1,1,0,0,10,0,118,0,0,0,1,3,2,90,95,0,0,10,0,1,112,0,0,1,1,110,0,0,0,4, +118,101,99,52,95,115,103,116,0,18,112,0,59,120,121,0,0,18,118,0,0,17,48,0,48,0,0,0,0,4,118,101,99, +52,95,115,103,116,0,18,110,0,59,120,121,0,0,17,48,0,48,0,0,0,18,118,0,0,0,4,118,101,99,52,95,115, +117,98,116,114,97,99,116,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,112,0,0,18,110,0,0,0, +0,1,90,95,0,0,11,0,0,115,105,103,110,0,1,1,0,0,11,0,118,0,0,0,1,3,2,90,95,0,0,11,0,1,112,0,0,1,1, +110,0,0,0,4,118,101,99,52,95,115,103,116,0,18,112,0,59,120,121,122,0,0,18,118,0,0,17,48,0,48,0,0,0, +0,4,118,101,99,52,95,115,103,116,0,18,110,0,59,120,121,122,0,0,17,48,0,48,0,0,0,18,118,0,0,0,4,118, +101,99,52,95,115,117,98,116,114,97,99,116,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18, +112,0,0,18,110,0,0,0,0,1,90,95,0,0,12,0,0,115,105,103,110,0,1,1,0,0,12,0,118,0,0,0,1,3,2,90,95,0,0, +12,0,1,112,0,0,1,1,110,0,0,0,4,118,101,99,52,95,115,103,116,0,18,112,0,0,18,118,0,0,17,48,0,48,0,0, +0,0,4,118,101,99,52,95,115,103,116,0,18,110,0,0,17,48,0,48,0,0,0,18,118,0,0,0,4,118,101,99,52,95, +115,117,98,116,114,97,99,116,0,18,95,95,114,101,116,86,97,108,0,0,18,112,0,0,18,110,0,0,0,0,1,90, +95,0,0,9,0,0,102,108,111,111,114,0,1,1,0,0,9,0,97,0,0,0,1,4,118,101,99,52,95,102,108,111,111,114,0, +18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,0,0,1,90,95,0,0,10,0,0,102,108,111,111,114,0,1,1,0,0, +10,0,97,0,0,0,1,4,118,101,99,52,95,102,108,111,111,114,0,18,95,95,114,101,116,86,97,108,0,59,120, +121,0,0,18,97,0,0,0,0,1,90,95,0,0,11,0,0,102,108,111,111,114,0,1,1,0,0,11,0,97,0,0,0,1,4,118,101, +99,52,95,102,108,111,111,114,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,97,0,0,0,0,1, +90,95,0,0,12,0,0,102,108,111,111,114,0,1,1,0,0,12,0,97,0,0,0,1,4,118,101,99,52,95,102,108,111,111, +114,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,0,0,1,90,95,0,0,9,0,0,99,101,105,108,0,1,1,0,0, +9,0,97,0,0,0,1,3,2,90,95,0,0,9,0,1,98,0,2,18,97,0,54,0,0,4,118,101,99,52,95,102,108,111,111,114,0, +18,98,0,0,18,98,0,0,0,9,18,95,95,114,101,116,86,97,108,0,18,98,0,54,20,0,0,1,90,95,0,0,10,0,0,99, +101,105,108,0,1,1,0,0,10,0,97,0,0,0,1,3,2,90,95,0,0,10,0,1,98,0,2,18,97,0,54,0,0,4,118,101,99,52, +95,102,108,111,111,114,0,18,98,0,0,18,98,0,0,0,9,18,95,95,114,101,116,86,97,108,0,59,120,121,0,18, +98,0,54,20,0,0,1,90,95,0,0,11,0,0,99,101,105,108,0,1,1,0,0,11,0,97,0,0,0,1,3,2,90,95,0,0,11,0,1,98, +0,2,18,97,0,54,0,0,4,118,101,99,52,95,102,108,111,111,114,0,18,98,0,0,18,98,0,0,0,9,18,95,95,114, +101,116,86,97,108,0,59,120,121,122,0,18,98,0,54,20,0,0,1,90,95,0,0,12,0,0,99,101,105,108,0,1,1,0,0, +12,0,97,0,0,0,1,3,2,90,95,0,0,12,0,1,98,0,2,18,97,0,54,0,0,4,118,101,99,52,95,102,108,111,111,114, +0,18,98,0,0,18,98,0,0,0,9,18,95,95,114,101,116,86,97,108,0,18,98,0,54,20,0,0,1,90,95,0,0,9,0,0,102, +114,97,99,116,0,1,1,0,0,9,0,97,0,0,0,1,4,118,101,99,52,95,102,114,97,99,0,18,95,95,114,101,116,86, +97,108,0,0,18,97,0,0,0,0,1,90,95,0,0,10,0,0,102,114,97,99,116,0,1,1,0,0,10,0,97,0,0,0,1,4,118,101, +99,52,95,102,114,97,99,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,97,0,0,0,0,1,90,95,0,0, +11,0,0,102,114,97,99,116,0,1,1,0,0,11,0,97,0,0,0,1,4,118,101,99,52,95,102,114,97,99,0,18,95,95,114, +101,116,86,97,108,0,59,120,121,122,0,0,18,97,0,0,0,0,1,90,95,0,0,12,0,0,102,114,97,99,116,0,1,1,0, +0,12,0,97,0,0,0,1,4,118,101,99,52,95,102,114,97,99,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0, +0,0,1,90,95,0,0,9,0,0,109,111,100,0,1,1,0,0,9,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,3,2,90,95,0,0,9,0,1, +111,110,101,79,118,101,114,66,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,111,110,101,79,118,101, +114,66,0,0,18,98,0,0,0,9,18,95,95,114,101,116,86,97,108,0,18,97,0,18,98,0,58,102,108,111,111,114,0, +0,18,97,0,18,111,110,101,79,118,101,114,66,0,48,0,0,48,47,20,0,0,1,90,95,0,0,10,0,0,109,111,100,0, +1,1,0,0,10,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,3,2,90,95,0,0,9,0,1,111,110,101,79,118,101,114,66,0,0,0, +4,102,108,111,97,116,95,114,99,112,0,18,111,110,101,79,118,101,114,66,0,0,18,98,0,0,0,9,18,95,95, +114,101,116,86,97,108,0,59,120,121,0,18,97,0,18,98,0,58,102,108,111,111,114,0,0,18,97,0,18,111,110, +101,79,118,101,114,66,0,48,0,0,48,47,20,0,0,1,90,95,0,0,11,0,0,109,111,100,0,1,1,0,0,11,0,97,0,0,1, +1,0,0,9,0,98,0,0,0,1,3,2,90,95,0,0,9,0,1,111,110,101,79,118,101,114,66,0,0,0,4,102,108,111,97,116, +95,114,99,112,0,18,111,110,101,79,118,101,114,66,0,0,18,98,0,0,0,9,18,95,95,114,101,116,86,97,108, +0,59,120,121,122,0,18,97,0,18,98,0,58,102,108,111,111,114,0,0,18,97,0,18,111,110,101,79,118,101, +114,66,0,48,0,0,48,47,20,0,0,1,90,95,0,0,12,0,0,109,111,100,0,1,1,0,0,12,0,97,0,0,1,1,0,0,9,0,98,0, +0,0,1,3,2,90,95,0,0,9,0,1,111,110,101,79,118,101,114,66,0,0,0,4,102,108,111,97,116,95,114,99,112,0, +18,111,110,101,79,118,101,114,66,0,0,18,98,0,0,0,9,18,95,95,114,101,116,86,97,108,0,18,97,0,18,98, +0,58,102,108,111,111,114,0,0,18,97,0,18,111,110,101,79,118,101,114,66,0,48,0,0,48,47,20,0,0,1,90, +95,0,0,10,0,0,109,111,100,0,1,1,0,0,10,0,97,0,0,1,1,0,0,10,0,98,0,0,0,1,3,2,90,95,0,0,10,0,1,111, +110,101,79,118,101,114,66,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,111,110,101,79,118,101,114, +66,0,59,120,0,0,18,98,0,59,120,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,111,110,101,79,118, +101,114,66,0,59,121,0,0,18,98,0,59,121,0,0,0,9,18,95,95,114,101,116,86,97,108,0,18,97,0,18,98,0,58, +102,108,111,111,114,0,0,18,97,0,18,111,110,101,79,118,101,114,66,0,48,0,0,48,47,20,0,0,1,90,95,0,0, +11,0,0,109,111,100,0,1,1,0,0,11,0,97,0,0,1,1,0,0,11,0,98,0,0,0,1,3,2,90,95,0,0,11,0,1,111,110,101, +79,118,101,114,66,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,111,110,101,79,118,101,114,66,0,59, +120,0,0,18,98,0,59,120,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,111,110,101,79,118,101,114,66, +0,59,121,0,0,18,98,0,59,121,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,111,110,101,79,118,101, +114,66,0,59,122,0,0,18,98,0,59,122,0,0,0,9,18,95,95,114,101,116,86,97,108,0,18,97,0,18,98,0,58,102, +108,111,111,114,0,0,18,97,0,18,111,110,101,79,118,101,114,66,0,48,0,0,48,47,20,0,0,1,90,95,0,0,12, +0,0,109,111,100,0,1,1,0,0,12,0,97,0,0,1,1,0,0,12,0,98,0,0,0,1,3,2,90,95,0,0,12,0,1,111,110,101,79, +118,101,114,66,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,111,110,101,79,118,101,114,66,0,59, +120,0,0,18,98,0,59,120,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,111,110,101,79,118,101,114,66, +0,59,121,0,0,18,98,0,59,121,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,111,110,101,79,118,101, +114,66,0,59,122,0,0,18,98,0,59,122,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,111,110,101,79, +118,101,114,66,0,59,119,0,0,18,98,0,59,119,0,0,0,9,18,95,95,114,101,116,86,97,108,0,18,97,0,18,98, +0,58,102,108,111,111,114,0,0,18,97,0,18,111,110,101,79,118,101,114,66,0,48,0,0,48,47,20,0,0,1,90, +95,0,0,9,0,0,109,105,110,0,1,1,0,0,9,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,109,105, +110,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1,90,95,0,0,10,0,0,109,105,110,0, +1,1,0,0,10,0,97,0,0,1,1,0,0,10,0,98,0,0,0,1,4,118,101,99,52,95,109,105,110,0,18,95,95,114,101,116, +86,97,108,0,59,120,121,0,0,18,97,0,59,120,121,0,0,18,98,0,59,120,121,0,0,0,0,1,90,95,0,0,11,0,0, +109,105,110,0,1,1,0,0,11,0,97,0,0,1,1,0,0,11,0,98,0,0,0,1,4,118,101,99,52,95,109,105,110,0,18,95, +95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,97,0,59,120,121,122,0,0,18,98,0,59,120,121,122,0, +0,0,0,1,90,95,0,0,12,0,0,109,105,110,0,1,1,0,0,12,0,97,0,0,1,1,0,0,12,0,98,0,0,0,1,4,118,101,99,52, +95,109,105,110,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1,90,95,0,0,10,0,0,109, +105,110,0,1,1,0,0,10,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,109,105,110,0,18,95,95,114, +101,116,86,97,108,0,0,18,97,0,59,120,121,0,0,18,98,0,0,0,0,1,90,95,0,0,11,0,0,109,105,110,0,1,1,0, +0,11,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,109,105,110,0,18,95,95,114,101,116,86,97, +108,0,0,18,97,0,59,120,121,122,0,0,18,98,0,0,0,0,1,90,95,0,0,12,0,0,109,105,110,0,1,1,0,0,12,0,97, +0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,109,105,110,0,18,95,95,114,101,116,86,97,108,0,0,18, +97,0,0,18,98,0,0,0,0,1,90,95,0,0,9,0,0,109,97,120,0,1,1,0,0,9,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,4, +118,101,99,52,95,109,97,120,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1,90,95,0, +0,10,0,0,109,97,120,0,1,1,0,0,10,0,97,0,0,1,1,0,0,10,0,98,0,0,0,1,4,118,101,99,52,95,109,97,120,0, +18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,97,0,59,120,121,0,0,18,98,0,59,120,121,0,0,0,0, +1,90,95,0,0,11,0,0,109,97,120,0,1,1,0,0,11,0,97,0,0,1,1,0,0,11,0,98,0,0,0,1,4,118,101,99,52,95,109, +97,120,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,97,0,59,120,121,122,0,0,18,98,0,59, +120,121,122,0,0,0,0,1,90,95,0,0,12,0,0,109,97,120,0,1,1,0,0,12,0,97,0,0,1,1,0,0,12,0,98,0,0,0,1,4, +118,101,99,52,95,109,97,120,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1,90,95,0, +0,10,0,0,109,97,120,0,1,1,0,0,10,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,109,97,120,0, +18,95,95,114,101,116,86,97,108,0,0,18,97,0,59,120,121,0,0,18,98,0,0,0,0,1,90,95,0,0,11,0,0,109,97, +120,0,1,1,0,0,11,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,109,97,120,0,18,95,95,114,101, +116,86,97,108,0,0,18,97,0,59,120,121,122,0,0,18,98,0,0,0,0,1,90,95,0,0,12,0,0,109,97,120,0,1,1,0,0, +12,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,109,97,120,0,18,95,95,114,101,116,86,97,108, +0,0,18,97,0,0,18,98,0,0,0,0,1,90,95,0,0,9,0,0,99,108,97,109,112,0,1,1,0,0,9,0,118,97,108,0,0,1,1,0, +0,9,0,109,105,110,86,97,108,0,0,1,1,0,0,9,0,109,97,120,86,97,108,0,0,0,1,4,118,101,99,52,95,99,108, +97,109,112,0,18,95,95,114,101,116,86,97,108,0,0,18,118,97,108,0,0,18,109,105,110,86,97,108,0,0,18, +109,97,120,86,97,108,0,0,0,0,1,90,95,0,0,10,0,0,99,108,97,109,112,0,1,1,0,0,10,0,118,97,108,0,0,1, +1,0,0,9,0,109,105,110,86,97,108,0,0,1,1,0,0,9,0,109,97,120,86,97,108,0,0,0,1,4,118,101,99,52,95,99, +108,97,109,112,0,18,95,95,114,101,116,86,97,108,0,0,18,118,97,108,0,0,18,109,105,110,86,97,108,0,0, +18,109,97,120,86,97,108,0,0,0,0,1,90,95,0,0,11,0,0,99,108,97,109,112,0,1,1,0,0,11,0,118,97,108,0,0, +1,1,0,0,9,0,109,105,110,86,97,108,0,0,1,1,0,0,9,0,109,97,120,86,97,108,0,0,0,1,4,118,101,99,52,95, +99,108,97,109,112,0,18,95,95,114,101,116,86,97,108,0,0,18,118,97,108,0,0,18,109,105,110,86,97,108, +0,0,18,109,97,120,86,97,108,0,0,0,0,1,90,95,0,0,12,0,0,99,108,97,109,112,0,1,1,0,0,12,0,118,97,108, +0,0,1,1,0,0,9,0,109,105,110,86,97,108,0,0,1,1,0,0,9,0,109,97,120,86,97,108,0,0,0,1,4,118,101,99,52, +95,99,108,97,109,112,0,18,95,95,114,101,116,86,97,108,0,0,18,118,97,108,0,0,18,109,105,110,86,97, +108,0,0,18,109,97,120,86,97,108,0,0,0,0,1,90,95,0,0,10,0,0,99,108,97,109,112,0,1,1,0,0,10,0,118,97, +108,0,0,1,1,0,0,10,0,109,105,110,86,97,108,0,0,1,1,0,0,10,0,109,97,120,86,97,108,0,0,0,1,4,118,101, +99,52,95,99,108,97,109,112,0,18,95,95,114,101,116,86,97,108,0,0,18,118,97,108,0,0,18,109,105,110, +86,97,108,0,0,18,109,97,120,86,97,108,0,0,0,0,1,90,95,0,0,11,0,0,99,108,97,109,112,0,1,1,0,0,11,0, +118,97,108,0,0,1,1,0,0,11,0,109,105,110,86,97,108,0,0,1,1,0,0,11,0,109,97,120,86,97,108,0,0,0,1,4, +118,101,99,52,95,99,108,97,109,112,0,18,95,95,114,101,116,86,97,108,0,0,18,118,97,108,0,0,18,109, +105,110,86,97,108,0,0,18,109,97,120,86,97,108,0,0,0,0,1,90,95,0,0,12,0,0,99,108,97,109,112,0,1,1,0, +0,12,0,118,97,108,0,0,1,1,0,0,12,0,109,105,110,86,97,108,0,0,1,1,0,0,12,0,109,97,120,86,97,108,0,0, +0,1,4,118,101,99,52,95,99,108,97,109,112,0,18,95,95,114,101,116,86,97,108,0,0,18,118,97,108,0,0,18, +109,105,110,86,97,108,0,0,18,109,97,120,86,97,108,0,0,0,0,1,90,95,0,0,9,0,0,109,105,120,0,1,1,0,0, +9,0,120,0,0,1,1,0,0,9,0,121,0,0,1,1,0,0,9,0,97,0,0,0,1,4,118,101,99,52,95,108,114,112,0,18,95,95, +114,101,116,86,97,108,0,0,18,97,0,0,18,121,0,0,18,120,0,0,0,0,1,90,95,0,0,10,0,0,109,105,120,0,1,1, +0,0,10,0,120,0,0,1,1,0,0,10,0,121,0,0,1,1,0,0,9,0,97,0,0,0,1,4,118,101,99,52,95,108,114,112,0,18, +95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,121,0,0,18,120,0,0,0,0,1,90,95,0,0,11,0,0,109,105,120, +0,1,1,0,0,11,0,120,0,0,1,1,0,0,11,0,121,0,0,1,1,0,0,9,0,97,0,0,0,1,4,118,101,99,52,95,108,114,112, +0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,121,0,0,18,120,0,0,0,0,1,90,95,0,0,12,0,0,109, +105,120,0,1,1,0,0,12,0,120,0,0,1,1,0,0,12,0,121,0,0,1,1,0,0,9,0,97,0,0,0,1,4,118,101,99,52,95,108, +114,112,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,121,0,0,18,120,0,0,0,0,1,90,95,0,0,10,0, +0,109,105,120,0,1,1,0,0,10,0,120,0,0,1,1,0,0,10,0,121,0,0,1,1,0,0,10,0,97,0,0,0,1,4,118,101,99,52, +95,108,114,112,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,121,0,0,18,120,0,0,0,0,1,90,95,0, +0,11,0,0,109,105,120,0,1,1,0,0,11,0,120,0,0,1,1,0,0,11,0,121,0,0,1,1,0,0,11,0,97,0,0,0,1,4,118,101, +99,52,95,108,114,112,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,121,0,0,18,120,0,0,0,0,1,90, +95,0,0,12,0,0,109,105,120,0,1,1,0,0,12,0,120,0,0,1,1,0,0,12,0,121,0,0,1,1,0,0,12,0,97,0,0,0,1,4, +118,101,99,52,95,108,114,112,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,121,0,0,18,120,0,0, +0,0,1,90,95,0,0,9,0,0,115,116,101,112,0,1,1,0,0,9,0,101,100,103,101,0,0,1,1,0,0,9,0,120,0,0,0,1,4, +118,101,99,52,95,115,103,101,0,18,95,95,114,101,116,86,97,108,0,0,18,120,0,0,18,101,100,103,101,0, +0,0,0,1,90,95,0,0,10,0,0,115,116,101,112,0,1,1,0,0,10,0,101,100,103,101,0,0,1,1,0,0,10,0,120,0,0,0, +1,4,118,101,99,52,95,115,103,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,120,0,0,18, +101,100,103,101,0,0,0,0,1,90,95,0,0,11,0,0,115,116,101,112,0,1,1,0,0,11,0,101,100,103,101,0,0,1,1, +0,0,11,0,120,0,0,0,1,4,118,101,99,52,95,115,103,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121, +122,0,0,18,120,0,0,18,101,100,103,101,0,0,0,0,1,90,95,0,0,12,0,0,115,116,101,112,0,1,1,0,0,12,0, +101,100,103,101,0,0,1,1,0,0,12,0,120,0,0,0,1,4,118,101,99,52,95,115,103,101,0,18,95,95,114,101,116, +86,97,108,0,0,18,120,0,0,18,101,100,103,101,0,0,0,0,1,90,95,0,0,10,0,0,115,116,101,112,0,1,1,0,0,9, +0,101,100,103,101,0,0,1,1,0,0,10,0,118,0,0,0,1,4,118,101,99,52,95,115,103,101,0,18,95,95,114,101, +116,86,97,108,0,59,120,121,0,0,18,118,0,0,18,101,100,103,101,0,0,0,0,1,90,95,0,0,11,0,0,115,116, +101,112,0,1,1,0,0,9,0,101,100,103,101,0,0,1,1,0,0,11,0,118,0,0,0,1,4,118,101,99,52,95,115,103,101, +0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,118,0,0,18,101,100,103,101,0,0,0,0,1,90, +95,0,0,12,0,0,115,116,101,112,0,1,1,0,0,9,0,101,100,103,101,0,0,1,1,0,0,12,0,118,0,0,0,1,4,118,101, +99,52,95,115,103,101,0,18,95,95,114,101,116,86,97,108,0,0,18,118,0,0,18,101,100,103,101,0,0,0,0,1, +90,95,0,0,9,0,0,115,109,111,111,116,104,115,116,101,112,0,1,1,0,0,9,0,101,100,103,101,48,0,0,1,1,0, +0,9,0,101,100,103,101,49,0,0,1,1,0,0,9,0,120,0,0,0,1,3,2,90,95,0,0,9,0,1,116,0,2,58,99,108,97,109, +112,0,0,18,120,0,18,101,100,103,101,48,0,47,18,101,100,103,101,49,0,18,101,100,103,101,48,0,47,49, +0,17,48,0,48,0,0,0,17,49,0,48,0,0,0,0,0,0,8,18,116,0,18,116,0,48,17,51,0,48,0,0,17,50,0,48,0,0,18, +116,0,48,47,48,0,0,1,90,95,0,0,10,0,0,115,109,111,111,116,104,115,116,101,112,0,1,1,0,0,10,0,101, +100,103,101,48,0,0,1,1,0,0,10,0,101,100,103,101,49,0,0,1,1,0,0,10,0,118,0,0,0,1,3,2,90,95,0,0,10,0, +1,116,0,2,58,99,108,97,109,112,0,0,18,118,0,18,101,100,103,101,48,0,47,18,101,100,103,101,49,0,18, +101,100,103,101,48,0,47,49,0,17,48,0,48,0,0,0,17,49,0,48,0,0,0,0,0,0,8,18,116,0,18,116,0,48,17,51, +0,48,0,0,17,50,0,48,0,0,18,116,0,48,47,48,0,0,1,90,95,0,0,11,0,0,115,109,111,111,116,104,115,116, +101,112,0,1,1,0,0,11,0,101,100,103,101,48,0,0,1,1,0,0,11,0,101,100,103,101,49,0,0,1,1,0,0,11,0,118, +0,0,0,1,3,2,90,95,0,0,11,0,1,116,0,2,58,99,108,97,109,112,0,0,18,118,0,18,101,100,103,101,48,0,47, +18,101,100,103,101,49,0,18,101,100,103,101,48,0,47,49,0,17,48,0,48,0,0,0,17,49,0,48,0,0,0,0,0,0,8, +18,116,0,18,116,0,48,17,51,0,48,0,0,17,50,0,48,0,0,18,116,0,48,47,48,0,0,1,90,95,0,0,12,0,0,115, +109,111,111,116,104,115,116,101,112,0,1,1,0,0,12,0,101,100,103,101,48,0,0,1,1,0,0,12,0,101,100,103, +101,49,0,0,1,1,0,0,12,0,118,0,0,0,1,3,2,90,95,0,0,12,0,1,116,0,2,58,99,108,97,109,112,0,0,18,118,0, +18,101,100,103,101,48,0,47,18,101,100,103,101,49,0,18,101,100,103,101,48,0,47,49,0,17,48,0,48,0,0, +0,17,49,0,48,0,0,0,0,0,0,8,18,116,0,18,116,0,48,17,51,0,48,0,0,17,50,0,48,0,0,18,116,0,48,47,48,0, +0,1,90,95,0,0,10,0,0,115,109,111,111,116,104,115,116,101,112,0,1,1,0,0,9,0,101,100,103,101,48,0,0, +1,1,0,0,9,0,101,100,103,101,49,0,0,1,1,0,0,10,0,118,0,0,0,1,3,2,90,95,0,0,10,0,1,116,0,2,58,99,108, +97,109,112,0,0,18,118,0,18,101,100,103,101,48,0,47,18,101,100,103,101,49,0,18,101,100,103,101,48,0, +47,49,0,17,48,0,48,0,0,0,17,49,0,48,0,0,0,0,0,0,8,18,116,0,18,116,0,48,17,51,0,48,0,0,17,50,0,48,0, +0,18,116,0,48,47,48,0,0,1,90,95,0,0,11,0,0,115,109,111,111,116,104,115,116,101,112,0,1,1,0,0,9,0, +101,100,103,101,48,0,0,1,1,0,0,9,0,101,100,103,101,49,0,0,1,1,0,0,11,0,118,0,0,0,1,3,2,90,95,0,0, +11,0,1,116,0,2,58,99,108,97,109,112,0,0,18,118,0,18,101,100,103,101,48,0,47,18,101,100,103,101,49, +0,18,101,100,103,101,48,0,47,49,0,17,48,0,48,0,0,0,17,49,0,48,0,0,0,0,0,0,8,18,116,0,18,116,0,48, +17,51,0,48,0,0,17,50,0,48,0,0,18,116,0,48,47,48,0,0,1,90,95,0,0,12,0,0,115,109,111,111,116,104,115, +116,101,112,0,1,1,0,0,9,0,101,100,103,101,48,0,0,1,1,0,0,9,0,101,100,103,101,49,0,0,1,1,0,0,12,0, +118,0,0,0,1,3,2,90,95,0,0,12,0,1,116,0,2,58,99,108,97,109,112,0,0,18,118,0,18,101,100,103,101,48,0, +47,18,101,100,103,101,49,0,18,101,100,103,101,48,0,47,49,0,17,48,0,48,0,0,0,17,49,0,48,0,0,0,0,0,0, +8,18,116,0,18,116,0,48,17,51,0,48,0,0,17,50,0,48,0,0,18,116,0,48,47,48,0,0,1,90,95,0,0,9,0,0,108, +101,110,103,116,104,0,1,1,0,0,9,0,120,0,0,0,1,8,58,97,98,115,0,0,18,120,0,0,0,0,0,1,90,95,0,0,9,0, +0,108,101,110,103,116,104,0,1,1,0,0,10,0,118,0,0,0,1,3,2,90,95,0,0,9,0,1,114,0,0,0,3,2,90,95,1,0,9, +0,1,112,0,2,58,100,111,116,0,0,18,118,0,0,18,118,0,0,0,0,0,4,102,108,111,97,116,95,114,115,113,0, +18,114,0,0,18,112,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,95,95,114,101,116,86,97,108,0,59, +120,0,0,18,114,0,0,0,0,1,90,95,0,0,9,0,0,108,101,110,103,116,104,0,1,1,0,0,11,0,118,0,0,0,1,3,2,90, +95,0,0,9,0,1,114,0,0,0,3,2,90,95,1,0,9,0,1,112,0,2,58,100,111,116,0,0,18,118,0,0,18,118,0,0,0,0,0, +4,102,108,111,97,116,95,114,115,113,0,18,114,0,0,18,112,0,0,0,4,102,108,111,97,116,95,114,99,112,0, +18,95,95,114,101,116,86,97,108,0,0,18,114,0,0,0,0,1,90,95,0,0,9,0,0,108,101,110,103,116,104,0,1,1, +0,0,12,0,118,0,0,0,1,3,2,90,95,0,0,9,0,1,114,0,0,0,3,2,90,95,1,0,9,0,1,112,0,2,58,100,111,116,0,0, +18,118,0,0,18,118,0,0,0,0,0,4,102,108,111,97,116,95,114,115,113,0,18,114,0,0,18,112,0,0,0,4,102, +108,111,97,116,95,114,99,112,0,18,95,95,114,101,116,86,97,108,0,0,18,114,0,0,0,0,1,90,95,0,0,9,0,0, +100,105,115,116,97,110,99,101,0,1,1,0,0,9,0,120,0,0,1,1,0,0,9,0,121,0,0,0,1,3,2,90,95,1,0,9,0,1, +100,0,2,18,120,0,18,121,0,47,0,0,9,18,95,95,114,101,116,86,97,108,0,58,108,101,110,103,116,104,0,0, +18,100,0,0,0,20,0,0,1,90,95,0,0,9,0,0,100,105,115,116,97,110,99,101,0,1,1,0,0,10,0,118,0,0,1,1,0,0, +10,0,117,0,0,0,1,3,2,90,95,1,0,10,0,1,100,50,0,2,18,118,0,18,117,0,47,0,0,9,18,95,95,114,101,116, +86,97,108,0,58,108,101,110,103,116,104,0,0,18,100,50,0,0,0,20,0,0,1,90,95,0,0,9,0,0,100,105,115, +116,97,110,99,101,0,1,1,0,0,11,0,118,0,0,1,1,0,0,11,0,117,0,0,0,1,3,2,90,95,1,0,11,0,1,100,51,0,2, +18,118,0,18,117,0,47,0,0,9,18,95,95,114,101,116,86,97,108,0,58,108,101,110,103,116,104,0,0,18,100, +51,0,0,0,20,0,0,1,90,95,0,0,9,0,0,100,105,115,116,97,110,99,101,0,1,1,0,0,12,0,118,0,0,1,1,0,0,12, +0,117,0,0,0,1,3,2,90,95,1,0,12,0,1,100,52,0,2,18,118,0,18,117,0,47,0,0,9,18,95,95,114,101,116,86, +97,108,0,58,108,101,110,103,116,104,0,0,18,100,52,0,0,0,20,0,0,1,90,95,0,0,11,0,0,99,114,111,115, +115,0,1,1,0,0,11,0,118,0,0,1,1,0,0,11,0,117,0,0,0,1,4,118,101,99,51,95,99,114,111,115,115,0,18,95, +95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,118,0,0,18,117,0,0,0,0,1,90,95,0,0,9,0,0,102,97, +99,101,102,111,114,119,97,114,100,0,1,1,0,0,9,0,78,0,0,1,1,0,0,9,0,73,0,0,1,1,0,0,9,0,78,114,101, +102,0,0,0,1,3,2,90,95,1,0,9,0,1,100,0,2,58,100,111,116,0,0,18,78,114,101,102,0,0,18,73,0,0,0,0,0,3, +2,90,95,0,0,9,0,1,115,0,0,0,4,118,101,99,52,95,115,103,116,0,18,115,0,0,17,48,0,48,0,0,0,18,100,0, +0,0,8,58,109,105,120,0,0,18,78,0,54,0,18,78,0,0,18,115,0,0,0,0,0,1,90,95,0,0,10,0,0,102,97,99,101, +102,111,114,119,97,114,100,0,1,1,0,0,10,0,78,0,0,1,1,0,0,10,0,73,0,0,1,1,0,0,10,0,78,114,101,102,0, +0,0,1,3,2,90,95,1,0,9,0,1,100,0,2,58,100,111,116,0,0,18,78,114,101,102,0,0,18,73,0,0,0,0,0,3,2,90, +95,0,0,9,0,1,115,0,0,0,4,118,101,99,52,95,115,103,116,0,18,115,0,0,17,48,0,48,0,0,0,18,100,0,0,0,8, +58,109,105,120,0,0,18,78,0,54,0,18,78,0,0,18,115,0,0,0,0,0,1,90,95,0,0,11,0,0,102,97,99,101,102, +111,114,119,97,114,100,0,1,1,0,0,11,0,78,0,0,1,1,0,0,11,0,73,0,0,1,1,0,0,11,0,78,114,101,102,0,0,0, +1,3,2,90,95,1,0,9,0,1,100,0,2,58,100,111,116,0,0,18,78,114,101,102,0,0,18,73,0,0,0,0,0,3,2,90,95,0, +0,9,0,1,115,0,0,0,4,118,101,99,52,95,115,103,116,0,18,115,0,0,17,48,0,48,0,0,0,18,100,0,0,0,8,58, +109,105,120,0,0,18,78,0,54,0,18,78,0,0,18,115,0,0,0,0,0,1,90,95,0,0,12,0,0,102,97,99,101,102,111, +114,119,97,114,100,0,1,1,0,0,12,0,78,0,0,1,1,0,0,12,0,73,0,0,1,1,0,0,12,0,78,114,101,102,0,0,0,1,3, +2,90,95,1,0,9,0,1,100,0,2,58,100,111,116,0,0,18,78,114,101,102,0,0,18,73,0,0,0,0,0,3,2,90,95,0,0,9, +0,1,115,0,0,0,4,118,101,99,52,95,115,103,116,0,18,115,0,0,17,48,0,48,0,0,0,18,100,0,0,0,8,58,109, +105,120,0,0,18,78,0,54,0,18,78,0,0,18,115,0,0,0,0,0,1,90,95,0,0,9,0,0,114,101,102,108,101,99,116,0, +1,1,0,0,9,0,73,0,0,1,1,0,0,9,0,78,0,0,0,1,8,18,73,0,17,50,0,48,0,0,58,100,111,116,0,0,18,78,0,0,18, +73,0,0,0,48,18,78,0,48,47,0,0,1,90,95,0,0,10,0,0,114,101,102,108,101,99,116,0,1,1,0,0,10,0,73,0,0, +1,1,0,0,10,0,78,0,0,0,1,8,18,73,0,17,50,0,48,0,0,58,100,111,116,0,0,18,78,0,0,18,73,0,0,0,48,18,78, +0,48,47,0,0,1,90,95,0,0,11,0,0,114,101,102,108,101,99,116,0,1,1,0,0,11,0,73,0,0,1,1,0,0,11,0,78,0, +0,0,1,8,18,73,0,17,50,0,48,0,0,58,100,111,116,0,0,18,78,0,0,18,73,0,0,0,48,18,78,0,48,47,0,0,1,90, +95,0,0,12,0,0,114,101,102,108,101,99,116,0,1,1,0,0,12,0,73,0,0,1,1,0,0,12,0,78,0,0,0,1,8,18,73,0, +17,50,0,48,0,0,58,100,111,116,0,0,18,78,0,0,18,73,0,0,0,48,18,78,0,48,47,0,0,1,90,95,0,0,9,0,0,114, +101,102,114,97,99,116,0,1,1,0,0,9,0,73,0,0,1,1,0,0,9,0,78,0,0,1,1,0,0,9,0,101,116,97,0,0,0,1,3,2, +90,95,0,0,9,0,1,110,95,100,111,116,95,105,0,2,58,100,111,116,0,0,18,78,0,0,18,73,0,0,0,0,0,3,2,90, +95,0,0,9,0,1,107,0,2,17,49,0,48,0,0,18,101,116,97,0,18,101,116,97,0,48,17,49,0,48,0,0,18,110,95, +100,111,116,95,105,0,18,110,95,100,111,116,95,105,0,48,47,48,47,0,0,3,2,90,95,0,0,9,0,1,114,101, +116,118,97,108,0,0,0,10,18,107,0,17,48,0,48,0,0,40,0,9,18,114,101,116,118,97,108,0,17,48,0,48,0,0, +20,0,9,18,114,101,116,118,97,108,0,18,101,116,97,0,18,73,0,48,18,101,116,97,0,18,110,95,100,111, +116,95,105,0,48,58,115,113,114,116,0,0,18,107,0,0,0,46,18,78,0,48,47,20,0,8,18,114,101,116,118,97, +108,0,0,0,1,90,95,0,0,10,0,0,114,101,102,114,97,99,116,0,1,1,0,0,10,0,73,0,0,1,1,0,0,10,0,78,0,0,1, +1,0,0,9,0,101,116,97,0,0,0,1,3,2,90,95,0,0,9,0,1,110,95,100,111,116,95,105,0,2,58,100,111,116,0,0, +18,78,0,0,18,73,0,0,0,0,0,3,2,90,95,0,0,9,0,1,107,0,2,17,49,0,48,0,0,18,101,116,97,0,18,101,116,97, +0,48,17,49,0,48,0,0,18,110,95,100,111,116,95,105,0,18,110,95,100,111,116,95,105,0,48,47,48,47,0,0, +3,2,90,95,0,0,10,0,1,114,101,116,118,97,108,0,0,0,10,18,107,0,17,48,0,48,0,0,40,0,9,18,114,101,116, +118,97,108,0,58,118,101,99,50,0,0,17,48,0,48,0,0,0,0,20,0,9,18,114,101,116,118,97,108,0,18,101,116, +97,0,18,73,0,48,18,101,116,97,0,18,110,95,100,111,116,95,105,0,48,58,115,113,114,116,0,0,18,107,0, +0,0,46,18,78,0,48,47,20,0,8,18,114,101,116,118,97,108,0,0,0,1,90,95,0,0,11,0,0,114,101,102,114,97, +99,116,0,1,1,0,0,11,0,73,0,0,1,1,0,0,11,0,78,0,0,1,1,0,0,9,0,101,116,97,0,0,0,1,3,2,90,95,0,0,9,0, +1,110,95,100,111,116,95,105,0,2,58,100,111,116,0,0,18,78,0,0,18,73,0,0,0,0,0,3,2,90,95,0,0,9,0,1, +107,0,2,17,49,0,48,0,0,18,101,116,97,0,18,101,116,97,0,48,17,49,0,48,0,0,18,110,95,100,111,116,95, +105,0,18,110,95,100,111,116,95,105,0,48,47,48,47,0,0,3,2,90,95,0,0,11,0,1,114,101,116,118,97,108,0, +0,0,10,18,107,0,17,48,0,48,0,0,40,0,9,18,114,101,116,118,97,108,0,58,118,101,99,51,0,0,17,48,0,48, +0,0,0,0,20,0,9,18,114,101,116,118,97,108,0,18,101,116,97,0,18,73,0,48,18,101,116,97,0,18,110,95, +100,111,116,95,105,0,48,58,115,113,114,116,0,0,18,107,0,0,0,46,18,78,0,48,47,20,0,8,18,114,101,116, +118,97,108,0,0,0,1,90,95,0,0,12,0,0,114,101,102,114,97,99,116,0,1,1,0,0,12,0,73,0,0,1,1,0,0,12,0, +78,0,0,1,1,0,0,9,0,101,116,97,0,0,0,1,3,2,90,95,0,0,9,0,1,110,95,100,111,116,95,105,0,2,58,100,111, +116,0,0,18,78,0,0,18,73,0,0,0,0,0,3,2,90,95,0,0,9,0,1,107,0,2,17,49,0,48,0,0,18,101,116,97,0,18, +101,116,97,0,48,17,49,0,48,0,0,18,110,95,100,111,116,95,105,0,18,110,95,100,111,116,95,105,0,48,47, +48,47,0,0,3,2,90,95,0,0,12,0,1,114,101,116,118,97,108,0,0,0,10,18,107,0,17,48,0,48,0,0,40,0,9,18, +114,101,116,118,97,108,0,58,118,101,99,52,0,0,17,48,0,48,0,0,0,0,20,0,9,18,114,101,116,118,97,108, +0,18,101,116,97,0,18,73,0,48,18,101,116,97,0,18,110,95,100,111,116,95,105,0,48,58,115,113,114,116, +0,0,18,107,0,0,0,46,18,78,0,48,47,20,0,8,18,114,101,116,118,97,108,0,0,0,1,90,95,0,0,13,0,0,109,97, +116,114,105,120,67,111,109,112,77,117,108,116,0,1,0,0,0,13,0,109,0,0,1,0,0,0,13,0,110,0,0,0,1,8,58, +109,97,116,50,0,0,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,48,0,18,109,0,16,10,49,0,57,18,110,0, +16,10,49,0,57,48,0,0,0,0,1,90,95,0,0,14,0,0,109,97,116,114,105,120,67,111,109,112,77,117,108,116,0, +1,0,0,0,14,0,109,0,0,1,0,0,0,14,0,110,0,0,0,1,8,58,109,97,116,51,0,0,18,109,0,16,8,48,0,57,18,110, +0,16,8,48,0,57,48,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,48,0,18,109,0,16,10,50,0,57,18, +110,0,16,10,50,0,57,48,0,0,0,0,1,90,95,0,0,15,0,0,109,97,116,114,105,120,67,111,109,112,77,117,108, +116,0,1,0,0,0,15,0,109,0,0,1,0,0,0,15,0,110,0,0,0,1,8,58,109,97,116,52,0,0,18,109,0,16,8,48,0,57, +18,110,0,16,8,48,0,57,48,0,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,48,0,18,109,0,16,10,50,0, +57,18,110,0,16,10,50,0,57,48,0,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,48,0,0,0,0,1,90,95,0, +0,2,0,0,108,101,115,115,84,104,97,110,0,1,1,0,0,10,0,117,0,0,1,1,0,0,10,0,118,0,0,0,1,4,118,101,99, +52,95,115,108,116,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,117,0,0,18,118,0,0,0,0,1,90, +95,0,0,3,0,0,108,101,115,115,84,104,97,110,0,1,1,0,0,11,0,117,0,0,1,1,0,0,11,0,118,0,0,0,1,4,118, +101,99,52,95,115,108,116,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,117,0,0,18,118,0, +0,0,0,1,90,95,0,0,4,0,0,108,101,115,115,84,104,97,110,0,1,1,0,0,12,0,117,0,0,1,1,0,0,12,0,118,0,0, +0,1,4,118,101,99,52,95,115,108,116,0,18,95,95,114,101,116,86,97,108,0,0,18,117,0,0,18,118,0,0,0,0, +1,90,95,0,0,2,0,0,108,101,115,115,84,104,97,110,0,1,1,0,0,6,0,117,0,0,1,1,0,0,6,0,118,0,0,0,1,4, +118,101,99,52,95,115,108,116,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,117,0,0,18,118,0, +0,0,0,1,90,95,0,0,3,0,0,108,101,115,115,84,104,97,110,0,1,1,0,0,7,0,117,0,0,1,1,0,0,7,0,118,0,0,0, +1,4,118,101,99,52,95,115,108,116,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,117,0,0, +18,118,0,0,0,0,1,90,95,0,0,4,0,0,108,101,115,115,84,104,97,110,0,1,1,0,0,8,0,117,0,0,1,1,0,0,8,0, +118,0,0,0,1,4,118,101,99,52,95,115,108,116,0,18,95,95,114,101,116,86,97,108,0,0,18,117,0,0,18,118, +0,0,0,0,1,90,95,0,0,2,0,0,108,101,115,115,84,104,97,110,69,113,117,97,108,0,1,1,0,0,10,0,117,0,0,1, +1,0,0,10,0,118,0,0,0,1,4,118,101,99,52,95,115,108,101,0,18,95,95,114,101,116,86,97,108,0,59,120, +121,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,3,0,0,108,101,115,115,84,104,97,110,69,113,117,97, +108,0,1,1,0,0,11,0,117,0,0,1,1,0,0,11,0,118,0,0,0,1,4,118,101,99,52,95,115,108,101,0,18,95,95,114, +101,116,86,97,108,0,59,120,121,122,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,4,0,0,108,101,115,115, +84,104,97,110,69,113,117,97,108,0,1,1,0,0,12,0,117,0,0,1,1,0,0,12,0,118,0,0,0,1,4,118,101,99,52,95, +115,108,101,0,18,95,95,114,101,116,86,97,108,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,2,0,0,108, +101,115,115,84,104,97,110,69,113,117,97,108,0,1,1,0,0,6,0,117,0,0,1,1,0,0,6,0,118,0,0,0,1,4,118, +101,99,52,95,115,108,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,117,0,0,18,118,0,0,0, +0,1,90,95,0,0,3,0,0,108,101,115,115,84,104,97,110,69,113,117,97,108,0,1,1,0,0,7,0,117,0,0,1,1,0,0, +7,0,118,0,0,0,1,4,118,101,99,52,95,115,108,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0, +0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,4,0,0,108,101,115,115,84,104,97,110,69,113,117,97,108,0,1, +1,0,0,8,0,117,0,0,1,1,0,0,8,0,118,0,0,0,1,4,118,101,99,52,95,115,108,101,0,18,95,95,114,101,116,86, +97,108,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,2,0,0,103,114,101,97,116,101,114,84,104,97,110,0, +1,1,0,0,10,0,117,0,0,1,1,0,0,10,0,118,0,0,0,1,4,118,101,99,52,95,115,103,116,0,18,95,95,114,101, +116,86,97,108,0,59,120,121,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,3,0,0,103,114,101,97,116,101, +114,84,104,97,110,0,1,1,0,0,11,0,117,0,0,1,1,0,0,11,0,118,0,0,0,1,4,118,101,99,52,95,115,103,116,0, +18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,4,0,0, +103,114,101,97,116,101,114,84,104,97,110,0,1,1,0,0,12,0,117,0,0,1,1,0,0,12,0,118,0,0,0,1,4,118,101, +99,52,95,115,103,116,0,18,95,95,114,101,116,86,97,108,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,2, +0,0,103,114,101,97,116,101,114,84,104,97,110,0,1,1,0,0,6,0,117,0,0,1,1,0,0,6,0,118,0,0,0,1,4,118, +101,99,52,95,115,103,116,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,117,0,59,120,121,0,0, +18,118,0,59,120,121,0,0,0,0,1,90,95,0,0,3,0,0,103,114,101,97,116,101,114,84,104,97,110,0,1,1,0,0,7, +0,117,0,0,1,1,0,0,7,0,118,0,0,0,1,4,118,101,99,52,95,115,103,116,0,18,95,95,114,101,116,86,97,108, +0,59,120,121,122,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,4,0,0,103,114,101,97,116,101,114,84,104, +97,110,0,1,1,0,0,8,0,117,0,0,1,1,0,0,8,0,118,0,0,0,1,4,118,101,99,52,95,115,103,116,0,18,95,95,114, +101,116,86,97,108,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,2,0,0,103,114,101,97,116,101,114,84, +104,97,110,69,113,117,97,108,0,1,1,0,0,10,0,117,0,0,1,1,0,0,10,0,118,0,0,0,1,4,118,101,99,52,95, +115,103,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0, +0,3,0,0,103,114,101,97,116,101,114,84,104,97,110,69,113,117,97,108,0,1,1,0,0,11,0,117,0,0,1,1,0,0, +11,0,118,0,0,0,1,4,118,101,99,52,95,115,103,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122, +0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,4,0,0,103,114,101,97,116,101,114,84,104,97,110,69,113, +117,97,108,0,1,1,0,0,12,0,117,0,0,1,1,0,0,12,0,118,0,0,0,1,4,118,101,99,52,95,115,103,101,0,18,95, +95,114,101,116,86,97,108,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,2,0,0,103,114,101,97,116,101, +114,84,104,97,110,69,113,117,97,108,0,1,1,0,0,6,0,117,0,0,1,1,0,0,6,0,118,0,0,0,1,4,118,101,99,52, +95,115,103,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95, +0,0,3,0,0,103,114,101,97,116,101,114,84,104,97,110,69,113,117,97,108,0,1,1,0,0,7,0,117,0,0,1,1,0,0, +7,0,118,0,0,0,1,4,118,101,99,52,95,115,103,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0, +0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,4,0,0,103,114,101,97,116,101,114,84,104,97,110,69,113,117, +97,108,0,1,1,0,0,8,0,117,0,0,1,1,0,0,8,0,118,0,0,0,1,4,118,101,99,52,95,115,103,101,0,18,95,95,114, +101,116,86,97,108,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,2,0,0,101,113,117,97,108,0,1,1,0,0,10, +0,117,0,0,1,1,0,0,10,0,118,0,0,0,1,4,118,101,99,52,95,115,101,113,0,18,95,95,114,101,116,86,97,108, +0,59,120,121,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,3,0,0,101,113,117,97,108,0,1,1,0,0,11,0,117, +0,0,1,1,0,0,11,0,118,0,0,0,1,4,118,101,99,52,95,115,101,113,0,18,95,95,114,101,116,86,97,108,0,59, +120,121,122,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,4,0,0,101,113,117,97,108,0,1,1,0,0,12,0,117, +0,0,1,1,0,0,12,0,118,0,0,0,1,4,118,101,99,52,95,115,101,113,0,18,95,95,114,101,116,86,97,108,0,0, +18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,2,0,0,101,113,117,97,108,0,1,1,0,0,6,0,117,0,0,1,1,0,0,6,0, +118,0,0,0,1,4,118,101,99,52,95,115,101,113,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18, +117,0,0,18,118,0,0,0,0,1,90,95,0,0,3,0,0,101,113,117,97,108,0,1,1,0,0,7,0,117,0,0,1,1,0,0,7,0,118, +0,0,0,1,4,118,101,99,52,95,115,101,113,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18, +117,0,0,18,118,0,0,0,0,1,90,95,0,0,4,0,0,101,113,117,97,108,0,1,1,0,0,8,0,117,0,0,1,1,0,0,8,0,118, +0,0,0,1,4,118,101,99,52,95,115,101,113,0,18,95,95,114,101,116,86,97,108,0,0,18,117,0,0,18,118,0,0, +0,0,1,90,95,0,0,2,0,0,101,113,117,97,108,0,1,1,0,0,2,0,117,0,0,1,1,0,0,2,0,118,0,0,0,1,4,118,101, +99,52,95,115,101,113,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,117,0,0,18,118,0,0,0,0,1, +90,95,0,0,3,0,0,101,113,117,97,108,0,1,1,0,0,3,0,117,0,0,1,1,0,0,3,0,118,0,0,0,1,4,118,101,99,52, +95,115,101,113,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,117,0,0,18,118,0,0,0,0,1, +90,95,0,0,4,0,0,101,113,117,97,108,0,1,1,0,0,4,0,117,0,0,1,1,0,0,4,0,118,0,0,0,1,4,118,101,99,52, +95,115,101,113,0,18,95,95,114,101,116,86,97,108,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0,0,2,0,0, +110,111,116,69,113,117,97,108,0,1,1,0,0,10,0,117,0,0,1,1,0,0,10,0,118,0,0,0,1,4,118,101,99,52,95, +115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,117,0,0,18,118,0,0,0,0,1,90,95,0, +0,3,0,0,110,111,116,69,113,117,97,108,0,1,1,0,0,11,0,117,0,0,1,1,0,0,11,0,118,0,0,0,1,4,118,101,99, +52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,117,0,0,18,118,0,0,0,0, +1,90,95,0,0,4,0,0,110,111,116,69,113,117,97,108,0,1,1,0,0,12,0,117,0,0,1,1,0,0,12,0,118,0,0,0,1,4, +118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,0,18,117,0,0,18,118,0,0,0,0,1,90, +95,0,0,2,0,0,110,111,116,69,113,117,97,108,0,1,1,0,0,6,0,117,0,0,1,1,0,0,6,0,118,0,0,0,1,4,118,101, +99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,117,0,0,18,118,0,0,0,0,1, +90,95,0,0,3,0,0,110,111,116,69,113,117,97,108,0,1,1,0,0,7,0,117,0,0,1,1,0,0,7,0,118,0,0,0,1,4,118, +101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,117,0,0,18,118,0, +0,0,0,1,90,95,0,0,4,0,0,110,111,116,69,113,117,97,108,0,1,1,0,0,8,0,117,0,0,1,1,0,0,8,0,118,0,0,0, +1,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,0,18,117,0,0,18,118,0,0,0,0,1, +90,95,0,0,2,0,0,110,111,116,69,113,117,97,108,0,1,1,0,0,2,0,117,0,0,1,1,0,0,2,0,118,0,0,0,1,4,118, +101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,117,0,0,18,118,0,0,0, +0,1,90,95,0,0,3,0,0,110,111,116,69,113,117,97,108,0,1,1,0,0,3,0,117,0,0,1,1,0,0,3,0,118,0,0,0,1,4, +118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,117,0,0,18, +118,0,0,0,0,1,90,95,0,0,4,0,0,110,111,116,69,113,117,97,108,0,1,1,0,0,4,0,117,0,0,1,1,0,0,4,0,118, +0,0,0,1,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,0,18,117,0,0,18,118,0,0, +0,0,1,90,95,0,0,1,0,0,97,110,121,0,1,1,0,0,2,0,118,0,0,0,1,3,2,90,95,0,0,9,0,1,115,117,109,0,0,0,4, +118,101,99,52,95,97,100,100,0,18,115,117,109,0,59,120,0,0,18,118,0,59,120,0,0,18,118,0,59,121,0,0, +0,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,115,117,109,0,59, +120,0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,1,0,0,97,110,121,0,1,1,0,0,3,0,118,0,0,0,1,3,2,90,95,0,0, +9,0,1,115,117,109,0,0,0,4,118,101,99,52,95,97,100,100,0,18,115,117,109,0,59,120,0,0,18,118,0,59, +120,0,0,18,118,0,59,121,0,0,0,4,118,101,99,52,95,97,100,100,0,18,115,117,109,0,59,120,0,0,18,115, +117,109,0,59,120,0,0,18,118,0,59,122,0,0,0,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116, +86,97,108,0,59,120,0,0,18,115,117,109,0,59,120,0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,1,0,0,97,110, +121,0,1,1,0,0,4,0,118,0,0,0,1,3,2,90,95,0,0,9,0,1,115,117,109,0,0,0,4,118,101,99,52,95,97,100,100, +0,18,115,117,109,0,59,120,0,0,18,118,0,59,120,0,0,18,118,0,59,121,0,0,0,4,118,101,99,52,95,97,100, +100,0,18,115,117,109,0,59,120,0,0,18,115,117,109,0,59,120,0,0,18,118,0,59,122,0,0,0,4,118,101,99, +52,95,97,100,100,0,18,115,117,109,0,59,120,0,0,18,115,117,109,0,59,120,0,0,18,118,0,59,119,0,0,0,4, +118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,115,117,109,0,59,120, +0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,1,0,0,97,108,108,0,1,1,0,0,2,0,118,0,0,0,1,3,2,90,95,0,0,9,0, +1,112,114,111,100,0,0,0,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,112,114,111,100,0, +0,18,118,0,59,120,0,0,18,118,0,59,121,0,0,0,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116, +86,97,108,0,0,18,112,114,111,100,0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,1,0,0,97,108,108,0,1,1,0,0,3, +0,118,0,0,0,1,3,2,90,95,0,0,9,0,1,112,114,111,100,0,0,0,4,118,101,99,52,95,109,117,108,116,105,112, +108,121,0,18,112,114,111,100,0,0,18,118,0,59,120,0,0,18,118,0,59,121,0,0,0,4,118,101,99,52,95,109, +117,108,116,105,112,108,121,0,18,112,114,111,100,0,0,18,112,114,111,100,0,0,18,118,0,59,122,0,0,0, +4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,0,18,112,114,111,100,0,0,17,48,0, +48,0,0,0,0,0,1,90,95,0,0,1,0,0,97,108,108,0,1,1,0,0,4,0,118,0,0,0,1,3,2,90,95,0,0,9,0,1,112,114, +111,100,0,0,0,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,112,114,111,100,0,0,18,118,0, +59,120,0,0,18,118,0,59,121,0,0,0,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,112,114, +111,100,0,0,18,112,114,111,100,0,0,18,118,0,59,122,0,0,0,4,118,101,99,52,95,109,117,108,116,105, +112,108,121,0,18,112,114,111,100,0,0,18,112,114,111,100,0,0,18,118,0,59,119,0,0,0,4,118,101,99,52, +95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,0,18,112,114,111,100,0,0,17,48,0,48,0,0,0,0,0,1, +90,95,0,0,2,0,0,110,111,116,0,1,1,0,0,2,0,118,0,0,0,1,4,118,101,99,52,95,115,101,113,0,18,95,95, +114,101,116,86,97,108,0,59,120,121,0,0,18,118,0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,3,0,0,110,111, +116,0,1,1,0,0,3,0,118,0,0,0,1,4,118,101,99,52,95,115,101,113,0,18,95,95,114,101,116,86,97,108,0,59, +120,121,122,0,0,18,118,0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,4,0,0,110,111,116,0,1,1,0,0,4,0,118,0, +0,0,1,4,118,101,99,52,95,115,101,113,0,18,95,95,114,101,116,86,97,108,0,0,18,118,0,0,17,48,0,48,0, +0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,49,68,0,1,1,0,0,16,0,115,97,109,112,108,101, +114,0,0,1,1,0,0,9,0,99,111,111,114,100,0,0,0,1,4,118,101,99,52,95,116,101,120,95,49,100,0,18,95,95, +114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,0,0,0,1,90,95, +0,0,12,0,0,116,101,120,116,117,114,101,49,68,80,114,111,106,0,1,1,0,0,16,0,115,97,109,112,108,101, +114,0,0,1,1,0,0,10,0,99,111,111,114,100,0,0,0,1,4,118,101,99,52,95,116,101,120,95,49,100,95,112, +114,111,106,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111, +114,100,0,59,120,121,121,121,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,49,68,80,114, +111,106,0,1,1,0,0,16,0,115,97,109,112,108,101,114,0,0,1,1,0,0,12,0,99,111,111,114,100,0,0,0,1,4, +118,101,99,52,95,116,101,120,95,49,100,95,112,114,111,106,0,18,95,95,114,101,116,86,97,108,0,0,18, +115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116, +117,114,101,50,68,0,1,1,0,0,17,0,115,97,109,112,108,101,114,0,0,1,1,0,0,10,0,99,111,111,114,100,0, +0,0,1,4,118,101,99,52,95,116,101,120,95,50,100,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109, +112,108,101,114,0,0,18,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101, +50,68,80,114,111,106,0,1,1,0,0,17,0,115,97,109,112,108,101,114,0,0,1,1,0,0,11,0,99,111,111,114,100, +0,0,0,1,4,118,101,99,52,95,116,101,120,95,50,100,95,112,114,111,106,0,18,95,95,114,101,116,86,97, +108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,59,120,121,122,122,0,0,0,0,1,90, +95,0,0,12,0,0,116,101,120,116,117,114,101,50,68,80,114,111,106,0,1,1,0,0,17,0,115,97,109,112,108, +101,114,0,0,1,1,0,0,12,0,99,111,111,114,100,0,0,0,1,4,118,101,99,52,95,116,101,120,95,50,100,95, +112,114,111,106,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111, +111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,51,68,0,1,1,0,0,18,0,115,97,109, +112,108,101,114,0,0,1,1,0,0,11,0,99,111,111,114,100,0,0,0,1,4,118,101,99,52,95,116,101,120,95,51, +100,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0, +0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,51,68,80,114,111,106,0,1,1,0,0,18,0,115,97, +109,112,108,101,114,0,0,1,1,0,0,12,0,99,111,111,114,100,0,0,0,1,4,118,101,99,52,95,116,101,120,95, +51,100,95,112,114,111,106,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0, +18,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,67,117,98,101,0,1,1,0, +0,19,0,115,97,109,112,108,101,114,0,0,1,1,0,0,11,0,99,111,111,114,100,0,0,0,1,4,118,101,99,52,95, +116,101,120,95,99,117,98,101,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0, +0,18,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,115,104,97,100,111,119,49,68,0,1,1,0,0,20,0,115, +97,109,112,108,101,114,0,0,1,1,0,0,11,0,99,111,111,114,100,0,0,0,1,4,118,101,99,52,95,116,101,120, +95,49,100,95,115,104,97,100,111,119,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101, +114,0,0,18,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,115,104,97,100,111,119,49,68,80,114,111, +106,0,1,1,0,0,20,0,115,97,109,112,108,101,114,0,0,1,1,0,0,12,0,99,111,111,114,100,0,0,0,1,4,118, +101,99,52,95,116,101,120,95,49,100,95,112,114,111,106,95,115,104,97,100,111,119,0,18,95,95,114,101, +116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0, +0,115,104,97,100,111,119,50,68,0,1,1,0,0,21,0,115,97,109,112,108,101,114,0,0,1,1,0,0,11,0,99,111, +111,114,100,0,0,0,1,4,118,101,99,52,95,116,101,120,95,50,100,95,115,104,97,100,111,119,0,18,95,95, +114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,0,0,0,1,90,95, +0,0,12,0,0,115,104,97,100,111,119,50,68,80,114,111,106,0,1,1,0,0,21,0,115,97,109,112,108,101,114,0, +0,1,1,0,0,12,0,99,111,111,114,100,0,0,0,1,4,118,101,99,52,95,116,101,120,95,50,100,95,112,114,111, +106,95,115,104,97,100,111,119,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0, +0,18,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,50,68,82,101,99,116, +0,1,1,0,0,22,0,115,97,109,112,108,101,114,0,0,1,1,0,0,10,0,99,111,111,114,100,0,0,0,1,4,118,101,99, +52,95,116,101,120,95,114,101,99,116,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101, +114,0,0,18,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,50,68,82,101, +99,116,80,114,111,106,0,1,1,0,0,22,0,115,97,109,112,108,101,114,0,0,1,1,0,0,11,0,99,111,111,114, +100,0,0,0,1,4,118,101,99,52,95,116,101,120,95,114,101,99,116,95,112,114,111,106,0,18,95,95,114,101, +116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,59,120,121,122,122,0,0, +0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,50,68,82,101,99,116,80,114,111,106,0,1,1,0,0,22, +0,115,97,109,112,108,101,114,0,0,1,1,0,0,12,0,99,111,111,114,100,0,0,0,1,4,118,101,99,52,95,116, +101,120,95,114,101,99,116,95,112,114,111,106,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109, +112,108,101,114,0,0,18,99,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,115,104,97,100,111,119,50, +68,82,101,99,116,0,1,1,0,0,23,0,115,97,109,112,108,101,114,0,0,1,1,0,0,11,0,99,111,111,114,100,0,0, +0,1,4,118,101,99,52,95,116,101,120,95,114,101,99,116,95,115,104,97,100,111,119,0,18,95,95,114,101, +116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0, +0,115,104,97,100,111,119,50,68,82,101,99,116,80,114,111,106,0,1,1,0,0,23,0,115,97,109,112,108,101, +114,0,0,1,1,0,0,12,0,99,111,111,114,100,0,0,0,1,4,118,101,99,52,95,116,101,120,95,114,101,99,116, +95,112,114,111,106,95,115,104,97,100,111,119,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109, +112,108,101,114,0,0,18,99,111,111,114,100,0,0,0,0,1,90,95,0,0,9,0,0,110,111,105,115,101,49,0,1,1,0, +0,9,0,120,0,0,0,1,4,102,108,111,97,116,95,110,111,105,115,101,49,0,18,95,95,114,101,116,86,97,108, +0,0,18,120,0,0,0,0,1,90,95,0,0,9,0,0,110,111,105,115,101,49,0,1,1,0,0,10,0,120,0,0,0,1,4,102,108, +111,97,116,95,110,111,105,115,101,50,0,18,95,95,114,101,116,86,97,108,0,0,18,120,0,0,0,0,1,90,95,0, +0,9,0,0,110,111,105,115,101,49,0,1,1,0,0,11,0,120,0,0,0,1,4,102,108,111,97,116,95,110,111,105,115, +101,51,0,18,95,95,114,101,116,86,97,108,0,0,18,120,0,0,0,0,1,90,95,0,0,9,0,0,110,111,105,115,101, +49,0,1,1,0,0,12,0,120,0,0,0,1,4,102,108,111,97,116,95,110,111,105,115,101,52,0,18,95,95,114,101, +116,86,97,108,0,0,18,120,0,0,0,0,1,90,95,0,0,10,0,0,110,111,105,115,101,50,0,1,1,0,0,9,0,120,0,0,0, +1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,58,110,111,105,115,101,49,0,0,18,120,0,0,0,20,0,9,18, +95,95,114,101,116,86,97,108,0,59,121,0,58,110,111,105,115,101,49,0,0,18,120,0,17,49,57,0,51,52,0,0, +46,0,0,20,0,0,1,90,95,0,0,10,0,0,110,111,105,115,101,50,0,1,1,0,0,10,0,120,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,59,120,0,58,110,111,105,115,101,49,0,0,18,120,0,0,0,20,0,9,18,95,95,114,101, +116,86,97,108,0,59,121,0,58,110,111,105,115,101,49,0,0,18,120,0,58,118,101,99,50,0,0,17,49,57,0,51, +52,0,0,0,17,55,0,54,54,0,0,0,0,46,0,0,20,0,0,1,90,95,0,0,10,0,0,110,111,105,115,101,50,0,1,1,0,0, +11,0,120,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,58,110,111,105,115,101,49,0,0,18,120, +0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,58,110,111,105,115,101,49,0,0,18,120,0,58, +118,101,99,51,0,0,17,49,57,0,51,52,0,0,0,17,55,0,54,54,0,0,0,17,51,0,50,51,0,0,0,0,46,0,0,20,0,0,1, +90,95,0,0,10,0,0,110,111,105,115,101,50,0,1,1,0,0,12,0,120,0,0,0,1,9,18,95,95,114,101,116,86,97, +108,0,59,120,0,58,110,111,105,115,101,49,0,0,18,120,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0, +59,121,0,58,110,111,105,115,101,49,0,0,18,120,0,58,118,101,99,52,0,0,17,49,57,0,51,52,0,0,0,17,55, +0,54,54,0,0,0,17,51,0,50,51,0,0,0,17,50,0,55,55,0,0,0,0,46,0,0,20,0,0,1,90,95,0,0,11,0,0,110,111, +105,115,101,51,0,1,1,0,0,9,0,120,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,58,110,111, +105,115,101,49,0,0,18,120,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,58,110,111,105, +115,101,49,0,0,18,120,0,17,49,57,0,51,52,0,0,46,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122, +0,58,110,111,105,115,101,49,0,0,18,120,0,17,53,0,52,55,0,0,46,0,0,20,0,0,1,90,95,0,0,11,0,0,110, +111,105,115,101,51,0,1,1,0,0,10,0,120,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,58,110, +111,105,115,101,49,0,0,18,120,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,58,110,111, +105,115,101,49,0,0,18,120,0,58,118,101,99,50,0,0,17,49,57,0,51,52,0,0,0,17,55,0,54,54,0,0,0,0,46,0, +0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,58,110,111,105,115,101,49,0,0,18,120,0,58,118, +101,99,50,0,0,17,53,0,52,55,0,0,0,17,49,55,0,56,53,0,0,0,0,46,0,0,20,0,0,1,90,95,0,0,11,0,0,110, +111,105,115,101,51,0,1,1,0,0,11,0,120,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,58,110, +111,105,115,101,49,0,0,18,120,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,58,110,111, +105,115,101,49,0,0,18,120,0,58,118,101,99,51,0,0,17,49,57,0,51,52,0,0,0,17,55,0,54,54,0,0,0,17,51, +0,50,51,0,0,0,0,46,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,58,110,111,105,115,101,49, +0,0,18,120,0,58,118,101,99,51,0,0,17,53,0,52,55,0,0,0,17,49,55,0,56,53,0,0,0,17,49,49,0,48,52,0,0, +0,0,46,0,0,20,0,0,1,90,95,0,0,11,0,0,110,111,105,115,101,51,0,1,1,0,0,12,0,120,0,0,0,1,9,18,95,95, +114,101,116,86,97,108,0,59,120,0,58,110,111,105,115,101,49,0,0,18,120,0,0,0,20,0,9,18,95,95,114, +101,116,86,97,108,0,59,121,0,58,110,111,105,115,101,49,0,0,18,120,0,58,118,101,99,52,0,0,17,49,57, +0,51,52,0,0,0,17,55,0,54,54,0,0,0,17,51,0,50,51,0,0,0,17,50,0,55,55,0,0,0,0,46,0,0,20,0,9,18,95,95, +114,101,116,86,97,108,0,59,122,0,58,110,111,105,115,101,49,0,0,18,120,0,58,118,101,99,52,0,0,17,53, +0,52,55,0,0,0,17,49,55,0,56,53,0,0,0,17,49,49,0,48,52,0,0,0,17,49,51,0,49,57,0,0,0,0,46,0,0,20,0,0, +1,90,95,0,0,12,0,0,110,111,105,115,101,52,0,1,1,0,0,9,0,120,0,0,0,1,9,18,95,95,114,101,116,86,97, +108,0,59,120,0,58,110,111,105,115,101,49,0,0,18,120,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0, +59,121,0,58,110,111,105,115,101,49,0,0,18,120,0,17,49,57,0,51,52,0,0,46,0,0,20,0,9,18,95,95,114, +101,116,86,97,108,0,59,122,0,58,110,111,105,115,101,49,0,0,18,120,0,17,53,0,52,55,0,0,46,0,0,20,0, +9,18,95,95,114,101,116,86,97,108,0,59,119,0,58,110,111,105,115,101,49,0,0,18,120,0,17,50,51,0,53, +52,0,0,46,0,0,20,0,0,1,90,95,0,0,12,0,0,110,111,105,115,101,52,0,1,1,0,0,10,0,120,0,0,0,1,9,18,95, +95,114,101,116,86,97,108,0,59,120,0,58,110,111,105,115,101,49,0,0,18,120,0,0,0,20,0,9,18,95,95,114, +101,116,86,97,108,0,59,121,0,58,110,111,105,115,101,49,0,0,18,120,0,58,118,101,99,50,0,0,17,49,57, +0,51,52,0,0,0,17,55,0,54,54,0,0,0,0,46,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,58,110, +111,105,115,101,49,0,0,18,120,0,58,118,101,99,50,0,0,17,53,0,52,55,0,0,0,17,49,55,0,56,53,0,0,0,0, +46,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,119,0,58,110,111,105,115,101,49,0,0,18,120,0,58, +118,101,99,50,0,0,17,50,51,0,53,52,0,0,0,17,50,57,0,49,49,0,0,0,0,46,0,0,20,0,0,1,90,95,0,0,12,0,0, +110,111,105,115,101,52,0,1,1,0,0,11,0,120,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,58, +110,111,105,115,101,49,0,0,18,120,0,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,58,110, +111,105,115,101,49,0,0,18,120,0,58,118,101,99,51,0,0,17,49,57,0,51,52,0,0,0,17,55,0,54,54,0,0,0,17, +51,0,50,51,0,0,0,0,46,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,58,110,111,105,115,101, +49,0,0,18,120,0,58,118,101,99,51,0,0,17,53,0,52,55,0,0,0,17,49,55,0,56,53,0,0,0,17,49,49,0,48,52,0, +0,0,0,46,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,119,0,58,110,111,105,115,101,49,0,0,18,120, +0,58,118,101,99,51,0,0,17,50,51,0,53,52,0,0,0,17,50,57,0,49,49,0,0,0,17,51,49,0,57,49,0,0,0,0,46,0, +0,20,0,0,1,90,95,0,0,12,0,0,110,111,105,115,101,52,0,1,1,0,0,12,0,120,0,0,0,1,9,18,95,95,114,101, +116,86,97,108,0,59,120,0,58,110,111,105,115,101,49,0,0,18,120,0,0,0,20,0,9,18,95,95,114,101,116,86, +97,108,0,59,121,0,58,110,111,105,115,101,49,0,0,18,120,0,58,118,101,99,52,0,0,17,49,57,0,51,52,0,0, +0,17,55,0,54,54,0,0,0,17,51,0,50,51,0,0,0,17,50,0,55,55,0,0,0,0,46,0,0,20,0,9,18,95,95,114,101,116, +86,97,108,0,59,122,0,58,110,111,105,115,101,49,0,0,18,120,0,58,118,101,99,52,0,0,17,53,0,52,55,0,0, +0,17,49,55,0,56,53,0,0,0,17,49,49,0,48,52,0,0,0,17,49,51,0,49,57,0,0,0,0,46,0,0,20,0,9,18,95,95, +114,101,116,86,97,108,0,59,119,0,58,110,111,105,115,101,49,0,0,18,120,0,58,118,101,99,52,0,0,17,50, +51,0,53,52,0,0,0,17,50,57,0,49,49,0,0,0,17,51,49,0,57,49,0,0,0,17,51,55,0,52,56,0,0,0,0,46,0,0,20, +0,0,0 diff --git a/mesalib/src/mesa/shader/slang/library/slang_core.gc b/mesalib/src/mesa/shader/slang/library/slang_core.gc new file mode 100644 index 000000000..0a0d15903 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_core.gc @@ -0,0 +1,2619 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// +// This file defines nearly all constructors and operators for built-in data +// types, using extended language syntax. In general, compiler treats +// constructors and operators as ordinary functions with some exceptions. +// For example, the language does not allow functions to be called in +// constant expressions - here the exception is made to allow it. +// +// Each implementation provides its own version of this file. Each +// implementation can define the required set of operators and constructors +// in its own fashion. +// +// The extended language syntax is only present when compiling this file. +// It is implicitly included at the very beginning of the compiled shader, +// so no built-in functions can be used. +// +// To communicate with the implementation, a special extended "__asm" keyword +// is used, followed by an instruction name (any valid identifier), a +// destination variable identifier and a list of zero or more source +// variable identifiers. +// +// A variable identifier is a variable name declared earlier in the code +// (as a function parameter, local or global variable). +// +// An instruction name designates an instruction that must be exported +// by the implementation. Each instruction receives data from source +// variable identifiers and returns data in the destination variable +// identifier. +// +// It is up to the implementation how to define a particular operator +// or constructor. If it is expected to being used rarely, it can be +// defined in terms of other operators and constructors, +// for example: +// +// ivec2 __operator + (const ivec2 x, const ivec2 y) { +// return ivec2 (x[0] + y[0], x[1] + y[1]); +// } +// +// If a particular operator or constructor is expected to be used very +// often or is an atomic operation (that is, an operation that cannot be +// expressed in terms of other operations or would create a dependency +// cycle) it must be defined using one or more __asm constructs. +// +// Each implementation must define constructors for all scalar types +// (bool, float, int). There are 9 scalar-to-scalar constructors +// (including identity constructors). However, since the language +// introduces special constructors (like matrix constructor with a single +// scalar value), implementations must also implement these cases. +// The compiler provides the following algorithm when resolving a constructor: +// - try to find a constructor with a prototype matching ours, +// - if no constructor is found and this is a scalar-to-scalar constructor, +// raise an error, +// - if a constructor is found, execute it and return, +// - count the size of the constructor parameter list - if it is less than +// the size of our constructor's type, raise an error, +// - for each parameter in the list do a recursive constructor matching for +// appropriate scalar fields in the constructed variable, +// +// Each implementation must also define a set of operators that deal with +// built-in data types. +// There are four kinds of operators: +// 1) Operators that are implemented only by the compiler: "()" (function +// call), "," (sequence) and "?:" (selection). +// 2) Operators that are implemented by the compiler by expressing it in +// terms of other operators: +// - "." (field selection) - translated to subscript access, +// - "&&" (logical and) - translated to "<left_expr> ? <right_expr> : +// false", +// - "||" (logical or) - translated to "<left_expr> ? true : <right_expr>", +// 3) Operators that can be defined by the implementation and if the required +// prototype is not found, standard behaviour is used: +// - "==", "!=", "=" (equality, assignment) - compare or assign +// matching fields one-by-one; +// note that at least operators for scalar data types must be defined +// by the implementation to get it work, +// 4) All other operators not mentioned above. If no required prototype is +// found, an error is raised. An implementation must follow the language +// specification to provide all valid operator prototypes. +// + + + +//// Basic, scalar constructors/casts + +int __constructor(const float f) +{ + __asm vec4_to_ivec4 __retVal, f; +} + +int __constructor(const bool b) +{ + __retVal = b; +} + +int __constructor(const int i) +{ + __retVal = i; +} + +bool __constructor(const int i) +{ + __asm vec4_sne __retVal, i, 0.0; +} + +bool __constructor(const float f) +{ + __asm vec4_sne __retVal, f, 0.0; +} + +bool __constructor(const bool b) +{ + __retVal = b; +} + +float __constructor(const int i) +{ + __asm ivec4_to_vec4 __retVal, i; +} + +float __constructor(const bool b) +{ + __asm ivec4_to_vec4 __retVal, b; +} + +float __constructor(const float f) +{ + __retVal = f; +} + + +//// vec2 constructors + +vec2 __constructor(const float x, const float y) +{ + __retVal.x = x; + __retVal.y = y; +} + +vec2 __constructor(const float f) +{ + __asm vec4_move __retVal.xy, f; +} + +vec2 __constructor(const int i) +{ + __asm ivec4_to_vec4 __retVal.xy, i; +} + +vec2 __constructor(const bool b) +{ + __asm ivec4_to_vec4 __retVal.xy, b; +} + +vec2 __constructor(const bvec2 b) +{ +// __retVal = b; + __asm ivec4_to_vec4 __retVal.xy, b; +} + +vec2 __constructor(const vec3 v) +{ + __asm vec4_move __retVal.xy, v.xy; +} + +vec2 __constructor(const vec4 v) +{ + __asm vec4_move __retVal.xy, v.xy; +} + + +//// vec3 constructors + +vec3 __constructor(const float x, const float y, const float z) +{ + __retVal.x = x; + __retVal.y = y; + __retVal.z = z; +} + +vec3 __constructor(const float f) +{ + // Note: this could be "__retVal.xyz = f" but that's an illegal assignment + __asm vec4_move __retVal.xyz, f; +} + +vec3 __constructor(const int i) +{ + __asm ivec4_to_vec4 __retVal.xyz, i; +} + +vec3 __constructor(const bool b) +{ + __asm ivec4_to_vec4 __retVal.xyz, b; +} + +vec3 __constructor(const bvec3 b) +{ + __asm ivec4_to_vec4 __retVal.xyz, b; +} + +vec3 __constructor(const vec4 v) +{ + __asm vec4_move __retVal.xyz, v; +} + + +//// vec4 constructors + +vec4 __constructor(const float x, const float y, const float z, const float w) +{ + __retVal.x = x; + __retVal.y = y; + __retVal.z = z; + __retVal.w = w; +} + +vec4 __constructor(const float f) +{ + // Note: this could be "__retVal = f" but that's an illegal assignment + __asm vec4_move __retVal, f; +} + +vec4 __constructor(const int i) +{ + __asm ivec4_to_vec4 __retVal, i; +} + +vec4 __constructor(const bool b) +{ + __asm ivec4_to_vec4 __retVal, b; +} + +vec4 __constructor(const bvec4 b) +{ + __asm ivec4_to_vec4 __retVal, b; +} + +vec4 __constructor(const ivec4 i) +{ + __asm ivec4_to_vec4 __retVal, i; +} + +vec4 __constructor(const vec3 v3, const float f) +{ + // XXX this constructor shouldn't be needed anymore + __retVal.xyz = v3; + __retVal.w = f; +} + +vec4 __constructor(const vec2 v2, const float f1, const float f2) +{ + // XXX this constructor shouldn't be needed anymore + __retVal.xy = v2; + __retVal.z = f1; + __retVal.w = f2; +} + + +//// ivec2 constructors + +ivec2 __constructor(const int i, const int j) +{ + __retVal.x = i; + __retVal.y = j; +} + +ivec2 __constructor(const int i) +{ + __asm vec4_move __retVal.xy, i; +} + +ivec2 __constructor(const float f) +{ + __asm vec4_to_ivec4 __retVal.xy, f; +} + +ivec2 __constructor(const bool b) +{ + __asm vec4_to_ivec4 __retVal.xy, b; +} + + +//// ivec3 constructors + +ivec3 __constructor(const int i, const int j, const int k) +{ + __retVal.x = i; + __retVal.y = j; + __retVal.z = k; +} + +ivec3 __constructor(const int i) +{ + __asm vec4_move __retVal.xyz, i; +} + +ivec3 __constructor(const float f) +{ + __asm vec4_to_ivec4 __retVal.xyz, f; +} + +ivec3 __constructor(const bool b) +{ + __asm vec4_move __retVal.xyz, b; +} + + +//// ivec4 constructors + +ivec4 __constructor(const int x, const int y, const int z, const int w) +{ + __retVal.x = x; + __retVal.y = y; + __retVal.z = z; + __retVal.w = w; +} + +ivec4 __constructor(const int i) +{ + __asm vec4_move __retVal, i; +} + +ivec4 __constructor(const float f) +{ + __asm vec4_to_ivec4 __retVal, f; +} + +ivec4 __constructor(const bool b) +{ + __asm vec4_to_ivec4 __retVal, b; +} + + +//// bvec2 constructors + +bvec2 __constructor(const bool b1, const bool b2) +{ + __retVal.x = b1; + __retVal.y = b2; +} + +bvec2 __constructor(const int i1, const int i2) +{ + __asm vec4_sne __retVal.x, i1, 0.0; + __asm vec4_sne __retVal.y, i2, 0.0; +} + + +bvec2 __constructor(const bool b) +{ + __asm vec4_move __retVal.xy, b; +} + +bvec2 __constructor(const float f) +{ + __asm vec4_sne __retVal.xy, f, 0.0; +} + +bvec2 __constructor(const int i) +{ + __asm vec4_sne __retVal.xy, i, 0.0; +} + +bvec2 __constructor(const vec2 v) +{ + __asm vec4_sne __retVal.xy, v, 0.0; +} + +bvec2 __constructor(const ivec2 v) +{ + __asm vec4_sne __retVal.xy, v, 0.0; +} + + + +//// bvec3 constructors + +bvec3 __constructor(const bool b1, const bool b2, const bool b3) +{ + __retVal.x = b1; + __retVal.y = b2; + __retVal.z = b3; +} + +bvec3 __constructor(const float f1, const float f2, const float f3) +{ + __asm vec4_sne __retVal.x, f1, 0.0; + __asm vec4_sne __retVal.y, f2, 0.0; + __asm vec4_sne __retVal.z, f3, 0.0; +} + +bvec3 __constructor(const bool b) +{ + __asm vec4_move __retVal.xyz, b; +} + +bvec3 __constructor(const float f) +{ + __asm vec4_sne __retVal.xyz, f, 0.0; +} + +bvec3 __constructor(const int i) +{ + __asm vec4_sne __retVal.xyz, i, 0.0; +} + +bvec3 __constructor(const vec3 v) +{ + __asm vec4_sne __retVal.xyz, v, 0.0; +} + +bvec3 __constructor(const ivec3 v) +{ + __asm vec4_sne __retVal.xyz, v, 0.0; +} + + + +//// bvec4 constructors + +bvec4 __constructor(const bool b1, const bool b2, const bool b3, const bool b4) +{ + __retVal.x = b1; + __retVal.y = b2; + __retVal.z = b3; + __retVal.w = b4; +} + +bvec4 __constructor(const float f1, const float f2, const float f3, const float f4) +{ + const float zero = 0.0; + __asm vec4_sne __retVal.x, f1, zero; + __asm vec4_sne __retVal.y, f2, zero; + __asm vec4_sne __retVal.z, f3, zero; + __asm vec4_sne __retVal.w, f4, zero; +} + +bvec4 __constructor(const bool b) +{ + __asm vec4_move __retVal.xyzw, b; +} + +bvec4 __constructor(const float f) +{ + __asm vec4_sne __retVal.xyzw, f, 0.0; +} + +bvec4 __constructor(const int i) +{ + __asm vec4_sne __retVal.xyzw, i, 0.0; +} + +bvec4 __constructor(const vec4 v) +{ + __asm vec4_sne __retVal.xyzw, v, 0.0; +} + +bvec4 __constructor(const ivec4 v) +{ + __asm vec4_sne __retVal.xyzw, v, 0.0; +} + + + +//// mat2 constructors + +mat2 __constructor(const float m00, const float m10, + const float m01, const float m11) +{ + __retVal[0].x = m00; + __retVal[0].y = m10; + __retVal[1].x = m01; + __retVal[1].y = m11; +} + +mat2 __constructor(const float f) +{ + __retVal[0].x = f; + __retVal[0].y = 0.0; + __retVal[1].x = 0.0; + __retVal[1].y = f; +} + +mat2 __constructor(const int i) +{ + return mat2(float(i)); +} + +mat2 __constructor(const bool b) +{ + return mat2(float(b)); +} + +mat2 __constructor(const vec2 c0, const vec2 c1) +{ + __retVal[0] = c0; + __retVal[1] = c1; +} + + +//// mat3 constructors + +mat3 __constructor(const float m00, const float m10, const float m20, + const float m01, const float m11, const float m21, + const float m02, const float m12, const float m22) +{ + __retVal[0].x = m00; + __retVal[0].y = m10; + __retVal[0].z = m20; + __retVal[1].x = m01; + __retVal[1].y = m11; + __retVal[1].z = m21; + __retVal[2].x = m02; + __retVal[2].y = m12; + __retVal[2].z = m22; +} + +mat3 __constructor(const float f) +{ + vec2 v = vec2(f, 0.0); + __retVal[0] = v.xyy; + __retVal[1] = v.yxy; + __retVal[2] = v.yyx; +} + +mat3 __constructor(const int i) +{ + return mat3(float(i)); +} + +mat3 __constructor(const bool b) +{ + return mat3(float(b)); +} + +mat3 __constructor(const vec3 c0, const vec3 c1, const vec3 c2) +{ + __retVal[0] = c0; + __retVal[1] = c1; + __retVal[2] = c2; +} + + +//// mat4 constructors + +mat4 __constructor(const float m00, const float m10, const float m20, const float m30, + const float m01, const float m11, const float m21, const float m31, + const float m02, const float m12, const float m22, const float m32, + const float m03, const float m13, const float m23, const float m33) +{ + __retVal[0].x = m00; + __retVal[0].y = m10; + __retVal[0].z = m20; + __retVal[0].w = m30; + __retVal[1].x = m01; + __retVal[1].y = m11; + __retVal[1].z = m21; + __retVal[1].w = m31; + __retVal[2].x = m02; + __retVal[2].y = m12; + __retVal[2].z = m22; + __retVal[2].w = m32; + __retVal[3].x = m03; + __retVal[3].y = m13; + __retVal[3].z = m23; + __retVal[3].w = m33; +} + + +mat4 __constructor(const float f) +{ + vec2 v = vec2(f, 0.0); + __retVal[0] = v.xyyy; + __retVal[1] = v.yxyy; + __retVal[2] = v.yyxy; + __retVal[3] = v.yyyx; +} + +mat4 __constructor(const int i) +{ + return mat4(float(i)); +} + +mat4 __constructor(const bool b) +{ + return mat4(float(b)); +} + +mat4 __constructor(const vec4 c0, const vec4 c1, const vec4 c2, const vec4 c3) +{ + __retVal[0] = c0; + __retVal[1] = c1; + __retVal[2] = c2; + __retVal[3] = c3; +} + + + +//// Basic int operators + +int __operator + (const int a, const int b) +{ + __asm vec4_add __retVal, a, b; +} + +int __operator - (const int a, const int b) +{ + __asm vec4_subtract __retVal, a, b; +} + +int __operator * (const int a, const int b) +{ + __asm vec4_multiply __retVal, a, b; +} + +int __operator / (const int a, const int b) +{ + float bInv, x; + __asm float_rcp bInv, b; + __asm vec4_multiply x, a, bInv; + __asm vec4_to_ivec4 __retVal, x; +} + + +//// Basic ivec2 operators + +ivec2 __operator + (const ivec2 a, const ivec2 b) +{ + __asm vec4_add __retVal, a, b; +} + +ivec2 __operator - (const ivec2 a, const ivec2 b) +{ + __asm vec4_subtract __retVal, a, b; +} + +ivec2 __operator * (const ivec2 a, const ivec2 b) +{ + __asm vec4_multiply __retVal, a, b; +} + +ivec2 __operator / (const ivec2 a, const ivec2 b) +{ + vec2 bInv, x; + __asm float_rcp bInv.x, b.x; + __asm float_rcp bInv.y, b.y; + __asm vec4_multiply x, a, bInv; + __asm vec4_to_ivec4 __retVal, x; +} + + +//// Basic ivec3 operators + +ivec3 __operator + (const ivec3 a, const ivec3 b) +{ + __asm vec4_add __retVal, a, b; +} + +ivec3 __operator - (const ivec3 a, const ivec3 b) +{ + __asm vec4_subtract __retVal, a, b; +} + +ivec3 __operator * (const ivec3 a, const ivec3 b) +{ + __asm vec4_multiply __retVal, a, b; +} + +ivec3 __operator / (const ivec3 a, const ivec3 b) +{ + vec3 bInv, x; + __asm float_rcp bInv.x, b.x; + __asm float_rcp bInv.y, b.y; + __asm float_rcp bInv.z, b.z; + __asm vec4_multiply x, a, bInv; + __asm vec4_to_ivec4 __retVal, x; +} + + +//// Basic ivec4 operators + +ivec4 __operator + (const ivec4 a, const ivec4 b) +{ + __asm vec4_add __retVal, a, b; +} + +ivec4 __operator - (const ivec4 a, const ivec4 b) +{ + __asm vec4_subtract __retVal, a, b; +} + +ivec4 __operator * (const ivec4 a, const ivec4 b) +{ + __asm vec4_multiply __retVal, a, b; +} + +ivec4 __operator / (const ivec4 a, const ivec4 b) +{ + vec4 bInv, x; + __asm float_rcp bInv.x, b.x; + __asm float_rcp bInv.y, b.y; + __asm float_rcp bInv.z, b.z; + __asm float_rcp bInv.w, b.w; + __asm vec4_multiply x, a, bInv; + __asm vec4_to_ivec4 __retVal, x; +} + + +//// Basic float operators + +float __operator + (const float a, const float b) +{ + __asm vec4_add __retVal, a, b; +} + +float __operator - (const float a, const float b) +{ + __asm vec4_subtract __retVal, a, b; +} + +float __operator * (const float a, const float b) +{ + __asm vec4_multiply __retVal, a, b; +} + +float __operator / (const float a, const float b) +{ + float bInv; + __asm float_rcp bInv.x, b; + __asm vec4_multiply __retVal, a, bInv; +} + + +//// Basic vec2 operators + +vec2 __operator + (const vec2 v, const vec2 u) +{ + __asm vec4_add __retVal.xy, v, u; +} + +vec2 __operator - (const vec2 v, const vec2 u) +{ + __asm vec4_subtract __retVal.xy, v, u; +} + +vec2 __operator * (const vec2 v, const vec2 u) +{ + __asm vec4_multiply __retVal.xy, v, u; +} + +vec2 __operator / (const vec2 v, const vec2 u) +{ + vec2 w; // = 1 / u + __asm float_rcp w.x, u.x; + __asm float_rcp w.y, u.y; + __asm vec4_multiply __retVal.xy, v, w; +} + + +//// Basic vec3 operators + +vec3 __operator + (const vec3 v, const vec3 u) +{ + __asm vec4_add __retVal.xyz, v, u; +} + +vec3 __operator - (const vec3 v, const vec3 u) +{ + __asm vec4_subtract __retVal.xyz, v, u; +} + +vec3 __operator * (const vec3 v, const vec3 u) +{ + __asm vec4_multiply __retVal.xyz, v, u; +} + +vec3 __operator / (const vec3 v, const vec3 u) +{ + vec3 w; // = 1 / u + __asm float_rcp w.x, u.x; + __asm float_rcp w.y, u.y; + __asm float_rcp w.z, u.z; + __asm vec4_multiply __retVal.xyz, v, w; +} + + +//// Basic vec4 operators + +vec4 __operator + (const vec4 v, const vec4 u) +{ + __asm vec4_add __retVal, v, u; +} + +vec4 __operator - (const vec4 v, const vec4 u) +{ + __asm vec4_subtract __retVal, v, u; +} + +vec4 __operator * (const vec4 v, const vec4 u) +{ + __asm vec4_multiply __retVal, v, u; +} + +vec4 __operator / (const vec4 v, const vec4 u) +{ + vec4 w; // = 1 / u + __asm float_rcp w.x, u.x; + __asm float_rcp w.y, u.y; + __asm float_rcp w.z, u.z; + __asm float_rcp w.w, u.w; + __asm vec4_multiply __retVal, v, w; +} + + + + +//// Basic vec2/float operators + +vec2 __operator + (const float a, const vec2 u) +{ + __asm vec4_add __retVal.xy, a, u.xy; +} + +vec2 __operator + (const vec2 v, const float b) +{ + __asm vec4_add __retVal.xy, v.xy, b; +} + +vec2 __operator - (const float a, const vec2 u) +{ + __asm vec4_subtract __retVal.xy, a, u.xy; +} + +vec2 __operator - (const vec2 v, const float b) +{ + __asm vec4_subtract __retVal.xy, v.xy, b; +} + +vec2 __operator * (const float a, const vec2 u) +{ + __asm vec4_multiply __retVal.xy, a, u.xy; +} + +vec2 __operator * (const vec2 v, const float b) +{ + __asm vec4_multiply __retVal.xy, v.xy, b; +} + +vec2 __operator / (const float a, const vec2 u) +{ + vec2 invU; + __asm float_rcp invU.x, u.x; + __asm float_rcp invU.y, u.y; + __asm vec4_multiply __retVal.xy, a, invU.xy; +} + +vec2 __operator / (const vec2 v, const float b) +{ + float invB; + __asm float_rcp invB, b; + __asm vec4_multiply __retVal.xy, v.xy, invB; +} + + +//// Basic vec3/float operators + +vec3 __operator + (const float a, const vec3 u) +{ + __asm vec4_add __retVal.xyz, a, u.xyz; +} + +vec3 __operator + (const vec3 v, const float b) +{ + __asm vec4_add __retVal.xyz, v.xyz, b; +} + +vec3 __operator - (const float a, const vec3 u) +{ + __asm vec4_subtract __retVal.xyz, a, u.xyz; +} + +vec3 __operator - (const vec3 v, const float b) +{ + __asm vec4_subtract __retVal.xyz, v.xyz, b; +} + +vec3 __operator * (const float a, const vec3 u) +{ + __asm vec4_multiply __retVal.xyz, a, u.xyz; +} + +vec3 __operator * (const vec3 v, const float b) +{ + __asm vec4_multiply __retVal.xyz, v.xyz, b; +} + +vec3 __operator / (const float a, const vec3 u) +{ + vec3 invU; + __asm float_rcp invU.x, u.x; + __asm float_rcp invU.y, u.y; + __asm float_rcp invU.z, u.z; + __asm vec4_multiply __retVal.xyz, a, invU.xyz; +} + +vec3 __operator / (const vec3 v, const float b) +{ + float invB; + __asm float_rcp invB, b; + __asm vec4_multiply __retVal.xyz, v.xyz, invB; +} + + +//// Basic vec4/float operators + +vec4 __operator + (const float a, const vec4 u) +{ + __asm vec4_add __retVal, a, u; +} + +vec4 __operator + (const vec4 v, const float b) +{ + __asm vec4_add __retVal, v, b; +} + +vec4 __operator - (const float a, const vec4 u) +{ + __asm vec4_subtract __retVal, a, u; +} + +vec4 __operator - (const vec4 v, const float b) +{ + __asm vec4_subtract __retVal, v, b; +} + +vec4 __operator * (const float a, const vec4 u) +{ + __asm vec4_multiply __retVal, a, u; +} + +vec4 __operator * (const vec4 v, const float b) +{ + __asm vec4_multiply __retVal, v, b; +} + +vec4 __operator / (const float a, const vec4 u) +{ + vec4 invU; + __asm float_rcp invU.x, u.x; + __asm float_rcp invU.y, u.y; + __asm float_rcp invU.z, u.z; + __asm float_rcp invU.w, u.w; + __asm vec4_multiply __retVal, a, invU; +} + +vec4 __operator / (const vec4 v, const float b) +{ + float invB; + __asm float_rcp invB, b; + __asm vec4_multiply __retVal, v, invB; +} + + + +//// Basic ivec2/int operators + +ivec2 __operator + (const int a, const ivec2 u) +{ + __retVal = ivec2(a) + u; +} + +ivec2 __operator + (const ivec2 v, const int b) +{ + __retVal = v + ivec2(b); +} + +ivec2 __operator - (const int a, const ivec2 u) +{ + __retVal = ivec2(a) - u; +} + +ivec2 __operator - (const ivec2 v, const int b) +{ + __retVal = v - ivec2(b); +} + +ivec2 __operator * (const int a, const ivec2 u) +{ + __retVal = ivec2(a) * u; +} + +ivec2 __operator * (const ivec2 v, const int b) +{ + __retVal = v * ivec2(b); +} + +ivec2 __operator / (const int a, const ivec2 u) +{ + __retVal = ivec2(a) / u; +} + +ivec2 __operator / (const ivec2 v, const int b) +{ + __retVal = v / ivec2(b); +} + + +//// Basic ivec3/int operators + +ivec3 __operator + (const int a, const ivec3 u) +{ + __retVal = ivec3(a) + u; +} + +ivec3 __operator + (const ivec3 v, const int b) +{ + __retVal = v + ivec3(b); +} + +ivec3 __operator - (const int a, const ivec3 u) +{ + __retVal = ivec3(a) - u; +} + +ivec3 __operator - (const ivec3 v, const int b) +{ + __retVal = v - ivec3(b); +} + +ivec3 __operator * (const int a, const ivec3 u) +{ + __retVal = ivec3(a) * u; +} + +ivec3 __operator * (const ivec3 v, const int b) +{ + __retVal = v * ivec3(b); +} + +ivec3 __operator / (const int a, const ivec3 u) +{ + __retVal = ivec3(a) / u; +} + +ivec3 __operator / (const ivec3 v, const int b) +{ + __retVal = v / ivec3(b); +} + + +//// Basic ivec4/int operators + +ivec4 __operator + (const int a, const ivec4 u) +{ + __retVal = ivec4(a) + u; +} + +ivec4 __operator + (const ivec4 v, const int b) +{ + __retVal = v + ivec4(b); +} + +ivec4 __operator - (const int a, const ivec4 u) +{ + __retVal = ivec4(a) - u; +} + +ivec4 __operator - (const ivec4 v, const int b) +{ + __retVal = v - ivec4(b); +} + +ivec4 __operator * (const int a, const ivec4 u) +{ + __retVal = ivec4(a) * u; +} + +ivec4 __operator * (const ivec4 v, const int b) +{ + __retVal = v * ivec4(b); +} + +ivec4 __operator / (const int a, const ivec4 u) +{ + __retVal = ivec4(a) / u; +} + +ivec4 __operator / (const ivec4 v, const int b) +{ + __retVal = v / ivec4(b); +} + + + + +//// Unary negation operator + +int __operator - (const int a) +{ + __asm vec4_negate __retVal.x, a; +} + +ivec2 __operator - (const ivec2 v) +{ + __asm vec4_negate __retVal, v; +} + +ivec3 __operator - (const ivec3 v) +{ + __asm vec4_negate __retVal, v; +} + +ivec4 __operator - (const ivec4 v) +{ + __asm vec4_negate __retVal, v; +} + +float __operator - (const float a) +{ + __asm vec4_negate __retVal.x, a; +} + +vec2 __operator - (const vec2 v) +{ + __asm vec4_negate __retVal.xy, v.xy; +} + +vec3 __operator - (const vec3 v) +{ + __asm vec4_negate __retVal.xyz, v.xyz; +} + +vec4 __operator - (const vec4 v) +{ + __asm vec4_negate __retVal, v; +} + +mat2 __operator - (const mat2 m) +{ + __retVal[0] = -m[0]; + __retVal[1] = -m[1]; +} + +mat3 __operator - (const mat3 m) +{ + __retVal[0] = -m[0]; + __retVal[1] = -m[1]; + __retVal[2] = -m[2]; +} + +mat4 __operator - (const mat4 m) +{ + __retVal[0] = -m[0]; + __retVal[1] = -m[1]; + __retVal[2] = -m[2]; + __retVal[3] = -m[3]; +} + + + +//// dot product + +float dot(const float a, const float b) +{ + __retVal = a * b; +} + +float dot(const vec2 a, const vec2 b) +{ + __retVal = a.x * b.x + a.y * b.y; +} + +float dot(const vec3 a, const vec3 b) +{ + __asm vec3_dot __retVal, a, b; +} + +float dot(const vec4 a, const vec4 b) +{ + __asm vec4_dot __retVal, a, b; +} + + + +//// int assignment operators + +int __operator += (inout int a, const int b) +{ + a = a + b; + return a; +} + +int __operator -= (inout int a, const int b) +{ + a = a - b; + return a; +} + +int __operator *= (inout int a, const int b) +{ + a = a * b; + return a; +} + +int __operator /= (inout int a, const int b) +{ + a = a / b; + return a; +} + + +//// ivec2 assignment operators + +ivec2 __operator += (inout ivec2 v, const ivec2 u) +{ + v = v + u; + return v; +} + +ivec2 __operator -= (inout ivec2 v, const ivec2 u) +{ + v = v - u; + return v; +} + +ivec2 __operator *= (inout ivec2 v, const ivec2 u) +{ + v = v * u; + return v; +} + +ivec2 __operator /= (inout ivec2 v, const ivec2 u) +{ + v = v / u; + return v; +} + + +//// ivec3 assignment operators + +ivec3 __operator += (inout ivec3 v, const ivec3 u) +{ + v = v + u; + return v; +} + +ivec3 __operator -= (inout ivec3 v, const ivec3 u) +{ + v = v - u; + return v; +} + +ivec3 __operator *= (inout ivec3 v, const ivec3 u) +{ + v = v * u; + return v; +} + +ivec3 __operator /= (inout ivec3 v, const ivec3 u) +{ + v = v / u; + return v; +} + + +//// ivec4 assignment operators + +ivec4 __operator += (inout ivec4 v, const ivec4 u) +{ + v = v + u; + return v; +} + +ivec4 __operator -= (inout ivec4 v, const ivec4 u) +{ + v = v - u; + return v; +} + +ivec4 __operator *= (inout ivec4 v, const ivec4 u) +{ + v = v * u; + return v; +} + +ivec4 __operator /= (inout ivec4 v, const ivec4 u) +{ + v = v / u; + return v; +} + + +//// float assignment operators + +float __operator += (inout float a, const float b) +{ + a = a + b; + return a; +} + +float __operator -= (inout float a, const float b) +{ + a = a - b; + return a; +} + +float __operator *= (inout float a, const float b) +{ + a = a * b; + return a; +} + +float __operator /= (inout float a, const float b) +{ + a = a / b; + return a; +} + + +//// vec2 assignment operators + +vec2 __operator += (inout vec2 v, const vec2 u) +{ + v = v + u; + return v; +} + +vec2 __operator -= (inout vec2 v, const vec2 u) +{ + v = v - u; + return v; +} + +vec2 __operator *= (inout vec2 v, const vec2 u) +{ + v = v * u; + return v; +} + +vec2 __operator /= (inout vec2 v, const vec2 u) +{ + v = v / u; + return v; +} + + +//// vec3 assignment operators + +vec3 __operator += (inout vec3 v, const vec3 u) +{ + v = v + u; + return v; +} + +vec3 __operator -= (inout vec3 v, const vec3 u) +{ + v = v - u; + return v; +} + +vec3 __operator *= (inout vec3 v, const vec3 u) +{ + v = v * u; + return v; +} + +vec3 __operator /= (inout vec3 v, const vec3 u) +{ + v = v / u; + return v; +} + + +//// vec4 assignment operators + +vec4 __operator += (inout vec4 v, const vec4 u) +{ + v = v + u; + return v; +} + +vec4 __operator -= (inout vec4 v, const vec4 u) +{ + v = v - u; + return v; +} + +vec4 __operator *= (inout vec4 v, const vec4 u) +{ + v = v * u; + return v; +} + +vec4 __operator /= (inout vec4 v, const vec4 u) +{ + v = v / u; + return v; +} + + + +//// ivec2/int assignment operators + +ivec2 __operator += (inout ivec2 v, const int a) +{ + v = v + ivec2(a); + return v; +} + +ivec2 __operator -= (inout ivec2 v, const int a) +{ + v = v - ivec2(a); + return v; +} + +ivec2 __operator *= (inout ivec2 v, const int a) +{ + v = v * ivec2(a); + return v; +} + +ivec2 __operator /= (inout ivec2 v, const int a) +{ + v = v / ivec2(a); + return v; +} + + +//// ivec3/int assignment operators + +ivec3 __operator += (inout ivec3 v, const int a) +{ + v = v + ivec3(a); + return v; +} + +ivec3 __operator -= (inout ivec3 v, const int a) +{ + v = v - ivec3(a); + return v; +} + +ivec3 __operator *= (inout ivec3 v, const int a) +{ + v = v * ivec3(a); + return v; +} + +ivec4 __operator /= (inout ivec3 v, const int a) +{ + v = v / ivec3(a); + return v; +} + + +//// ivec4/int assignment operators + +ivec4 __operator += (inout ivec4 v, const int a) +{ + v = v + ivec4(a); + return v; +} + +ivec4 __operator -= (inout ivec4 v, const int a) +{ + v = v - ivec4(a); + return v; +} + +ivec4 __operator *= (inout ivec4 v, const int a) +{ + v = v * ivec4(a); + return v; +} + +ivec4 __operator /= (inout ivec4 v, const int a) +{ + v = v / ivec4(a); + return v; +} + + + +//// vec2/float assignment operators + +vec2 __operator += (inout vec2 v, const float a) +{ + v = v + vec2(a); + return v; +} + +vec2 __operator -= (inout vec2 v, const float a) +{ + v = v - vec2(a); + return v; +} + +vec2 __operator *= (inout vec2 v, const float a) +{ + v = v * vec2(a); + return v; +} + +vec2 __operator /= (inout vec2 v, const float a) +{ + v = v / vec2(a); + return v; +} + + +//// vec3/float assignment operators + +vec3 __operator += (inout vec3 v, const float a) +{ + v = v + vec3(a); + return v; +} + +vec3 __operator -= (inout vec3 v, const float a) +{ + v = v - vec3(a); + return v; +} + +vec3 __operator *= (inout vec3 v, const float a) +{ + v = v * vec3(a); + return v; +} + +vec3 __operator /= (inout vec3 v, const float a) +{ + v = v / vec3(a); + return v; +} + + +//// vec4/float assignment operators + +vec4 __operator += (inout vec4 v, const float a) +{ + v = v + vec4(a); + return v; +} + +vec4 __operator -= (inout vec4 v, const float a) +{ + v = v - vec4(a); + return v; +} + +vec4 __operator *= (inout vec4 v, const float a) +{ + v = v * vec4(a); + return v; +} + +vec4 __operator /= (inout vec4 v, const float a) +{ + v = v / vec4(a); + return v; +} + + + + + +//// Basic mat2 operations + +mat2 __operator + (const mat2 m, const mat2 n) +{ + __retVal[0] = m[0] + n[0]; + __retVal[1] = m[1] + n[1]; +} + +mat2 __operator - (const mat2 m, const mat2 n) +{ + __retVal[0] = m[0] - n[0]; + __retVal[1] = m[1] - n[1]; +} + +mat2 __operator * (const mat2 m, const mat2 n) +{ + __retVal[0] = m[0] * n[0].xx + m[1] * n[0].yy; + __retVal[1] = m[0] * n[1].xx + m[1] * n[1].yy; +} + +mat2 __operator / (const mat2 m, const mat2 n) +{ + __retVal[0] = m[0] / n[0]; + __retVal[1] = m[1] / n[1]; +} + + +//// Basic mat3 operations + +mat3 __operator + (const mat3 m, const mat3 n) +{ + __retVal[0] = m[0] + n[0]; + __retVal[1] = m[1] + n[1]; + __retVal[2] = m[2] + n[2]; +} + +mat3 __operator - (const mat3 m, const mat3 n) +{ + __retVal[0] = m[0] - n[0]; + __retVal[1] = m[1] - n[1]; + __retVal[2] = m[2] - n[2]; +} + +mat3 __operator * (const mat3 m, const mat3 n) +{ + __retVal[0] = m[0] * n[0].xxx + m[1] * n[0].yyy + m[2] * n[0].zzz; + __retVal[1] = m[0] * n[1].xxx + m[1] * n[1].yyy + m[2] * n[1].zzz; + __retVal[2] = m[0] * n[2].xxx + m[1] * n[2].yyy + m[2] * n[2].zzz; +} + +mat3 __operator / (const mat3 m, const mat3 n) +{ + __retVal[0] = m[0] / n[0]; + __retVal[1] = m[1] / n[1]; + __retVal[2] = m[2] / n[2]; +} + + +//// Basic mat4 operations + +mat4 __operator + (const mat4 m, const mat4 n) +{ + __retVal[0] = m[0] + n[0]; + __retVal[1] = m[1] + n[1]; + __retVal[2] = m[2] + n[2]; + __retVal[3] = m[3] + n[3]; +} + +mat4 __operator - (const mat4 m, const mat4 n) +{ + __retVal[0] = m[0] - n[0]; + __retVal[1] = m[1] - n[1]; + __retVal[2] = m[2] - n[2]; + __retVal[3] = m[3] - n[3]; +} + +mat4 __operator * (const mat4 m, const mat4 n) +{ + __retVal[0] = m[0] * n[0].xxxx + m[1] * n[0].yyyy + m[2] * n[0].zzzz + m[3] * n[0].wwww; + __retVal[1] = m[0] * n[1].xxxx + m[1] * n[1].yyyy + m[2] * n[1].zzzz + m[3] * n[1].wwww; + __retVal[2] = m[0] * n[2].xxxx + m[1] * n[2].yyyy + m[2] * n[2].zzzz + m[3] * n[2].wwww; + __retVal[3] = m[0] * n[3].xxxx + m[1] * n[3].yyyy + m[2] * n[3].zzzz + m[3] * n[3].wwww; +} + +mat4 __operator / (const mat4 m, const mat4 n) +{ + __retVal[0] = m[0] / n[0]; + __retVal[1] = m[1] / n[1]; + __retVal[2] = m[2] / n[2]; + __retVal[3] = m[3] / n[3]; +} + + +//// mat2/float operations + +mat2 __operator + (const float a, const mat2 n) +{ + __retVal[0] = a + n[0]; + __retVal[1] = a + n[1]; +} + +mat2 __operator + (const mat2 m, const float b) +{ + __retVal[0] = m[0] + b; + __retVal[1] = m[1] + b; +} + +mat2 __operator - (const float a, const mat2 n) +{ + __retVal[0] = a - n[0]; + __retVal[1] = a - n[1]; +} + +mat2 __operator - (const mat2 m, const float b) +{ + __retVal[0] = m[0] - b; + __retVal[1] = m[1] - b; +} + +mat2 __operator * (const float a, const mat2 n) +{ + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; +} + +mat2 __operator * (const mat2 m, const float b) +{ + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; +} + +mat2 __operator / (const float a, const mat2 n) +{ + __retVal[0] = a / n[0]; + __retVal[1] = a / n[1]; +} + +mat2 __operator / (const mat2 m, const float b) +{ + __retVal[0] = m[0] / b; + __retVal[1] = m[1] / b; +} + + +//// mat3/float operations + +mat3 __operator + (const float a, const mat3 n) +{ + __retVal[0] = a + n[0]; + __retVal[1] = a + n[1]; + __retVal[2] = a + n[2]; +} + +mat3 __operator + (const mat3 m, const float b) +{ + __retVal[0] = m[0] + b; + __retVal[1] = m[1] + b; + __retVal[2] = m[2] + b; +} + +mat3 __operator - (const float a, const mat3 n) +{ + __retVal[0] = a - n[0]; + __retVal[1] = a - n[1]; + __retVal[2] = a - n[2]; +} + +mat3 __operator - (const mat3 m, const float b) +{ + __retVal[0] = m[0] - b; + __retVal[1] = m[1] - b; + __retVal[2] = m[2] - b; +} + +mat3 __operator * (const float a, const mat3 n) +{ + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; + __retVal[2] = a * n[2]; +} + +mat3 __operator * (const mat3 m, const float b) +{ + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; + __retVal[2] = m[2] * b; +} + +mat3 __operator / (const float a, const mat3 n) +{ + __retVal[0] = a / n[0]; + __retVal[1] = a / n[1]; + __retVal[2] = a / n[2]; +} + +mat3 __operator / (const mat3 m, const float b) +{ + __retVal[0] = m[0] / b; + __retVal[1] = m[1] / b; + __retVal[2] = m[2] / b; +} + + +//// mat4/float operations + +mat4 __operator + (const float a, const mat4 n) +{ + __retVal[0] = a + n[0]; + __retVal[1] = a + n[1]; + __retVal[2] = a + n[2]; + __retVal[3] = a + n[3]; +} + +mat4 __operator + (const mat4 m, const float b) +{ + __retVal[0] = m[0] + b; + __retVal[1] = m[1] + b; + __retVal[2] = m[2] + b; + __retVal[3] = m[3] + b; +} + +mat4 __operator - (const float a, const mat4 n) +{ + __retVal[0] = a - n[0]; + __retVal[1] = a - n[1]; + __retVal[2] = a - n[2]; + __retVal[3] = a - n[3]; +} + +mat4 __operator - (const mat4 m, const float b) +{ + __retVal[0] = m[0] - b; + __retVal[1] = m[1] - b; + __retVal[2] = m[2] - b; + __retVal[3] = m[3] - b; +} + +mat4 __operator * (const float a, const mat4 n) +{ + __retVal[0] = a * n[0]; + __retVal[1] = a * n[1]; + __retVal[2] = a * n[2]; + __retVal[3] = a * n[3]; +} + +mat4 __operator * (const mat4 m, const float b) +{ + __retVal[0] = m[0] * b; + __retVal[1] = m[1] * b; + __retVal[2] = m[2] * b; + __retVal[3] = m[3] * b; +} + +mat4 __operator / (const float a, const mat4 n) +{ + __retVal[0] = a / n[0]; + __retVal[1] = a / n[1]; + __retVal[2] = a / n[2]; + __retVal[3] = a / n[3]; +} + +mat4 __operator / (const mat4 m, const float b) +{ + __retVal[0] = m[0] / b; + __retVal[1] = m[1] / b; + __retVal[2] = m[2] / b; + __retVal[3] = m[3] / b; +} + + + +//// matrix / vector products + +vec2 __operator * (const mat2 m, const vec2 v) +{ + __retVal = m[0] * v.xx + + m[1] * v.yy; +} + +vec2 __operator * (const vec2 v, const mat2 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); +} + +vec3 __operator * (const mat3 m, const vec3 v) +{ + __retVal = m[0] * v.xxx + + m[1] * v.yyy + + m[2] * v.zzz; +} + +vec3 __operator * (const vec3 v, const mat3 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); + __retVal.z = dot(v, m[2]); +} + +vec4 __operator * (const mat4 m, const vec4 v) +{ + __retVal = m[0] * v.xxxx + + m[1] * v.yyyy + + m[2] * v.zzzz + + m[3] * v.wwww; +} + +vec4 __operator * (const vec4 v, const mat4 m) +{ + __retVal.x = dot(v, m[0]); + __retVal.y = dot(v, m[1]); + __retVal.z = dot(v, m[2]); + __retVal.w = dot(v, m[3]); +} + + + +//// mat2 assignment operators + +mat2 __operator += (inout mat2 m, const mat2 n) +{ + m[0] = m[0] + n[0]; + m[1] = m[1] + n[1]; + return m; +} + +mat2 __operator -= (inout mat2 m, const mat2 n) +{ + m[0] = m[0] - n[0]; + m[1] = m[1] - n[1]; + return m; +} + +mat2 __operator *= (inout mat2 m, const mat2 n) +{ + m = m * n; + return m; +} + +mat2 __operator /= (inout mat2 m, const mat2 n) +{ + m[0] = m[0] / n[0]; + m[1] = m[1] / n[1]; + return m; +} + + +//// mat3 assignment operators + +mat3 __operator += (inout mat3 m, const mat3 n) +{ + m[0] = m[0] + n[0]; + m[1] = m[1] + n[1]; + m[2] = m[2] + n[2]; + return m; +} + +mat3 __operator -= (inout mat3 m, const mat3 n) +{ + m[0] = m[0] - n[0]; + m[1] = m[1] - n[1]; + m[2] = m[2] - n[2]; + return m; +} + +mat3 __operator *= (inout mat3 m, const mat3 n) +{ + m = m * n; + return m; +} + +mat3 __operator /= (inout mat3 m, const mat3 n) +{ + m[0] = m[0] / n[0]; + m[1] = m[1] / n[1]; + m[2] = m[2] / n[2]; + return m; +} + + +// mat4 assignment operators + +mat4 __operator += (inout mat4 m, const mat4 n) +{ + m[0] = m[0] + n[0]; + m[1] = m[1] + n[1]; + m[2] = m[2] + n[2]; + m[3] = m[3] + n[3]; + return m; +} + +mat4 __operator -= (inout mat4 m, const mat4 n) +{ + m[0] = m[0] - n[0]; + m[1] = m[1] - n[1]; + m[2] = m[2] - n[2]; + m[3] = m[3] - n[3]; + return m; +} + +mat4 __operator *= (inout mat4 m, const mat4 n) +{ + m = m * n; + return m; +} + +mat4 __operator /= (inout mat4 m, const mat4 n) +{ + m[0] = m[0] / n[0]; + m[1] = m[1] / n[1]; + m[2] = m[2] / n[2]; + m[3] = m[3] / n[3]; + return m; +} + + +//// mat2/float assignment operators + +mat2 __operator += (inout mat2 m, const float a) +{ + vec2 v = vec2(a); + m[0] = m[0] + v; + m[1] = m[1] + v; + return m; +} + +mat2 __operator -= (inout mat2 m, const float a) +{ + vec2 v = vec2(a); + m[0] = m[0] - v; + m[1] = m[1] - v; + return m; +} + +mat2 __operator *= (inout mat2 m, const float a) +{ + vec2 v = vec2(a); + m[0] = m[0] * v; + m[1] = m[1] * v; + return m; +} + +mat2 __operator /= (inout mat2 m, const float a) +{ + vec2 v = vec2(1.0 / a); + m[0] = m[0] * v; + m[1] = m[1] * v; + return m; +} + + +//// mat3/float assignment operators + +mat3 __operator += (inout mat3 m, const float a) +{ + vec3 v = vec3(a); + m[0] = m[0] + v; + m[1] = m[1] + v; + m[2] = m[2] + v; + return m; +} + +mat3 __operator -= (inout mat3 m, const float a) +{ + vec3 v = vec3(a); + m[0] = m[0] - v; + m[1] = m[1] - v; + m[2] = m[2] - v; + return m; +} + +mat3 __operator *= (inout mat3 m, const float a) +{ + vec3 v = vec3(a); + m[0] = m[0] * v; + m[1] = m[1] * v; + m[2] = m[2] * v; + return m; +} + +mat3 __operator /= (inout mat3 m, const float a) +{ + vec3 v = vec3(1.0 / a); + m[0] = m[0] * v; + m[1] = m[1] * v; + m[2] = m[2] * v; + return m; +} + + +//// mat4/float assignment operators + +mat4 __operator += (inout mat4 m, const float a) +{ + vec4 v = vec4(a); + m[0] = m[0] + v; + m[1] = m[1] + v; + m[2] = m[2] + v; + m[3] = m[3] + v; + return m; +} + +mat4 __operator -= (inout mat4 m, const float a) +{ + vec4 v = vec4(a); + m[0] = m[0] - v; + m[1] = m[1] - v; + m[2] = m[2] - v; + m[3] = m[3] - v; + return m; +} + +mat4 __operator *= (inout mat4 m, const float a) +{ + vec4 v = vec4(a); + m[0] = m[0] * v; + m[1] = m[1] * v; + m[2] = m[2] * v; + m[3] = m[3] * v; + return m; +} + +mat4 __operator /= (inout mat4 m, const float a) +{ + vec4 v = vec4(1.0 / a); + m[0] = m[0] * v; + m[1] = m[1] * v; + m[2] = m[2] * v; + m[3] = m[3] * v; + return m; +} + + + +//// vec/mat assignment operators + +vec2 __operator *= (inout vec2 v, const mat2 m) +{ + v = v * m; + return v; +} + +vec3 __operator *= (inout vec3 v, const mat3 m) +{ + v = v * m; + return v; +} + +vec4 __operator *= (inout vec4 v, const mat4 m) +{ + v = v * m; + return v; +} + + + +//// pre-decrement operators + +int __operator --(inout int a) +{ + a = a - 1; + __retVal = a; +} + +ivec2 __operator --(inout ivec2 v) +{ + v = v - ivec2(1); + __retVal = v; +} + +ivec3 __operator --(inout ivec3 v) +{ + v = v - ivec3(1); + __retVal = v; +} + +ivec4 __operator --(inout ivec4 v) +{ + v = v - ivec4(1); + __retVal = v; +} + + +float __operator --(inout float a) +{ + a = a - 1.0; + __retVal = a; +} + +vec2 __operator --(inout vec2 v) +{ + v = v - vec2(1.0); + __retVal = v; +} + +vec3 __operator --(inout vec3 v) +{ + v = v - vec3(1.0); + __retVal = v; +} + +vec4 __operator --(inout vec4 v) +{ + v = v - vec4(1.0); + __retVal = v; +} + + +mat2 __operator --(inout mat2 m) +{ + m[0] = m[0] - vec2(1.0); + m[1] = m[1] - vec2(1.0); + __retVal = m; +} + +mat3 __operator --(inout mat3 m) +{ + m[0] = m[0] - vec3(1.0); + m[1] = m[1] - vec3(1.0); + m[2] = m[2] - vec3(1.0); + __retVal = m; +} + +mat4 __operator --(inout mat4 m) +{ + m[0] = m[0] - vec4(1.0); + m[1] = m[1] - vec4(1.0); + m[2] = m[2] - vec4(1.0); + m[3] = m[3] - vec4(1.0); + __retVal = m; +} + + +//// pre-increment operators + +int __operator ++(inout int a) +{ + a = a + 1; + __retVal = a; +} + +ivec2 __operator ++(inout ivec2 v) +{ + v = v + ivec2(1); + __retVal = v; +} + +ivec3 __operator ++(inout ivec3 v) +{ + v = v + ivec3(1); + __retVal = v; +} + +ivec4 __operator ++(inout ivec4 v) +{ + v = v + ivec4(1); + __retVal = v; +} + + +float __operator ++(inout float a) +{ + a = a + 1.0; + __retVal = a; +} + +vec2 __operator ++(inout vec2 v) +{ + v = v + vec2(1.0); + __retVal = v; +} + +vec3 __operator ++(inout vec3 v) +{ + v = v + vec3(1.0); + __retVal = v; +} + +vec4 __operator ++(inout vec4 v) +{ + v = v + vec4(1.0); + __retVal = v; +} + + +mat2 __operator ++(inout mat2 m) +{ + m[0] = m[0] + vec2(1.0); + m[1] = m[1] + vec2(1.0); + __retVal = m; +} + +mat3 __operator ++(inout mat3 m) +{ + m[0] = m[0] + vec3(1.0); + m[1] = m[1] + vec3(1.0); + m[2] = m[2] + vec3(1.0); + __retVal = m; +} + +mat4 __operator ++(inout mat4 m) +{ + m[0] = m[0] + vec4(1.0); + m[1] = m[1] + vec4(1.0); + m[2] = m[2] + vec4(1.0); + m[3] = m[3] + vec4(1.0); + __retVal = m; +} + + + +//// post-decrement + +int __postDecr(inout int a) +{ + __retVal = a; + a = a - 1; +} + +ivec2 __postDecr(inout ivec2 v) +{ + __retVal = v; + v = v - ivec2(1); +} + +ivec3 __postDecr(inout ivec3 v) +{ + __retVal = v; + v = v - ivec3(1); +} + +ivec4 __postDecr(inout ivec4 v) +{ + __retVal = v; + v = v - ivec4(1); +} + + +float __postDecr(inout float a) +{ + __retVal = a; + a = a - 1.0; +} + +vec2 __postDecr(inout vec2 v) +{ + __retVal = v; + v = v - vec2(1.0); +} + +vec3 __postDecr(inout vec3 v) +{ + __retVal = v; + v = v - vec3(1.0); +} + +vec4 __postDecr(inout vec4 v) +{ + __retVal = v; + v = v - vec4(1.0); +} + + +mat2 __postDecr(inout mat2 m) +{ + __retVal = m; + m[0] = m[0] - vec2(1.0); + m[1] = m[1] - vec2(1.0); +} + +mat3 __postDecr(inout mat3 m) +{ + __retVal = m; + m[0] = m[0] - vec3(1.0); + m[1] = m[1] - vec3(1.0); + m[2] = m[2] - vec3(1.0); +} + +mat4 __postDecr(inout mat4 m) +{ + __retVal = m; + m[0] = m[0] - vec4(1.0); + m[1] = m[1] - vec4(1.0); + m[2] = m[2] - vec4(1.0); + m[3] = m[3] - vec4(1.0); +} + + +//// post-increment + +float __postIncr(inout float a) +{ + __retVal = a; + a = a + 1; +} + +vec2 __postIncr(inout vec2 v) +{ + __retVal = v; + v = v + vec2(1.0); +} + +vec3 __postIncr(inout vec3 v) +{ + __retVal = v; + v = v + vec3(1.0); +} + +vec4 __postIncr(inout vec4 v) +{ + __retVal = v; + v = v + vec4(1.0); +} + + +int __postIncr(inout int a) +{ + __retVal = a; + a = a + 1; +} + +ivec2 __postIncr(inout ivec2 v) +{ + __retVal = v; + v = v + ivec2(1); +} + +ivec3 __postIncr(inout ivec3 v) +{ + __retVal = v; + v = v + ivec3(1); +} + +ivec4 __postIncr(inout ivec4 v) +{ + __retVal = v; + v = v + ivec3(1); +} + + +mat2 __postIncr(inout mat2 m) +{ + mat2 n = m; + m[0] = m[0] + vec2(1.0); + m[1] = m[1] + vec2(1.0); + return n; +} + +mat3 __postIncr(inout mat3 m) +{ + mat3 n = m; + m[0] = m[0] + vec3(1.0); + m[1] = m[1] + vec3(1.0); + m[2] = m[2] + vec3(1.0); + return n; +} + +mat4 __postIncr(inout mat4 m) +{ + mat4 n = m; + m[0] = m[0] + vec4(1.0); + m[1] = m[1] + vec4(1.0); + m[2] = m[2] + vec4(1.0); + m[3] = m[3] + vec4(1.0); + return n; +} + + + +//// inequality operators + + +// XXX are the inequality operators for floats/ints really needed???? +bool __operator < (const float a, const float b) +{ + __asm vec4_sgt __retVal.x, b, a; +} + + +bool __operator < (const int a, const int b) { + return float (a) < float (b); +} + +bool __operator > (const float a, const float b) { + bool c; + __asm float_less c, b, a; + return c; +} + +bool __operator > (const int a, const int b) { + return float (a) > float (b); +} + +bool __operator >= (const float a, const float b) { + bool g, e; + __asm float_less g, b, a; + __asm float_equal e, a, b; + return g || e; +} + +bool __operator >= (const int a, const int b) { + return float (a) >= float (b); +} + +bool __operator <= (const float a, const float b) { + bool g, e; + __asm float_less g, a, b; + __asm float_equal e, a, b; + return g || e; +} + +bool __operator <= (const int a, const int b) { + return float (a) <= float (b); +} + + + +// +// MESA-specific extension functions. +// + +void printMESA (const float f) { + __asm float_print f; +} + +void printMESA (const int i) { + __asm int_print i; +} + +void printMESA (const bool b) { + __asm bool_print b; +} + +void printMESA (const vec2 v) { + printMESA (v.x); + printMESA (v.y); +} + +void printMESA (const vec3 v) { + printMESA (v.x); + printMESA (v.y); + printMESA (v.z); +} + +void printMESA (const vec4 v) { + printMESA (v.x); + printMESA (v.y); + printMESA (v.z); + printMESA (v.w); +} + +void printMESA (const ivec2 v) { + printMESA (v.x); + printMESA (v.y); +} + +void printMESA (const ivec3 v) { + printMESA (v.x); + printMESA (v.y); + printMESA (v.z); +} + +void printMESA (const ivec4 v) { + printMESA (v.x); + printMESA (v.y); + printMESA (v.z); + printMESA (v.w); +} + +void printMESA (const bvec2 v) { + printMESA (v.x); + printMESA (v.y); +} + +void printMESA (const bvec3 v) { + printMESA (v.x); + printMESA (v.y); + printMESA (v.z); +} + +void printMESA (const bvec4 v) { + printMESA (v.x); + printMESA (v.y); + printMESA (v.z); + printMESA (v.w); +} + +void printMESA (const mat2 m) { + printMESA (m[0]); + printMESA (m[1]); +} + +void printMESA (const mat3 m) { + printMESA (m[0]); + printMESA (m[1]); + printMESA (m[2]); +} + +void printMESA (const mat4 m) { + printMESA (m[0]); + printMESA (m[1]); + printMESA (m[2]); + printMESA (m[3]); +} + +void printMESA (const sampler1D e) { + __asm int_print e; +} + +void printMESA (const sampler2D e) { + __asm int_print e; +} + +void printMESA (const sampler3D e) { + __asm int_print e; +} + +void printMESA (const samplerCube e) { + __asm int_print e; +} + +void printMESA (const sampler1DShadow e) { + __asm int_print e; +} + +void printMESA (const sampler2DShadow e) { + __asm int_print e; +} + diff --git a/mesalib/src/mesa/shader/slang/library/slang_core_gc.h b/mesalib/src/mesa/shader/slang/library/slang_core_gc.h new file mode 100644 index 000000000..b3d3e87cf --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_core_gc.h @@ -0,0 +1,869 @@ + +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */ +/* slang_core.gc */ + +5,1,90,95,0,0,5,0,1,1,1,0,0,9,0,102,0,0,0,1,4,118,101,99,52,95,116,111,95,105,118,101,99,52,0,18, +95,95,114,101,116,86,97,108,0,0,18,102,0,0,0,0,1,90,95,0,0,5,0,1,1,1,0,0,1,0,98,0,0,0,1,9,18,95,95, +114,101,116,86,97,108,0,18,98,0,20,0,0,1,90,95,0,0,5,0,1,1,1,0,0,5,0,105,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,18,105,0,20,0,0,1,90,95,0,0,1,0,1,1,1,0,0,5,0,105,0,0,0,1,4,118,101,99,52,95, +115,110,101,0,18,95,95,114,101,116,86,97,108,0,0,18,105,0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,1,0,1, +1,1,0,0,9,0,102,0,0,0,1,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,0,18,102, +0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,1,0,1,1,1,0,0,1,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108, +0,18,98,0,20,0,0,1,90,95,0,0,9,0,1,1,1,0,0,5,0,105,0,0,0,1,4,105,118,101,99,52,95,116,111,95,118, +101,99,52,0,18,95,95,114,101,116,86,97,108,0,0,18,105,0,0,0,0,1,90,95,0,0,9,0,1,1,1,0,0,1,0,98,0,0, +0,1,4,105,118,101,99,52,95,116,111,95,118,101,99,52,0,18,95,95,114,101,116,86,97,108,0,0,18,98,0,0, +0,0,1,90,95,0,0,9,0,1,1,1,0,0,9,0,102,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,102,0,20,0,0,1, +90,95,0,0,10,0,1,1,1,0,0,9,0,120,0,0,1,1,0,0,9,0,121,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59, +120,0,18,120,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,18,121,0,20,0,0,1,90,95,0,0,10,0,1, +1,1,0,0,9,0,102,0,0,0,1,4,118,101,99,52,95,109,111,118,101,0,18,95,95,114,101,116,86,97,108,0,59, +120,121,0,0,18,102,0,0,0,0,1,90,95,0,0,10,0,1,1,1,0,0,5,0,105,0,0,0,1,4,105,118,101,99,52,95,116, +111,95,118,101,99,52,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,105,0,0,0,0,1,90,95,0,0, +10,0,1,1,1,0,0,1,0,98,0,0,0,1,4,105,118,101,99,52,95,116,111,95,118,101,99,52,0,18,95,95,114,101, +116,86,97,108,0,59,120,121,0,0,18,98,0,0,0,0,1,90,95,0,0,10,0,1,1,1,0,0,2,0,98,0,0,0,1,4,105,118, +101,99,52,95,116,111,95,118,101,99,52,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,98,0,0, +0,0,1,90,95,0,0,10,0,1,1,1,0,0,11,0,118,0,0,0,1,4,118,101,99,52,95,109,111,118,101,0,18,95,95,114, +101,116,86,97,108,0,59,120,121,0,0,18,118,0,59,120,121,0,0,0,0,1,90,95,0,0,10,0,1,1,1,0,0,12,0,118, +0,0,0,1,4,118,101,99,52,95,109,111,118,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18, +118,0,59,120,121,0,0,0,0,1,90,95,0,0,11,0,1,1,1,0,0,9,0,120,0,0,1,1,0,0,9,0,121,0,0,1,1,0,0,9,0, +122,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,18,120,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,59,121,0,18,121,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,18,122,0,20,0,0,1,90,95,0, +0,11,0,1,1,1,0,0,9,0,102,0,0,0,1,4,118,101,99,52,95,109,111,118,101,0,18,95,95,114,101,116,86,97, +108,0,59,120,121,122,0,0,18,102,0,0,0,0,1,90,95,0,0,11,0,1,1,1,0,0,5,0,105,0,0,0,1,4,105,118,101, +99,52,95,116,111,95,118,101,99,52,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,105,0,0, +0,0,1,90,95,0,0,11,0,1,1,1,0,0,1,0,98,0,0,0,1,4,105,118,101,99,52,95,116,111,95,118,101,99,52,0,18, +95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,98,0,0,0,0,1,90,95,0,0,11,0,1,1,1,0,0,3,0,98,0, +0,0,1,4,105,118,101,99,52,95,116,111,95,118,101,99,52,0,18,95,95,114,101,116,86,97,108,0,59,120, +121,122,0,0,18,98,0,0,0,0,1,90,95,0,0,11,0,1,1,1,0,0,12,0,118,0,0,0,1,4,118,101,99,52,95,109,111, +118,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,118,0,0,0,0,1,90,95,0,0,12,0,1,1, +1,0,0,9,0,120,0,0,1,1,0,0,9,0,121,0,0,1,1,0,0,9,0,122,0,0,1,1,0,0,9,0,119,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,59,120,0,18,120,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,18,121,0,20, +0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,18,122,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59, +119,0,18,119,0,20,0,0,1,90,95,0,0,12,0,1,1,1,0,0,9,0,102,0,0,0,1,4,118,101,99,52,95,109,111,118, +101,0,18,95,95,114,101,116,86,97,108,0,0,18,102,0,0,0,0,1,90,95,0,0,12,0,1,1,1,0,0,5,0,105,0,0,0,1, +4,105,118,101,99,52,95,116,111,95,118,101,99,52,0,18,95,95,114,101,116,86,97,108,0,0,18,105,0,0,0, +0,1,90,95,0,0,12,0,1,1,1,0,0,1,0,98,0,0,0,1,4,105,118,101,99,52,95,116,111,95,118,101,99,52,0,18, +95,95,114,101,116,86,97,108,0,0,18,98,0,0,0,0,1,90,95,0,0,12,0,1,1,1,0,0,4,0,98,0,0,0,1,4,105,118, +101,99,52,95,116,111,95,118,101,99,52,0,18,95,95,114,101,116,86,97,108,0,0,18,98,0,0,0,0,1,90,95,0, +0,12,0,1,1,1,0,0,8,0,105,0,0,0,1,4,105,118,101,99,52,95,116,111,95,118,101,99,52,0,18,95,95,114, +101,116,86,97,108,0,0,18,105,0,0,0,0,1,90,95,0,0,12,0,1,1,1,0,0,11,0,118,51,0,0,1,1,0,0,9,0,102,0, +0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,18,118,51,0,20,0,9,18,95,95,114,101,116, +86,97,108,0,59,119,0,18,102,0,20,0,0,1,90,95,0,0,12,0,1,1,1,0,0,10,0,118,50,0,0,1,1,0,0,9,0,102,49, +0,0,1,1,0,0,9,0,102,50,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,121,0,18,118,50,0,20,0,9, +18,95,95,114,101,116,86,97,108,0,59,122,0,18,102,49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59, +119,0,18,102,50,0,20,0,0,1,90,95,0,0,6,0,1,1,1,0,0,5,0,105,0,0,1,1,0,0,5,0,106,0,0,0,1,9,18,95,95, +114,101,116,86,97,108,0,59,120,0,18,105,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,18,106, +0,20,0,0,1,90,95,0,0,6,0,1,1,1,0,0,5,0,105,0,0,0,1,4,118,101,99,52,95,109,111,118,101,0,18,95,95, +114,101,116,86,97,108,0,59,120,121,0,0,18,105,0,0,0,0,1,90,95,0,0,6,0,1,1,1,0,0,9,0,102,0,0,0,1,4, +118,101,99,52,95,116,111,95,105,118,101,99,52,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18, +102,0,0,0,0,1,90,95,0,0,6,0,1,1,1,0,0,1,0,98,0,0,0,1,4,118,101,99,52,95,116,111,95,105,118,101,99, +52,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,98,0,0,0,0,1,90,95,0,0,7,0,1,1,1,0,0,5,0, +105,0,0,1,1,0,0,5,0,106,0,0,1,1,0,0,5,0,107,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,18, +105,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,18,106,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,59,122,0,18,107,0,20,0,0,1,90,95,0,0,7,0,1,1,1,0,0,5,0,105,0,0,0,1,4,118,101,99,52,95,109, +111,118,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,105,0,0,0,0,1,90,95,0,0,7,0,1, +1,1,0,0,9,0,102,0,0,0,1,4,118,101,99,52,95,116,111,95,105,118,101,99,52,0,18,95,95,114,101,116,86, +97,108,0,59,120,121,122,0,0,18,102,0,0,0,0,1,90,95,0,0,7,0,1,1,1,0,0,1,0,98,0,0,0,1,4,118,101,99, +52,95,109,111,118,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,98,0,0,0,0,1,90,95, +0,0,8,0,1,1,1,0,0,5,0,120,0,0,1,1,0,0,5,0,121,0,0,1,1,0,0,5,0,122,0,0,1,1,0,0,5,0,119,0,0,0,1,9,18, +95,95,114,101,116,86,97,108,0,59,120,0,18,120,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0, +18,121,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,18,122,0,20,0,9,18,95,95,114,101,116,86, +97,108,0,59,119,0,18,119,0,20,0,0,1,90,95,0,0,8,0,1,1,1,0,0,5,0,105,0,0,0,1,4,118,101,99,52,95,109, +111,118,101,0,18,95,95,114,101,116,86,97,108,0,0,18,105,0,0,0,0,1,90,95,0,0,8,0,1,1,1,0,0,9,0,102, +0,0,0,1,4,118,101,99,52,95,116,111,95,105,118,101,99,52,0,18,95,95,114,101,116,86,97,108,0,0,18, +102,0,0,0,0,1,90,95,0,0,8,0,1,1,1,0,0,1,0,98,0,0,0,1,4,118,101,99,52,95,116,111,95,105,118,101,99, +52,0,18,95,95,114,101,116,86,97,108,0,0,18,98,0,0,0,0,1,90,95,0,0,2,0,1,1,1,0,0,1,0,98,49,0,0,1,1, +0,0,1,0,98,50,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,18,98,49,0,20,0,9,18,95,95,114, +101,116,86,97,108,0,59,121,0,18,98,50,0,20,0,0,1,90,95,0,0,2,0,1,1,1,0,0,5,0,105,49,0,0,1,1,0,0,5, +0,105,50,0,0,0,1,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18, +105,49,0,0,17,48,0,48,0,0,0,0,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59, +121,0,0,18,105,50,0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,2,0,1,1,1,0,0,1,0,98,0,0,0,1,4,118,101,99, +52,95,109,111,118,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,98,0,0,0,0,1,90,95,0,0, +2,0,1,1,1,0,0,9,0,102,0,0,0,1,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59, +120,121,0,0,18,102,0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,2,0,1,1,1,0,0,5,0,105,0,0,0,1,4,118,101,99, +52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,105,0,0,17,48,0,48,0,0,0,0, +0,1,90,95,0,0,2,0,1,1,1,0,0,10,0,118,0,0,0,1,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116, +86,97,108,0,59,120,121,0,0,18,118,0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,2,0,1,1,1,0,0,6,0,118,0,0,0, +1,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,118,0,0,17, +48,0,48,0,0,0,0,0,1,90,95,0,0,3,0,1,1,1,0,0,1,0,98,49,0,0,1,1,0,0,1,0,98,50,0,0,1,1,0,0,1,0,98,51, +0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,18,98,49,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,59,121,0,18,98,50,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,18,98,51,0,20,0,0,1,90, +95,0,0,3,0,1,1,1,0,0,9,0,102,49,0,0,1,1,0,0,9,0,102,50,0,0,1,1,0,0,9,0,102,51,0,0,0,1,4,118,101,99, +52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,102,49,0,0,17,48,0,48,0,0,0,0,4, +118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18,102,50,0,0,17,48,0, +48,0,0,0,0,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,122,0,0,18,102,51, +0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,3,0,1,1,1,0,0,1,0,98,0,0,0,1,4,118,101,99,52,95,109,111,118, +101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,98,0,0,0,0,1,90,95,0,0,3,0,1,1,1,0,0, +9,0,102,0,0,0,1,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0, +0,18,102,0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,3,0,1,1,1,0,0,5,0,105,0,0,0,1,4,118,101,99,52,95,115, +110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,105,0,0,17,48,0,48,0,0,0,0,0,1,90, +95,0,0,3,0,1,1,1,0,0,11,0,118,0,0,0,1,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97, +108,0,59,120,121,122,0,0,18,118,0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,3,0,1,1,1,0,0,7,0,118,0,0,0,1, +4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,118,0,0,17, +48,0,48,0,0,0,0,0,1,90,95,0,0,4,0,1,1,1,0,0,1,0,98,49,0,0,1,1,0,0,1,0,98,50,0,0,1,1,0,0,1,0,98,51, +0,0,1,1,0,0,1,0,98,52,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,18,98,49,0,20,0,9,18,95, +95,114,101,116,86,97,108,0,59,121,0,18,98,50,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,18, +98,51,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,119,0,18,98,52,0,20,0,0,1,90,95,0,0,4,0,1,1,1,0, +0,9,0,102,49,0,0,1,1,0,0,9,0,102,50,0,0,1,1,0,0,9,0,102,51,0,0,1,1,0,0,9,0,102,52,0,0,0,1,3,2,90, +95,1,0,9,0,1,122,101,114,111,0,2,17,48,0,48,0,0,0,0,4,118,101,99,52,95,115,110,101,0,18,95,95,114, +101,116,86,97,108,0,59,120,0,0,18,102,49,0,0,18,122,101,114,111,0,0,0,4,118,101,99,52,95,115,110, +101,0,18,95,95,114,101,116,86,97,108,0,59,121,0,0,18,102,50,0,0,18,122,101,114,111,0,0,0,4,118,101, +99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,122,0,0,18,102,51,0,0,18,122,101,114, +111,0,0,0,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,119,0,0,18,102,52,0, +0,18,122,101,114,111,0,0,0,0,1,90,95,0,0,4,0,1,1,1,0,0,1,0,98,0,0,0,1,4,118,101,99,52,95,109,111, +118,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,119,0,0,18,98,0,0,0,0,1,90,95,0,0,4,0,1, +1,1,0,0,9,0,102,0,0,0,1,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120, +121,122,119,0,0,18,102,0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,4,0,1,1,1,0,0,5,0,105,0,0,0,1,4,118, +101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,119,0,0,18,105,0,0,17, +48,0,48,0,0,0,0,0,1,90,95,0,0,4,0,1,1,1,0,0,12,0,118,0,0,0,1,4,118,101,99,52,95,115,110,101,0,18, +95,95,114,101,116,86,97,108,0,59,120,121,122,119,0,0,18,118,0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,4, +0,1,1,1,0,0,8,0,118,0,0,0,1,4,118,101,99,52,95,115,110,101,0,18,95,95,114,101,116,86,97,108,0,59, +120,121,122,119,0,0,18,118,0,0,17,48,0,48,0,0,0,0,0,1,90,95,0,0,13,0,1,1,1,0,0,9,0,109,48,48,0,0,1, +1,0,0,9,0,109,49,48,0,0,1,1,0,0,9,0,109,48,49,0,0,1,1,0,0,9,0,109,49,49,0,0,0,1,9,18,95,95,114,101, +116,86,97,108,0,16,8,48,0,57,59,120,0,18,109,48,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,8, +48,0,57,59,121,0,18,109,49,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,120,0,18, +109,48,49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,121,0,18,109,49,49,0,20,0,0,1, +90,95,0,0,13,0,1,1,1,0,0,9,0,102,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,59,120,0, +18,102,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,59,121,0,17,48,0,48,0,0,20,0,9,18,95, +95,114,101,116,86,97,108,0,16,10,49,0,57,59,120,0,17,48,0,48,0,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,10,49,0,57,59,121,0,18,102,0,20,0,0,1,90,95,0,0,13,0,1,1,1,0,0,5,0,105,0,0,0,1,8,58,109, +97,116,50,0,0,58,102,108,111,97,116,0,0,18,105,0,0,0,0,0,0,0,1,90,95,0,0,13,0,1,1,1,0,0,1,0,98,0,0, +0,1,8,58,109,97,116,50,0,0,58,102,108,111,97,116,0,0,18,98,0,0,0,0,0,0,0,1,90,95,0,0,13,0,1,1,1,0, +0,10,0,99,48,0,0,1,1,0,0,10,0,99,49,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,99, +48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,99,49,0,20,0,0,1,90,95,0,0,14,0,1,1, +1,0,0,9,0,109,48,48,0,0,1,1,0,0,9,0,109,49,48,0,0,1,1,0,0,9,0,109,50,48,0,0,1,1,0,0,9,0,109,48,49, +0,0,1,1,0,0,9,0,109,49,49,0,0,1,1,0,0,9,0,109,50,49,0,0,1,1,0,0,9,0,109,48,50,0,0,1,1,0,0,9,0,109, +49,50,0,0,1,1,0,0,9,0,109,50,50,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,59,120,0, +18,109,48,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,59,121,0,18,109,49,48,0,20,0,9, +18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,59,122,0,18,109,50,48,0,20,0,9,18,95,95,114,101,116, +86,97,108,0,16,10,49,0,57,59,120,0,18,109,48,49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49, +0,57,59,121,0,18,109,49,49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,122,0,18,109, +50,49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,59,120,0,18,109,48,50,0,20,0,9,18,95, +95,114,101,116,86,97,108,0,16,10,50,0,57,59,121,0,18,109,49,50,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,10,50,0,57,59,122,0,18,109,50,50,0,20,0,0,1,90,95,0,0,14,0,1,1,1,0,0,9,0,102,0,0,0,1,3,2, +90,95,0,0,10,0,1,118,0,2,58,118,101,99,50,0,0,18,102,0,0,17,48,0,48,0,0,0,0,0,0,9,18,95,95,114,101, +116,86,97,108,0,16,8,48,0,57,18,118,0,59,120,121,121,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16, +10,49,0,57,18,118,0,59,121,120,121,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,118, +0,59,121,121,120,0,20,0,0,1,90,95,0,0,14,0,1,1,1,0,0,5,0,105,0,0,0,1,8,58,109,97,116,51,0,0,58,102, +108,111,97,116,0,0,18,105,0,0,0,0,0,0,0,1,90,95,0,0,14,0,1,1,1,0,0,1,0,98,0,0,0,1,8,58,109,97,116, +51,0,0,58,102,108,111,97,116,0,0,18,98,0,0,0,0,0,0,0,1,90,95,0,0,14,0,1,1,1,0,0,11,0,99,48,0,0,1,1, +0,0,11,0,99,49,0,0,1,1,0,0,11,0,99,50,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18, +99,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,99,49,0,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,50,0,57,18,99,50,0,20,0,0,1,90,95,0,0,15,0,1,1,1,0,0,9,0,109,48,48,0,0,1,1,0, +0,9,0,109,49,48,0,0,1,1,0,0,9,0,109,50,48,0,0,1,1,0,0,9,0,109,51,48,0,0,1,1,0,0,9,0,109,48,49,0,0, +1,1,0,0,9,0,109,49,49,0,0,1,1,0,0,9,0,109,50,49,0,0,1,1,0,0,9,0,109,51,49,0,0,1,1,0,0,9,0,109,48, +50,0,0,1,1,0,0,9,0,109,49,50,0,0,1,1,0,0,9,0,109,50,50,0,0,1,1,0,0,9,0,109,51,50,0,0,1,1,0,0,9,0, +109,48,51,0,0,1,1,0,0,9,0,109,49,51,0,0,1,1,0,0,9,0,109,50,51,0,0,1,1,0,0,9,0,109,51,51,0,0,0,1,9, +18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,59,120,0,18,109,48,48,0,20,0,9,18,95,95,114,101,116, +86,97,108,0,16,8,48,0,57,59,121,0,18,109,49,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0, +57,59,122,0,18,109,50,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,59,119,0,18,109,51, +48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,59,120,0,18,109,48,49,0,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,49,0,57,59,121,0,18,109,49,49,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,10,49,0,57,59,122,0,18,109,50,49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57, +59,119,0,18,109,51,49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,59,120,0,18,109,48, +50,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,59,121,0,18,109,49,50,0,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,50,0,57,59,122,0,18,109,50,50,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,10,50,0,57,59,119,0,18,109,51,50,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57, +59,120,0,18,109,48,51,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,59,121,0,18,109,49, +51,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,59,122,0,18,109,50,51,0,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,51,0,57,59,119,0,18,109,51,51,0,20,0,0,1,90,95,0,0,15,0,1,1,1,0,0,9, +0,102,0,0,0,1,3,2,90,95,0,0,10,0,1,118,0,2,58,118,101,99,50,0,0,18,102,0,0,17,48,0,48,0,0,0,0,0,0, +9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,118,0,59,120,121,121,121,0,20,0,9,18,95,95,114, +101,116,86,97,108,0,16,10,49,0,57,18,118,0,59,121,120,121,121,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,10,50,0,57,18,118,0,59,121,121,120,121,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51, +0,57,18,118,0,59,121,121,121,120,0,20,0,0,1,90,95,0,0,15,0,1,1,1,0,0,5,0,105,0,0,0,1,8,58,109,97, +116,52,0,0,58,102,108,111,97,116,0,0,18,105,0,0,0,0,0,0,0,1,90,95,0,0,15,0,1,1,1,0,0,1,0,98,0,0,0, +1,8,58,109,97,116,52,0,0,58,102,108,111,97,116,0,0,18,98,0,0,0,0,0,0,0,1,90,95,0,0,15,0,1,1,1,0,0, +12,0,99,48,0,0,1,1,0,0,12,0,99,49,0,0,1,1,0,0,12,0,99,50,0,0,1,1,0,0,12,0,99,51,0,0,0,1,9,18,95,95, +114,101,116,86,97,108,0,16,8,48,0,57,18,99,48,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0, +57,18,99,49,0,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,99,50,0,20,0,9,18,95,95,114, +101,116,86,97,108,0,16,10,51,0,57,18,99,51,0,20,0,0,1,90,95,0,0,5,0,2,26,1,1,0,0,5,0,97,0,0,1,1,0, +0,5,0,98,0,0,0,1,4,118,101,99,52,95,97,100,100,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18, +98,0,0,0,0,1,90,95,0,0,5,0,2,27,1,1,0,0,5,0,97,0,0,1,1,0,0,5,0,98,0,0,0,1,4,118,101,99,52,95,115, +117,98,116,114,97,99,116,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1,90,95,0,0, +5,0,2,21,1,1,0,0,5,0,97,0,0,1,1,0,0,5,0,98,0,0,0,1,4,118,101,99,52,95,109,117,108,116,105,112,108, +121,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1,90,95,0,0,5,0,2,22,1,1,0,0,5,0, +97,0,0,1,1,0,0,5,0,98,0,0,0,1,3,2,90,95,0,0,9,0,1,98,73,110,118,0,0,1,1,120,0,0,0,4,102,108,111,97, +116,95,114,99,112,0,18,98,73,110,118,0,0,18,98,0,0,0,4,118,101,99,52,95,109,117,108,116,105,112, +108,121,0,18,120,0,0,18,97,0,0,18,98,73,110,118,0,0,0,4,118,101,99,52,95,116,111,95,105,118,101,99, +52,0,18,95,95,114,101,116,86,97,108,0,0,18,120,0,0,0,0,1,90,95,0,0,6,0,2,26,1,1,0,0,6,0,97,0,0,1,1, +0,0,6,0,98,0,0,0,1,4,118,101,99,52,95,97,100,100,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18, +98,0,0,0,0,1,90,95,0,0,6,0,2,27,1,1,0,0,6,0,97,0,0,1,1,0,0,6,0,98,0,0,0,1,4,118,101,99,52,95,115, +117,98,116,114,97,99,116,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1,90,95,0,0, +6,0,2,21,1,1,0,0,6,0,97,0,0,1,1,0,0,6,0,98,0,0,0,1,4,118,101,99,52,95,109,117,108,116,105,112,108, +121,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1,90,95,0,0,6,0,2,22,1,1,0,0,6,0, +97,0,0,1,1,0,0,6,0,98,0,0,0,1,3,2,90,95,0,0,10,0,1,98,73,110,118,0,0,1,1,120,0,0,0,4,102,108,111, +97,116,95,114,99,112,0,18,98,73,110,118,0,59,120,0,0,18,98,0,59,120,0,0,0,4,102,108,111,97,116,95, +114,99,112,0,18,98,73,110,118,0,59,121,0,0,18,98,0,59,121,0,0,0,4,118,101,99,52,95,109,117,108,116, +105,112,108,121,0,18,120,0,0,18,97,0,0,18,98,73,110,118,0,0,0,4,118,101,99,52,95,116,111,95,105, +118,101,99,52,0,18,95,95,114,101,116,86,97,108,0,0,18,120,0,0,0,0,1,90,95,0,0,7,0,2,26,1,1,0,0,7,0, +97,0,0,1,1,0,0,7,0,98,0,0,0,1,4,118,101,99,52,95,97,100,100,0,18,95,95,114,101,116,86,97,108,0,0, +18,97,0,0,18,98,0,0,0,0,1,90,95,0,0,7,0,2,27,1,1,0,0,7,0,97,0,0,1,1,0,0,7,0,98,0,0,0,1,4,118,101, +99,52,95,115,117,98,116,114,97,99,116,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0, +1,90,95,0,0,7,0,2,21,1,1,0,0,7,0,97,0,0,1,1,0,0,7,0,98,0,0,0,1,4,118,101,99,52,95,109,117,108,116, +105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1,90,95,0,0,7,0,2,22, +1,1,0,0,7,0,97,0,0,1,1,0,0,7,0,98,0,0,0,1,3,2,90,95,0,0,11,0,1,98,73,110,118,0,0,1,1,120,0,0,0,4, +102,108,111,97,116,95,114,99,112,0,18,98,73,110,118,0,59,120,0,0,18,98,0,59,120,0,0,0,4,102,108, +111,97,116,95,114,99,112,0,18,98,73,110,118,0,59,121,0,0,18,98,0,59,121,0,0,0,4,102,108,111,97,116, +95,114,99,112,0,18,98,73,110,118,0,59,122,0,0,18,98,0,59,122,0,0,0,4,118,101,99,52,95,109,117,108, +116,105,112,108,121,0,18,120,0,0,18,97,0,0,18,98,73,110,118,0,0,0,4,118,101,99,52,95,116,111,95, +105,118,101,99,52,0,18,95,95,114,101,116,86,97,108,0,0,18,120,0,0,0,0,1,90,95,0,0,8,0,2,26,1,1,0,0, +8,0,97,0,0,1,1,0,0,8,0,98,0,0,0,1,4,118,101,99,52,95,97,100,100,0,18,95,95,114,101,116,86,97,108,0, +0,18,97,0,0,18,98,0,0,0,0,1,90,95,0,0,8,0,2,27,1,1,0,0,8,0,97,0,0,1,1,0,0,8,0,98,0,0,0,1,4,118,101, +99,52,95,115,117,98,116,114,97,99,116,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0, +1,90,95,0,0,8,0,2,21,1,1,0,0,8,0,97,0,0,1,1,0,0,8,0,98,0,0,0,1,4,118,101,99,52,95,109,117,108,116, +105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1,90,95,0,0,8,0,2,22, +1,1,0,0,8,0,97,0,0,1,1,0,0,8,0,98,0,0,0,1,3,2,90,95,0,0,12,0,1,98,73,110,118,0,0,1,1,120,0,0,0,4, +102,108,111,97,116,95,114,99,112,0,18,98,73,110,118,0,59,120,0,0,18,98,0,59,120,0,0,0,4,102,108, +111,97,116,95,114,99,112,0,18,98,73,110,118,0,59,121,0,0,18,98,0,59,121,0,0,0,4,102,108,111,97,116, +95,114,99,112,0,18,98,73,110,118,0,59,122,0,0,18,98,0,59,122,0,0,0,4,102,108,111,97,116,95,114,99, +112,0,18,98,73,110,118,0,59,119,0,0,18,98,0,59,119,0,0,0,4,118,101,99,52,95,109,117,108,116,105, +112,108,121,0,18,120,0,0,18,97,0,0,18,98,73,110,118,0,0,0,4,118,101,99,52,95,116,111,95,105,118, +101,99,52,0,18,95,95,114,101,116,86,97,108,0,0,18,120,0,0,0,0,1,90,95,0,0,9,0,2,26,1,1,0,0,9,0,97, +0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,97,100,100,0,18,95,95,114,101,116,86,97,108,0,0,18, +97,0,0,18,98,0,0,0,0,1,90,95,0,0,9,0,2,27,1,1,0,0,9,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99, +52,95,115,117,98,116,114,97,99,116,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1, +90,95,0,0,9,0,2,21,1,1,0,0,9,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,109,117,108,116, +105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1,90,95,0,0,9,0,2,22, +1,1,0,0,9,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,3,2,90,95,0,0,9,0,1,98,73,110,118,0,0,0,4,102,108,111,97, +116,95,114,99,112,0,18,98,73,110,118,0,59,120,0,0,18,98,0,0,0,4,118,101,99,52,95,109,117,108,116, +105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,73,110,118,0,0,0,0,1,90,95,0, +0,10,0,2,26,1,1,0,0,10,0,118,0,0,1,1,0,0,10,0,117,0,0,0,1,4,118,101,99,52,95,97,100,100,0,18,95,95, +114,101,116,86,97,108,0,59,120,121,0,0,18,118,0,0,18,117,0,0,0,0,1,90,95,0,0,10,0,2,27,1,1,0,0,10, +0,118,0,0,1,1,0,0,10,0,117,0,0,0,1,4,118,101,99,52,95,115,117,98,116,114,97,99,116,0,18,95,95,114, +101,116,86,97,108,0,59,120,121,0,0,18,118,0,0,18,117,0,0,0,0,1,90,95,0,0,10,0,2,21,1,1,0,0,10,0, +118,0,0,1,1,0,0,10,0,117,0,0,0,1,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,95,95,114, +101,116,86,97,108,0,59,120,121,0,0,18,118,0,0,18,117,0,0,0,0,1,90,95,0,0,10,0,2,22,1,1,0,0,10,0, +118,0,0,1,1,0,0,10,0,117,0,0,0,1,3,2,90,95,0,0,10,0,1,119,0,0,0,4,102,108,111,97,116,95,114,99,112, +0,18,119,0,59,120,0,0,18,117,0,59,120,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,119,0,59,121,0, +0,18,117,0,59,121,0,0,0,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,95,95,114,101,116, +86,97,108,0,59,120,121,0,0,18,118,0,0,18,119,0,0,0,0,1,90,95,0,0,11,0,2,26,1,1,0,0,11,0,118,0,0,1, +1,0,0,11,0,117,0,0,0,1,4,118,101,99,52,95,97,100,100,0,18,95,95,114,101,116,86,97,108,0,59,120,121, +122,0,0,18,118,0,0,18,117,0,0,0,0,1,90,95,0,0,11,0,2,27,1,1,0,0,11,0,118,0,0,1,1,0,0,11,0,117,0,0, +0,1,4,118,101,99,52,95,115,117,98,116,114,97,99,116,0,18,95,95,114,101,116,86,97,108,0,59,120,121, +122,0,0,18,118,0,0,18,117,0,0,0,0,1,90,95,0,0,11,0,2,21,1,1,0,0,11,0,118,0,0,1,1,0,0,11,0,117,0,0, +0,1,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,59,120, +121,122,0,0,18,118,0,0,18,117,0,0,0,0,1,90,95,0,0,11,0,2,22,1,1,0,0,11,0,118,0,0,1,1,0,0,11,0,117, +0,0,0,1,3,2,90,95,0,0,11,0,1,119,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,119,0,59,120,0,0,18, +117,0,59,120,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,119,0,59,121,0,0,18,117,0,59,121,0,0,0, +4,102,108,111,97,116,95,114,99,112,0,18,119,0,59,122,0,0,18,117,0,59,122,0,0,0,4,118,101,99,52,95, +109,117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,118,0,0, +18,119,0,0,0,0,1,90,95,0,0,12,0,2,26,1,1,0,0,12,0,118,0,0,1,1,0,0,12,0,117,0,0,0,1,4,118,101,99,52, +95,97,100,100,0,18,95,95,114,101,116,86,97,108,0,0,18,118,0,0,18,117,0,0,0,0,1,90,95,0,0,12,0,2,27, +1,1,0,0,12,0,118,0,0,1,1,0,0,12,0,117,0,0,0,1,4,118,101,99,52,95,115,117,98,116,114,97,99,116,0,18, +95,95,114,101,116,86,97,108,0,0,18,118,0,0,18,117,0,0,0,0,1,90,95,0,0,12,0,2,21,1,1,0,0,12,0,118,0, +0,1,1,0,0,12,0,117,0,0,0,1,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,95,95,114,101, +116,86,97,108,0,0,18,118,0,0,18,117,0,0,0,0,1,90,95,0,0,12,0,2,22,1,1,0,0,12,0,118,0,0,1,1,0,0,12, +0,117,0,0,0,1,3,2,90,95,0,0,12,0,1,119,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,119,0,59,120, +0,0,18,117,0,59,120,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,119,0,59,121,0,0,18,117,0,59,121, +0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,119,0,59,122,0,0,18,117,0,59,122,0,0,0,4,102,108,111, +97,116,95,114,99,112,0,18,119,0,59,119,0,0,18,117,0,59,119,0,0,0,4,118,101,99,52,95,109,117,108, +116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,0,18,118,0,0,18,119,0,0,0,0,1,90,95,0,0,10, +0,2,26,1,1,0,0,9,0,97,0,0,1,1,0,0,10,0,117,0,0,0,1,4,118,101,99,52,95,97,100,100,0,18,95,95,114, +101,116,86,97,108,0,59,120,121,0,0,18,97,0,0,18,117,0,59,120,121,0,0,0,0,1,90,95,0,0,10,0,2,26,1,1, +0,0,10,0,118,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,97,100,100,0,18,95,95,114,101,116,86,97, +108,0,59,120,121,0,0,18,118,0,59,120,121,0,0,18,98,0,0,0,0,1,90,95,0,0,10,0,2,27,1,1,0,0,9,0,97,0, +0,1,1,0,0,10,0,117,0,0,0,1,4,118,101,99,52,95,115,117,98,116,114,97,99,116,0,18,95,95,114,101,116, +86,97,108,0,59,120,121,0,0,18,97,0,0,18,117,0,59,120,121,0,0,0,0,1,90,95,0,0,10,0,2,27,1,1,0,0,10, +0,118,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,115,117,98,116,114,97,99,116,0,18,95,95,114, +101,116,86,97,108,0,59,120,121,0,0,18,118,0,59,120,121,0,0,18,98,0,0,0,0,1,90,95,0,0,10,0,2,21,1,1, +0,0,9,0,97,0,0,1,1,0,0,10,0,117,0,0,0,1,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,95, +95,114,101,116,86,97,108,0,59,120,121,0,0,18,97,0,0,18,117,0,59,120,121,0,0,0,0,1,90,95,0,0,10,0,2, +21,1,1,0,0,10,0,118,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,109,117,108,116,105,112,108,121, +0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,118,0,59,120,121,0,0,18,98,0,0,0,0,1,90,95,0, +0,10,0,2,22,1,1,0,0,9,0,97,0,0,1,1,0,0,10,0,117,0,0,0,1,3,2,90,95,0,0,10,0,1,105,110,118,85,0,0,0, +4,102,108,111,97,116,95,114,99,112,0,18,105,110,118,85,0,59,120,0,0,18,117,0,59,120,0,0,0,4,102, +108,111,97,116,95,114,99,112,0,18,105,110,118,85,0,59,121,0,0,18,117,0,59,121,0,0,0,4,118,101,99, +52,95,109,117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,97,0,0, +18,105,110,118,85,0,59,120,121,0,0,0,0,1,90,95,0,0,10,0,2,22,1,1,0,0,10,0,118,0,0,1,1,0,0,9,0,98,0, +0,0,1,3,2,90,95,0,0,9,0,1,105,110,118,66,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,105,110,118, +66,0,0,18,98,0,0,0,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97, +108,0,59,120,121,0,0,18,118,0,59,120,121,0,0,18,105,110,118,66,0,0,0,0,1,90,95,0,0,11,0,2,26,1,1,0, +0,9,0,97,0,0,1,1,0,0,11,0,117,0,0,0,1,4,118,101,99,52,95,97,100,100,0,18,95,95,114,101,116,86,97, +108,0,59,120,121,122,0,0,18,97,0,0,18,117,0,59,120,121,122,0,0,0,0,1,90,95,0,0,11,0,2,26,1,1,0,0, +11,0,118,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,97,100,100,0,18,95,95,114,101,116,86,97,108, +0,59,120,121,122,0,0,18,118,0,59,120,121,122,0,0,18,98,0,0,0,0,1,90,95,0,0,11,0,2,27,1,1,0,0,9,0, +97,0,0,1,1,0,0,11,0,117,0,0,0,1,4,118,101,99,52,95,115,117,98,116,114,97,99,116,0,18,95,95,114,101, +116,86,97,108,0,59,120,121,122,0,0,18,97,0,0,18,117,0,59,120,121,122,0,0,0,0,1,90,95,0,0,11,0,2,27, +1,1,0,0,11,0,118,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,115,117,98,116,114,97,99,116,0,18, +95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,118,0,59,120,121,122,0,0,18,98,0,0,0,0,1,90,95, +0,0,11,0,2,21,1,1,0,0,9,0,97,0,0,1,1,0,0,11,0,117,0,0,0,1,4,118,101,99,52,95,109,117,108,116,105, +112,108,121,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,97,0,0,18,117,0,59,120,121, +122,0,0,0,0,1,90,95,0,0,11,0,2,21,1,1,0,0,11,0,118,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95, +109,117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,118,0,59, +120,121,122,0,0,18,98,0,0,0,0,1,90,95,0,0,11,0,2,22,1,1,0,0,9,0,97,0,0,1,1,0,0,11,0,117,0,0,0,1,3, +2,90,95,0,0,11,0,1,105,110,118,85,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,105,110,118,85,0, +59,120,0,0,18,117,0,59,120,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,105,110,118,85,0,59,121,0, +0,18,117,0,59,121,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18,105,110,118,85,0,59,122,0,0,18,117, +0,59,122,0,0,0,4,118,101,99,52,95,109,117,108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108, +0,59,120,121,122,0,0,18,97,0,0,18,105,110,118,85,0,59,120,121,122,0,0,0,0,1,90,95,0,0,11,0,2,22,1, +1,0,0,11,0,118,0,0,1,1,0,0,9,0,98,0,0,0,1,3,2,90,95,0,0,9,0,1,105,110,118,66,0,0,0,4,102,108,111, +97,116,95,114,99,112,0,18,105,110,118,66,0,0,18,98,0,0,0,4,118,101,99,52,95,109,117,108,116,105, +112,108,121,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,118,0,59,120,121,122,0,0,18, +105,110,118,66,0,0,0,0,1,90,95,0,0,12,0,2,26,1,1,0,0,9,0,97,0,0,1,1,0,0,12,0,117,0,0,0,1,4,118,101, +99,52,95,97,100,100,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,117,0,0,0,0,1,90,95,0,0,12,0, +2,26,1,1,0,0,12,0,118,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,97,100,100,0,18,95,95,114,101, +116,86,97,108,0,0,18,118,0,0,18,98,0,0,0,0,1,90,95,0,0,12,0,2,27,1,1,0,0,9,0,97,0,0,1,1,0,0,12,0, +117,0,0,0,1,4,118,101,99,52,95,115,117,98,116,114,97,99,116,0,18,95,95,114,101,116,86,97,108,0,0, +18,97,0,0,18,117,0,0,0,0,1,90,95,0,0,12,0,2,27,1,1,0,0,12,0,118,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118, +101,99,52,95,115,117,98,116,114,97,99,116,0,18,95,95,114,101,116,86,97,108,0,0,18,118,0,0,18,98,0, +0,0,0,1,90,95,0,0,12,0,2,21,1,1,0,0,9,0,97,0,0,1,1,0,0,12,0,117,0,0,0,1,4,118,101,99,52,95,109,117, +108,116,105,112,108,121,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,117,0,0,0,0,1,90,95,0,0, +12,0,2,21,1,1,0,0,12,0,118,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,109,117,108,116,105,112, +108,121,0,18,95,95,114,101,116,86,97,108,0,0,18,118,0,0,18,98,0,0,0,0,1,90,95,0,0,12,0,2,22,1,1,0, +0,9,0,97,0,0,1,1,0,0,12,0,117,0,0,0,1,3,2,90,95,0,0,12,0,1,105,110,118,85,0,0,0,4,102,108,111,97, +116,95,114,99,112,0,18,105,110,118,85,0,59,120,0,0,18,117,0,59,120,0,0,0,4,102,108,111,97,116,95, +114,99,112,0,18,105,110,118,85,0,59,121,0,0,18,117,0,59,121,0,0,0,4,102,108,111,97,116,95,114,99, +112,0,18,105,110,118,85,0,59,122,0,0,18,117,0,59,122,0,0,0,4,102,108,111,97,116,95,114,99,112,0,18, +105,110,118,85,0,59,119,0,0,18,117,0,59,119,0,0,0,4,118,101,99,52,95,109,117,108,116,105,112,108, +121,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,105,110,118,85,0,0,0,0,1,90,95,0,0,12,0,2,22, +1,1,0,0,12,0,118,0,0,1,1,0,0,9,0,98,0,0,0,1,3,2,90,95,0,0,9,0,1,105,110,118,66,0,0,0,4,102,108,111, +97,116,95,114,99,112,0,18,105,110,118,66,0,0,18,98,0,0,0,4,118,101,99,52,95,109,117,108,116,105, +112,108,121,0,18,95,95,114,101,116,86,97,108,0,0,18,118,0,0,18,105,110,118,66,0,0,0,0,1,90,95,0,0, +6,0,2,26,1,1,0,0,5,0,97,0,0,1,1,0,0,6,0,117,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,105,118, +101,99,50,0,0,18,97,0,0,0,18,117,0,46,20,0,0,1,90,95,0,0,6,0,2,26,1,1,0,0,6,0,118,0,0,1,1,0,0,5,0, +98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,118,0,58,105,118,101,99,50,0,0,18,98,0,0,0,46,20, +0,0,1,90,95,0,0,6,0,2,27,1,1,0,0,5,0,97,0,0,1,1,0,0,6,0,117,0,0,0,1,9,18,95,95,114,101,116,86,97, +108,0,58,105,118,101,99,50,0,0,18,97,0,0,0,18,117,0,47,20,0,0,1,90,95,0,0,6,0,2,27,1,1,0,0,6,0,118, +0,0,1,1,0,0,5,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,118,0,58,105,118,101,99,50,0,0,18, +98,0,0,0,47,20,0,0,1,90,95,0,0,6,0,2,21,1,1,0,0,5,0,97,0,0,1,1,0,0,6,0,117,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,58,105,118,101,99,50,0,0,18,97,0,0,0,18,117,0,48,20,0,0,1,90,95,0,0,6,0,2,21,1, +1,0,0,6,0,118,0,0,1,1,0,0,5,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,118,0,58,105,118, +101,99,50,0,0,18,98,0,0,0,48,20,0,0,1,90,95,0,0,6,0,2,22,1,1,0,0,5,0,97,0,0,1,1,0,0,6,0,117,0,0,0, +1,9,18,95,95,114,101,116,86,97,108,0,58,105,118,101,99,50,0,0,18,97,0,0,0,18,117,0,49,20,0,0,1,90, +95,0,0,6,0,2,22,1,1,0,0,6,0,118,0,0,1,1,0,0,5,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18, +118,0,58,105,118,101,99,50,0,0,18,98,0,0,0,49,20,0,0,1,90,95,0,0,7,0,2,26,1,1,0,0,5,0,97,0,0,1,1,0, +0,7,0,117,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,105,118,101,99,51,0,0,18,97,0,0,0,18,117,0, +46,20,0,0,1,90,95,0,0,7,0,2,26,1,1,0,0,7,0,118,0,0,1,1,0,0,5,0,98,0,0,0,1,9,18,95,95,114,101,116, +86,97,108,0,18,118,0,58,105,118,101,99,51,0,0,18,98,0,0,0,46,20,0,0,1,90,95,0,0,7,0,2,27,1,1,0,0,5, +0,97,0,0,1,1,0,0,7,0,117,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,105,118,101,99,51,0,0,18,97, +0,0,0,18,117,0,47,20,0,0,1,90,95,0,0,7,0,2,27,1,1,0,0,7,0,118,0,0,1,1,0,0,5,0,98,0,0,0,1,9,18,95, +95,114,101,116,86,97,108,0,18,118,0,58,105,118,101,99,51,0,0,18,98,0,0,0,47,20,0,0,1,90,95,0,0,7,0, +2,21,1,1,0,0,5,0,97,0,0,1,1,0,0,7,0,117,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,105,118,101, +99,51,0,0,18,97,0,0,0,18,117,0,48,20,0,0,1,90,95,0,0,7,0,2,21,1,1,0,0,7,0,118,0,0,1,1,0,0,5,0,98,0, +0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,118,0,58,105,118,101,99,51,0,0,18,98,0,0,0,48,20,0,0,1, +90,95,0,0,7,0,2,22,1,1,0,0,5,0,97,0,0,1,1,0,0,7,0,117,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0, +58,105,118,101,99,51,0,0,18,97,0,0,0,18,117,0,49,20,0,0,1,90,95,0,0,7,0,2,22,1,1,0,0,7,0,118,0,0,1, +1,0,0,5,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,118,0,58,105,118,101,99,51,0,0,18,98,0, +0,0,49,20,0,0,1,90,95,0,0,8,0,2,26,1,1,0,0,5,0,97,0,0,1,1,0,0,8,0,117,0,0,0,1,9,18,95,95,114,101, +116,86,97,108,0,58,105,118,101,99,52,0,0,18,97,0,0,0,18,117,0,46,20,0,0,1,90,95,0,0,8,0,2,26,1,1,0, +0,8,0,118,0,0,1,1,0,0,5,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,118,0,58,105,118,101,99, +52,0,0,18,98,0,0,0,46,20,0,0,1,90,95,0,0,8,0,2,27,1,1,0,0,5,0,97,0,0,1,1,0,0,8,0,117,0,0,0,1,9,18, +95,95,114,101,116,86,97,108,0,58,105,118,101,99,52,0,0,18,97,0,0,0,18,117,0,47,20,0,0,1,90,95,0,0, +8,0,2,27,1,1,0,0,8,0,118,0,0,1,1,0,0,5,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,118,0,58, +105,118,101,99,52,0,0,18,98,0,0,0,47,20,0,0,1,90,95,0,0,8,0,2,21,1,1,0,0,5,0,97,0,0,1,1,0,0,8,0, +117,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,105,118,101,99,52,0,0,18,97,0,0,0,18,117,0,48,20, +0,0,1,90,95,0,0,8,0,2,21,1,1,0,0,8,0,118,0,0,1,1,0,0,5,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97, +108,0,18,118,0,58,105,118,101,99,52,0,0,18,98,0,0,0,48,20,0,0,1,90,95,0,0,8,0,2,22,1,1,0,0,5,0,97, +0,0,1,1,0,0,8,0,117,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,58,105,118,101,99,52,0,0,18,97,0,0, +0,18,117,0,49,20,0,0,1,90,95,0,0,8,0,2,22,1,1,0,0,8,0,118,0,0,1,1,0,0,5,0,98,0,0,0,1,9,18,95,95, +114,101,116,86,97,108,0,18,118,0,58,105,118,101,99,52,0,0,18,98,0,0,0,49,20,0,0,1,90,95,0,0,5,0,2, +27,1,1,0,0,5,0,97,0,0,0,1,4,118,101,99,52,95,110,101,103,97,116,101,0,18,95,95,114,101,116,86,97, +108,0,59,120,0,0,18,97,0,0,0,0,1,90,95,0,0,6,0,2,27,1,1,0,0,6,0,118,0,0,0,1,4,118,101,99,52,95,110, +101,103,97,116,101,0,18,95,95,114,101,116,86,97,108,0,0,18,118,0,0,0,0,1,90,95,0,0,7,0,2,27,1,1,0, +0,7,0,118,0,0,0,1,4,118,101,99,52,95,110,101,103,97,116,101,0,18,95,95,114,101,116,86,97,108,0,0, +18,118,0,0,0,0,1,90,95,0,0,8,0,2,27,1,1,0,0,8,0,118,0,0,0,1,4,118,101,99,52,95,110,101,103,97,116, +101,0,18,95,95,114,101,116,86,97,108,0,0,18,118,0,0,0,0,1,90,95,0,0,9,0,2,27,1,1,0,0,9,0,97,0,0,0, +1,4,118,101,99,52,95,110,101,103,97,116,101,0,18,95,95,114,101,116,86,97,108,0,59,120,0,0,18,97,0, +0,0,0,1,90,95,0,0,10,0,2,27,1,1,0,0,10,0,118,0,0,0,1,4,118,101,99,52,95,110,101,103,97,116,101,0, +18,95,95,114,101,116,86,97,108,0,59,120,121,0,0,18,118,0,59,120,121,0,0,0,0,1,90,95,0,0,11,0,2,27, +1,1,0,0,11,0,118,0,0,0,1,4,118,101,99,52,95,110,101,103,97,116,101,0,18,95,95,114,101,116,86,97, +108,0,59,120,121,122,0,0,18,118,0,59,120,121,122,0,0,0,0,1,90,95,0,0,12,0,2,27,1,1,0,0,12,0,118,0, +0,0,1,4,118,101,99,52,95,110,101,103,97,116,101,0,18,95,95,114,101,116,86,97,108,0,0,18,118,0,0,0, +0,1,90,95,0,0,13,0,2,27,1,1,0,0,13,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57, +18,109,0,16,8,48,0,57,54,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0, +57,54,20,0,0,1,90,95,0,0,14,0,2,27,1,1,0,0,14,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16, +8,48,0,57,18,109,0,16,8,48,0,57,54,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0, +16,10,49,0,57,54,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,16,10,50,0,57,54, +20,0,0,1,90,95,0,0,15,0,2,27,1,1,0,0,15,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0, +57,18,109,0,16,8,48,0,57,54,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10, +49,0,57,54,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,16,10,50,0,57,54,20,0,9, +18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,18,109,0,16,10,51,0,57,54,20,0,0,1,90,95,0,0,9,0,0, +100,111,116,0,1,1,0,0,9,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,97,0, +18,98,0,48,20,0,0,1,90,95,0,0,9,0,0,100,111,116,0,1,1,0,0,10,0,97,0,0,1,1,0,0,10,0,98,0,0,0,1,9,18, +95,95,114,101,116,86,97,108,0,18,97,0,59,120,0,18,98,0,59,120,0,48,18,97,0,59,121,0,18,98,0,59,121, +0,48,46,20,0,0,1,90,95,0,0,9,0,0,100,111,116,0,1,1,0,0,11,0,97,0,0,1,1,0,0,11,0,98,0,0,0,1,4,118, +101,99,51,95,100,111,116,0,18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1,90,95,0,0, +9,0,0,100,111,116,0,1,1,0,0,12,0,97,0,0,1,1,0,0,12,0,98,0,0,0,1,4,118,101,99,52,95,100,111,116,0, +18,95,95,114,101,116,86,97,108,0,0,18,97,0,0,18,98,0,0,0,0,1,90,95,0,0,5,0,2,1,1,0,2,0,5,0,97,0,0, +1,1,0,0,5,0,98,0,0,0,1,9,18,97,0,18,97,0,18,98,0,46,20,0,8,18,97,0,0,0,1,90,95,0,0,5,0,2,2,1,0,2,0, +5,0,97,0,0,1,1,0,0,5,0,98,0,0,0,1,9,18,97,0,18,97,0,18,98,0,47,20,0,8,18,97,0,0,0,1,90,95,0,0,5,0, +2,3,1,0,2,0,5,0,97,0,0,1,1,0,0,5,0,98,0,0,0,1,9,18,97,0,18,97,0,18,98,0,48,20,0,8,18,97,0,0,0,1,90, +95,0,0,5,0,2,4,1,0,2,0,5,0,97,0,0,1,1,0,0,5,0,98,0,0,0,1,9,18,97,0,18,97,0,18,98,0,49,20,0,8,18,97, +0,0,0,1,90,95,0,0,6,0,2,1,1,0,2,0,6,0,118,0,0,1,1,0,0,6,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0, +46,20,0,8,18,118,0,0,0,1,90,95,0,0,6,0,2,2,1,0,2,0,6,0,118,0,0,1,1,0,0,6,0,117,0,0,0,1,9,18,118,0, +18,118,0,18,117,0,47,20,0,8,18,118,0,0,0,1,90,95,0,0,6,0,2,3,1,0,2,0,6,0,118,0,0,1,1,0,0,6,0,117,0, +0,0,1,9,18,118,0,18,118,0,18,117,0,48,20,0,8,18,118,0,0,0,1,90,95,0,0,6,0,2,4,1,0,2,0,6,0,118,0,0, +1,1,0,0,6,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0,49,20,0,8,18,118,0,0,0,1,90,95,0,0,7,0,2,1,1, +0,2,0,7,0,118,0,0,1,1,0,0,7,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0,46,20,0,8,18,118,0,0,0,1,90, +95,0,0,7,0,2,2,1,0,2,0,7,0,118,0,0,1,1,0,0,7,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0,47,20,0,8, +18,118,0,0,0,1,90,95,0,0,7,0,2,3,1,0,2,0,7,0,118,0,0,1,1,0,0,7,0,117,0,0,0,1,9,18,118,0,18,118,0, +18,117,0,48,20,0,8,18,118,0,0,0,1,90,95,0,0,7,0,2,4,1,0,2,0,7,0,118,0,0,1,1,0,0,7,0,117,0,0,0,1,9, +18,118,0,18,118,0,18,117,0,49,20,0,8,18,118,0,0,0,1,90,95,0,0,8,0,2,1,1,0,2,0,8,0,118,0,0,1,1,0,0, +8,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0,46,20,0,8,18,118,0,0,0,1,90,95,0,0,8,0,2,2,1,0,2,0,8, +0,118,0,0,1,1,0,0,8,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0,47,20,0,8,18,118,0,0,0,1,90,95,0,0, +8,0,2,3,1,0,2,0,8,0,118,0,0,1,1,0,0,8,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0,48,20,0,8,18,118, +0,0,0,1,90,95,0,0,8,0,2,4,1,0,2,0,8,0,118,0,0,1,1,0,0,8,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0, +49,20,0,8,18,118,0,0,0,1,90,95,0,0,9,0,2,1,1,0,2,0,9,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,9,18,97,0,18, +97,0,18,98,0,46,20,0,8,18,97,0,0,0,1,90,95,0,0,9,0,2,2,1,0,2,0,9,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,9, +18,97,0,18,97,0,18,98,0,47,20,0,8,18,97,0,0,0,1,90,95,0,0,9,0,2,3,1,0,2,0,9,0,97,0,0,1,1,0,0,9,0, +98,0,0,0,1,9,18,97,0,18,97,0,18,98,0,48,20,0,8,18,97,0,0,0,1,90,95,0,0,9,0,2,4,1,0,2,0,9,0,97,0,0, +1,1,0,0,9,0,98,0,0,0,1,9,18,97,0,18,97,0,18,98,0,49,20,0,8,18,97,0,0,0,1,90,95,0,0,10,0,2,1,1,0,2, +0,10,0,118,0,0,1,1,0,0,10,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0,46,20,0,8,18,118,0,0,0,1,90, +95,0,0,10,0,2,2,1,0,2,0,10,0,118,0,0,1,1,0,0,10,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0,47,20,0, +8,18,118,0,0,0,1,90,95,0,0,10,0,2,3,1,0,2,0,10,0,118,0,0,1,1,0,0,10,0,117,0,0,0,1,9,18,118,0,18, +118,0,18,117,0,48,20,0,8,18,118,0,0,0,1,90,95,0,0,10,0,2,4,1,0,2,0,10,0,118,0,0,1,1,0,0,10,0,117,0, +0,0,1,9,18,118,0,18,118,0,18,117,0,49,20,0,8,18,118,0,0,0,1,90,95,0,0,11,0,2,1,1,0,2,0,11,0,118,0, +0,1,1,0,0,11,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0,46,20,0,8,18,118,0,0,0,1,90,95,0,0,11,0,2, +2,1,0,2,0,11,0,118,0,0,1,1,0,0,11,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0,47,20,0,8,18,118,0,0, +0,1,90,95,0,0,11,0,2,3,1,0,2,0,11,0,118,0,0,1,1,0,0,11,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0, +48,20,0,8,18,118,0,0,0,1,90,95,0,0,11,0,2,4,1,0,2,0,11,0,118,0,0,1,1,0,0,11,0,117,0,0,0,1,9,18,118, +0,18,118,0,18,117,0,49,20,0,8,18,118,0,0,0,1,90,95,0,0,12,0,2,1,1,0,2,0,12,0,118,0,0,1,1,0,0,12,0, +117,0,0,0,1,9,18,118,0,18,118,0,18,117,0,46,20,0,8,18,118,0,0,0,1,90,95,0,0,12,0,2,2,1,0,2,0,12,0, +118,0,0,1,1,0,0,12,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0,47,20,0,8,18,118,0,0,0,1,90,95,0,0, +12,0,2,3,1,0,2,0,12,0,118,0,0,1,1,0,0,12,0,117,0,0,0,1,9,18,118,0,18,118,0,18,117,0,48,20,0,8,18, +118,0,0,0,1,90,95,0,0,12,0,2,4,1,0,2,0,12,0,118,0,0,1,1,0,0,12,0,117,0,0,0,1,9,18,118,0,18,118,0, +18,117,0,49,20,0,8,18,118,0,0,0,1,90,95,0,0,6,0,2,1,1,0,2,0,6,0,118,0,0,1,1,0,0,5,0,97,0,0,0,1,9, +18,118,0,18,118,0,58,105,118,101,99,50,0,0,18,97,0,0,0,46,20,0,8,18,118,0,0,0,1,90,95,0,0,6,0,2,2, +1,0,2,0,6,0,118,0,0,1,1,0,0,5,0,97,0,0,0,1,9,18,118,0,18,118,0,58,105,118,101,99,50,0,0,18,97,0,0, +0,47,20,0,8,18,118,0,0,0,1,90,95,0,0,6,0,2,3,1,0,2,0,6,0,118,0,0,1,1,0,0,5,0,97,0,0,0,1,9,18,118,0, +18,118,0,58,105,118,101,99,50,0,0,18,97,0,0,0,48,20,0,8,18,118,0,0,0,1,90,95,0,0,6,0,2,4,1,0,2,0,6, +0,118,0,0,1,1,0,0,5,0,97,0,0,0,1,9,18,118,0,18,118,0,58,105,118,101,99,50,0,0,18,97,0,0,0,49,20,0, +8,18,118,0,0,0,1,90,95,0,0,7,0,2,1,1,0,2,0,7,0,118,0,0,1,1,0,0,5,0,97,0,0,0,1,9,18,118,0,18,118,0, +58,105,118,101,99,51,0,0,18,97,0,0,0,46,20,0,8,18,118,0,0,0,1,90,95,0,0,7,0,2,2,1,0,2,0,7,0,118,0, +0,1,1,0,0,5,0,97,0,0,0,1,9,18,118,0,18,118,0,58,105,118,101,99,51,0,0,18,97,0,0,0,47,20,0,8,18,118, +0,0,0,1,90,95,0,0,7,0,2,3,1,0,2,0,7,0,118,0,0,1,1,0,0,5,0,97,0,0,0,1,9,18,118,0,18,118,0,58,105, +118,101,99,51,0,0,18,97,0,0,0,48,20,0,8,18,118,0,0,0,1,90,95,0,0,8,0,2,4,1,0,2,0,7,0,118,0,0,1,1,0, +0,5,0,97,0,0,0,1,9,18,118,0,18,118,0,58,105,118,101,99,51,0,0,18,97,0,0,0,49,20,0,8,18,118,0,0,0,1, +90,95,0,0,8,0,2,1,1,0,2,0,8,0,118,0,0,1,1,0,0,5,0,97,0,0,0,1,9,18,118,0,18,118,0,58,105,118,101,99, +52,0,0,18,97,0,0,0,46,20,0,8,18,118,0,0,0,1,90,95,0,0,8,0,2,2,1,0,2,0,8,0,118,0,0,1,1,0,0,5,0,97,0, +0,0,1,9,18,118,0,18,118,0,58,105,118,101,99,52,0,0,18,97,0,0,0,47,20,0,8,18,118,0,0,0,1,90,95,0,0, +8,0,2,3,1,0,2,0,8,0,118,0,0,1,1,0,0,5,0,97,0,0,0,1,9,18,118,0,18,118,0,58,105,118,101,99,52,0,0,18, +97,0,0,0,48,20,0,8,18,118,0,0,0,1,90,95,0,0,8,0,2,4,1,0,2,0,8,0,118,0,0,1,1,0,0,5,0,97,0,0,0,1,9, +18,118,0,18,118,0,58,105,118,101,99,52,0,0,18,97,0,0,0,49,20,0,8,18,118,0,0,0,1,90,95,0,0,10,0,2,1, +1,0,2,0,10,0,118,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,118,0,18,118,0,58,118,101,99,50,0,0,18,97,0,0,0, +46,20,0,8,18,118,0,0,0,1,90,95,0,0,10,0,2,2,1,0,2,0,10,0,118,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,118,0, +18,118,0,58,118,101,99,50,0,0,18,97,0,0,0,47,20,0,8,18,118,0,0,0,1,90,95,0,0,10,0,2,3,1,0,2,0,10,0, +118,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,118,0,18,118,0,58,118,101,99,50,0,0,18,97,0,0,0,48,20,0,8,18, +118,0,0,0,1,90,95,0,0,10,0,2,4,1,0,2,0,10,0,118,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,118,0,18,118,0,58, +118,101,99,50,0,0,18,97,0,0,0,49,20,0,8,18,118,0,0,0,1,90,95,0,0,11,0,2,1,1,0,2,0,11,0,118,0,0,1,1, +0,0,9,0,97,0,0,0,1,9,18,118,0,18,118,0,58,118,101,99,51,0,0,18,97,0,0,0,46,20,0,8,18,118,0,0,0,1, +90,95,0,0,11,0,2,2,1,0,2,0,11,0,118,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,118,0,18,118,0,58,118,101,99, +51,0,0,18,97,0,0,0,47,20,0,8,18,118,0,0,0,1,90,95,0,0,11,0,2,3,1,0,2,0,11,0,118,0,0,1,1,0,0,9,0,97, +0,0,0,1,9,18,118,0,18,118,0,58,118,101,99,51,0,0,18,97,0,0,0,48,20,0,8,18,118,0,0,0,1,90,95,0,0,11, +0,2,4,1,0,2,0,11,0,118,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,118,0,18,118,0,58,118,101,99,51,0,0,18,97,0, +0,0,49,20,0,8,18,118,0,0,0,1,90,95,0,0,12,0,2,1,1,0,2,0,12,0,118,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18, +118,0,18,118,0,58,118,101,99,52,0,0,18,97,0,0,0,46,20,0,8,18,118,0,0,0,1,90,95,0,0,12,0,2,2,1,0,2, +0,12,0,118,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,118,0,18,118,0,58,118,101,99,52,0,0,18,97,0,0,0,47,20,0, +8,18,118,0,0,0,1,90,95,0,0,12,0,2,3,1,0,2,0,12,0,118,0,0,1,1,0,0,9,0,97,0,0,0,1,9,18,118,0,18,118, +0,58,118,101,99,52,0,0,18,97,0,0,0,48,20,0,8,18,118,0,0,0,1,90,95,0,0,12,0,2,4,1,0,2,0,12,0,118,0, +0,1,1,0,0,9,0,97,0,0,0,1,9,18,118,0,18,118,0,58,118,101,99,52,0,0,18,97,0,0,0,49,20,0,8,18,118,0,0, +0,1,90,95,0,0,13,0,2,26,1,1,0,0,13,0,109,0,0,1,1,0,0,13,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97, +108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,46,20,0,9,18,95,95,114,101,116,86, +97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,46,20,0,0,1,90,95,0,0,13,0,2, +27,1,1,0,0,13,0,109,0,0,1,1,0,0,13,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57, +18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,47,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0, +57,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,47,20,0,0,1,90,95,0,0,13,0,2,21,1,1,0,0,13,0,109, +0,0,1,1,0,0,13,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57, +18,110,0,16,8,48,0,57,59,120,120,0,48,18,109,0,16,10,49,0,57,18,110,0,16,8,48,0,57,59,121,121,0,48, +46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,8,48,0,57,18,110,0,16,10,49,0, +57,59,120,120,0,48,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,59,121,121,0,48,46,20,0,0,1,90,95, +0,0,13,0,2,22,1,1,0,0,13,0,109,0,0,1,1,0,0,13,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16, +8,48,0,57,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,49,20,0,9,18,95,95,114,101,116,86,97,108,0, +16,10,49,0,57,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,49,20,0,0,1,90,95,0,0,14,0,2,26,1,1,0, +0,14,0,109,0,0,1,1,0,0,14,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0, +16,8,48,0,57,18,110,0,16,8,48,0,57,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109, +0,16,10,49,0,57,18,110,0,16,10,49,0,57,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18, +109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,46,20,0,0,1,90,95,0,0,14,0,2,27,1,1,0,0,14,0,109,0,0,1, +1,0,0,14,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18, +110,0,16,8,48,0,57,47,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57, +18,110,0,16,10,49,0,57,47,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,16,10,50, +0,57,18,110,0,16,10,50,0,57,47,20,0,0,1,90,95,0,0,14,0,2,21,1,1,0,0,14,0,109,0,0,1,1,0,0,14,0,110, +0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0, +57,59,120,120,120,0,48,18,109,0,16,10,49,0,57,18,110,0,16,8,48,0,57,59,121,121,121,0,48,46,18,109, +0,16,10,50,0,57,18,110,0,16,8,48,0,57,59,122,122,122,0,48,46,20,0,9,18,95,95,114,101,116,86,97,108, +0,16,10,49,0,57,18,109,0,16,8,48,0,57,18,110,0,16,10,49,0,57,59,120,120,120,0,48,18,109,0,16,10,49, +0,57,18,110,0,16,10,49,0,57,59,121,121,121,0,48,46,18,109,0,16,10,50,0,57,18,110,0,16,10,49,0,57, +59,122,122,122,0,48,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,16,8,48,0,57, +18,110,0,16,10,50,0,57,59,120,120,120,0,48,18,109,0,16,10,49,0,57,18,110,0,16,10,50,0,57,59,121, +121,121,0,48,46,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,59,122,122,122,0,48,46,20,0,0,1,90, +95,0,0,14,0,2,22,1,1,0,0,14,0,109,0,0,1,1,0,0,14,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0, +16,8,48,0,57,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,49,20,0,9,18,95,95,114,101,116,86,97,108, +0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,49,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,49,20,0,0,1,90,95,0,0,15,0,2,26, +1,1,0,0,15,0,109,0,0,1,1,0,0,15,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18, +109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57, +18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50, +0,57,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16, +10,51,0,57,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,46,20,0,0,1,90,95,0,0,15,0,2,27,1,1,0,0, +15,0,109,0,0,1,1,0,0,15,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16, +8,48,0,57,18,110,0,16,8,48,0,57,47,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0, +16,10,49,0,57,18,110,0,16,10,49,0,57,47,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18, +109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,47,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0, +57,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,47,20,0,0,1,90,95,0,0,15,0,2,21,1,1,0,0,15,0,109, +0,0,1,1,0,0,15,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57, +18,110,0,16,8,48,0,57,59,120,120,120,120,0,48,18,109,0,16,10,49,0,57,18,110,0,16,8,48,0,57,59,121, +121,121,121,0,48,46,18,109,0,16,10,50,0,57,18,110,0,16,8,48,0,57,59,122,122,122,122,0,48,46,18,109, +0,16,10,51,0,57,18,110,0,16,8,48,0,57,59,119,119,119,119,0,48,46,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,10,49,0,57,18,109,0,16,8,48,0,57,18,110,0,16,10,49,0,57,59,120,120,120,120,0,48,18,109,0, +16,10,49,0,57,18,110,0,16,10,49,0,57,59,121,121,121,121,0,48,46,18,109,0,16,10,50,0,57,18,110,0,16, +10,49,0,57,59,122,122,122,122,0,48,46,18,109,0,16,10,51,0,57,18,110,0,16,10,49,0,57,59,119,119,119, +119,0,48,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,16,8,48,0,57,18,110,0, +16,10,50,0,57,59,120,120,120,120,0,48,18,109,0,16,10,49,0,57,18,110,0,16,10,50,0,57,59,121,121,121, +121,0,48,46,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,59,122,122,122,122,0,48,46,18,109,0,16, +10,51,0,57,18,110,0,16,10,50,0,57,59,119,119,119,119,0,48,46,20,0,9,18,95,95,114,101,116,86,97,108, +0,16,10,51,0,57,18,109,0,16,8,48,0,57,18,110,0,16,10,51,0,57,59,120,120,120,120,0,48,18,109,0,16, +10,49,0,57,18,110,0,16,10,51,0,57,59,121,121,121,121,0,48,46,18,109,0,16,10,50,0,57,18,110,0,16,10, +51,0,57,59,122,122,122,122,0,48,46,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0,57,59,119,119,119, +119,0,48,46,20,0,0,1,90,95,0,0,15,0,2,22,1,1,0,0,15,0,109,0,0,1,1,0,0,15,0,110,0,0,0,1,9,18,95,95, +114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,49,20,0,9,18,95, +95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,49,20,0,9, +18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,49,20, +0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,18,109,0,16,10,51,0,57,18,110,0,16,10,51,0,57, +49,20,0,0,1,90,95,0,0,13,0,2,26,1,1,0,0,9,0,97,0,0,1,1,0,0,13,0,110,0,0,0,1,9,18,95,95,114,101,116, +86,97,108,0,16,8,48,0,57,18,97,0,18,110,0,16,8,48,0,57,46,20,0,9,18,95,95,114,101,116,86,97,108,0, +16,10,49,0,57,18,97,0,18,110,0,16,10,49,0,57,46,20,0,0,1,90,95,0,0,13,0,2,26,1,1,0,0,13,0,109,0,0, +1,1,0,0,9,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,98, +0,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,98,0,46,20,0, +0,1,90,95,0,0,13,0,2,27,1,1,0,0,9,0,97,0,0,1,1,0,0,13,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97, +108,0,16,8,48,0,57,18,97,0,18,110,0,16,8,48,0,57,47,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10, +49,0,57,18,97,0,18,110,0,16,10,49,0,57,47,20,0,0,1,90,95,0,0,13,0,2,27,1,1,0,0,13,0,109,0,0,1,1,0, +0,9,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,98,0,47, +20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,98,0,47,20,0,0,1, +90,95,0,0,13,0,2,21,1,1,0,0,9,0,97,0,0,1,1,0,0,13,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0, +16,8,48,0,57,18,97,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0, +57,18,97,0,18,110,0,16,10,49,0,57,48,20,0,0,1,90,95,0,0,13,0,2,21,1,1,0,0,13,0,109,0,0,1,1,0,0,9,0, +98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,98,0,48,20,0,9, +18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,98,0,48,20,0,0,1,90,95,0, +0,13,0,2,22,1,1,0,0,9,0,97,0,0,1,1,0,0,13,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48, +0,57,18,97,0,18,110,0,16,8,48,0,57,49,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,97, +0,18,110,0,16,10,49,0,57,49,20,0,0,1,90,95,0,0,13,0,2,22,1,1,0,0,13,0,109,0,0,1,1,0,0,9,0,98,0,0,0, +1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,98,0,49,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,98,0,49,20,0,0,1,90,95,0,0,14,0,2, +26,1,1,0,0,9,0,97,0,0,1,1,0,0,14,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18, +97,0,18,110,0,16,8,48,0,57,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,97,0,18,110, +0,16,10,49,0,57,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,97,0,18,110,0,16,10,50, +0,57,46,20,0,0,1,90,95,0,0,14,0,2,26,1,1,0,0,14,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,98,0,46,20,0,9,18,95,95,114,101,116,86, +97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,98,0,46,20,0,9,18,95,95,114,101,116,86,97,108,0, +16,10,50,0,57,18,109,0,16,10,50,0,57,18,98,0,46,20,0,0,1,90,95,0,0,14,0,2,27,1,1,0,0,9,0,97,0,0,1, +1,0,0,14,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,97,0,18,110,0,16,8,48,0, +57,47,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,97,0,18,110,0,16,10,49,0,57,47,20,0, +9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,97,0,18,110,0,16,10,50,0,57,47,20,0,0,1,90,95, +0,0,14,0,2,27,1,1,0,0,14,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8, +48,0,57,18,109,0,16,8,48,0,57,18,98,0,47,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18, +109,0,16,10,49,0,57,18,98,0,47,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,16, +10,50,0,57,18,98,0,47,20,0,0,1,90,95,0,0,14,0,2,21,1,1,0,0,9,0,97,0,0,1,1,0,0,14,0,110,0,0,0,1,9, +18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,97,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114, +101,116,86,97,108,0,16,10,49,0,57,18,97,0,18,110,0,16,10,49,0,57,48,20,0,9,18,95,95,114,101,116,86, +97,108,0,16,10,50,0,57,18,97,0,18,110,0,16,10,50,0,57,48,20,0,0,1,90,95,0,0,14,0,2,21,1,1,0,0,14,0, +109,0,0,1,1,0,0,9,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0, +57,18,98,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,98,0, +48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,98,0,48,20,0,0, +1,90,95,0,0,14,0,2,22,1,1,0,0,9,0,97,0,0,1,1,0,0,14,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108, +0,16,8,48,0,57,18,97,0,18,110,0,16,8,48,0,57,49,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0, +57,18,97,0,18,110,0,16,10,49,0,57,49,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,97,0, +18,110,0,16,10,50,0,57,49,20,0,0,1,90,95,0,0,14,0,2,22,1,1,0,0,14,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1, +9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,98,0,49,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,98,0,49,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,98,0,49,20,0,0,1,90,95,0,0,15,0,2,26,1,1,0, +0,9,0,97,0,0,1,1,0,0,15,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,97,0,18, +110,0,16,8,48,0,57,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,97,0,18,110,0,16,10, +49,0,57,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,97,0,18,110,0,16,10,50,0,57,46, +20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,18,97,0,18,110,0,16,10,51,0,57,46,20,0,0,1, +90,95,0,0,15,0,2,26,1,1,0,0,15,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0, +16,8,48,0,57,18,109,0,16,8,48,0,57,18,98,0,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0, +57,18,109,0,16,10,49,0,57,18,98,0,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109, +0,16,10,50,0,57,18,98,0,46,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,18,109,0,16,10,51, +0,57,18,98,0,46,20,0,0,1,90,95,0,0,15,0,2,27,1,1,0,0,9,0,97,0,0,1,1,0,0,15,0,110,0,0,0,1,9,18,95, +95,114,101,116,86,97,108,0,16,8,48,0,57,18,97,0,18,110,0,16,8,48,0,57,47,20,0,9,18,95,95,114,101, +116,86,97,108,0,16,10,49,0,57,18,97,0,18,110,0,16,10,49,0,57,47,20,0,9,18,95,95,114,101,116,86,97, +108,0,16,10,50,0,57,18,97,0,18,110,0,16,10,50,0,57,47,20,0,9,18,95,95,114,101,116,86,97,108,0,16, +10,51,0,57,18,97,0,18,110,0,16,10,51,0,57,47,20,0,0,1,90,95,0,0,15,0,2,27,1,1,0,0,15,0,109,0,0,1,1, +0,0,9,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,98,0, +47,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,98,0,47,20,0,9, +18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,98,0,47,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,51,0,57,18,109,0,16,10,51,0,57,18,98,0,47,20,0,0,1,90,95,0,0,15,0,2, +21,1,1,0,0,9,0,97,0,0,1,1,0,0,15,0,110,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18, +97,0,18,110,0,16,8,48,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,97,0,18,110, +0,16,10,49,0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,97,0,18,110,0,16,10,50, +0,57,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,18,97,0,18,110,0,16,10,51,0,57,48,20, +0,0,1,90,95,0,0,15,0,2,21,1,1,0,0,15,0,109,0,0,1,1,0,0,9,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97, +108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,98,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10, +49,0,57,18,109,0,16,10,49,0,57,18,98,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18, +109,0,16,10,50,0,57,18,98,0,48,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,51,0,57,18,109,0,16, +10,51,0,57,18,98,0,48,20,0,0,1,90,95,0,0,15,0,2,22,1,1,0,0,9,0,97,0,0,1,1,0,0,15,0,110,0,0,0,1,9, +18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,97,0,18,110,0,16,8,48,0,57,49,20,0,9,18,95,95,114, +101,116,86,97,108,0,16,10,49,0,57,18,97,0,18,110,0,16,10,49,0,57,49,20,0,9,18,95,95,114,101,116,86, +97,108,0,16,10,50,0,57,18,97,0,18,110,0,16,10,50,0,57,49,20,0,9,18,95,95,114,101,116,86,97,108,0, +16,10,51,0,57,18,97,0,18,110,0,16,10,51,0,57,49,20,0,0,1,90,95,0,0,15,0,2,22,1,1,0,0,15,0,109,0,0, +1,1,0,0,9,0,98,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,98, +0,49,20,0,9,18,95,95,114,101,116,86,97,108,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,98,0,49,20,0, +9,18,95,95,114,101,116,86,97,108,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,98,0,49,20,0,9,18,95,95, +114,101,116,86,97,108,0,16,10,51,0,57,18,109,0,16,10,51,0,57,18,98,0,49,20,0,0,1,90,95,0,0,10,0,2, +21,1,1,0,0,13,0,109,0,0,1,1,0,0,10,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,109,0,16,8, +48,0,57,18,118,0,59,120,120,0,48,18,109,0,16,10,49,0,57,18,118,0,59,121,121,0,48,46,20,0,0,1,90,95, +0,0,10,0,2,21,1,1,0,0,10,0,118,0,0,1,1,0,0,13,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59, +120,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,8,48,0,57,0,0,20,0,9,18,95,95,114,101,116,86,97, +108,0,59,121,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10,49,0,57,0,0,20,0,0,1,90,95,0,0,11,0,2, +21,1,1,0,0,14,0,109,0,0,1,1,0,0,11,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,109,0,16,8, +48,0,57,18,118,0,59,120,120,120,0,48,18,109,0,16,10,49,0,57,18,118,0,59,121,121,121,0,48,46,18,109, +0,16,10,50,0,57,18,118,0,59,122,122,122,0,48,46,20,0,0,1,90,95,0,0,11,0,2,21,1,1,0,0,11,0,118,0,0, +1,1,0,0,14,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,59,120,0,58,100,111,116,0,0,18,118,0,0, +18,109,0,16,8,48,0,57,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,121,0,58,100,111,116,0,0,18, +118,0,0,18,109,0,16,10,49,0,57,0,0,20,0,9,18,95,95,114,101,116,86,97,108,0,59,122,0,58,100,111,116, +0,0,18,118,0,0,18,109,0,16,10,50,0,57,0,0,20,0,0,1,90,95,0,0,12,0,2,21,1,1,0,0,15,0,109,0,0,1,1,0, +0,12,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,109,0,16,8,48,0,57,18,118,0,59,120,120, +120,120,0,48,18,109,0,16,10,49,0,57,18,118,0,59,121,121,121,121,0,48,46,18,109,0,16,10,50,0,57,18, +118,0,59,122,122,122,122,0,48,46,18,109,0,16,10,51,0,57,18,118,0,59,119,119,119,119,0,48,46,20,0,0, +1,90,95,0,0,12,0,2,21,1,1,0,0,12,0,118,0,0,1,1,0,0,15,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97, +108,0,59,120,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,8,48,0,57,0,0,20,0,9,18,95,95,114,101,116, +86,97,108,0,59,121,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10,49,0,57,0,0,20,0,9,18,95,95,114, +101,116,86,97,108,0,59,122,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10,50,0,57,0,0,20,0,9,18,95, +95,114,101,116,86,97,108,0,59,119,0,58,100,111,116,0,0,18,118,0,0,18,109,0,16,10,51,0,57,0,0,20,0, +0,1,90,95,0,0,13,0,2,1,1,0,2,0,13,0,109,0,0,1,1,0,0,13,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18, +109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,46,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57, +18,110,0,16,10,49,0,57,46,20,0,8,18,109,0,0,0,1,90,95,0,0,13,0,2,2,1,0,2,0,13,0,109,0,0,1,1,0,0,13, +0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,47,20,0,9,18,109, +0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,47,20,0,8,18,109,0,0,0,1,90,95,0,0, +13,0,2,3,1,0,2,0,13,0,109,0,0,1,1,0,0,13,0,110,0,0,0,1,9,18,109,0,18,109,0,18,110,0,48,20,0,8,18, +109,0,0,0,1,90,95,0,0,13,0,2,4,1,0,2,0,13,0,109,0,0,1,1,0,0,13,0,110,0,0,0,1,9,18,109,0,16,8,48,0, +57,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,49,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49, +0,57,18,110,0,16,10,49,0,57,49,20,0,8,18,109,0,0,0,1,90,95,0,0,14,0,2,1,1,0,2,0,14,0,109,0,0,1,1,0, +0,14,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,46,20,0,9, +18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,46,20,0,9,18,109,0,16,10,50,0, +57,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,46,20,0,8,18,109,0,0,0,1,90,95,0,0,14,0,2,2,1,0,2, +0,14,0,109,0,0,1,1,0,0,14,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,110,0,16, +8,48,0,57,47,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,47,20,0,9, +18,109,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,47,20,0,8,18,109,0,0,0,1,90, +95,0,0,14,0,2,3,1,0,2,0,14,0,109,0,0,1,1,0,0,14,0,110,0,0,0,1,9,18,109,0,18,109,0,18,110,0,48,20,0, +8,18,109,0,0,0,1,90,95,0,0,14,0,2,4,1,0,2,0,14,0,109,0,0,1,1,0,0,14,0,110,0,0,0,1,9,18,109,0,16,8, +48,0,57,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,49,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16, +10,49,0,57,18,110,0,16,10,49,0,57,49,20,0,9,18,109,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,110,0, +16,10,50,0,57,49,20,0,8,18,109,0,0,0,1,90,95,0,0,15,0,2,1,1,0,2,0,15,0,109,0,0,1,1,0,0,15,0,110,0, +0,0,1,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,46,20,0,9,18,109,0,16,10, +49,0,57,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,46,20,0,9,18,109,0,16,10,50,0,57,18,109,0,16, +10,50,0,57,18,110,0,16,10,50,0,57,46,20,0,9,18,109,0,16,10,51,0,57,18,109,0,16,10,51,0,57,18,110,0, +16,10,51,0,57,46,20,0,8,18,109,0,0,0,1,90,95,0,0,15,0,2,2,1,0,2,0,15,0,109,0,0,1,1,0,0,15,0,110,0, +0,0,1,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,47,20,0,9,18,109,0,16,10, +49,0,57,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,47,20,0,9,18,109,0,16,10,50,0,57,18,109,0,16, +10,50,0,57,18,110,0,16,10,50,0,57,47,20,0,9,18,109,0,16,10,51,0,57,18,109,0,16,10,51,0,57,18,110,0, +16,10,51,0,57,47,20,0,8,18,109,0,0,0,1,90,95,0,0,15,0,2,3,1,0,2,0,15,0,109,0,0,1,1,0,0,15,0,110,0, +0,0,1,9,18,109,0,18,109,0,18,110,0,48,20,0,8,18,109,0,0,0,1,90,95,0,0,15,0,2,4,1,0,2,0,15,0,109,0, +0,1,1,0,0,15,0,110,0,0,0,1,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,110,0,16,8,48,0,57,49, +20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,110,0,16,10,49,0,57,49,20,0,9,18,109,0,16, +10,50,0,57,18,109,0,16,10,50,0,57,18,110,0,16,10,50,0,57,49,20,0,9,18,109,0,16,10,51,0,57,18,109,0, +16,10,51,0,57,18,110,0,16,10,51,0,57,49,20,0,8,18,109,0,0,0,1,90,95,0,0,13,0,2,1,1,0,2,0,13,0,109, +0,0,1,1,0,0,9,0,97,0,0,0,1,3,2,90,95,0,0,10,0,1,118,0,2,58,118,101,99,50,0,0,18,97,0,0,0,0,0,9,18, +109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,118,0,46,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10, +49,0,57,18,118,0,46,20,0,8,18,109,0,0,0,1,90,95,0,0,13,0,2,2,1,0,2,0,13,0,109,0,0,1,1,0,0,9,0,97,0, +0,0,1,3,2,90,95,0,0,10,0,1,118,0,2,58,118,101,99,50,0,0,18,97,0,0,0,0,0,9,18,109,0,16,8,48,0,57,18, +109,0,16,8,48,0,57,18,118,0,47,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,118,0,47,20, +0,8,18,109,0,0,0,1,90,95,0,0,13,0,2,3,1,0,2,0,13,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,3,2,90,95,0,0,10, +0,1,118,0,2,58,118,101,99,50,0,0,18,97,0,0,0,0,0,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18, +118,0,48,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,118,0,48,20,0,8,18,109,0,0,0,1,90, +95,0,0,13,0,2,4,1,0,2,0,13,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,3,2,90,95,0,0,10,0,1,118,0,2,58,118, +101,99,50,0,0,17,49,0,48,0,0,18,97,0,49,0,0,0,0,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18, +118,0,48,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,118,0,48,20,0,8,18,109,0,0,0,1,90, +95,0,0,14,0,2,1,1,0,2,0,14,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,3,2,90,95,0,0,11,0,1,118,0,2,58,118, +101,99,51,0,0,18,97,0,0,0,0,0,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,118,0,46,20,0,9,18, +109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,118,0,46,20,0,9,18,109,0,16,10,50,0,57,18,109,0,16, +10,50,0,57,18,118,0,46,20,0,8,18,109,0,0,0,1,90,95,0,0,14,0,2,2,1,0,2,0,14,0,109,0,0,1,1,0,0,9,0, +97,0,0,0,1,3,2,90,95,0,0,11,0,1,118,0,2,58,118,101,99,51,0,0,18,97,0,0,0,0,0,9,18,109,0,16,8,48,0, +57,18,109,0,16,8,48,0,57,18,118,0,47,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,118,0, +47,20,0,9,18,109,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,118,0,47,20,0,8,18,109,0,0,0,1,90,95,0, +0,14,0,2,3,1,0,2,0,14,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,3,2,90,95,0,0,11,0,1,118,0,2,58,118,101,99, +51,0,0,18,97,0,0,0,0,0,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,118,0,48,20,0,9,18,109,0, +16,10,49,0,57,18,109,0,16,10,49,0,57,18,118,0,48,20,0,9,18,109,0,16,10,50,0,57,18,109,0,16,10,50,0, +57,18,118,0,48,20,0,8,18,109,0,0,0,1,90,95,0,0,14,0,2,4,1,0,2,0,14,0,109,0,0,1,1,0,0,9,0,97,0,0,0, +1,3,2,90,95,0,0,11,0,1,118,0,2,58,118,101,99,51,0,0,17,49,0,48,0,0,18,97,0,49,0,0,0,0,9,18,109,0, +16,8,48,0,57,18,109,0,16,8,48,0,57,18,118,0,48,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0, +57,18,118,0,48,20,0,9,18,109,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,118,0,48,20,0,8,18,109,0,0, +0,1,90,95,0,0,15,0,2,1,1,0,2,0,15,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,3,2,90,95,0,0,12,0,1,118,0,2,58, +118,101,99,52,0,0,18,97,0,0,0,0,0,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,118,0,46,20,0,9, +18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,118,0,46,20,0,9,18,109,0,16,10,50,0,57,18,109,0, +16,10,50,0,57,18,118,0,46,20,0,9,18,109,0,16,10,51,0,57,18,109,0,16,10,51,0,57,18,118,0,46,20,0,8, +18,109,0,0,0,1,90,95,0,0,15,0,2,2,1,0,2,0,15,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,3,2,90,95,0,0,12,0,1, +118,0,2,58,118,101,99,52,0,0,18,97,0,0,0,0,0,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,18,118, +0,47,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,118,0,47,20,0,9,18,109,0,16,10,50,0, +57,18,109,0,16,10,50,0,57,18,118,0,47,20,0,9,18,109,0,16,10,51,0,57,18,109,0,16,10,51,0,57,18,118, +0,47,20,0,8,18,109,0,0,0,1,90,95,0,0,15,0,2,3,1,0,2,0,15,0,109,0,0,1,1,0,0,9,0,97,0,0,0,1,3,2,90, +95,0,0,12,0,1,118,0,2,58,118,101,99,52,0,0,18,97,0,0,0,0,0,9,18,109,0,16,8,48,0,57,18,109,0,16,8, +48,0,57,18,118,0,48,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,18,118,0,48,20,0,9,18,109, +0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,118,0,48,20,0,9,18,109,0,16,10,51,0,57,18,109,0,16,10,51, +0,57,18,118,0,48,20,0,8,18,109,0,0,0,1,90,95,0,0,15,0,2,4,1,0,2,0,15,0,109,0,0,1,1,0,0,9,0,97,0,0, +0,1,3,2,90,95,0,0,12,0,1,118,0,2,58,118,101,99,52,0,0,17,49,0,48,0,0,18,97,0,49,0,0,0,0,9,18,109,0, +16,8,48,0,57,18,109,0,16,8,48,0,57,18,118,0,48,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0, +57,18,118,0,48,20,0,9,18,109,0,16,10,50,0,57,18,109,0,16,10,50,0,57,18,118,0,48,20,0,9,18,109,0,16, +10,51,0,57,18,109,0,16,10,51,0,57,18,118,0,48,20,0,8,18,109,0,0,0,1,90,95,0,0,10,0,2,3,1,0,2,0,10, +0,118,0,0,1,1,0,0,13,0,109,0,0,0,1,9,18,118,0,18,118,0,18,109,0,48,20,0,8,18,118,0,0,0,1,90,95,0,0, +11,0,2,3,1,0,2,0,11,0,118,0,0,1,1,0,0,14,0,109,0,0,0,1,9,18,118,0,18,118,0,18,109,0,48,20,0,8,18, +118,0,0,0,1,90,95,0,0,12,0,2,3,1,0,2,0,12,0,118,0,0,1,1,0,0,15,0,109,0,0,0,1,9,18,118,0,18,118,0, +18,109,0,48,20,0,8,18,118,0,0,0,1,90,95,0,0,5,0,2,25,1,0,2,0,5,0,97,0,0,0,1,9,18,97,0,18,97,0,16, +10,49,0,47,20,0,9,18,95,95,114,101,116,86,97,108,0,18,97,0,20,0,0,1,90,95,0,0,6,0,2,25,1,0,2,0,6,0, +118,0,0,0,1,9,18,118,0,18,118,0,58,105,118,101,99,50,0,0,16,10,49,0,0,0,47,20,0,9,18,95,95,114,101, +116,86,97,108,0,18,118,0,20,0,0,1,90,95,0,0,7,0,2,25,1,0,2,0,7,0,118,0,0,0,1,9,18,118,0,18,118,0, +58,105,118,101,99,51,0,0,16,10,49,0,0,0,47,20,0,9,18,95,95,114,101,116,86,97,108,0,18,118,0,20,0,0, +1,90,95,0,0,8,0,2,25,1,0,2,0,8,0,118,0,0,0,1,9,18,118,0,18,118,0,58,105,118,101,99,52,0,0,16,10,49, +0,0,0,47,20,0,9,18,95,95,114,101,116,86,97,108,0,18,118,0,20,0,0,1,90,95,0,0,9,0,2,25,1,0,2,0,9,0, +97,0,0,0,1,9,18,97,0,18,97,0,17,49,0,48,0,0,47,20,0,9,18,95,95,114,101,116,86,97,108,0,18,97,0,20, +0,0,1,90,95,0,0,10,0,2,25,1,0,2,0,10,0,118,0,0,0,1,9,18,118,0,18,118,0,58,118,101,99,50,0,0,17,49, +0,48,0,0,0,0,47,20,0,9,18,95,95,114,101,116,86,97,108,0,18,118,0,20,0,0,1,90,95,0,0,11,0,2,25,1,0, +2,0,11,0,118,0,0,0,1,9,18,118,0,18,118,0,58,118,101,99,51,0,0,17,49,0,48,0,0,0,0,47,20,0,9,18,95, +95,114,101,116,86,97,108,0,18,118,0,20,0,0,1,90,95,0,0,12,0,2,25,1,0,2,0,12,0,118,0,0,0,1,9,18,118, +0,18,118,0,58,118,101,99,52,0,0,17,49,0,48,0,0,0,0,47,20,0,9,18,95,95,114,101,116,86,97,108,0,18, +118,0,20,0,0,1,90,95,0,0,13,0,2,25,1,0,2,0,13,0,109,0,0,0,1,9,18,109,0,16,8,48,0,57,18,109,0,16,8, +48,0,57,58,118,101,99,50,0,0,17,49,0,48,0,0,0,0,47,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49, +0,57,58,118,101,99,50,0,0,17,49,0,48,0,0,0,0,47,20,0,9,18,95,95,114,101,116,86,97,108,0,18,109,0, +20,0,0,1,90,95,0,0,14,0,2,25,1,0,2,0,14,0,109,0,0,0,1,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0, +57,58,118,101,99,51,0,0,17,49,0,48,0,0,0,0,47,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57, +58,118,101,99,51,0,0,17,49,0,48,0,0,0,0,47,20,0,9,18,109,0,16,10,50,0,57,18,109,0,16,10,50,0,57,58, +118,101,99,51,0,0,17,49,0,48,0,0,0,0,47,20,0,9,18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,0,1, +90,95,0,0,15,0,2,25,1,0,2,0,15,0,109,0,0,0,1,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,58,118, +101,99,52,0,0,17,49,0,48,0,0,0,0,47,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,58,118, +101,99,52,0,0,17,49,0,48,0,0,0,0,47,20,0,9,18,109,0,16,10,50,0,57,18,109,0,16,10,50,0,57,58,118, +101,99,52,0,0,17,49,0,48,0,0,0,0,47,20,0,9,18,109,0,16,10,51,0,57,18,109,0,16,10,51,0,57,58,118, +101,99,52,0,0,17,49,0,48,0,0,0,0,47,20,0,9,18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,0,1,90, +95,0,0,5,0,2,24,1,0,2,0,5,0,97,0,0,0,1,9,18,97,0,18,97,0,16,10,49,0,46,20,0,9,18,95,95,114,101,116, +86,97,108,0,18,97,0,20,0,0,1,90,95,0,0,6,0,2,24,1,0,2,0,6,0,118,0,0,0,1,9,18,118,0,18,118,0,58,105, +118,101,99,50,0,0,16,10,49,0,0,0,46,20,0,9,18,95,95,114,101,116,86,97,108,0,18,118,0,20,0,0,1,90, +95,0,0,7,0,2,24,1,0,2,0,7,0,118,0,0,0,1,9,18,118,0,18,118,0,58,105,118,101,99,51,0,0,16,10,49,0,0, +0,46,20,0,9,18,95,95,114,101,116,86,97,108,0,18,118,0,20,0,0,1,90,95,0,0,8,0,2,24,1,0,2,0,8,0,118, +0,0,0,1,9,18,118,0,18,118,0,58,105,118,101,99,52,0,0,16,10,49,0,0,0,46,20,0,9,18,95,95,114,101,116, +86,97,108,0,18,118,0,20,0,0,1,90,95,0,0,9,0,2,24,1,0,2,0,9,0,97,0,0,0,1,9,18,97,0,18,97,0,17,49,0, +48,0,0,46,20,0,9,18,95,95,114,101,116,86,97,108,0,18,97,0,20,0,0,1,90,95,0,0,10,0,2,24,1,0,2,0,10, +0,118,0,0,0,1,9,18,118,0,18,118,0,58,118,101,99,50,0,0,17,49,0,48,0,0,0,0,46,20,0,9,18,95,95,114, +101,116,86,97,108,0,18,118,0,20,0,0,1,90,95,0,0,11,0,2,24,1,0,2,0,11,0,118,0,0,0,1,9,18,118,0,18, +118,0,58,118,101,99,51,0,0,17,49,0,48,0,0,0,0,46,20,0,9,18,95,95,114,101,116,86,97,108,0,18,118,0, +20,0,0,1,90,95,0,0,12,0,2,24,1,0,2,0,12,0,118,0,0,0,1,9,18,118,0,18,118,0,58,118,101,99,52,0,0,17, +49,0,48,0,0,0,0,46,20,0,9,18,95,95,114,101,116,86,97,108,0,18,118,0,20,0,0,1,90,95,0,0,13,0,2,24,1, +0,2,0,13,0,109,0,0,0,1,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,58,118,101,99,50,0,0,17,49,0, +48,0,0,0,0,46,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,58,118,101,99,50,0,0,17,49,0,48, +0,0,0,0,46,20,0,9,18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,0,1,90,95,0,0,14,0,2,24,1,0,2,0, +14,0,109,0,0,0,1,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,58,118,101,99,51,0,0,17,49,0,48,0,0, +0,0,46,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,58,118,101,99,51,0,0,17,49,0,48,0,0,0, +0,46,20,0,9,18,109,0,16,10,50,0,57,18,109,0,16,10,50,0,57,58,118,101,99,51,0,0,17,49,0,48,0,0,0,0, +46,20,0,9,18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,0,1,90,95,0,0,15,0,2,24,1,0,2,0,15,0,109, +0,0,0,1,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,58,118,101,99,52,0,0,17,49,0,48,0,0,0,0,46, +20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,58,118,101,99,52,0,0,17,49,0,48,0,0,0,0,46,20, +0,9,18,109,0,16,10,50,0,57,18,109,0,16,10,50,0,57,58,118,101,99,52,0,0,17,49,0,48,0,0,0,0,46,20,0, +9,18,109,0,16,10,51,0,57,18,109,0,16,10,51,0,57,58,118,101,99,52,0,0,17,49,0,48,0,0,0,0,46,20,0,9, +18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,0,1,90,95,0,0,5,0,0,95,95,112,111,115,116,68,101,99, +114,0,1,0,2,0,5,0,97,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,97,0,20,0,9,18,97,0,18,97,0,16, +10,49,0,47,20,0,0,1,90,95,0,0,6,0,0,95,95,112,111,115,116,68,101,99,114,0,1,0,2,0,6,0,118,0,0,0,1, +9,18,95,95,114,101,116,86,97,108,0,18,118,0,20,0,9,18,118,0,18,118,0,58,105,118,101,99,50,0,0,16, +10,49,0,0,0,47,20,0,0,1,90,95,0,0,7,0,0,95,95,112,111,115,116,68,101,99,114,0,1,0,2,0,7,0,118,0,0, +0,1,9,18,95,95,114,101,116,86,97,108,0,18,118,0,20,0,9,18,118,0,18,118,0,58,105,118,101,99,51,0,0, +16,10,49,0,0,0,47,20,0,0,1,90,95,0,0,8,0,0,95,95,112,111,115,116,68,101,99,114,0,1,0,2,0,8,0,118,0, +0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,118,0,20,0,9,18,118,0,18,118,0,58,105,118,101,99,52,0, +0,16,10,49,0,0,0,47,20,0,0,1,90,95,0,0,9,0,0,95,95,112,111,115,116,68,101,99,114,0,1,0,2,0,9,0,97, +0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,97,0,20,0,9,18,97,0,18,97,0,17,49,0,48,0,0,47,20,0,0, +1,90,95,0,0,10,0,0,95,95,112,111,115,116,68,101,99,114,0,1,0,2,0,10,0,118,0,0,0,1,9,18,95,95,114, +101,116,86,97,108,0,18,118,0,20,0,9,18,118,0,18,118,0,58,118,101,99,50,0,0,17,49,0,48,0,0,0,0,47, +20,0,0,1,90,95,0,0,11,0,0,95,95,112,111,115,116,68,101,99,114,0,1,0,2,0,11,0,118,0,0,0,1,9,18,95, +95,114,101,116,86,97,108,0,18,118,0,20,0,9,18,118,0,18,118,0,58,118,101,99,51,0,0,17,49,0,48,0,0,0, +0,47,20,0,0,1,90,95,0,0,12,0,0,95,95,112,111,115,116,68,101,99,114,0,1,0,2,0,12,0,118,0,0,0,1,9,18, +95,95,114,101,116,86,97,108,0,18,118,0,20,0,9,18,118,0,18,118,0,58,118,101,99,52,0,0,17,49,0,48,0, +0,0,0,47,20,0,0,1,90,95,0,0,13,0,0,95,95,112,111,115,116,68,101,99,114,0,1,0,2,0,13,0,109,0,0,0,1, +9,18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,58, +118,101,99,50,0,0,17,49,0,48,0,0,0,0,47,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,58, +118,101,99,50,0,0,17,49,0,48,0,0,0,0,47,20,0,0,1,90,95,0,0,14,0,0,95,95,112,111,115,116,68,101,99, +114,0,1,0,2,0,14,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,109,0,20,0,9,18,109,0,16,8,48, +0,57,18,109,0,16,8,48,0,57,58,118,101,99,51,0,0,17,49,0,48,0,0,0,0,47,20,0,9,18,109,0,16,10,49,0, +57,18,109,0,16,10,49,0,57,58,118,101,99,51,0,0,17,49,0,48,0,0,0,0,47,20,0,9,18,109,0,16,10,50,0,57, +18,109,0,16,10,50,0,57,58,118,101,99,51,0,0,17,49,0,48,0,0,0,0,47,20,0,0,1,90,95,0,0,15,0,0,95,95, +112,111,115,116,68,101,99,114,0,1,0,2,0,15,0,109,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,109, +0,20,0,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,58,118,101,99,52,0,0,17,49,0,48,0,0,0,0,47,20, +0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,58,118,101,99,52,0,0,17,49,0,48,0,0,0,0,47,20,0, +9,18,109,0,16,10,50,0,57,18,109,0,16,10,50,0,57,58,118,101,99,52,0,0,17,49,0,48,0,0,0,0,47,20,0,9, +18,109,0,16,10,51,0,57,18,109,0,16,10,51,0,57,58,118,101,99,52,0,0,17,49,0,48,0,0,0,0,47,20,0,0,1, +90,95,0,0,9,0,0,95,95,112,111,115,116,73,110,99,114,0,1,0,2,0,9,0,97,0,0,0,1,9,18,95,95,114,101, +116,86,97,108,0,18,97,0,20,0,9,18,97,0,18,97,0,16,10,49,0,46,20,0,0,1,90,95,0,0,10,0,0,95,95,112, +111,115,116,73,110,99,114,0,1,0,2,0,10,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,118,0, +20,0,9,18,118,0,18,118,0,58,118,101,99,50,0,0,17,49,0,48,0,0,0,0,46,20,0,0,1,90,95,0,0,11,0,0,95, +95,112,111,115,116,73,110,99,114,0,1,0,2,0,11,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18, +118,0,20,0,9,18,118,0,18,118,0,58,118,101,99,51,0,0,17,49,0,48,0,0,0,0,46,20,0,0,1,90,95,0,0,12,0, +0,95,95,112,111,115,116,73,110,99,114,0,1,0,2,0,12,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108, +0,18,118,0,20,0,9,18,118,0,18,118,0,58,118,101,99,52,0,0,17,49,0,48,0,0,0,0,46,20,0,0,1,90,95,0,0, +5,0,0,95,95,112,111,115,116,73,110,99,114,0,1,0,2,0,5,0,97,0,0,0,1,9,18,95,95,114,101,116,86,97, +108,0,18,97,0,20,0,9,18,97,0,18,97,0,16,10,49,0,46,20,0,0,1,90,95,0,0,6,0,0,95,95,112,111,115,116, +73,110,99,114,0,1,0,2,0,6,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,118,0,20,0,9,18,118, +0,18,118,0,58,105,118,101,99,50,0,0,16,10,49,0,0,0,46,20,0,0,1,90,95,0,0,7,0,0,95,95,112,111,115, +116,73,110,99,114,0,1,0,2,0,7,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,118,0,20,0,9,18, +118,0,18,118,0,58,105,118,101,99,51,0,0,16,10,49,0,0,0,46,20,0,0,1,90,95,0,0,8,0,0,95,95,112,111, +115,116,73,110,99,114,0,1,0,2,0,8,0,118,0,0,0,1,9,18,95,95,114,101,116,86,97,108,0,18,118,0,20,0,9, +18,118,0,18,118,0,58,105,118,101,99,51,0,0,16,10,49,0,0,0,46,20,0,0,1,90,95,0,0,13,0,0,95,95,112, +111,115,116,73,110,99,114,0,1,0,2,0,13,0,109,0,0,0,1,3,2,90,95,0,0,13,0,1,110,0,2,18,109,0,0,0,9, +18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,58,118,101,99,50,0,0,17,49,0,48,0,0,0,0,46,20,0,9,18, +109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,58,118,101,99,50,0,0,17,49,0,48,0,0,0,0,46,20,0,8,18, +110,0,0,0,1,90,95,0,0,14,0,0,95,95,112,111,115,116,73,110,99,114,0,1,0,2,0,14,0,109,0,0,0,1,3,2,90, +95,0,0,14,0,1,110,0,2,18,109,0,0,0,9,18,109,0,16,8,48,0,57,18,109,0,16,8,48,0,57,58,118,101,99,51, +0,0,17,49,0,48,0,0,0,0,46,20,0,9,18,109,0,16,10,49,0,57,18,109,0,16,10,49,0,57,58,118,101,99,51,0, +0,17,49,0,48,0,0,0,0,46,20,0,9,18,109,0,16,10,50,0,57,18,109,0,16,10,50,0,57,58,118,101,99,51,0,0, +17,49,0,48,0,0,0,0,46,20,0,8,18,110,0,0,0,1,90,95,0,0,15,0,0,95,95,112,111,115,116,73,110,99,114,0, +1,0,2,0,15,0,109,0,0,0,1,3,2,90,95,0,0,15,0,1,110,0,2,18,109,0,0,0,9,18,109,0,16,8,48,0,57,18,109, +0,16,8,48,0,57,58,118,101,99,52,0,0,17,49,0,48,0,0,0,0,46,20,0,9,18,109,0,16,10,49,0,57,18,109,0, +16,10,49,0,57,58,118,101,99,52,0,0,17,49,0,48,0,0,0,0,46,20,0,9,18,109,0,16,10,50,0,57,18,109,0,16, +10,50,0,57,58,118,101,99,52,0,0,17,49,0,48,0,0,0,0,46,20,0,9,18,109,0,16,10,51,0,57,18,109,0,16,10, +51,0,57,58,118,101,99,52,0,0,17,49,0,48,0,0,0,0,46,20,0,8,18,110,0,0,0,1,90,95,0,0,1,0,2,15,1,1,0, +0,9,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,4,118,101,99,52,95,115,103,116,0,18,95,95,114,101,116,86,97, +108,0,59,120,0,0,18,98,0,0,18,97,0,0,0,0,1,90,95,0,0,1,0,2,15,1,1,0,0,5,0,97,0,0,1,1,0,0,5,0,98,0, +0,0,1,8,58,102,108,111,97,116,0,0,18,97,0,0,0,58,102,108,111,97,116,0,0,18,98,0,0,0,40,0,0,1,90,95, +0,0,1,0,2,16,1,1,0,0,9,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,3,2,90,95,0,0,1,0,1,99,0,0,0,4,102,108,111, +97,116,95,108,101,115,115,0,18,99,0,0,18,98,0,0,18,97,0,0,0,8,18,99,0,0,0,1,90,95,0,0,1,0,2,16,1,1, +0,0,5,0,97,0,0,1,1,0,0,5,0,98,0,0,0,1,8,58,102,108,111,97,116,0,0,18,97,0,0,0,58,102,108,111,97, +116,0,0,18,98,0,0,0,41,0,0,1,90,95,0,0,1,0,2,18,1,1,0,0,9,0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,3,2,90, +95,0,0,1,0,1,103,0,0,1,1,101,0,0,0,4,102,108,111,97,116,95,108,101,115,115,0,18,103,0,0,18,98,0,0, +18,97,0,0,0,4,102,108,111,97,116,95,101,113,117,97,108,0,18,101,0,0,18,97,0,0,18,98,0,0,0,8,18,103, +0,18,101,0,32,0,0,1,90,95,0,0,1,0,2,18,1,1,0,0,5,0,97,0,0,1,1,0,0,5,0,98,0,0,0,1,8,58,102,108,111, +97,116,0,0,18,97,0,0,0,58,102,108,111,97,116,0,0,18,98,0,0,0,43,0,0,1,90,95,0,0,1,0,2,17,1,1,0,0,9, +0,97,0,0,1,1,0,0,9,0,98,0,0,0,1,3,2,90,95,0,0,1,0,1,103,0,0,1,1,101,0,0,0,4,102,108,111,97,116,95, +108,101,115,115,0,18,103,0,0,18,97,0,0,18,98,0,0,0,4,102,108,111,97,116,95,101,113,117,97,108,0,18, +101,0,0,18,97,0,0,18,98,0,0,0,8,18,103,0,18,101,0,32,0,0,1,90,95,0,0,1,0,2,17,1,1,0,0,5,0,97,0,0,1, +1,0,0,5,0,98,0,0,0,1,8,58,102,108,111,97,116,0,0,18,97,0,0,0,58,102,108,111,97,116,0,0,18,98,0,0,0, +42,0,0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,0,9,0,102,0,0,0,1,4,102,108,111, +97,116,95,112,114,105,110,116,0,18,102,0,0,0,0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69,83,65,0, +1,1,0,0,5,0,105,0,0,0,1,4,105,110,116,95,112,114,105,110,116,0,18,105,0,0,0,0,1,90,95,0,0,0,0,0, +112,114,105,110,116,77,69,83,65,0,1,1,0,0,1,0,98,0,0,0,1,4,98,111,111,108,95,112,114,105,110,116,0, +18,98,0,0,0,0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,0,10,0,118,0,0,0,1,9,58, +112,114,105,110,116,77,69,83,65,0,0,18,118,0,59,120,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0, +0,18,118,0,59,121,0,0,0,0,0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,0,11,0,118,0, +0,0,1,9,58,112,114,105,110,116,77,69,83,65,0,0,18,118,0,59,120,0,0,0,0,9,58,112,114,105,110,116,77, +69,83,65,0,0,18,118,0,59,121,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,0,18,118,0,59,122,0,0, +0,0,0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,0,12,0,118,0,0,0,1,9,58,112,114, +105,110,116,77,69,83,65,0,0,18,118,0,59,120,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,0,18, +118,0,59,121,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,0,18,118,0,59,122,0,0,0,0,9,58,112,114, +105,110,116,77,69,83,65,0,0,18,118,0,59,119,0,0,0,0,0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69, +83,65,0,1,1,0,0,6,0,118,0,0,0,1,9,58,112,114,105,110,116,77,69,83,65,0,0,18,118,0,59,120,0,0,0,0,9, +58,112,114,105,110,116,77,69,83,65,0,0,18,118,0,59,121,0,0,0,0,0,1,90,95,0,0,0,0,0,112,114,105,110, +116,77,69,83,65,0,1,1,0,0,7,0,118,0,0,0,1,9,58,112,114,105,110,116,77,69,83,65,0,0,18,118,0,59,120, +0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,0,18,118,0,59,121,0,0,0,0,9,58,112,114,105,110,116, +77,69,83,65,0,0,18,118,0,59,122,0,0,0,0,0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1, +0,0,8,0,118,0,0,0,1,9,58,112,114,105,110,116,77,69,83,65,0,0,18,118,0,59,120,0,0,0,0,9,58,112,114, +105,110,116,77,69,83,65,0,0,18,118,0,59,121,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,0,18, +118,0,59,122,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,0,18,118,0,59,119,0,0,0,0,0,1,90,95,0, +0,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,0,2,0,118,0,0,0,1,9,58,112,114,105,110,116,77,69, +83,65,0,0,18,118,0,59,120,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,0,18,118,0,59,121,0,0,0,0, +0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,0,3,0,118,0,0,0,1,9,58,112,114,105,110, +116,77,69,83,65,0,0,18,118,0,59,120,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,0,18,118,0,59, +121,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,0,18,118,0,59,122,0,0,0,0,0,1,90,95,0,0,0,0,0, +112,114,105,110,116,77,69,83,65,0,1,1,0,0,4,0,118,0,0,0,1,9,58,112,114,105,110,116,77,69,83,65,0,0, +18,118,0,59,120,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,0,18,118,0,59,121,0,0,0,0,9,58,112, +114,105,110,116,77,69,83,65,0,0,18,118,0,59,122,0,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,0, +18,118,0,59,119,0,0,0,0,0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,0,13,0,109,0,0, +0,1,9,58,112,114,105,110,116,77,69,83,65,0,0,18,109,0,16,8,48,0,57,0,0,0,9,58,112,114,105,110,116, +77,69,83,65,0,0,18,109,0,16,10,49,0,57,0,0,0,0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69,83,65,0, +1,1,0,0,14,0,109,0,0,0,1,9,58,112,114,105,110,116,77,69,83,65,0,0,18,109,0,16,8,48,0,57,0,0,0,9,58, +112,114,105,110,116,77,69,83,65,0,0,18,109,0,16,10,49,0,57,0,0,0,9,58,112,114,105,110,116,77,69,83, +65,0,0,18,109,0,16,10,50,0,57,0,0,0,0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,0, +15,0,109,0,0,0,1,9,58,112,114,105,110,116,77,69,83,65,0,0,18,109,0,16,8,48,0,57,0,0,0,9,58,112,114, +105,110,116,77,69,83,65,0,0,18,109,0,16,10,49,0,57,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,0, +18,109,0,16,10,50,0,57,0,0,0,9,58,112,114,105,110,116,77,69,83,65,0,0,18,109,0,16,10,51,0,57,0,0,0, +0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,0,16,0,101,0,0,0,1,4,105,110,116,95, +112,114,105,110,116,0,18,101,0,0,0,0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,0, +17,0,101,0,0,0,1,4,105,110,116,95,112,114,105,110,116,0,18,101,0,0,0,0,1,90,95,0,0,0,0,0,112,114, +105,110,116,77,69,83,65,0,1,1,0,0,18,0,101,0,0,0,1,4,105,110,116,95,112,114,105,110,116,0,18,101,0, +0,0,0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0,0,19,0,101,0,0,0,1,4,105,110,116, +95,112,114,105,110,116,0,18,101,0,0,0,0,1,90,95,0,0,0,0,0,112,114,105,110,116,77,69,83,65,0,1,1,0, +0,20,0,101,0,0,0,1,4,105,110,116,95,112,114,105,110,116,0,18,101,0,0,0,0,1,90,95,0,0,0,0,0,112,114, +105,110,116,77,69,83,65,0,1,1,0,0,21,0,101,0,0,0,1,4,105,110,116,95,112,114,105,110,116,0,18,101,0, +0,0,0,0 diff --git a/mesalib/src/mesa/shader/slang/library/slang_fragment_builtin.gc b/mesalib/src/mesa/shader/slang/library/slang_fragment_builtin.gc new file mode 100644 index 000000000..2e063e641 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_fragment_builtin.gc @@ -0,0 +1,235 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// +// From Shader Spec, ver. 1.10, rev. 59 +// + +__fixed_input vec4 gl_FragCoord; +__fixed_input bool gl_FrontFacing; +__fixed_output vec4 gl_FragColor; +__fixed_output vec4 gl_FragData[gl_MaxDrawBuffers]; +__fixed_output float gl_FragDepth; + +varying vec4 gl_Color; +varying vec4 gl_SecondaryColor; +varying vec4 gl_TexCoord[gl_MaxTextureCoords]; +varying float gl_FogFragCoord; + + + +//// 8.7 Texture Lookup Functions (with bias) + +vec4 texture1D(const sampler1D sampler, const float coord, const float bias) +{ + vec4 coord4; + coord4.x = coord; + coord4.w = bias; + __asm vec4_tex_1d_bias __retVal, sampler, coord4; +} + +vec4 texture1DProj(const sampler1D sampler, const vec2 coord, const float bias) +{ + // do projection here (there's no vec4_texbp1d instruction) + vec4 pcoord; + pcoord.x = coord.x / coord.y; + pcoord.w = bias; + __asm vec4_tex_1d_bias __retVal, sampler, pcoord; +} + +vec4 texture1DProj(const sampler1D sampler, const vec4 coord, const float bias) +{ + // do projection here (there's no vec4_texbp1d instruction) + vec4 pcoord; + pcoord.x = coord.x / coord.z; + pcoord.w = bias; + __asm vec4_tex_1d_bias __retVal, sampler, pcoord; +} + + + + +vec4 texture2D(const sampler2D sampler, const vec2 coord, const float bias) +{ + vec4 coord4; + coord4.xy = coord.xy; + coord4.w = bias; + __asm vec4_tex_2d_bias __retVal, sampler, coord4; +} + +vec4 texture2DProj(const sampler2D sampler, const vec3 coord, const float bias) +{ + // do projection here (there's no vec4_texbp2d instruction) + vec4 pcoord; + pcoord.xy = coord.xy / coord.z; + pcoord.w = bias; + __asm vec4_tex_2d_bias __retVal, sampler, pcoord; +} + +vec4 texture2DProj(const sampler2D sampler, const vec4 coord, const float bias) +{ + // do projection here (there's no vec4_texbp2d instruction) + vec4 pcoord; + pcoord.xy = coord.xy / coord.w; + pcoord.w = bias; + __asm vec4_tex_2d_bias __retVal, sampler, pcoord; +} + + + + +vec4 texture3D(const sampler3D sampler, const vec3 coord, const float bias) +{ + vec4 coord4; + coord4.xyz = coord.xyz; + coord4.w = bias; + __asm vec4_tex_3d_bias __retVal, sampler, coord4; +} + +vec4 texture3DProj(const sampler3D sampler, const vec4 coord, const float bias) +{ + // do projection here (there's no vec4_texbp3d instruction) + vec4 pcoord; + pcoord.xyz = coord.xyz / coord.w; + pcoord.w = bias; + __asm vec4_tex_3d_bias __retVal, sampler, pcoord; +} + + + + +vec4 textureCube(const samplerCube sampler, const vec3 coord, const float bias) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = bias; + __asm vec4_tex_cube __retVal, sampler, coord4; +} + + + +vec4 shadow1D(const sampler1DShadow sampler, const vec3 coord, const float bias) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = bias; + __asm vec4_tex_1d_bias_shadow __retVal, sampler, coord4; +} + +vec4 shadow1DProj(const sampler1DShadow sampler, const vec4 coord, const float bias) +{ + vec4 pcoord; + pcoord.x = coord.x / coord.w; + pcoord.z = coord.z; + pcoord.w = bias; + __asm vec4_tex_1d_bias_shadow __retVal, sampler, pcoord; +} + +vec4 shadow2D(const sampler2DShadow sampler, const vec3 coord, const float bias) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = bias; + __asm vec4_tex_2d_bias_shadow __retVal, sampler, coord4; +} + +vec4 shadow2DProj(const sampler2DShadow sampler, const vec4 coord, const float bias) +{ + vec4 pcoord; + pcoord.xy = coord.xy / coord.w; + pcoord.z = coord.z; + pcoord.w = bias; + __asm vec4_tex_2d_bias_shadow __retVal, sampler, pcoord; +} + + + +// +// 8.8 Fragment Processing Functions +// + +float dFdx(const float p) +{ + __asm vec4_ddx __retVal.x, p.xxxx; +} + +vec2 dFdx(const vec2 p) +{ + __asm vec4_ddx __retVal.xy, p.xyyy; +} + +vec3 dFdx(const vec3 p) +{ + __asm vec4_ddx __retVal.xyz, p.xyzz; +} + +vec4 dFdx(const vec4 p) +{ + __asm vec4_ddx __retVal, p; +} + +float dFdy(const float p) +{ + __asm vec4_ddy __retVal.x, p.xxxx; +} + +vec2 dFdy(const vec2 p) +{ + __asm vec4_ddy __retVal.xy, p.xyyy; +} + +vec3 dFdy(const vec3 p) +{ + __asm vec4_ddy __retVal.xyz, p.xyzz; +} + +vec4 dFdy(const vec4 p) +{ + __asm vec4_ddy __retVal, p; +} + +float fwidth (const float p) +{ + // XXX hand-write with __asm + return abs(dFdx(p)) + abs(dFdy(p)); +} + +vec2 fwidth(const vec2 p) +{ + // XXX hand-write with __asm + return abs(dFdx(p)) + abs(dFdy(p)); +} + +vec3 fwidth(const vec3 p) +{ + // XXX hand-write with __asm + return abs(dFdx(p)) + abs(dFdy(p)); +} + +vec4 fwidth(const vec4 p) +{ + // XXX hand-write with __asm + return abs(dFdx(p)) + abs(dFdy(p)); +} + diff --git a/mesalib/src/mesa/shader/slang/library/slang_fragment_builtin_gc.h b/mesalib/src/mesa/shader/slang/library/slang_fragment_builtin_gc.h new file mode 100644 index 000000000..c5a1cce2a --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_fragment_builtin_gc.h @@ -0,0 +1,110 @@ + +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */ +/* slang_fragment_builtin.gc */ + +5,2,2,90,95,6,0,12,0,1,103,108,95,70,114,97,103,67,111,111,114,100,0,0,0,2,2,90,95,6,0,1,0,1,103, +108,95,70,114,111,110,116,70,97,99,105,110,103,0,0,0,2,2,90,95,5,0,12,0,1,103,108,95,70,114,97,103, +67,111,108,111,114,0,0,0,2,2,90,95,5,0,12,0,1,103,108,95,70,114,97,103,68,97,116,97,0,3,18,103,108, +95,77,97,120,68,114,97,119,66,117,102,102,101,114,115,0,0,0,2,2,90,95,5,0,9,0,1,103,108,95,70,114, +97,103,68,101,112,116,104,0,0,0,2,2,90,95,3,0,12,0,1,103,108,95,67,111,108,111,114,0,0,0,2,2,90,95, +3,0,12,0,1,103,108,95,83,101,99,111,110,100,97,114,121,67,111,108,111,114,0,0,0,2,2,90,95,3,0,12,0, +1,103,108,95,84,101,120,67,111,111,114,100,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114,101, +67,111,111,114,100,115,0,0,0,2,2,90,95,3,0,9,0,1,103,108,95,70,111,103,70,114,97,103,67,111,111, +114,100,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,49,68,0,1,1,0,0,16,0,115,97,109,112, +108,101,114,0,0,1,1,0,0,9,0,99,111,111,114,100,0,0,1,1,0,0,9,0,98,105,97,115,0,0,0,1,3,2,90,95,0,0, +12,0,1,99,111,111,114,100,52,0,0,0,9,18,99,111,111,114,100,52,0,59,120,0,18,99,111,111,114,100,0, +20,0,9,18,99,111,111,114,100,52,0,59,119,0,18,98,105,97,115,0,20,0,4,118,101,99,52,95,116,101,120, +95,49,100,95,98,105,97,115,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0, +18,99,111,111,114,100,52,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,49,68,80,114,111, +106,0,1,1,0,0,16,0,115,97,109,112,108,101,114,0,0,1,1,0,0,10,0,99,111,111,114,100,0,0,1,1,0,0,9,0, +98,105,97,115,0,0,0,1,3,2,90,95,0,0,12,0,1,112,99,111,111,114,100,0,0,0,9,18,112,99,111,111,114, +100,0,59,120,0,18,99,111,111,114,100,0,59,120,0,18,99,111,111,114,100,0,59,121,0,49,20,0,9,18,112, +99,111,111,114,100,0,59,119,0,18,98,105,97,115,0,20,0,4,118,101,99,52,95,116,101,120,95,49,100,95, +98,105,97,115,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,112,99,111, +111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,49,68,80,114,111,106,0,1,1,0,0, +16,0,115,97,109,112,108,101,114,0,0,1,1,0,0,12,0,99,111,111,114,100,0,0,1,1,0,0,9,0,98,105,97,115, +0,0,0,1,3,2,90,95,0,0,12,0,1,112,99,111,111,114,100,0,0,0,9,18,112,99,111,111,114,100,0,59,120,0, +18,99,111,111,114,100,0,59,120,0,18,99,111,111,114,100,0,59,122,0,49,20,0,9,18,112,99,111,111,114, +100,0,59,119,0,18,98,105,97,115,0,20,0,4,118,101,99,52,95,116,101,120,95,49,100,95,98,105,97,115,0, +18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,112,99,111,111,114,100,0,0, +0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,50,68,0,1,1,0,0,17,0,115,97,109,112,108,101,114, +0,0,1,1,0,0,10,0,99,111,111,114,100,0,0,1,1,0,0,9,0,98,105,97,115,0,0,0,1,3,2,90,95,0,0,12,0,1,99, +111,111,114,100,52,0,0,0,9,18,99,111,111,114,100,52,0,59,120,121,0,18,99,111,111,114,100,0,59,120, +121,0,20,0,9,18,99,111,111,114,100,52,0,59,119,0,18,98,105,97,115,0,20,0,4,118,101,99,52,95,116, +101,120,95,50,100,95,98,105,97,115,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101, +114,0,0,18,99,111,111,114,100,52,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,50,68,80, +114,111,106,0,1,1,0,0,17,0,115,97,109,112,108,101,114,0,0,1,1,0,0,11,0,99,111,111,114,100,0,0,1,1, +0,0,9,0,98,105,97,115,0,0,0,1,3,2,90,95,0,0,12,0,1,112,99,111,111,114,100,0,0,0,9,18,112,99,111, +111,114,100,0,59,120,121,0,18,99,111,111,114,100,0,59,120,121,0,18,99,111,111,114,100,0,59,122,0, +49,20,0,9,18,112,99,111,111,114,100,0,59,119,0,18,98,105,97,115,0,20,0,4,118,101,99,52,95,116,101, +120,95,50,100,95,98,105,97,115,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114, +0,0,18,112,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,50,68,80,114, +111,106,0,1,1,0,0,17,0,115,97,109,112,108,101,114,0,0,1,1,0,0,12,0,99,111,111,114,100,0,0,1,1,0,0, +9,0,98,105,97,115,0,0,0,1,3,2,90,95,0,0,12,0,1,112,99,111,111,114,100,0,0,0,9,18,112,99,111,111, +114,100,0,59,120,121,0,18,99,111,111,114,100,0,59,120,121,0,18,99,111,111,114,100,0,59,119,0,49,20, +0,9,18,112,99,111,111,114,100,0,59,119,0,18,98,105,97,115,0,20,0,4,118,101,99,52,95,116,101,120,95, +50,100,95,98,105,97,115,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18, +112,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,51,68,0,1,1,0,0,18,0, +115,97,109,112,108,101,114,0,0,1,1,0,0,11,0,99,111,111,114,100,0,0,1,1,0,0,9,0,98,105,97,115,0,0,0, +1,3,2,90,95,0,0,12,0,1,99,111,111,114,100,52,0,0,0,9,18,99,111,111,114,100,52,0,59,120,121,122,0, +18,99,111,111,114,100,0,59,120,121,122,0,20,0,9,18,99,111,111,114,100,52,0,59,119,0,18,98,105,97, +115,0,20,0,4,118,101,99,52,95,116,101,120,95,51,100,95,98,105,97,115,0,18,95,95,114,101,116,86,97, +108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,52,0,0,0,0,1,90,95,0,0,12,0,0,116, +101,120,116,117,114,101,51,68,80,114,111,106,0,1,1,0,0,18,0,115,97,109,112,108,101,114,0,0,1,1,0,0, +12,0,99,111,111,114,100,0,0,1,1,0,0,9,0,98,105,97,115,0,0,0,1,3,2,90,95,0,0,12,0,1,112,99,111,111, +114,100,0,0,0,9,18,112,99,111,111,114,100,0,59,120,121,122,0,18,99,111,111,114,100,0,59,120,121, +122,0,18,99,111,111,114,100,0,59,119,0,49,20,0,9,18,112,99,111,111,114,100,0,59,119,0,18,98,105,97, +115,0,20,0,4,118,101,99,52,95,116,101,120,95,51,100,95,98,105,97,115,0,18,95,95,114,101,116,86,97, +108,0,0,18,115,97,109,112,108,101,114,0,0,18,112,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,116, +101,120,116,117,114,101,67,117,98,101,0,1,1,0,0,19,0,115,97,109,112,108,101,114,0,0,1,1,0,0,11,0, +99,111,111,114,100,0,0,1,1,0,0,9,0,98,105,97,115,0,0,0,1,3,2,90,95,0,0,12,0,1,99,111,111,114,100, +52,0,0,0,9,18,99,111,111,114,100,52,0,59,120,121,122,0,18,99,111,111,114,100,0,20,0,9,18,99,111, +111,114,100,52,0,59,119,0,18,98,105,97,115,0,20,0,4,118,101,99,52,95,116,101,120,95,99,117,98,101, +0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,52,0, +0,0,0,1,90,95,0,0,12,0,0,115,104,97,100,111,119,49,68,0,1,1,0,0,20,0,115,97,109,112,108,101,114,0, +0,1,1,0,0,11,0,99,111,111,114,100,0,0,1,1,0,0,9,0,98,105,97,115,0,0,0,1,3,2,90,95,0,0,12,0,1,99, +111,111,114,100,52,0,0,0,9,18,99,111,111,114,100,52,0,59,120,121,122,0,18,99,111,111,114,100,0,20, +0,9,18,99,111,111,114,100,52,0,59,119,0,18,98,105,97,115,0,20,0,4,118,101,99,52,95,116,101,120,95, +49,100,95,98,105,97,115,95,115,104,97,100,111,119,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97, +109,112,108,101,114,0,0,18,99,111,111,114,100,52,0,0,0,0,1,90,95,0,0,12,0,0,115,104,97,100,111,119, +49,68,80,114,111,106,0,1,1,0,0,20,0,115,97,109,112,108,101,114,0,0,1,1,0,0,12,0,99,111,111,114,100, +0,0,1,1,0,0,9,0,98,105,97,115,0,0,0,1,3,2,90,95,0,0,12,0,1,112,99,111,111,114,100,0,0,0,9,18,112, +99,111,111,114,100,0,59,120,0,18,99,111,111,114,100,0,59,120,0,18,99,111,111,114,100,0,59,119,0,49, +20,0,9,18,112,99,111,111,114,100,0,59,122,0,18,99,111,111,114,100,0,59,122,0,20,0,9,18,112,99,111, +111,114,100,0,59,119,0,18,98,105,97,115,0,20,0,4,118,101,99,52,95,116,101,120,95,49,100,95,98,105, +97,115,95,115,104,97,100,111,119,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101, +114,0,0,18,112,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,115,104,97,100,111,119,50,68,0,1,1,0, +0,21,0,115,97,109,112,108,101,114,0,0,1,1,0,0,11,0,99,111,111,114,100,0,0,1,1,0,0,9,0,98,105,97, +115,0,0,0,1,3,2,90,95,0,0,12,0,1,99,111,111,114,100,52,0,0,0,9,18,99,111,111,114,100,52,0,59,120, +121,122,0,18,99,111,111,114,100,0,20,0,9,18,99,111,111,114,100,52,0,59,119,0,18,98,105,97,115,0,20, +0,4,118,101,99,52,95,116,101,120,95,50,100,95,98,105,97,115,95,115,104,97,100,111,119,0,18,95,95, +114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,52,0,0,0,0,1,90, +95,0,0,12,0,0,115,104,97,100,111,119,50,68,80,114,111,106,0,1,1,0,0,21,0,115,97,109,112,108,101, +114,0,0,1,1,0,0,12,0,99,111,111,114,100,0,0,1,1,0,0,9,0,98,105,97,115,0,0,0,1,3,2,90,95,0,0,12,0,1, +112,99,111,111,114,100,0,0,0,9,18,112,99,111,111,114,100,0,59,120,121,0,18,99,111,111,114,100,0,59, +120,121,0,18,99,111,111,114,100,0,59,119,0,49,20,0,9,18,112,99,111,111,114,100,0,59,122,0,18,99, +111,111,114,100,0,59,122,0,20,0,9,18,112,99,111,111,114,100,0,59,119,0,18,98,105,97,115,0,20,0,4, +118,101,99,52,95,116,101,120,95,50,100,95,98,105,97,115,95,115,104,97,100,111,119,0,18,95,95,114, +101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,112,99,111,111,114,100,0,0,0,0,1,90,95, +0,0,9,0,0,100,70,100,120,0,1,1,0,0,9,0,112,0,0,0,1,4,118,101,99,52,95,100,100,120,0,18,95,95,114, +101,116,86,97,108,0,59,120,0,0,18,112,0,59,120,120,120,120,0,0,0,0,1,90,95,0,0,10,0,0,100,70,100, +120,0,1,1,0,0,10,0,112,0,0,0,1,4,118,101,99,52,95,100,100,120,0,18,95,95,114,101,116,86,97,108,0, +59,120,121,0,0,18,112,0,59,120,121,121,121,0,0,0,0,1,90,95,0,0,11,0,0,100,70,100,120,0,1,1,0,0,11, +0,112,0,0,0,1,4,118,101,99,52,95,100,100,120,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0, +18,112,0,59,120,121,122,122,0,0,0,0,1,90,95,0,0,12,0,0,100,70,100,120,0,1,1,0,0,12,0,112,0,0,0,1,4, +118,101,99,52,95,100,100,120,0,18,95,95,114,101,116,86,97,108,0,0,18,112,0,0,0,0,1,90,95,0,0,9,0,0, +100,70,100,121,0,1,1,0,0,9,0,112,0,0,0,1,4,118,101,99,52,95,100,100,121,0,18,95,95,114,101,116,86, +97,108,0,59,120,0,0,18,112,0,59,120,120,120,120,0,0,0,0,1,90,95,0,0,10,0,0,100,70,100,121,0,1,1,0, +0,10,0,112,0,0,0,1,4,118,101,99,52,95,100,100,121,0,18,95,95,114,101,116,86,97,108,0,59,120,121,0, +0,18,112,0,59,120,121,121,121,0,0,0,0,1,90,95,0,0,11,0,0,100,70,100,121,0,1,1,0,0,11,0,112,0,0,0,1, +4,118,101,99,52,95,100,100,121,0,18,95,95,114,101,116,86,97,108,0,59,120,121,122,0,0,18,112,0,59, +120,121,122,122,0,0,0,0,1,90,95,0,0,12,0,0,100,70,100,121,0,1,1,0,0,12,0,112,0,0,0,1,4,118,101,99, +52,95,100,100,121,0,18,95,95,114,101,116,86,97,108,0,0,18,112,0,0,0,0,1,90,95,0,0,9,0,0,102,119, +105,100,116,104,0,1,1,0,0,9,0,112,0,0,0,1,8,58,97,98,115,0,0,58,100,70,100,120,0,0,18,112,0,0,0,0, +0,58,97,98,115,0,0,58,100,70,100,121,0,0,18,112,0,0,0,0,0,46,0,0,1,90,95,0,0,10,0,0,102,119,105, +100,116,104,0,1,1,0,0,10,0,112,0,0,0,1,8,58,97,98,115,0,0,58,100,70,100,120,0,0,18,112,0,0,0,0,0, +58,97,98,115,0,0,58,100,70,100,121,0,0,18,112,0,0,0,0,0,46,0,0,1,90,95,0,0,11,0,0,102,119,105,100, +116,104,0,1,1,0,0,11,0,112,0,0,0,1,8,58,97,98,115,0,0,58,100,70,100,120,0,0,18,112,0,0,0,0,0,58,97, +98,115,0,0,58,100,70,100,121,0,0,18,112,0,0,0,0,0,46,0,0,1,90,95,0,0,12,0,0,102,119,105,100,116, +104,0,1,1,0,0,12,0,112,0,0,0,1,8,58,97,98,115,0,0,58,100,70,100,120,0,0,18,112,0,0,0,0,0,58,97,98, +115,0,0,58,100,70,100,121,0,0,18,112,0,0,0,0,0,46,0,0,0 diff --git a/mesalib/src/mesa/shader/slang/library/slang_pp_directives.syn b/mesalib/src/mesa/shader/slang/library/slang_pp_directives.syn new file mode 100644 index 000000000..b51d168cc --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_pp_directives.syn @@ -0,0 +1,405 @@ +/* + * Mesa 3-D graphics library + * Version: 6.6 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_pp_directives.syn + * slang preprocessor directives parser + * \author Michal Krol + */ + +.syntax source; + +/* + * This syntax script preprocesses a GLSL shader. + * It is assumed, that the #version directive has been parsed. Separate pass for parsing + * version gives better control on behavior depending on the version number given. + * + * The output is a source string with comments and directives removed. White spaces and comments + * are replaced with on or more spaces. All new-lines are preserved and converted to Linux format. + * Directives are escaped with a null character. The end of the source string is marked by + * two consecutive null characters. The consumer is responsible for executing the escaped + * directives, removing dead portions of code and expanding macros. + */ + +.emtcode ESCAPE_TOKEN 0 + +/* + * The TOKEN_* symbols follow the ESCAPE_TOKEN. + * + * NOTE: + * There is no TOKEN_IFDEF and neither is TOKEN_IFNDEF. They are handled with TOKEN_IF and + * operator defined. + * The "#ifdef SYMBOL" is replaced with "#if defined SYMBOL" + * The "#ifndef SYMBOL" is replaced with "#if !defined SYMBOL" + */ +.emtcode TOKEN_END 0 +.emtcode TOKEN_DEFINE 1 +.emtcode TOKEN_UNDEF 2 +.emtcode TOKEN_IF 3 +.emtcode TOKEN_ELSE 4 +.emtcode TOKEN_ELIF 5 +.emtcode TOKEN_ENDIF 6 +.emtcode TOKEN_ERROR 7 +.emtcode TOKEN_PRAGMA 8 +.emtcode TOKEN_EXTENSION 9 +.emtcode TOKEN_LINE 10 + +/* + * The PARAM_* symbols follow the TOKEN_DEFINE. + */ +.emtcode PARAM_END 0 +.emtcode PARAM_PARAMETER 1 + +/* + * The BEHAVIOR_* symbols follow the TOKEN_EXTENSION. + */ +.emtcode BEHAVIOR_REQUIRE 1 +.emtcode BEHAVIOR_ENABLE 2 +.emtcode BEHAVIOR_WARN 3 +.emtcode BEHAVIOR_DISABLE 4 + +/* + * The PRAGMA_* symbols follow TOKEN_PRAGMA + */ +.emtcode PRAGMA_NO_PARAM 0 +.emtcode PRAGMA_PARAM 1 + +source + optional_directive .and .loop source_element .and '\0' .emit ESCAPE_TOKEN .emit TOKEN_END; + +source_element + c_style_comment_block .or cpp_style_comment_block .or new_line_directive .or source_token; + +c_style_comment_block + '/' .and '*' .and c_style_comment_rest .and .true .emit ' '; + +c_style_comment_rest + .loop c_style_comment_body .and c_style_comment_end; + +c_style_comment_body + c_style_comment_char_nostar .or c_style_comment_char_star_noslashstar; + +c_style_comment_char_nostar + new_line .or '\x2B'-'\xFF' .or '\x01'-'\x29'; + +c_style_comment_char_star_noslashstar + '*' .and c_style_comment_char_star_noslashstar_1; +c_style_comment_char_star_noslashstar_1 + c_style_comment_char_noslashstar .or c_style_comment_char_star_noslashstar; + +c_style_comment_char_noslashstar + new_line .or '\x30'-'\xFF' .or '\x01'-'\x29' .or '\x2B'-'\x2E'; + +c_style_comment_end + '*' .and .loop c_style_comment_char_star .and '/'; + +c_style_comment_char_star + '*'; + +cpp_style_comment_block + '/' .and '/' .and cpp_style_comment_block_1; +cpp_style_comment_block_1 + cpp_style_comment_block_2 .or cpp_style_comment_block_3; +cpp_style_comment_block_2 + .loop cpp_style_comment_char .and new_line_directive; +cpp_style_comment_block_3 + .loop cpp_style_comment_char; + +cpp_style_comment_char + '\x0E'-'\xFF' .or '\x01'-'\x09' .or '\x0B'-'\x0C'; + +new_line_directive + new_line .and optional_directive; + +new_line + generic_new_line .emit '\n'; + +generic_new_line + carriage_return_line_feed .or line_feed_carriage_return .or '\n' .or '\r'; + +carriage_return_line_feed + '\r' .and '\n'; + +line_feed_carriage_return + '\n' .and '\r'; + +optional_directive + directive .emit ESCAPE_TOKEN .or .true; + +directive + dir_define .emit TOKEN_DEFINE .or + dir_undef .emit TOKEN_UNDEF .or + dir_if .emit TOKEN_IF .or + dir_ifdef .emit TOKEN_IF .emit 'd' .emit 'e' .emit 'f' .emit 'i' .emit 'n' .emit 'e' .emit 'd' + .emit ' ' .or + dir_ifndef .emit TOKEN_IF .emit '!' .emit 'd' .emit 'e' .emit 'f' .emit 'i' .emit 'n' .emit 'e' + .emit 'd' .emit ' ' .or + dir_else .emit TOKEN_ELSE .or + dir_elif .emit TOKEN_ELIF .or + dir_endif .emit TOKEN_ENDIF .or + dir_ext .emit TOKEN_EXTENSION .or + dir_pragma .emit TOKEN_PRAGMA .or + dir_line .emit TOKEN_LINE; + +dir_define + optional_space .and '#' .and optional_space .and "define" .and symbol .and opt_parameters .and + definition; + +dir_undef + optional_space .and '#' .and optional_space .and "undef" .and symbol; + +dir_if + optional_space .and '#' .and optional_space .and "if" .and expression; + +dir_ifdef + optional_space .and '#' .and optional_space .and "ifdef" .and symbol; + +dir_ifndef + optional_space .and '#' .and optional_space .and "ifndef" .and symbol; + +dir_else + optional_space .and '#' .and optional_space .and "else"; + +dir_elif + optional_space .and '#' .and optional_space .and "elif" .and expression; + +dir_endif + optional_space .and '#' .and optional_space .and "endif"; + +dir_ext + optional_space .and '#' .and optional_space .and "extension" .and space .and extension_name .and + optional_space .and ':' .and optional_space .and extension_behavior; + +dir_line + optional_space .and '#' .and optional_space .and "line" .and expression; + +dir_pragma + optional_space .and '#' .and optional_space .and "pragma" .and symbol .and opt_pragma_param; + + +opt_pragma_param + pragma_param .or .true .emit PRAGMA_NO_PARAM; + +pragma_param + optional_space .and '(' .emit PRAGMA_PARAM .and optional_space .and symbol_no_space .and optional_space .and ')'; + +symbol_no_space + symbol_character .emit * .and .loop symbol_character2 .emit * .and .true .emit '\0'; + +symbol + space .and symbol_character .emit * .and .loop symbol_character2 .emit * .and .true .emit '\0'; + +opt_parameters + parameters .or .true .emit PARAM_END; + +parameters + '(' .and parameters_1 .and optional_space .and ')' .emit PARAM_END; +parameters_1 + parameters_2 .or .true; +parameters_2 + parameter .emit PARAM_PARAMETER .and .loop parameters_3; +parameters_3 + optional_space .and ',' .and parameter .emit PARAM_PARAMETER; + +parameter + optional_space .and symbol_character .emit * .and .loop symbol_character2 .emit * .and + .true .emit '\0'; + +definition + .loop definition_character .emit * .and .true .emit '\0'; + +definition_character + '\x0E'-'\xFF' .or '\x01'-'\x09' .or '\x0B'-'\x0C'; + +expression + expression_element .and .loop expression_element .and .true .emit '\0'; + +expression_element + expression_character .emit *; + +expression_character + '\x0E'-'\xFF' .or '\x01'-'\x09' .or '\x0B'-'\x0C'; + +extension_name + symbol_character .emit * .and .loop symbol_character2 .emit * .and .true .emit '\0'; + +extension_behavior + "require" .emit BEHAVIOR_REQUIRE .or + "enable" .emit BEHAVIOR_ENABLE .or + "warn" .emit BEHAVIOR_WARN .or + "disable" .emit BEHAVIOR_DISABLE; + +optional_space + .loop single_space; + +space + single_space .and .loop single_space; + +single_space + ' ' .or '\t'; + +source_token + space .emit ' ' .or complex_token .or source_token_1; +source_token_1 + simple_token .emit ' ' .and .true .emit ' '; + +/* + * All possible tokens. + */ + +complex_token + identifier .or number; + +simple_token + increment .or decrement .or lequal .or gequal .or equal .or nequal .or and .or xor .or or .or + addto .or subtractfrom .or multiplyto .or divideto .or other; + +identifier + identifier_char1 .emit * .and .loop identifier_char2 .emit *; +identifier_char1 + 'a'-'z' .or 'A'-'Z' .or '_'; +identifier_char2 + 'a'-'z' .or 'A'-'Z' .or '0'-'9' .or '_'; + +number + float .or integer; + +digit_oct + '0'-'7'; + +digit_dec + '0'-'9'; + +digit_hex + '0'-'9' .or 'A'-'F' .or 'a'-'f'; + +float + float_1 .or float_2; +float_1 + float_fractional_constant .and float_optional_exponent_part; +float_2 + float_digit_sequence .and float_exponent_part; + +float_fractional_constant + float_fractional_constant_1 .or float_fractional_constant_2 .or float_fractional_constant_3; +float_fractional_constant_1 + float_digit_sequence .and '.' .emit '.' .and float_digit_sequence; +float_fractional_constant_2 + float_digit_sequence .and '.' .emit '.'; +float_fractional_constant_3 + '.' .emit '.' .and float_digit_sequence; + +float_optional_exponent_part + float_exponent_part .or .true; + +float_digit_sequence + digit_dec .emit * .and .loop digit_dec .emit *; + +float_exponent_part + float_exponent_part_1 .or float_exponent_part_2; +float_exponent_part_1 + 'e' .emit 'e' .and float_optional_sign .and float_digit_sequence; +float_exponent_part_2 + 'E' .emit 'E' .and float_optional_sign .and float_digit_sequence; + +float_optional_sign + '+' .emit '+' .or '-' .emit '-' .or .true; + +integer + integer_hex .or integer_oct .or integer_dec; + +integer_hex + '0' .emit '0' .and integer_hex_1 .emit * .and digit_hex .emit * .and + .loop digit_hex .emit *; +integer_hex_1 + 'x' .or 'X'; + +integer_oct + '0' .emit '0' .and .loop digit_oct .emit *; + +integer_dec + digit_dec .emit * .and .loop digit_dec .emit *; + +increment + '+' .emit * .and '+' .emit *; + +decrement + '-' .emit * .and '-' .emit *; + +lequal + '<' .emit * .and '=' .emit *; + +gequal + '>' .emit * .and '=' .emit *; + +equal + '=' .emit * .and '=' .emit *; + +nequal + '!' .emit * .and '=' .emit *; + +and + '&' .emit * .and '&' .emit *; + +xor + '^' .emit * .and '^' .emit *; + +or + '|' .emit * .and '|' .emit *; + +addto + '+' .emit * .and '=' .emit *; + +subtractfrom + '-' .emit * .and '=' .emit *; + +multiplyto + '*' .emit * .and '=' .emit *; + +divideto + '/' .emit * .and '=' .emit *; + +/* + * All characters except '\0' and '#'. + */ +other + '\x24'-'\xFF' .emit * .or '\x01'-'\x22' .emit *; + +symbol_character + 'A'-'Z' .or 'a'-'z' .or '_'; + +symbol_character2 + 'A'-'Z' .or 'a'-'z' .or '0'-'9' .or '_'; + +.string string_lexer; + +string_lexer + lex_first_identifier_character .and .loop lex_next_identifier_character; + +lex_first_identifier_character + 'a'-'z' .or 'A'-'Z' .or '_'; + +lex_next_identifier_character + 'a'-'z' .or 'A'-'Z' .or '0'-'9' .or '_'; + diff --git a/mesalib/src/mesa/shader/slang/library/slang_pp_directives_syn.h b/mesalib/src/mesa/shader/slang/library/slang_pp_directives_syn.h new file mode 100644 index 000000000..430f8d821 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_pp_directives_syn.h @@ -0,0 +1,250 @@ + +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE .syn FILE */ + +".syntax source;\n" +".emtcode ESCAPE_TOKEN 0\n" +".emtcode TOKEN_END 0\n" +".emtcode TOKEN_DEFINE 1\n" +".emtcode TOKEN_UNDEF 2\n" +".emtcode TOKEN_IF 3\n" +".emtcode TOKEN_ELSE 4\n" +".emtcode TOKEN_ELIF 5\n" +".emtcode TOKEN_ENDIF 6\n" +".emtcode TOKEN_ERROR 7\n" +".emtcode TOKEN_PRAGMA 8\n" +".emtcode TOKEN_EXTENSION 9\n" +".emtcode TOKEN_LINE 10\n" +".emtcode PARAM_END 0\n" +".emtcode PARAM_PARAMETER 1\n" +".emtcode BEHAVIOR_REQUIRE 1\n" +".emtcode BEHAVIOR_ENABLE 2\n" +".emtcode BEHAVIOR_WARN 3\n" +".emtcode BEHAVIOR_DISABLE 4\n" +".emtcode PRAGMA_NO_PARAM 0\n" +".emtcode PRAGMA_PARAM 1\n" +"source\n" +" optional_directive .and .loop source_element .and '\\0' .emit ESCAPE_TOKEN .emit TOKEN_END;\n" +"source_element\n" +" c_style_comment_block .or cpp_style_comment_block .or new_line_directive .or source_token;\n" +"c_style_comment_block\n" +" '/' .and '*' .and c_style_comment_rest .and .true .emit ' ';\n" +"c_style_comment_rest\n" +" .loop c_style_comment_body .and c_style_comment_end;\n" +"c_style_comment_body\n" +" c_style_comment_char_nostar .or c_style_comment_char_star_noslashstar;\n" +"c_style_comment_char_nostar\n" +" new_line .or '\\x2B'-'\\xFF' .or '\\x01'-'\\x29';\n" +"c_style_comment_char_star_noslashstar\n" +" '*' .and c_style_comment_char_star_noslashstar_1;\n" +"c_style_comment_char_star_noslashstar_1\n" +" c_style_comment_char_noslashstar .or c_style_comment_char_star_noslashstar;\n" +"c_style_comment_char_noslashstar\n" +" new_line .or '\\x30'-'\\xFF' .or '\\x01'-'\\x29' .or '\\x2B'-'\\x2E';\n" +"c_style_comment_end\n" +" '*' .and .loop c_style_comment_char_star .and '/';\n" +"c_style_comment_char_star\n" +" '*';\n" +"cpp_style_comment_block\n" +" '/' .and '/' .and cpp_style_comment_block_1;\n" +"cpp_style_comment_block_1\n" +" cpp_style_comment_block_2 .or cpp_style_comment_block_3;\n" +"cpp_style_comment_block_2\n" +" .loop cpp_style_comment_char .and new_line_directive;\n" +"cpp_style_comment_block_3\n" +" .loop cpp_style_comment_char;\n" +"cpp_style_comment_char\n" +" '\\x0E'-'\\xFF' .or '\\x01'-'\\x09' .or '\\x0B'-'\\x0C';\n" +"new_line_directive\n" +" new_line .and optional_directive;\n" +"new_line\n" +" generic_new_line .emit '\\n';\n" +"generic_new_line\n" +" carriage_return_line_feed .or line_feed_carriage_return .or '\\n' .or '\\r';\n" +"carriage_return_line_feed\n" +" '\\r' .and '\\n';\n" +"line_feed_carriage_return\n" +" '\\n' .and '\\r';\n" +"optional_directive\n" +" directive .emit ESCAPE_TOKEN .or .true;\n" +"directive\n" +" dir_define .emit TOKEN_DEFINE .or\n" +" dir_undef .emit TOKEN_UNDEF .or\n" +" dir_if .emit TOKEN_IF .or\n" +" dir_ifdef .emit TOKEN_IF .emit 'd' .emit 'e' .emit 'f' .emit 'i' .emit 'n' .emit 'e' .emit 'd'\n" +" .emit ' ' .or\n" +" dir_ifndef .emit TOKEN_IF .emit '!' .emit 'd' .emit 'e' .emit 'f' .emit 'i' .emit 'n' .emit 'e'\n" +" .emit 'd' .emit ' ' .or\n" +" dir_else .emit TOKEN_ELSE .or\n" +" dir_elif .emit TOKEN_ELIF .or\n" +" dir_endif .emit TOKEN_ENDIF .or\n" +" dir_ext .emit TOKEN_EXTENSION .or\n" +" dir_pragma .emit TOKEN_PRAGMA .or\n" +" dir_line .emit TOKEN_LINE;\n" +"dir_define\n" +" optional_space .and '#' .and optional_space .and \"define\" .and symbol .and opt_parameters .and\n" +" definition;\n" +"dir_undef\n" +" optional_space .and '#' .and optional_space .and \"undef\" .and symbol;\n" +"dir_if\n" +" optional_space .and '#' .and optional_space .and \"if\" .and expression;\n" +"dir_ifdef\n" +" optional_space .and '#' .and optional_space .and \"ifdef\" .and symbol;\n" +"dir_ifndef\n" +" optional_space .and '#' .and optional_space .and \"ifndef\" .and symbol;\n" +"dir_else\n" +" optional_space .and '#' .and optional_space .and \"else\";\n" +"dir_elif\n" +" optional_space .and '#' .and optional_space .and \"elif\" .and expression;\n" +"dir_endif\n" +" optional_space .and '#' .and optional_space .and \"endif\";\n" +"dir_ext\n" +" optional_space .and '#' .and optional_space .and \"extension\" .and space .and extension_name .and\n" +" optional_space .and ':' .and optional_space .and extension_behavior;\n" +"dir_line\n" +" optional_space .and '#' .and optional_space .and \"line\" .and expression;\n" +"dir_pragma\n" +" optional_space .and '#' .and optional_space .and \"pragma\" .and symbol .and opt_pragma_param;\n" +"opt_pragma_param\n" +" pragma_param .or .true .emit PRAGMA_NO_PARAM;\n" +"pragma_param\n" +" optional_space .and '(' .emit PRAGMA_PARAM .and optional_space .and symbol_no_space .and optional_space .and ')';\n" +"symbol_no_space\n" +" symbol_character .emit * .and .loop symbol_character2 .emit * .and .true .emit '\\0';\n" +"symbol\n" +" space .and symbol_character .emit * .and .loop symbol_character2 .emit * .and .true .emit '\\0';\n" +"opt_parameters\n" +" parameters .or .true .emit PARAM_END;\n" +"parameters\n" +" '(' .and parameters_1 .and optional_space .and ')' .emit PARAM_END;\n" +"parameters_1\n" +" parameters_2 .or .true;\n" +"parameters_2\n" +" parameter .emit PARAM_PARAMETER .and .loop parameters_3;\n" +"parameters_3\n" +" optional_space .and ',' .and parameter .emit PARAM_PARAMETER;\n" +"parameter\n" +" optional_space .and symbol_character .emit * .and .loop symbol_character2 .emit * .and\n" +" .true .emit '\\0';\n" +"definition\n" +" .loop definition_character .emit * .and .true .emit '\\0';\n" +"definition_character\n" +" '\\x0E'-'\\xFF' .or '\\x01'-'\\x09' .or '\\x0B'-'\\x0C';\n" +"expression\n" +" expression_element .and .loop expression_element .and .true .emit '\\0';\n" +"expression_element\n" +" expression_character .emit *;\n" +"expression_character\n" +" '\\x0E'-'\\xFF' .or '\\x01'-'\\x09' .or '\\x0B'-'\\x0C';\n" +"extension_name\n" +" symbol_character .emit * .and .loop symbol_character2 .emit * .and .true .emit '\\0';\n" +"extension_behavior\n" +" \"require\" .emit BEHAVIOR_REQUIRE .or\n" +" \"enable\" .emit BEHAVIOR_ENABLE .or\n" +" \"warn\" .emit BEHAVIOR_WARN .or\n" +" \"disable\" .emit BEHAVIOR_DISABLE;\n" +"optional_space\n" +" .loop single_space;\n" +"space\n" +" single_space .and .loop single_space;\n" +"single_space\n" +" ' ' .or '\\t';\n" +"source_token\n" +" space .emit ' ' .or complex_token .or source_token_1;\n" +"source_token_1\n" +" simple_token .emit ' ' .and .true .emit ' ';\n" +"complex_token\n" +" identifier .or number;\n" +"simple_token\n" +" increment .or decrement .or lequal .or gequal .or equal .or nequal .or and .or xor .or or .or\n" +" addto .or subtractfrom .or multiplyto .or divideto .or other;\n" +"identifier\n" +" identifier_char1 .emit * .and .loop identifier_char2 .emit *;\n" +"identifier_char1\n" +" 'a'-'z' .or 'A'-'Z' .or '_';\n" +"identifier_char2\n" +" 'a'-'z' .or 'A'-'Z' .or '0'-'9' .or '_';\n" +"number\n" +" float .or integer;\n" +"digit_oct\n" +" '0'-'7';\n" +"digit_dec\n" +" '0'-'9';\n" +"digit_hex\n" +" '0'-'9' .or 'A'-'F' .or 'a'-'f';\n" +"float\n" +" float_1 .or float_2;\n" +"float_1\n" +" float_fractional_constant .and float_optional_exponent_part;\n" +"float_2\n" +" float_digit_sequence .and float_exponent_part;\n" +"float_fractional_constant\n" +" float_fractional_constant_1 .or float_fractional_constant_2 .or float_fractional_constant_3;\n" +"float_fractional_constant_1\n" +" float_digit_sequence .and '.' .emit '.' .and float_digit_sequence;\n" +"float_fractional_constant_2\n" +" float_digit_sequence .and '.' .emit '.';\n" +"float_fractional_constant_3\n" +" '.' .emit '.' .and float_digit_sequence;\n" +"float_optional_exponent_part\n" +" float_exponent_part .or .true;\n" +"float_digit_sequence\n" +" digit_dec .emit * .and .loop digit_dec .emit *;\n" +"float_exponent_part\n" +" float_exponent_part_1 .or float_exponent_part_2;\n" +"float_exponent_part_1\n" +" 'e' .emit 'e' .and float_optional_sign .and float_digit_sequence;\n" +"float_exponent_part_2\n" +" 'E' .emit 'E' .and float_optional_sign .and float_digit_sequence;\n" +"float_optional_sign\n" +" '+' .emit '+' .or '-' .emit '-' .or .true;\n" +"integer\n" +" integer_hex .or integer_oct .or integer_dec;\n" +"integer_hex\n" +" '0' .emit '0' .and integer_hex_1 .emit * .and digit_hex .emit * .and\n" +" .loop digit_hex .emit *;\n" +"integer_hex_1\n" +" 'x' .or 'X';\n" +"integer_oct\n" +" '0' .emit '0' .and .loop digit_oct .emit *;\n" +"integer_dec\n" +" digit_dec .emit * .and .loop digit_dec .emit *;\n" +"increment\n" +" '+' .emit * .and '+' .emit *;\n" +"decrement\n" +" '-' .emit * .and '-' .emit *;\n" +"lequal\n" +" '<' .emit * .and '=' .emit *;\n" +"gequal\n" +" '>' .emit * .and '=' .emit *;\n" +"equal\n" +" '=' .emit * .and '=' .emit *;\n" +"nequal\n" +" '!' .emit * .and '=' .emit *;\n" +"and\n" +" '&' .emit * .and '&' .emit *;\n" +"xor\n" +" '^' .emit * .and '^' .emit *;\n" +"or\n" +" '|' .emit * .and '|' .emit *;\n" +"addto\n" +" '+' .emit * .and '=' .emit *;\n" +"subtractfrom\n" +" '-' .emit * .and '=' .emit *;\n" +"multiplyto\n" +" '*' .emit * .and '=' .emit *;\n" +"divideto\n" +" '/' .emit * .and '=' .emit *;\n" +"other\n" +" '\\x24'-'\\xFF' .emit * .or '\\x01'-'\\x22' .emit *;\n" +"symbol_character\n" +" 'A'-'Z' .or 'a'-'z' .or '_';\n" +"symbol_character2\n" +" 'A'-'Z' .or 'a'-'z' .or '0'-'9' .or '_';\n" +".string string_lexer;\n" +"string_lexer\n" +" lex_first_identifier_character .and .loop lex_next_identifier_character;\n" +"lex_first_identifier_character\n" +" 'a'-'z' .or 'A'-'Z' .or '_';\n" +"lex_next_identifier_character\n" +" 'a'-'z' .or 'A'-'Z' .or '0'-'9' .or '_';\n" +"" diff --git a/mesalib/src/mesa/shader/slang/library/slang_pp_expression.syn b/mesalib/src/mesa/shader/slang/library/slang_pp_expression.syn new file mode 100644 index 000000000..bfdb220bf --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_pp_expression.syn @@ -0,0 +1,265 @@ +/* + * Mesa 3-D graphics library + * Version: 6.6 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_pp_expression.syn + * slang preprocessor expression parser + * \author Michal Krol + */ + +/* + * Parses one or two (optional) expressions on literal integer constants. Those expressions come + * from #if #elif and #line directives. The preprocessor already parsed those directives and + * expanded the expression (expressions). All occurences of the operator "defined" are already + * replaced with either "0" or "1" literals. + */ + +.syntax expression; + +/* + * Those separate individual expressions. + * For #if/#elif case it is: EXP_EXPRESSION ... EXP_END + * For #line case it may be: EXP_EXPRESSION ... EXP_EXPRESSION ... EXP_END + */ +.emtcode EXP_END 0 +.emtcode EXP_EXPRESSION 1 + +.emtcode OP_END 0 +.emtcode OP_PUSHINT 1 +.emtcode OP_LOGICALOR 2 +.emtcode OP_LOGICALAND 3 +.emtcode OP_OR 4 +.emtcode OP_XOR 5 +.emtcode OP_AND 6 +.emtcode OP_EQUAL 7 +.emtcode OP_NOTEQUAL 8 +.emtcode OP_LESSEQUAL 9 +.emtcode OP_GREATEREQUAL 10 +.emtcode OP_LESS 11 +.emtcode OP_GREATER 12 +.emtcode OP_LEFTSHIFT 13 +.emtcode OP_RIGHTSHIFT 14 +.emtcode OP_ADD 15 +.emtcode OP_SUBTRACT 16 +.emtcode OP_MULTIPLY 17 +.emtcode OP_DIVIDE 18 +.emtcode OP_MODULUS 19 +.emtcode OP_PLUS 20 +.emtcode OP_MINUS 21 +.emtcode OP_NEGATE 22 +.emtcode OP_COMPLEMENT 23 + +expression + first_expression .and optional_second_expression .and optional_space .and '\0' .emit EXP_END; + +first_expression + optional_space .and logical_or_expression .emit EXP_EXPRESSION .and .true .emit OP_END; + +optional_second_expression + second_expression .or .true; + +second_expression + space .and logical_or_expression .emit EXP_EXPRESSION .and .true .emit OP_END; + +logical_or_expression + logical_and_expression .and .loop logical_or_expression_1; +logical_or_expression_1 + barbar .and logical_and_expression .and .true .emit OP_LOGICALOR; + +logical_and_expression + or_expression .and .loop logical_and_expression_1; +logical_and_expression_1 + ampersandampersand .and or_expression .and .true .emit OP_LOGICALAND; + +or_expression + xor_expression .and .loop or_expression_1; +or_expression_1 + bar .and xor_expression .and .true .emit OP_OR; + +xor_expression + and_expression .and .loop xor_expression_1; +xor_expression_1 + caret .and and_expression .and .true .emit OP_XOR; + +and_expression + equality_expression .and .loop and_expression_1; +and_expression_1 + ampersand .and equality_expression .and .true .emit OP_AND; + +equality_expression + relational_expression .and .loop equality_expression_1; +equality_expression_1 + equality_expression_2 .or equality_expression_3; +equality_expression_2 + equalsequals .and relational_expression .and .true .emit OP_EQUAL; +equality_expression_3 + bangequals .and relational_expression .and .true .emit OP_NOTEQUAL; + +relational_expression + shift_expression .and .loop relational_expression_1; +relational_expression_1 + relational_expression_2 .or relational_expression_3 .or relational_expression_4 .or + relational_expression_5; +relational_expression_2 + lessequals .and shift_expression .and .true .emit OP_LESSEQUAL; +relational_expression_3 + greaterequals .and shift_expression .and .true .emit OP_GREATEREQUAL; +relational_expression_4 + less .and shift_expression .and .true .emit OP_LESS; +relational_expression_5 + greater .and shift_expression .and .true .emit OP_GREATER; + +shift_expression + additive_expression .and .loop shift_expression_1; +shift_expression_1 + shift_expression_2 .or shift_expression_3; +shift_expression_2 + lessless .and additive_expression .and .true .emit OP_LEFTSHIFT; +shift_expression_3 + greatergreater .and additive_expression .and .true .emit OP_RIGHTSHIFT; + +additive_expression + multiplicative_expression .and .loop additive_expression_1; +additive_expression_1 + additive_expression_2 .or additive_expression_3; +additive_expression_2 + plus .and multiplicative_expression .and .true .emit OP_ADD; +additive_expression_3 + dash .and multiplicative_expression .and .true .emit OP_SUBTRACT; + +multiplicative_expression + unary_expression .and .loop multiplicative_expression_1; +multiplicative_expression_1 + multiplicative_expression_2 .or multiplicative_expression_3 .or multiplicative_expression_4; +multiplicative_expression_2 + star .and unary_expression .and .true .emit OP_MULTIPLY; +multiplicative_expression_3 + slash .and unary_expression .and .true .emit OP_DIVIDE; +multiplicative_expression_4 + percent .and unary_expression .and .true .emit OP_MODULUS; + +unary_expression + primary_expression .or unary_expression_1 .or unary_expression_2 .or unary_expression_3 .or + unary_expression_4; +unary_expression_1 + plus .and unary_expression .and .true .emit OP_PLUS; +unary_expression_2 + dash .and unary_expression .and .true .emit OP_MINUS; +unary_expression_3 + bang .and unary_expression .and .true .emit OP_NEGATE; +unary_expression_4 + tilda .and unary_expression .and .true .emit OP_COMPLEMENT; + +primary_expression + intconstant .or primary_expression_1; +primary_expression_1 + lparen .and logical_or_expression .and rparen; + +intconstant + integer .emit OP_PUSHINT; + +integer + integer_dec; + +integer_dec + digit_dec .emit 10 .emit * .and .loop digit_dec .emit * .and .true .emit '\0'; + +digit_dec + '0'-'9'; + +optional_space + .loop single_space; + +space + single_space .and .loop single_space; + +single_space + ' ' .or '\t'; + +ampersand + optional_space .and '&' .and optional_space; + +ampersandampersand + optional_space .and '&' .and '&' .and optional_space; + +bang + optional_space .and '!' .and optional_space; + +bangequals + optional_space .and '!' .and '=' .and optional_space; + +bar + optional_space .and '|' .and optional_space; + +barbar + optional_space .and '|' .and '|' .and optional_space; + +caret + optional_space .and '^' .and optional_space; + +dash + optional_space .and '-' .and optional_space; + +equalsequals + optional_space .and '=' .and '=' .and optional_space; + +greater + optional_space .and '>' .and optional_space; + +greaterequals + optional_space .and '>' .and '=' .and optional_space; + +greatergreater + optional_space .and '>' .and '>' .and optional_space; + +less + optional_space .and '<' .and optional_space; + +lessequals + optional_space .and '<' .and '=' .and optional_space; + +lessless + optional_space .and '<' .and '<' .and optional_space; + +lparen + optional_space .and '(' .and optional_space; + +percent + optional_space .and '%' .and optional_space; + +plus + optional_space .and '+' .and optional_space; + +rparen + optional_space .and ')' .and optional_space; + +slash + optional_space .and '/' .and optional_space; + +star + optional_space .and '*' .and optional_space; + +tilda + optional_space .and '~' .and optional_space; + diff --git a/mesalib/src/mesa/shader/slang/library/slang_pp_expression_syn.h b/mesalib/src/mesa/shader/slang/library/slang_pp_expression_syn.h new file mode 100644 index 000000000..f3e9ef6b2 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_pp_expression_syn.h @@ -0,0 +1,179 @@ + +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE .syn FILE */ + +".syntax expression;\n" +".emtcode EXP_END 0\n" +".emtcode EXP_EXPRESSION 1\n" +".emtcode OP_END 0\n" +".emtcode OP_PUSHINT 1\n" +".emtcode OP_LOGICALOR 2\n" +".emtcode OP_LOGICALAND 3\n" +".emtcode OP_OR 4\n" +".emtcode OP_XOR 5\n" +".emtcode OP_AND 6\n" +".emtcode OP_EQUAL 7\n" +".emtcode OP_NOTEQUAL 8\n" +".emtcode OP_LESSEQUAL 9\n" +".emtcode OP_GREATEREQUAL 10\n" +".emtcode OP_LESS 11\n" +".emtcode OP_GREATER 12\n" +".emtcode OP_LEFTSHIFT 13\n" +".emtcode OP_RIGHTSHIFT 14\n" +".emtcode OP_ADD 15\n" +".emtcode OP_SUBTRACT 16\n" +".emtcode OP_MULTIPLY 17\n" +".emtcode OP_DIVIDE 18\n" +".emtcode OP_MODULUS 19\n" +".emtcode OP_PLUS 20\n" +".emtcode OP_MINUS 21\n" +".emtcode OP_NEGATE 22\n" +".emtcode OP_COMPLEMENT 23\n" +"expression\n" +" first_expression .and optional_second_expression .and optional_space .and '\\0' .emit EXP_END;\n" +"first_expression\n" +" optional_space .and logical_or_expression .emit EXP_EXPRESSION .and .true .emit OP_END;\n" +"optional_second_expression\n" +" second_expression .or .true;\n" +"second_expression\n" +" space .and logical_or_expression .emit EXP_EXPRESSION .and .true .emit OP_END;\n" +"logical_or_expression\n" +" logical_and_expression .and .loop logical_or_expression_1;\n" +"logical_or_expression_1\n" +" barbar .and logical_and_expression .and .true .emit OP_LOGICALOR;\n" +"logical_and_expression\n" +" or_expression .and .loop logical_and_expression_1;\n" +"logical_and_expression_1\n" +" ampersandampersand .and or_expression .and .true .emit OP_LOGICALAND;\n" +"or_expression\n" +" xor_expression .and .loop or_expression_1;\n" +"or_expression_1\n" +" bar .and xor_expression .and .true .emit OP_OR;\n" +"xor_expression\n" +" and_expression .and .loop xor_expression_1;\n" +"xor_expression_1\n" +" caret .and and_expression .and .true .emit OP_XOR;\n" +"and_expression\n" +" equality_expression .and .loop and_expression_1;\n" +"and_expression_1\n" +" ampersand .and equality_expression .and .true .emit OP_AND;\n" +"equality_expression\n" +" relational_expression .and .loop equality_expression_1;\n" +"equality_expression_1\n" +" equality_expression_2 .or equality_expression_3;\n" +"equality_expression_2\n" +" equalsequals .and relational_expression .and .true .emit OP_EQUAL;\n" +"equality_expression_3\n" +" bangequals .and relational_expression .and .true .emit OP_NOTEQUAL;\n" +"relational_expression\n" +" shift_expression .and .loop relational_expression_1;\n" +"relational_expression_1\n" +" relational_expression_2 .or relational_expression_3 .or relational_expression_4 .or\n" +" relational_expression_5;\n" +"relational_expression_2\n" +" lessequals .and shift_expression .and .true .emit OP_LESSEQUAL;\n" +"relational_expression_3\n" +" greaterequals .and shift_expression .and .true .emit OP_GREATEREQUAL;\n" +"relational_expression_4\n" +" less .and shift_expression .and .true .emit OP_LESS;\n" +"relational_expression_5\n" +" greater .and shift_expression .and .true .emit OP_GREATER;\n" +"shift_expression\n" +" additive_expression .and .loop shift_expression_1;\n" +"shift_expression_1\n" +" shift_expression_2 .or shift_expression_3;\n" +"shift_expression_2\n" +" lessless .and additive_expression .and .true .emit OP_LEFTSHIFT;\n" +"shift_expression_3\n" +" greatergreater .and additive_expression .and .true .emit OP_RIGHTSHIFT;\n" +"additive_expression\n" +" multiplicative_expression .and .loop additive_expression_1;\n" +"additive_expression_1\n" +" additive_expression_2 .or additive_expression_3;\n" +"additive_expression_2\n" +" plus .and multiplicative_expression .and .true .emit OP_ADD;\n" +"additive_expression_3\n" +" dash .and multiplicative_expression .and .true .emit OP_SUBTRACT;\n" +"multiplicative_expression\n" +" unary_expression .and .loop multiplicative_expression_1;\n" +"multiplicative_expression_1\n" +" multiplicative_expression_2 .or multiplicative_expression_3 .or multiplicative_expression_4;\n" +"multiplicative_expression_2\n" +" star .and unary_expression .and .true .emit OP_MULTIPLY;\n" +"multiplicative_expression_3\n" +" slash .and unary_expression .and .true .emit OP_DIVIDE;\n" +"multiplicative_expression_4\n" +" percent .and unary_expression .and .true .emit OP_MODULUS;\n" +"unary_expression\n" +" primary_expression .or unary_expression_1 .or unary_expression_2 .or unary_expression_3 .or\n" +" unary_expression_4;\n" +"unary_expression_1\n" +" plus .and unary_expression .and .true .emit OP_PLUS;\n" +"unary_expression_2\n" +" dash .and unary_expression .and .true .emit OP_MINUS;\n" +"unary_expression_3\n" +" bang .and unary_expression .and .true .emit OP_NEGATE;\n" +"unary_expression_4\n" +" tilda .and unary_expression .and .true .emit OP_COMPLEMENT;\n" +"primary_expression\n" +" intconstant .or primary_expression_1;\n" +"primary_expression_1\n" +" lparen .and logical_or_expression .and rparen;\n" +"intconstant\n" +" integer .emit OP_PUSHINT;\n" +"integer\n" +" integer_dec;\n" +"integer_dec\n" +" digit_dec .emit 10 .emit * .and .loop digit_dec .emit * .and .true .emit '\\0';\n" +"digit_dec\n" +" '0'-'9';\n" +"optional_space\n" +" .loop single_space;\n" +"space\n" +" single_space .and .loop single_space;\n" +"single_space\n" +" ' ' .or '\\t';\n" +"ampersand\n" +" optional_space .and '&' .and optional_space;\n" +"ampersandampersand\n" +" optional_space .and '&' .and '&' .and optional_space;\n" +"bang\n" +" optional_space .and '!' .and optional_space;\n" +"bangequals\n" +" optional_space .and '!' .and '=' .and optional_space;\n" +"bar\n" +" optional_space .and '|' .and optional_space;\n" +"barbar\n" +" optional_space .and '|' .and '|' .and optional_space;\n" +"caret\n" +" optional_space .and '^' .and optional_space;\n" +"dash\n" +" optional_space .and '-' .and optional_space;\n" +"equalsequals\n" +" optional_space .and '=' .and '=' .and optional_space;\n" +"greater\n" +" optional_space .and '>' .and optional_space;\n" +"greaterequals\n" +" optional_space .and '>' .and '=' .and optional_space;\n" +"greatergreater\n" +" optional_space .and '>' .and '>' .and optional_space;\n" +"less\n" +" optional_space .and '<' .and optional_space;\n" +"lessequals\n" +" optional_space .and '<' .and '=' .and optional_space;\n" +"lessless\n" +" optional_space .and '<' .and '<' .and optional_space;\n" +"lparen\n" +" optional_space .and '(' .and optional_space;\n" +"percent\n" +" optional_space .and '%' .and optional_space;\n" +"plus\n" +" optional_space .and '+' .and optional_space;\n" +"rparen\n" +" optional_space .and ')' .and optional_space;\n" +"slash\n" +" optional_space .and '/' .and optional_space;\n" +"star\n" +" optional_space .and '*' .and optional_space;\n" +"tilda\n" +" optional_space .and '~' .and optional_space;\n" +"" diff --git a/mesalib/src/mesa/shader/slang/library/slang_pp_version.syn b/mesalib/src/mesa/shader/slang/library/slang_pp_version.syn new file mode 100644 index 000000000..3fe1a57ba --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_pp_version.syn @@ -0,0 +1,122 @@ +/* + * Mesa 3-D graphics library + * Version: 6.6 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_pp_version.syn + * slang #version directive syntax + * \author Michal Krol + */ + +.syntax version_directive; + +version_directive + version_directive_1; +version_directive_1 + prior_optional_spaces .and optional_version_directive .and .true .emit $; + +optional_version_directive + version_directive_body .or .true .emit 10 .emit 1; + +version_directive_body + '#' .and optional_space .and "version" .and space .and version_number .and optional_space .and + new_line; + +version_number + version_number_100 .or version_number_110 .or version_number_120; + +version_number_100 + leading_zeroes .and "100" .emit 0 .emit 1; + +version_number_110 + leading_zeroes .and "110" .emit 10 .emit 1; + +version_number_120 + leading_zeroes .and "120" .emit 20 .emit 1; + +leading_zeroes + .loop zero; + +zero + '0'; + +space + single_space .and .loop single_space; + +optional_space + .loop single_space; + +single_space + ' ' .or '\t'; + +prior_optional_spaces + .loop prior_space; + +prior_space + c_style_comment_block .or cpp_style_comment_block .or space .or new_line; + +c_style_comment_block + '/' .and '*' .and c_style_comment_rest; + +c_style_comment_rest + .loop c_style_comment_char_no_star .and c_style_comment_rest_1; +c_style_comment_rest_1 + c_style_comment_end .or c_style_comment_rest_2; +c_style_comment_rest_2 + '*' .and c_style_comment_rest; + +c_style_comment_char_no_star + '\x2B'-'\xFF' .or '\x01'-'\x29'; + +c_style_comment_end + '*' .and '/'; + +cpp_style_comment_block + '/' .and '/' .and cpp_style_comment_block_1; +cpp_style_comment_block_1 + cpp_style_comment_block_2 .or cpp_style_comment_block_3; +cpp_style_comment_block_2 + .loop cpp_style_comment_char .and new_line; +cpp_style_comment_block_3 + .loop cpp_style_comment_char; + +cpp_style_comment_char + '\x0E'-'\xFF' .or '\x01'-'\x09' .or '\x0B'-'\x0C'; + +new_line + cr_lf .or lf_cr .or '\n' .or '\r'; + +cr_lf + '\r' .and '\n'; + +lf_cr + '\n' .and '\r'; + +.string __string_filter; + +__string_filter + .loop __identifier_char; + +__identifier_char + 'a'-'z' .or 'A'-'Z' .or '_' .or '0'-'9'; + diff --git a/mesalib/src/mesa/shader/slang/library/slang_pp_version_syn.h b/mesalib/src/mesa/shader/slang/library/slang_pp_version_syn.h new file mode 100644 index 000000000..54aee3ff2 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_pp_version_syn.h @@ -0,0 +1,69 @@ + +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE .syn FILE */ + +".syntax version_directive;\n" +"version_directive\n" +" version_directive_1;\n" +"version_directive_1\n" +" prior_optional_spaces .and optional_version_directive .and .true .emit $;\n" +"optional_version_directive\n" +" version_directive_body .or .true .emit 10 .emit 1;\n" +"version_directive_body\n" +" '#' .and optional_space .and \"version\" .and space .and version_number .and optional_space .and\n" +" new_line;\n" +"version_number\n" +" version_number_100 .or version_number_110 .or version_number_120;\n" +"version_number_100\n" +" leading_zeroes .and \"100\" .emit 0 .emit 1;\n" +"version_number_110\n" +" leading_zeroes .and \"110\" .emit 10 .emit 1;\n" +"version_number_120\n" +" leading_zeroes .and \"120\" .emit 20 .emit 1;\n" +"leading_zeroes\n" +" .loop zero;\n" +"zero\n" +" '0';\n" +"space\n" +" single_space .and .loop single_space;\n" +"optional_space\n" +" .loop single_space;\n" +"single_space\n" +" ' ' .or '\\t';\n" +"prior_optional_spaces\n" +" .loop prior_space;\n" +"prior_space\n" +" c_style_comment_block .or cpp_style_comment_block .or space .or new_line;\n" +"c_style_comment_block\n" +" '/' .and '*' .and c_style_comment_rest;\n" +"c_style_comment_rest\n" +" .loop c_style_comment_char_no_star .and c_style_comment_rest_1;\n" +"c_style_comment_rest_1\n" +" c_style_comment_end .or c_style_comment_rest_2;\n" +"c_style_comment_rest_2\n" +" '*' .and c_style_comment_rest;\n" +"c_style_comment_char_no_star\n" +" '\\x2B'-'\\xFF' .or '\\x01'-'\\x29';\n" +"c_style_comment_end\n" +" '*' .and '/';\n" +"cpp_style_comment_block\n" +" '/' .and '/' .and cpp_style_comment_block_1;\n" +"cpp_style_comment_block_1\n" +" cpp_style_comment_block_2 .or cpp_style_comment_block_3;\n" +"cpp_style_comment_block_2\n" +" .loop cpp_style_comment_char .and new_line;\n" +"cpp_style_comment_block_3\n" +" .loop cpp_style_comment_char;\n" +"cpp_style_comment_char\n" +" '\\x0E'-'\\xFF' .or '\\x01'-'\\x09' .or '\\x0B'-'\\x0C';\n" +"new_line\n" +" cr_lf .or lf_cr .or '\\n' .or '\\r';\n" +"cr_lf\n" +" '\\r' .and '\\n';\n" +"lf_cr\n" +" '\\n' .and '\\r';\n" +".string __string_filter;\n" +"__string_filter\n" +" .loop __identifier_char;\n" +"__identifier_char\n" +" 'a'-'z' .or 'A'-'Z' .or '_' .or '0'-'9';\n" +"" diff --git a/mesalib/src/mesa/shader/slang/library/slang_shader.syn b/mesalib/src/mesa/shader/slang/library/slang_shader.syn new file mode 100644 index 000000000..cc5c70a02 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_shader.syn @@ -0,0 +1,1716 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2004-2006 Brian Paul All Rights Reserved. + * Copyright (C) 2008 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 slang_shader.syn + * slang vertex/fragment shader syntax + * \author Michal Krol + */ + +/* + * usage: + * syn2c slang_shader.syn > slang_shader_syn.h + * + * when modifying or extending this file, several things must be taken into + * consideration: + * + * - when adding new operators that were marked as reserved in the + * initial specification, one must only uncomment particular lines of + * code that refer to operators being added; + * + * - when adding new shader targets, one must reserve a new value for + * shader_type register and use it in .if constructs for symbols that + * are exclusive for that shader; + * + * - some symbols mimic output of other symbols - the best example is + * the "for" construct: expression "for (foo(); ; bar())" is seen as + * "for (foo(); true; bar())" by the output processor - hence, special + * care must be taken when rearranging output of essential symbols; + * + * - order of single-quoted tokens does matter in alternatives - so do not + * parse "<" operator before "<<" and "<<" before "<<="; + * + * - all double-quoted tokens are internally preprocessed to eliminate + * problems with parsing strings that are prefixes of other strings, + * like "sampler1D" and "sampler1DShadow"; + */ + +.syntax translation_unit; + +/* revision number - increment after each change affecting emitted output */ +.emtcode REVISION 5 + +/* external declaration (or precision or invariant stmt) */ +.emtcode EXTERNAL_NULL 0 +.emtcode EXTERNAL_FUNCTION_DEFINITION 1 +.emtcode EXTERNAL_DECLARATION 2 +.emtcode DEFAULT_PRECISION 3 +.emtcode INVARIANT_STMT 4 + +/* precision */ +.emtcode PRECISION_DEFAULT 0 +.emtcode PRECISION_LOW 1 +.emtcode PRECISION_MEDIUM 2 +.emtcode PRECISION_HIGH 3 + +/* declaration */ +.emtcode DECLARATION_FUNCTION_PROTOTYPE 1 +.emtcode DECLARATION_INIT_DECLARATOR_LIST 2 + +/* function type */ +.emtcode FUNCTION_ORDINARY 0 +.emtcode FUNCTION_CONSTRUCTOR 1 +.emtcode FUNCTION_OPERATOR 2 + +/* function call type */ +.emtcode FUNCTION_CALL_NONARRAY 0 +.emtcode FUNCTION_CALL_ARRAY 1 + +/* operator type */ +.emtcode OPERATOR_ADDASSIGN 1 +.emtcode OPERATOR_SUBASSIGN 2 +.emtcode OPERATOR_MULASSIGN 3 +.emtcode OPERATOR_DIVASSIGN 4 +/*.emtcode OPERATOR_MODASSIGN 5*/ +/*.emtcode OPERATOR_LSHASSIGN 6*/ +/*.emtcode OPERATOR_RSHASSIGN 7*/ +/*.emtcode OPERATOR_ORASSIGN 8*/ +/*.emtcode OPERATOR_XORASSIGN 9*/ +/*.emtcode OPERATOR_ANDASSIGN 10*/ +.emtcode OPERATOR_LOGICALXOR 11 +/*.emtcode OPERATOR_BITOR 12*/ +/*.emtcode OPERATOR_BITXOR 13*/ +/*.emtcode OPERATOR_BITAND 14*/ +.emtcode OPERATOR_LESS 15 +.emtcode OPERATOR_GREATER 16 +.emtcode OPERATOR_LESSEQUAL 17 +.emtcode OPERATOR_GREATEREQUAL 18 +/*.emtcode OPERATOR_LSHIFT 19*/ +/*.emtcode OPERATOR_RSHIFT 20*/ +.emtcode OPERATOR_MULTIPLY 21 +.emtcode OPERATOR_DIVIDE 22 +/*.emtcode OPERATOR_MODULUS 23*/ +.emtcode OPERATOR_INCREMENT 24 +.emtcode OPERATOR_DECREMENT 25 +.emtcode OPERATOR_PLUS 26 +.emtcode OPERATOR_MINUS 27 +/*.emtcode OPERATOR_COMPLEMENT 28*/ +.emtcode OPERATOR_NOT 29 + +/* init declarator list */ +.emtcode DECLARATOR_NONE 0 +.emtcode DECLARATOR_NEXT 1 + +/* variable declaration */ +.emtcode VARIABLE_NONE 0 +.emtcode VARIABLE_IDENTIFIER 1 +.emtcode VARIABLE_INITIALIZER 2 +.emtcode VARIABLE_ARRAY_EXPLICIT 3 +.emtcode VARIABLE_ARRAY_UNKNOWN 4 + +/* type qualifier */ +.emtcode TYPE_QUALIFIER_NONE 0 +.emtcode TYPE_QUALIFIER_CONST 1 +.emtcode TYPE_QUALIFIER_ATTRIBUTE 2 +.emtcode TYPE_QUALIFIER_VARYING 3 +.emtcode TYPE_QUALIFIER_UNIFORM 4 +.emtcode TYPE_QUALIFIER_FIXEDOUTPUT 5 +.emtcode TYPE_QUALIFIER_FIXEDINPUT 6 + +/* invariant qualifier */ +.emtcode TYPE_VARIANT 90 +.emtcode TYPE_INVARIANT 91 + +/* centroid qualifier */ +.emtcode TYPE_CENTER 95 +.emtcode TYPE_CENTROID 96 + +/* type specifier */ +.emtcode TYPE_SPECIFIER_VOID 0 +.emtcode TYPE_SPECIFIER_BOOL 1 +.emtcode TYPE_SPECIFIER_BVEC2 2 +.emtcode TYPE_SPECIFIER_BVEC3 3 +.emtcode TYPE_SPECIFIER_BVEC4 4 +.emtcode TYPE_SPECIFIER_INT 5 +.emtcode TYPE_SPECIFIER_IVEC2 6 +.emtcode TYPE_SPECIFIER_IVEC3 7 +.emtcode TYPE_SPECIFIER_IVEC4 8 +.emtcode TYPE_SPECIFIER_FLOAT 9 +.emtcode TYPE_SPECIFIER_VEC2 10 +.emtcode TYPE_SPECIFIER_VEC3 11 +.emtcode TYPE_SPECIFIER_VEC4 12 +.emtcode TYPE_SPECIFIER_MAT2 13 +.emtcode TYPE_SPECIFIER_MAT3 14 +.emtcode TYPE_SPECIFIER_MAT4 15 +.emtcode TYPE_SPECIFIER_SAMPLER1D 16 +.emtcode TYPE_SPECIFIER_SAMPLER2D 17 +.emtcode TYPE_SPECIFIER_SAMPLER3D 18 +.emtcode TYPE_SPECIFIER_SAMPLERCUBE 19 +.emtcode TYPE_SPECIFIER_SAMPLER1DSHADOW 20 +.emtcode TYPE_SPECIFIER_SAMPLER2DSHADOW 21 +.emtcode TYPE_SPECIFIER_SAMPLER2DRECT 22 +.emtcode TYPE_SPECIFIER_SAMPLER2DRECTSHADOW 23 +.emtcode TYPE_SPECIFIER_STRUCT 24 +.emtcode TYPE_SPECIFIER_TYPENAME 25 + +/* OpenGL 2.1 */ +.emtcode TYPE_SPECIFIER_MAT23 26 +.emtcode TYPE_SPECIFIER_MAT32 27 +.emtcode TYPE_SPECIFIER_MAT24 28 +.emtcode TYPE_SPECIFIER_MAT42 29 +.emtcode TYPE_SPECIFIER_MAT34 30 +.emtcode TYPE_SPECIFIER_MAT43 31 + +/* type specifier array */ +.emtcode TYPE_SPECIFIER_NONARRAY 0 +.emtcode TYPE_SPECIFIER_ARRAY 1 + +/* structure field */ +.emtcode FIELD_NONE 0 +.emtcode FIELD_NEXT 1 +.emtcode FIELD_ARRAY 2 + +/* operation */ +.emtcode OP_END 0 +.emtcode OP_BLOCK_BEGIN_NO_NEW_SCOPE 1 +.emtcode OP_BLOCK_BEGIN_NEW_SCOPE 2 +.emtcode OP_DECLARE 3 +.emtcode OP_ASM 4 +.emtcode OP_BREAK 5 +.emtcode OP_CONTINUE 6 +.emtcode OP_DISCARD 7 +.emtcode OP_RETURN 8 +.emtcode OP_EXPRESSION 9 +.emtcode OP_IF 10 +.emtcode OP_WHILE 11 +.emtcode OP_DO 12 +.emtcode OP_FOR 13 +.emtcode OP_PUSH_VOID 14 +.emtcode OP_PUSH_BOOL 15 +.emtcode OP_PUSH_INT 16 +.emtcode OP_PUSH_FLOAT 17 +.emtcode OP_PUSH_IDENTIFIER 18 +.emtcode OP_SEQUENCE 19 +.emtcode OP_ASSIGN 20 +.emtcode OP_ADDASSIGN 21 +.emtcode OP_SUBASSIGN 22 +.emtcode OP_MULASSIGN 23 +.emtcode OP_DIVASSIGN 24 +/*.emtcode OP_MODASSIGN 25*/ +/*.emtcode OP_LSHASSIGN 26*/ +/*.emtcode OP_RSHASSIGN 27*/ +/*.emtcode OP_ORASSIGN 28*/ +/*.emtcode OP_XORASSIGN 29*/ +/*.emtcode OP_ANDASSIGN 30*/ +.emtcode OP_SELECT 31 +.emtcode OP_LOGICALOR 32 +.emtcode OP_LOGICALXOR 33 +.emtcode OP_LOGICALAND 34 +/*.emtcode OP_BITOR 35*/ +/*.emtcode OP_BITXOR 36*/ +/*.emtcode OP_BITAND 37*/ +.emtcode OP_EQUAL 38 +.emtcode OP_NOTEQUAL 39 +.emtcode OP_LESS 40 +.emtcode OP_GREATER 41 +.emtcode OP_LESSEQUAL 42 +.emtcode OP_GREATEREQUAL 43 +/*.emtcode OP_LSHIFT 44*/ +/*.emtcode OP_RSHIFT 45*/ +.emtcode OP_ADD 46 +.emtcode OP_SUBTRACT 47 +.emtcode OP_MULTIPLY 48 +.emtcode OP_DIVIDE 49 +/*.emtcode OP_MODULUS 50*/ +.emtcode OP_PREINCREMENT 51 +.emtcode OP_PREDECREMENT 52 +.emtcode OP_PLUS 53 +.emtcode OP_MINUS 54 +/*.emtcode OP_COMPLEMENT 55*/ +.emtcode OP_NOT 56 +.emtcode OP_SUBSCRIPT 57 +.emtcode OP_CALL 58 +.emtcode OP_FIELD 59 +.emtcode OP_POSTINCREMENT 60 +.emtcode OP_POSTDECREMENT 61 +.emtcode OP_PRECISION 62 +.emtcode OP_METHOD 63 + +/* parameter qualifier */ +.emtcode PARAM_QUALIFIER_IN 0 +.emtcode PARAM_QUALIFIER_OUT 1 +.emtcode PARAM_QUALIFIER_INOUT 2 + +/* function parameter */ +.emtcode PARAMETER_NONE 0 +.emtcode PARAMETER_NEXT 1 + +/* function parameter array presence */ +.emtcode PARAMETER_ARRAY_NOT_PRESENT 0 +.emtcode PARAMETER_ARRAY_PRESENT 1 + +/* INVALID_EXTERNAL_DECLARATION seems to be reported when there's */ +/* any syntax errors... */ +.errtext INVALID_EXTERNAL_DECLARATION "2001: Syntax error." +.errtext INVALID_OPERATOR_OVERRIDE "2002: Invalid operator override." +.errtext LBRACE_EXPECTED "2003: '{' expected but '$err_token$' found." +.errtext LPAREN_EXPECTED "2004: '(' expected but '$err_token$' found." +.errtext RPAREN_EXPECTED "2005: ')' expected but '$err_token$' found." +.errtext INVALID_PRECISION "2006: Invalid precision specifier '$err_token$'." +.errtext INVALID_PRECISION_TYPE "2007: Invalid precision type '$err_token$'." + + +/* + * tells whether the shader that is being parsed is a built-in shader or not + * 0 - normal behaviour + * 1 - accepts constructor and operator definitions and __asm statements + * the implementation will set it to 1 when compiling internal built-in shaders + */ +.regbyte parsing_builtin 0 + +/* + * holds the type of the shader being parsed; possible values are + * listed below. + * FRAGMENT_SHADER 1 + * VERTEX_SHADER 2 + * shader type is set by the caller before parsing + */ +.regbyte shader_type 0 + +/* + * <variable_identifier> ::= <identifier> + */ +variable_identifier + identifier .emit OP_PUSH_IDENTIFIER; + +/* + * <primary_expression> ::= <variable_identifier> + * | <intconstant> + * | <floatconstant> + * | <boolconstant> + * | "(" <expression> ")" + */ +primary_expression + floatconstant .or boolconstant .or intconstant .or variable_identifier .or primary_expression_1; +primary_expression_1 + lparen .and expression .and rparen; + +/* + * <postfix_expression> ::= <primary_expression> + * | <postfix_expression> "[" <integer_expression> "]" + * | <function_call> + * | <postfix_expression> "." <field_selection> + * | <postfix_expression> "++" + * | <postfix_expression> "--" + */ +postfix_expression + postfix_expression_1 .and .loop postfix_expression_2; +postfix_expression_1 + function_call .or primary_expression; +postfix_expression_2 + postfix_expression_3 .or postfix_expression_4 .or + plusplus .emit OP_POSTINCREMENT .or + minusminus .emit OP_POSTDECREMENT; +postfix_expression_3 + lbracket .and integer_expression .and rbracket .emit OP_SUBSCRIPT; +postfix_expression_4 + dot .and field_selection .emit OP_FIELD; + +/* + * <integer_expression> ::= <expression> + */ +integer_expression + expression; + +/* + * <function_call> ::= <function_call_generic> + */ +function_call + function_call_or_method; + +/* + * <function_call_or_method> ::= <regular_function_call> + * | <postfix_expression> "." <function_call_generic> + */ +function_call_or_method + regular_function_call .or method_call; + +/* + * <method_call> ::= <identifier> "." <function_call_generic> + */ +method_call + identifier .emit OP_METHOD .and dot .and function_call_generic .and .true .emit OP_END; + +/* + * <regular_function_call> ::= <function_call_generic> + */ +regular_function_call + function_call_generic .emit OP_CALL .and .true .emit OP_END; + +/* + * <function_call_generic> ::= <function_call_header_with_parameters> ")" + * | <function_call_header_no_parameters> ")" + */ +function_call_generic + function_call_generic_1 .or function_call_generic_2; +function_call_generic_1 + function_call_header_with_parameters .and rparen .error RPAREN_EXPECTED; +function_call_generic_2 + function_call_header_no_parameters .and rparen .error RPAREN_EXPECTED; + +/* + * <function_call_header_no_parameters>::= <function_call_header> "void" + * | <function_call_header> + */ +function_call_header_no_parameters + function_call_header .and function_call_header_no_parameters_1; +function_call_header_no_parameters_1 + "void" .or .true; + +/* + * <function_call_header_with_parameters> ::= <function_call_header> <assignment_expression> + * | <function_call_header_with_parameters> "," <assignment_expression> + */ +function_call_header_with_parameters + function_call_header .and assignment_expression .and .true .emit OP_END .and + .loop function_call_header_with_parameters_1; +function_call_header_with_parameters_1 + comma .and assignment_expression .and .true .emit OP_END; + +/* + * <function_call_header> ::= <function_identifier> "(" + */ +function_call_header + function_identifier .and lparen; + +/* + * <function_identifier> ::= <constructor_identifier> + * | <identifier> + * | <type_specifier> + * + * note: <constructor_identifier> and <type_specifier> have been deleted + */ +function_identifier + identifier .and function_identifier_opt_array; +function_identifier_opt_array + function_identifier_array .emit FUNCTION_CALL_ARRAY .or + .true .emit FUNCTION_CALL_NONARRAY; +function_identifier_array + lbracket .and constant_expression .and rbracket; + +/* + * <unary_expression> ::= <postfix_expression> + * | "++" <unary_expression> + * | "--" <unary_expression> + * | <unary_operator> <unary_expression> + * + * <unary_operator> ::= "+" + * | "-" + * | "!" + * | "~" // reserved + */ +unary_expression + postfix_expression .or unary_expression_1 .or unary_expression_2 .or unary_expression_3 .or + unary_expression_4 .or unary_expression_5/* .or unary_expression_6*/; +unary_expression_1 + plusplus .and unary_expression .and .true .emit OP_PREINCREMENT; +unary_expression_2 + minusminus .and unary_expression .and .true .emit OP_PREDECREMENT; +unary_expression_3 + plus .and unary_expression .and .true .emit OP_PLUS; +unary_expression_4 + minus .and unary_expression .and .true .emit OP_MINUS; +unary_expression_5 + bang .and unary_expression .and .true .emit OP_NOT; +/*unary_expression_6 + tilde .and unary_expression .and .true .emit OP_COMPLEMENT;*/ + +/* + * <multiplicative_expression> ::= <unary_expression> + * | <multiplicative_expression> "*" <unary_expression> + * | <multiplicative_expression> "/" <unary_expression> + * | <multiplicative_expression> "%" <unary_expression> // reserved + */ +multiplicative_expression + unary_expression .and .loop multiplicative_expression_1; +multiplicative_expression_1 + multiplicative_expression_2 .or multiplicative_expression_3/* .or multiplicative_expression_4*/; +multiplicative_expression_2 + star .and unary_expression .and .true .emit OP_MULTIPLY; +multiplicative_expression_3 + slash .and unary_expression .and .true .emit OP_DIVIDE; +/*multiplicative_expression_4 + percent .and unary_expression .and .true .emit OP_MODULUS;*/ + +/* + * <additive_expression> ::= <multiplicative_expression> + * | <additive_expression> "+" <multiplicative_expression> + * | <additive_expression> "-" <multiplicative_expression> + */ +additive_expression + multiplicative_expression .and .loop additive_expression_1; +additive_expression_1 + additive_expression_2 .or additive_expression_3; +additive_expression_2 + plus .and multiplicative_expression .and .true .emit OP_ADD; +additive_expression_3 + minus .and multiplicative_expression .and .true .emit OP_SUBTRACT; + +/* + * <shift_expression> ::= <additive_expression> + * | <shift_expression> "<<" <additive_expression> // reserved + * | <shift_expression> ">>" <additive_expression> // reserved + */ +shift_expression + additive_expression/* .and .loop shift_expression_1*/; +/*shift_expression_1 + shift_expression_2 .or shift_expression_3;*/ +/*shift_expression_2 + lessless .and additive_expression .and .true .emit OP_LSHIFT;*/ +/*shift_expression_3 + greatergreater .and additive_expression .and .true .emit OP_RSHIFT;*/ + +/* + * <relational_expression> ::= <shift_expression> + * | <relational_expression> "<" <shift_expression> + * | <relational_expression> ">" <shift_expression> + * | <relational_expression> "<=" <shift_expression> + * | <relational_expression> ">=" <shift_expression> + */ +relational_expression + shift_expression .and .loop relational_expression_1; +relational_expression_1 + relational_expression_2 .or relational_expression_3 .or relational_expression_4 .or + relational_expression_5; +relational_expression_2 + lessequals .and shift_expression .and .true .emit OP_LESSEQUAL; +relational_expression_3 + greaterequals .and shift_expression .and .true .emit OP_GREATEREQUAL; +relational_expression_4 + less .and shift_expression .and .true .emit OP_LESS; +relational_expression_5 + greater .and shift_expression .and .true .emit OP_GREATER; + +/* + * <equality_expression> ::= <relational_expression> + * | <equality_expression> "==" <relational_expression> + * | <equality_expression> "!=" <relational_expression> + */ +equality_expression + relational_expression .and .loop equality_expression_1; +equality_expression_1 + equality_expression_2 .or equality_expression_3; +equality_expression_2 + equalsequals .and relational_expression .and .true .emit OP_EQUAL; +equality_expression_3 + bangequals .and relational_expression .and .true .emit OP_NOTEQUAL; + +/* + * <and_expression> ::= <equality_expression> + * | <and_expression> "&" <equality_expression> // reserved + */ +and_expression + equality_expression/* .and .loop and_expression_1*/; +/*and_expression_1 + ampersand .and equality_expression .and .true .emit OP_BITAND;*/ + +/* + * <exclusive_or_expression> ::= <and_expression> + * | <exclusive_or_expression> "^" <and_expression> // reserved + */ +exclusive_or_expression + and_expression/* .and .loop exclusive_or_expression_1*/; +/*exclusive_or_expression_1 + caret .and and_expression .and .true .emit OP_BITXOR;*/ + +/* + * <inclusive_or_expression> ::= <exclusive_or_expression> + * | <inclusive_or_expression> "|" <exclusive_or_expression> // reserved + */ +inclusive_or_expression + exclusive_or_expression/* .and .loop inclusive_or_expression_1*/; +/*inclusive_or_expression_1 + bar .and exclusive_or_expression .and .true .emit OP_BITOR;*/ + +/* + * <logical_and_expression> ::= <inclusive_or_expression> + * | <logical_and_expression> "&&" <inclusive_or_expression> + */ +logical_and_expression + inclusive_or_expression .and .loop logical_and_expression_1; +logical_and_expression_1 + ampersandampersand .and inclusive_or_expression .and .true .emit OP_LOGICALAND; + +/* + * <logical_xor_expression> ::= <logical_and_expression> + * | <logical_xor_expression> "^^" <logical_and_expression> + */ +logical_xor_expression + logical_and_expression .and .loop logical_xor_expression_1; +logical_xor_expression_1 + caretcaret .and logical_and_expression .and .true .emit OP_LOGICALXOR; + +/* + * <logical_or_expression> ::= <logical_xor_expression> + * | <logical_or_expression> "||" <logical_xor_expression> + */ +logical_or_expression + logical_xor_expression .and .loop logical_or_expression_1; +logical_or_expression_1 + barbar .and logical_xor_expression .and .true .emit OP_LOGICALOR; + +/* + * <conditional_expression> ::= <logical_or_expression> + * | <logical_or_expression> "?" <expression> ":" <conditional_expression> + */ +conditional_expression + logical_or_expression .and .loop conditional_expression_1; +conditional_expression_1 + question .and expression .and colon .and conditional_expression .and .true .emit OP_SELECT; + +/* + * <assignment_expression> ::= <conditional_expression> + * | <unary_expression> <assignment_operator> <assignment_expression> + * + * <assignment_operator> ::= "=" + * | "*=" + * | "/=" + * | "+=" + * | "-=" + * | "%=" // reserved + * | "<<=" // reserved + * | ">>=" // reserved + * | "&=" // reserved + * | "^=" // reserved + * | "|=" // reserved + */ +assignment_expression + assignment_expression_1 .or assignment_expression_2 .or assignment_expression_3 .or + assignment_expression_4 .or assignment_expression_5/* .or assignment_expression_6 .or + assignment_expression_7 .or assignment_expression_8 .or assignment_expression_9 .or + assignment_expression_10 .or assignment_expression_11*/ .or conditional_expression; +assignment_expression_1 + unary_expression .and equals .and assignment_expression .and .true .emit OP_ASSIGN; +assignment_expression_2 + unary_expression .and starequals .and assignment_expression .and .true .emit OP_MULASSIGN; +assignment_expression_3 + unary_expression .and slashequals .and assignment_expression .and .true .emit OP_DIVASSIGN; +assignment_expression_4 + unary_expression .and plusequals .and assignment_expression .and .true .emit OP_ADDASSIGN; +assignment_expression_5 + unary_expression .and minusequals .and assignment_expression .and .true .emit OP_SUBASSIGN; +/*assignment_expression_6 + unary_expression .and percentequals .and assignment_expression .and .true .emit OP_MODASSIGN;*/ +/*assignment_expression_7 + unary_expression .and lesslessequals .and assignment_expression .and .true .emit OP_LSHASSIGN;*/ +/*assignment_expression_8 + unary_expression .and greatergreaterequals .and assignment_expression .and + .true .emit OP_RSHASSIGN;*/ +/*assignment_expression_9 + unary_expression .and ampersandequals .and assignment_expression .and .true .emit OP_ANDASSIGN;*/ +/*assignment_expression_10 + unary_expression .and caretequals .and assignment_expression .and .true .emit OP_XORASSIGN;*/ +/*assignment_expression_11 + unary_expression .and barequals .and assignment_expression .and .true .emit OP_ORASSIGN;*/ + +/* + * <expression> ::= <assignment_expression> + * | <expression> "," <assignment_expression> + */ +expression + assignment_expression .and .loop expression_1; +expression_1 + comma .and assignment_expression .and .true .emit OP_SEQUENCE; + +/* + * <constant_expression> ::= <conditional_expression> + */ +constant_expression + conditional_expression .and .true .emit OP_END; + +/* + * <declaration> ::= <function_prototype> ";" + * | <init_declarator_list> ";" + */ +declaration + declaration_1 .or declaration_2; +declaration_1 + function_prototype .emit DECLARATION_FUNCTION_PROTOTYPE .and semicolon; +declaration_2 + init_declarator_list .emit DECLARATION_INIT_DECLARATOR_LIST .and semicolon; + +/* + * <function_prototype> ::= <function_header> "void" ")" + * | <function_declarator> ")" + */ +function_prototype + function_prototype_1 .or function_prototype_2; +function_prototype_1 + function_header .and "void" .and rparen .error RPAREN_EXPECTED .emit PARAMETER_NONE; +function_prototype_2 + function_declarator .and rparen .error RPAREN_EXPECTED .emit PARAMETER_NONE; + +/* + * <function_declarator> ::= <function_header> + * | <function_header_with_parameters> + */ +function_declarator + function_header_with_parameters .or function_header; + +/* + * <function_header_with_parameters> ::= <function_header> <parameter_declaration> + * | <function_header_with_parameters> "," + * <parameter_declaration> + */ +function_header_with_parameters + function_header .and parameter_declaration .and .loop function_header_with_parameters_1; +function_header_with_parameters_1 + comma .and parameter_declaration; + +/* + * <function_header> ::= <fully_specified_type> <identifier> "(" + */ +function_header + function_header_nospace .or function_header_space; +function_header_space + fully_specified_type_space .and space .and function_decl_identifier .and lparen; +function_header_nospace + fully_specified_type_nospace .and function_decl_identifier .and lparen; + +/* + * <function_decl_identifier> ::= "__constructor" + * | <__operator> + * | <identifier> + * + * note: this is an extension to the standard language specification. + * normally slang disallows operator and constructor prototypes and definitions + */ +function_decl_identifier + .if (parsing_builtin != 0) __operator .emit FUNCTION_OPERATOR .or + .if (parsing_builtin != 0) "__constructor" .emit FUNCTION_CONSTRUCTOR .or + identifier .emit FUNCTION_ORDINARY; + +/* + * <__operator> ::= "__operator" <overriden_op> + * + * note: this is an extension to the standard language specification. + * normally slang disallows operator prototypes and definitions + */ +__operator + "__operator" .and overriden_operator .error INVALID_OPERATOR_OVERRIDE; + +/* + * <overriden_op> ::= "=" + * | "+=" + * | "-=" + * | "*=" + * | "/=" + * | "%=" // reserved + * | "<<=" // reserved + * | ">>=" // reserved + * | "&=" // reserved + * | "^=" // reserved + * | "|=" // reserved + * | "^^" + * | "|" // reserved + * | "^" // reserved + * | "&" // reserved + * | "==" + * | "!=" + * | "<" + * | ">" + * | "<=" + * | ">=" + * | "<<" // reserved + * | ">>" // reserved + * | "*" + * | "/" + * | "%" // reserved + * | "++" + * | "--" + * | "+" + * | "-" + * | "~" // reserved + * | "!" + * + * note: this is an extension to the standard language specification. + * normally slang disallows operator prototypes and definitions + */ +overriden_operator + plusplus .emit OPERATOR_INCREMENT .or + plusequals .emit OPERATOR_ADDASSIGN .or + plus .emit OPERATOR_PLUS .or + minusminus .emit OPERATOR_DECREMENT .or + minusequals .emit OPERATOR_SUBASSIGN .or + minus .emit OPERATOR_MINUS .or + bang .emit OPERATOR_NOT .or + starequals .emit OPERATOR_MULASSIGN .or + star .emit OPERATOR_MULTIPLY .or + slashequals .emit OPERATOR_DIVASSIGN .or + slash .emit OPERATOR_DIVIDE .or + lessequals .emit OPERATOR_LESSEQUAL .or + /*lesslessequals .emit OPERATOR_LSHASSIGN .or*/ + /*lessless .emit OPERATOR_LSHIFT .or*/ + less .emit OPERATOR_LESS .or + greaterequals .emit OPERATOR_GREATEREQUAL .or + /*greatergreaterequals .emit OPERATOR_RSHASSIGN .or*/ + /*greatergreater .emit OPERATOR_RSHIFT .or*/ + greater .emit OPERATOR_GREATER .or + /*percentequals .emit OPERATOR_MODASSIGN .or*/ + /*percent .emit OPERATOR_MODULUS .or*/ + /*ampersandequals .emit OPERATOR_ANDASSIGN */ + /*ampersand .emit OPERATOR_BITAND .or*/ + /*barequals .emit OPERATOR_ORASSIGN .or*/ + /*bar .emit OPERATOR_BITOR .or*/ + /*tilde .emit OPERATOR_COMPLEMENT .or*/ + /*caretequals .emit OPERATOR_XORASSIGN .or*/ + caretcaret .emit OPERATOR_LOGICALXOR /*.or + caret .emit OPERATOR_BITXOR*/; + +/* + * <parameter_declarator> ::= <type_specifier> <identifier> + * | <type_specifier> <identifier> "[" <constant_expression> "]" + */ +parameter_declarator + parameter_declarator_nospace .or parameter_declarator_space; +parameter_declarator_nospace + type_specifier_nospace .and identifier .and parameter_declarator_1; +parameter_declarator_space + type_specifier_space .and space .and identifier .and parameter_declarator_1; +parameter_declarator_1 + parameter_declarator_2 .emit PARAMETER_ARRAY_PRESENT .or + .true .emit PARAMETER_ARRAY_NOT_PRESENT; +parameter_declarator_2 + lbracket .and constant_expression .and rbracket; + +/* + * <parameter_declaration> ::= <type_qualifier> <parameter_qualifier> + * <precision> <parameter_declarator> + * | <type_qualifier> <parameter_qualifier> + * <precision> <parameter_type_specifier> + * | <type_qualifier> <parameter_qualifier> + * <parameter_declarator> + * | <type_qualifier> <parameter_qualifier> + * <parameter_type_specifier> + * | <parameter_qualifier> <precision> + * <parameter_declarator> + * | <parameter_qualifier> <precision> + * <parameter_type_specifier> + * | <parameter_qualifier> <parameter_declarator> + * | <parameter_qualifier> <parameter_type_specifier> + */ +parameter_declaration + parameter_declaration_1 .emit PARAMETER_NEXT; +parameter_declaration_1 + parameter_declaration_2 .or parameter_declaration_3; +parameter_declaration_2 + type_qualifier .and space .and parameter_qualifier .and parameter_declaration_4; +parameter_declaration_3 + parameter_qualifier .emit TYPE_QUALIFIER_NONE .and parameter_declaration_4; +parameter_declaration_4 + parameter_declaration_optprec .and parameter_declaration_rest; +parameter_declaration_optprec + parameter_declaration_prec .or .true .emit PRECISION_DEFAULT; +parameter_declaration_prec + precision .and space; +parameter_declaration_rest + parameter_declarator .or parameter_type_specifier; + +/* + * <parameter_qualifier> ::= "in" + * | "out" + * | "inout" + * | "" + */ +parameter_qualifier + parameter_qualifier_1 .or .true .emit PARAM_QUALIFIER_IN; +parameter_qualifier_1 + parameter_qualifier_2 .and space; +parameter_qualifier_2 + "in" .emit PARAM_QUALIFIER_IN .or + "out" .emit PARAM_QUALIFIER_OUT .or + "inout" .emit PARAM_QUALIFIER_INOUT; + +/* + * <parameter_type_specifier> ::= <type_specifier> + * | <type_specifier> "[" <constant_expression> "]" + */ +parameter_type_specifier + parameter_type_specifier_1 .and .true .emit '\0' .and parameter_type_specifier_2; +parameter_type_specifier_1 + type_specifier_nospace .or type_specifier_space; +parameter_type_specifier_2 + parameter_type_specifier_3 .emit PARAMETER_ARRAY_PRESENT .or + .true .emit PARAMETER_ARRAY_NOT_PRESENT; +parameter_type_specifier_3 + lbracket .and constant_expression .and rbracket; + +/* + * <init_declarator_list> ::= <single_declaration> + * | <init_declarator_list> "," <identifier> + * | <init_declarator_list> "," <identifier> "[" "]" + * | <init_declarator_list> "," <identifier> "[" <constant_expression> "]" + * | <init_declarator_list> "," <identifier> "=" <initializer> + */ +init_declarator_list + single_declaration .and .loop init_declarator_list_1 .emit DECLARATOR_NEXT .and + .true .emit DECLARATOR_NONE; +init_declarator_list_1 + comma .and identifier .emit VARIABLE_IDENTIFIER .and init_declarator_list_2; +init_declarator_list_2 + init_declarator_list_3 .or init_declarator_list_4 .or .true .emit VARIABLE_NONE; +init_declarator_list_3 + equals .and initializer .emit VARIABLE_INITIALIZER; +init_declarator_list_4 + lbracket .and init_declarator_list_5 .and rbracket; +init_declarator_list_5 + constant_expression .emit VARIABLE_ARRAY_EXPLICIT .or .true .emit VARIABLE_ARRAY_UNKNOWN; + +/* + * <single_declaration> ::= <fully_specified_type> + * | <fully_specified_type> <identifier> + * | <fully_specified_type> <identifier> "[" "]" + * | <fully_specified_type> <identifier> "[" <constant_expression> "]" + * | <fully_specified_type> <identifier> "=" <initializer> + */ +single_declaration + single_declaration_nospace .or single_declaration_space; +single_declaration_space + fully_specified_type_space .and single_declaration_space_1; +single_declaration_nospace + fully_specified_type_nospace .and single_declaration_nospace_1; +single_declaration_space_1 + single_declaration_space_2 .emit VARIABLE_IDENTIFIER .or .true .emit VARIABLE_NONE; +single_declaration_nospace_1 + single_declaration_nospace_2 .emit VARIABLE_IDENTIFIER .or .true .emit VARIABLE_NONE; +single_declaration_space_2 + space .and identifier .and single_declaration_3; +single_declaration_nospace_2 + identifier .and single_declaration_3; +single_declaration_3 + single_declaration_4 .or single_declaration_5 .or .true .emit VARIABLE_NONE; +single_declaration_4 + equals .and initializer .emit VARIABLE_INITIALIZER; +single_declaration_5 + lbracket .and single_declaration_6 .and rbracket; +single_declaration_6 + constant_expression .emit VARIABLE_ARRAY_EXPLICIT .or .true .emit VARIABLE_ARRAY_UNKNOWN; + +/* + * <fully_specified_type> ::= <opt_invariant> <opt_centroid> <opt_qualifer> <opt_precision> <type_specifier> + * + * Example: "invariant varying highp vec3" + */ +fully_specified_type_space + fully_specified_type_optinvariant .and fully_specified_type_optcentroid .and fully_specified_type_optqual .and fully_specified_type_optprec .and type_specifier_space; +fully_specified_type_nospace + fully_specified_type_optinvariant .and fully_specified_type_optcentroid .and fully_specified_type_optqual .and fully_specified_type_optprec .and type_specifier_nospace; +fully_specified_type_optinvariant + fully_specified_type_invariant .or .true .emit TYPE_VARIANT; +fully_specified_type_invariant + invariant_qualifier .and space; +fully_specified_type_optcentroid + fully_specified_type_centroid .or .true .emit TYPE_CENTER; +fully_specified_type_centroid + centroid_qualifier .and space; +fully_specified_type_optqual + fully_specified_type_qual .or .true .emit TYPE_QUALIFIER_NONE; +fully_specified_type_qual + type_qualifier .and space; +fully_specified_type_optprec + fully_specified_type_prec .or .true .emit PRECISION_DEFAULT; +fully_specified_type_prec + precision .and space; + +/* + * <invariant_qualifier> ::= "invariant" + */ +invariant_qualifier + "invariant" .emit TYPE_INVARIANT; + +centroid_qualifier + "centroid" .emit TYPE_CENTROID; + + +/* + * <type_qualifier> ::= "const" + * | "attribute" // Vertex only. + * | "varying" + * | "uniform" + * | "__fixed_output" + * | "__fixed_input" + * + * note: this is an extension to the standard language specification, + * normally slang disallows __fixed_output and __fixed_input type qualifiers + */ +type_qualifier + "const" .emit TYPE_QUALIFIER_CONST .or + .if (shader_type == 2) "attribute" .emit TYPE_QUALIFIER_ATTRIBUTE .or + "varying" .emit TYPE_QUALIFIER_VARYING .or + "uniform" .emit TYPE_QUALIFIER_UNIFORM .or + .if (parsing_builtin != 0) "__fixed_output" .emit TYPE_QUALIFIER_FIXEDOUTPUT .or + .if (parsing_builtin != 0) "__fixed_input" .emit TYPE_QUALIFIER_FIXEDINPUT; + +/* + * <type_specifier_nonarray> ::= "void" + * | "float" + * | "int" + * | "bool" + * | "vec2" + * | "vec3" + * | "vec4" + * | "bvec2" + * | "bvec3" + * | "bvec4" + * | "ivec2" + * | "ivec3" + * | "ivec4" + * | "mat2" + * | "mat3" + * | "mat4" + * | "mat2x3" + * | "mat3x2" + * | "mat2x4" + * | "mat4x2" + * | "mat3x4" + * | "mat4x3" + * | "sampler1D" + * | "sampler2D" + * | "sampler3D" + * | "samplerCube" + * | "sampler1DShadow" + * | "sampler2DShadow" + * | "sampler2DRect" + * | "sampler2DRectShadow" + * | <struct_specifier> + * | <type_name> + */ +type_specifier_nonarray_space + "void" .emit TYPE_SPECIFIER_VOID .or + "float" .emit TYPE_SPECIFIER_FLOAT .or + "int" .emit TYPE_SPECIFIER_INT .or + "bool" .emit TYPE_SPECIFIER_BOOL .or + "vec2" .emit TYPE_SPECIFIER_VEC2 .or + "vec3" .emit TYPE_SPECIFIER_VEC3 .or + "vec4" .emit TYPE_SPECIFIER_VEC4 .or + "bvec2" .emit TYPE_SPECIFIER_BVEC2 .or + "bvec3" .emit TYPE_SPECIFIER_BVEC3 .or + "bvec4" .emit TYPE_SPECIFIER_BVEC4 .or + "ivec2" .emit TYPE_SPECIFIER_IVEC2 .or + "ivec3" .emit TYPE_SPECIFIER_IVEC3 .or + "ivec4" .emit TYPE_SPECIFIER_IVEC4 .or + "mat2" .emit TYPE_SPECIFIER_MAT2 .or + "mat3" .emit TYPE_SPECIFIER_MAT3 .or + "mat4" .emit TYPE_SPECIFIER_MAT4 .or + "mat2x3" .emit TYPE_SPECIFIER_MAT23 .or + "mat3x2" .emit TYPE_SPECIFIER_MAT32 .or + "mat2x4" .emit TYPE_SPECIFIER_MAT24 .or + "mat4x2" .emit TYPE_SPECIFIER_MAT42 .or + "mat3x4" .emit TYPE_SPECIFIER_MAT34 .or + "mat4x3" .emit TYPE_SPECIFIER_MAT43 .or + "sampler1D" .emit TYPE_SPECIFIER_SAMPLER1D .or + "sampler2D" .emit TYPE_SPECIFIER_SAMPLER2D .or + "sampler3D" .emit TYPE_SPECIFIER_SAMPLER3D .or + "samplerCube" .emit TYPE_SPECIFIER_SAMPLERCUBE .or + "sampler1DShadow" .emit TYPE_SPECIFIER_SAMPLER1DSHADOW .or + "sampler2DShadow" .emit TYPE_SPECIFIER_SAMPLER2DSHADOW .or + "sampler2DRect" .emit TYPE_SPECIFIER_SAMPLER2DRECT .or + "sampler2DRectShadow" .emit TYPE_SPECIFIER_SAMPLER2DRECTSHADOW .or + type_name .emit TYPE_SPECIFIER_TYPENAME; +type_specifier_nonarray_nospace + struct_specifier .emit TYPE_SPECIFIER_STRUCT; +type_specifier_nonarray + type_specifier_nonarray_nospace .or type_specifier_nonarray_space; + +/* + * <type_specifier> ::= <type_specifier_nonarray> + * | <type_specifier_nonarray> "[" <constant_expression> "]" + */ +type_specifier_space + type_specifier_nonarray_space .and .true .emit TYPE_SPECIFIER_NONARRAY; +type_specifier_nospace + type_specifier_nospace_array .or type_specifier_nospace_1; +type_specifier_nospace_1 + type_specifier_nonarray_nospace .and .true .emit TYPE_SPECIFIER_NONARRAY; +type_specifier_nospace_array + type_specifier_nonarray .and lbracket .emit TYPE_SPECIFIER_ARRAY .and constant_expression .and rbracket; + +/* + * <struct_specifier> ::= "struct" <identifier> "{" <struct_declaration_list> "}" + * | "struct" "{" <struct_declaration_list> "}" + */ +struct_specifier + "struct" .and struct_specifier_1 .and optional_space .and lbrace .error LBRACE_EXPECTED .and + struct_declaration_list .and rbrace .emit FIELD_NONE; +struct_specifier_1 + struct_specifier_2 .or .true .emit '\0'; +struct_specifier_2 + space .and identifier; + +/* + * <struct_declaration_list> ::= <struct_declaration> + * | <struct_declaration_list> <struct_declaration> + */ +struct_declaration_list + struct_declaration .and .loop struct_declaration .emit FIELD_NEXT; + +/* + * <struct_declaration> ::= <type_specifier> <struct_declarator_list> ";" + */ +struct_declaration + struct_declaration_nospace .or struct_declaration_space; +struct_declaration_space + type_specifier_space .and space .and struct_declarator_list .and semicolon .emit FIELD_NONE; +struct_declaration_nospace + type_specifier_nospace .and struct_declarator_list .and semicolon .emit FIELD_NONE; + +/* + * <struct_declarator_list> ::= <struct_declarator> + * | <struct_declarator_list> "," <struct_declarator> + */ +struct_declarator_list + struct_declarator .and .loop struct_declarator_list_1 .emit FIELD_NEXT; +struct_declarator_list_1 + comma .and struct_declarator; + +/* + * <struct_declarator> ::= <identifier> + * | <identifier> "[" <constant_expression> "]" + */ +struct_declarator + identifier .and struct_declarator_1; +struct_declarator_1 + struct_declarator_2 .emit FIELD_ARRAY .or .true .emit FIELD_NONE; +struct_declarator_2 + lbracket .and constant_expression .and rbracket; + +/* + * <initializer> ::= <assignment_expression> + */ +initializer + assignment_expression .and .true .emit OP_END; + +/* + * <declaration_statement> ::= <declaration> + */ +declaration_statement + declaration; + +/* + * <statement> ::= <compound_statement> + * | <simple_statement> + */ +statement + compound_statement .or simple_statement; +statement_space + compound_statement .or statement_space_1; +statement_space_1 + space .and simple_statement; + +/* + * <simple_statement> ::= <__asm_statement> + * | <selection_statement> + * | <iteration_statement> + * | <jump_statement> + * | <expression_statement> + * | <declaration_statement> + * + * note: this is an extension to the standard language specification. + * normally slang disallows use of __asm statements + */ +simple_statement + .if (parsing_builtin != 0) __asm_statement .emit OP_ASM .or + selection_statement .or + iteration_statement .or + precision_stmt .emit OP_PRECISION .or + jump_statement .or + expression_statement .emit OP_EXPRESSION .or + declaration_statement .emit OP_DECLARE; + +/* + * <compound_statement> ::= "{" "}" + * | "{" <statement_list> "}" + */ +compound_statement + compound_statement_1 .emit OP_BLOCK_BEGIN_NEW_SCOPE .and .true .emit OP_END; +compound_statement_1 + compound_statement_2 .or compound_statement_3; +compound_statement_2 + lbrace .and rbrace; +compound_statement_3 + lbrace .and statement_list .and rbrace; + +/* + * <compound_statement_no_new_scope> ::= "{" "}" + * | "{" <statement_list> "}" + */ +compound_statement_no_new_scope + compound_statement_no_new_scope_1 .emit OP_BLOCK_BEGIN_NO_NEW_SCOPE .and .true .emit OP_END; +compound_statement_no_new_scope_1 + compound_statement_no_new_scope_2 .or compound_statement_no_new_scope_3; +compound_statement_no_new_scope_2 + lbrace .and rbrace; +compound_statement_no_new_scope_3 + lbrace .and statement_list .and rbrace; + + +/* + * <statement_list> ::= <statement> + * | <statement_list> <statement> + */ +statement_list + statement .and .loop statement; + +/* + * <expression_statement> ::= ";" + * | <expression> ";" + */ +expression_statement + expression_statement_1 .or expression_statement_2; +expression_statement_1 + semicolon .emit OP_PUSH_VOID .emit OP_END; +expression_statement_2 + expression .and semicolon .emit OP_END; + +/* + * <selection_statement> ::= "if" "(" <expression> ")" <selection_rest_statement> + */ +selection_statement + "if" .emit OP_IF .and lparen .error LPAREN_EXPECTED .and expression .and + rparen .error RPAREN_EXPECTED .emit OP_END .and selection_rest_statement; + +/* + * <selection_rest_statement> ::= <statement> "else" <statement> + * | <statement> + */ +selection_rest_statement + statement .and selection_rest_statement_1; +selection_rest_statement_1 + selection_rest_statement_2 .or .true .emit OP_EXPRESSION .emit OP_PUSH_VOID .emit OP_END; +selection_rest_statement_2 + "else" .and optional_space .and statement; + +/* + * <condition> ::= <expression> + * | <fully_specified_type> <identifier> "=" <initializer> + * + * note: if <condition_1> is executed, the emit format must + * match <declaration> emit format + */ +condition + condition_1 .emit OP_DECLARE .emit DECLARATION_INIT_DECLARATOR_LIST .or + condition_3 .emit OP_EXPRESSION; +condition_1 + condition_1_nospace .or condition_1_space; +condition_1_nospace + fully_specified_type_nospace .and condition_2; +condition_1_space + fully_specified_type_space .and space .and condition_2; +condition_2 + identifier .emit VARIABLE_IDENTIFIER .and equals .emit VARIABLE_INITIALIZER .and + initializer .and .true .emit DECLARATOR_NONE; +condition_3 + expression .and .true .emit OP_END; + +/* + * <iteration_statement> ::= "while" "(" <condition> ")" <statement> + * | "do" <statement> "while" "(" <expression> ")" ";" + * | "for" "(" <for_init_statement> <for_rest_statement> ")" <statement> + */ +iteration_statement + iteration_statement_1 .or iteration_statement_2 .or iteration_statement_3; +iteration_statement_1 + "while" .emit OP_WHILE .and lparen .error LPAREN_EXPECTED .and condition .and + rparen .error RPAREN_EXPECTED .and statement; +iteration_statement_2 + "do" .emit OP_DO .and statement_space .and "while" .and lparen .error LPAREN_EXPECTED .and + expression .and rparen .error RPAREN_EXPECTED .emit OP_END .and semicolon; +iteration_statement_3 + "for" .emit OP_FOR .and lparen .error LPAREN_EXPECTED .and for_init_statement .and + for_rest_statement .and rparen .error RPAREN_EXPECTED .and statement; + +/* + * <for_init_statement> ::= <expression_statement> + * | <declaration_statement> + */ +for_init_statement + expression_statement .emit OP_EXPRESSION .or declaration_statement .emit OP_DECLARE; + +/* + * <conditionopt> ::= <condition> + * | "" + * + * note: <conditionopt> is used only by "for" statement. + * if <condition> is ommitted, parser simulates default behaviour, + * that is simulates "true" expression + */ +conditionopt + condition .or + .true .emit OP_EXPRESSION .emit OP_PUSH_BOOL .emit 2 .emit '1' .emit '\0' .emit OP_END; + +/* + * <for_rest_statement> ::= <conditionopt> ";" + * | <conditionopt> ";" <expression> + */ +for_rest_statement + conditionopt .and semicolon .and for_rest_statement_1; +for_rest_statement_1 + for_rest_statement_2 .or .true .emit OP_PUSH_VOID .emit OP_END; +for_rest_statement_2 + expression .and .true .emit OP_END; + +/* + * <jump_statement> ::= "continue" ";" + * | "break" ";" + * | "return" ";" + * | "return" <expression> ";" + * | "discard" ";" // Fragment shader only. + */ +jump_statement + jump_statement_1 .or jump_statement_2 .or jump_statement_3 .or jump_statement_4 .or + .if (shader_type == 1) jump_statement_5; +jump_statement_1 + "continue" .and semicolon .emit OP_CONTINUE; +jump_statement_2 + "break" .and semicolon .emit OP_BREAK; +jump_statement_3 + "return" .emit OP_RETURN .and optional_space .and expression .and semicolon .emit OP_END; +jump_statement_4 + "return" .emit OP_RETURN .and semicolon .emit OP_PUSH_VOID .emit OP_END; +jump_statement_5 + "discard" .and semicolon .emit OP_DISCARD; + +/* + * <__asm_statement> ::= "__asm" <identifier> <asm_arguments> ";" + * + * note: this is an extension to the standard language specification. + * normally slang disallows __asm statements + */ +__asm_statement + "__asm" .and space .and identifier .and space .and asm_arguments .and semicolon .emit OP_END; + +/* + * <asm_arguments> ::= <asm_argument> + * | <asm_arguments> "," <asm_argument> + * + * note: this is an extension to the standard language specification. + * normally slang disallows __asm statements + */ +asm_arguments + asm_argument .and .true .emit OP_END .and .loop asm_arguments_1; +asm_arguments_1 + comma .and asm_argument .and .true .emit OP_END; + +/* + * <asm_argument> ::= <variable_identifier> + * | <floatconstant> + * + * note: this is an extension to the standard language specification. + * normally slang disallows __asm statements + */ +asm_argument + var_with_field .or + variable_identifier .or + floatconstant; + +var_with_field + variable_identifier .and dot .and field_selection .emit OP_FIELD; + + +/* + * <translation_unit> ::= <external_declaration> + * | <translation_unit> <external_declaration> + */ +translation_unit + optional_space .emit REVISION .and external_declaration .error INVALID_EXTERNAL_DECLARATION .and + .loop external_declaration .and optional_space .and + '\0' .error INVALID_EXTERNAL_DECLARATION .emit EXTERNAL_NULL; + + +/* + * <external_declaration> ::= <function_definition> + * | <declaration> + */ +external_declaration + precision_stmt .emit DEFAULT_PRECISION .or + function_definition .emit EXTERNAL_FUNCTION_DEFINITION .or + invariant_stmt .emit INVARIANT_STMT .or + declaration .emit EXTERNAL_DECLARATION; + + +/* + * <precision_stmt> ::= "precision" <precision> <prectype> + */ +precision_stmt + "precision" .and space .and precision .error INVALID_PRECISION .and space .and prectype .error INVALID_PRECISION_TYPE .and semicolon; + +/* + * <precision> ::= "lowp" + * | "mediump" + * | "highp" + */ +precision + "lowp" .emit PRECISION_LOW .or + "mediump" .emit PRECISION_MEDIUM .or + "highp" .emit PRECISION_HIGH; + +/* + * <prectype> ::= "int" + * | "float" + * | "a sampler type" + */ +prectype + "int" .emit TYPE_SPECIFIER_INT .or + "float" .emit TYPE_SPECIFIER_FLOAT .or + "sampler1D" .emit TYPE_SPECIFIER_SAMPLER1D .or + "sampler2D" .emit TYPE_SPECIFIER_SAMPLER2D .or + "sampler3D" .emit TYPE_SPECIFIER_SAMPLER3D .or + "samplerCube" .emit TYPE_SPECIFIER_SAMPLERCUBE .or + "sampler1DShadow" .emit TYPE_SPECIFIER_SAMPLER1DSHADOW .or + "sampler2DShadow" .emit TYPE_SPECIFIER_SAMPLER2DSHADOW .or + "sampler2DRect" .emit TYPE_SPECIFIER_SAMPLER2DRECT .or + "sampler2DRectShadow" .emit TYPE_SPECIFIER_SAMPLER2DRECTSHADOW; + + +/* + * <invariant_stmt> ::= "invariant" identifier; + */ +invariant_stmt + "invariant" .and space .and identifier .and semicolon; + + +/* + * <function_definition> :: <function_prototype> <compound_statement_no_new_scope> + */ +function_definition + function_prototype .and compound_statement_no_new_scope; + + + +/* + * helper rules, not part of the official language syntax + */ + +digit_oct + '0'-'7'; + +digit_dec + '0'-'9'; + +digit_hex + '0'-'9' .or 'A'-'F' .or 'a'-'f'; + +id_character_first + 'a'-'z' .or 'A'-'Z' .or '_'; + +id_character_next + id_character_first .or digit_dec; + +identifier + id_character_first .emit * .and .loop id_character_next .emit * .and .true .emit '\0'; + +float + float_1 .or float_2 .or float_3; +float_1 + float_fractional_constant .and float_optional_exponent_part .and optional_f_suffix; +float_2 + float_digit_sequence .and .true .emit '\0' .and float_exponent_part .and optional_f_suffix; +float_3 + float_digit_sequence .and .true .emit '\0' .and 'f' .emit '\0'; + +float_fractional_constant + float_fractional_constant_1 .or float_fractional_constant_2 .or float_fractional_constant_3; +float_fractional_constant_1 + float_digit_sequence .and '.' .and float_digit_sequence; +float_fractional_constant_2 + float_digit_sequence .and '.' .and .true .emit '\0'; +float_fractional_constant_3 + '.' .emit '\0' .and float_digit_sequence; + +float_optional_exponent_part + float_exponent_part .or .true .emit '\0'; + +float_digit_sequence + digit_dec .emit * .and .loop digit_dec .emit * .and .true .emit '\0'; + +float_exponent_part + float_exponent_part_1 .or float_exponent_part_2; +float_exponent_part_1 + 'e' .and float_optional_sign .and float_digit_sequence; +float_exponent_part_2 + 'E' .and float_optional_sign .and float_digit_sequence; + +float_optional_sign + float_sign .or .true; + +float_sign + '+' .or '-' .emit '-'; + +optional_f_suffix + 'f' .or .true; + + +integer + integer_hex .or integer_oct .or integer_dec; + +integer_hex + '0' .and integer_hex_1 .emit 0x10 .and digit_hex .emit * .and .loop digit_hex .emit * .and + .true .emit '\0'; +integer_hex_1 + 'x' .or 'X'; + +integer_oct + '0' .emit 8 .emit * .and .loop digit_oct .emit * .and .true .emit '\0'; + +integer_dec + digit_dec .emit 10 .emit * .and .loop digit_dec .emit * .and .true .emit '\0'; + +boolean + "true" .emit 2 .emit '1' .emit '\0' .or + "false" .emit 2 .emit '0' .emit '\0'; + +type_name + identifier; + +field_selection + identifier; + +floatconstant + float .emit OP_PUSH_FLOAT; + +intconstant + integer .emit OP_PUSH_INT; + +boolconstant + boolean .emit OP_PUSH_BOOL; + +optional_space + .loop single_space; + +space + single_space .and .loop single_space; + +single_space + white_char .or c_style_comment_block .or cpp_style_comment_block; + +white_char + ' ' .or '\t' .or new_line .or '\v' .or '\f'; + +new_line + cr_lf .or lf_cr .or '\n' .or '\r'; + +cr_lf + '\r' .and '\n'; + +lf_cr + '\n' .and '\r'; + +c_style_comment_block + '/' .and '*' .and c_style_comment_rest; + +c_style_comment_rest + .loop c_style_comment_char_no_star .and c_style_comment_rest_1; +c_style_comment_rest_1 + c_style_comment_end .or c_style_comment_rest_2; +c_style_comment_rest_2 + '*' .and c_style_comment_rest; + +c_style_comment_char_no_star + '\x2B'-'\xFF' .or '\x01'-'\x29'; + +c_style_comment_end + '*' .and '/'; + +cpp_style_comment_block + '/' .and '/' .and cpp_style_comment_block_1; +cpp_style_comment_block_1 + cpp_style_comment_block_2 .or cpp_style_comment_block_3; +cpp_style_comment_block_2 + .loop cpp_style_comment_char .and new_line; +cpp_style_comment_block_3 + .loop cpp_style_comment_char; + +cpp_style_comment_char + '\x0E'-'\xFF' .or '\x01'-'\x09' .or '\x0B'-'\x0C'; + +/* lexical rules */ + +/*ampersand + optional_space .and '&' .and optional_space;*/ + +ampersandampersand + optional_space .and '&' .and '&' .and optional_space; + +/*ampersandequals + optional_space .and '&' .and '=' .and optional_space;*/ + +/*bar + optional_space .and '|' .and optional_space;*/ + +barbar + optional_space .and '|' .and '|' .and optional_space; + +/*barequals + optional_space .and '|' .and '=' .and optional_space;*/ + +bang + optional_space .and '!' .and optional_space; + +bangequals + optional_space .and '!' .and '=' .and optional_space; + +/*caret + optional_space .and '^' .and optional_space;*/ + +caretcaret + optional_space .and '^' .and '^' .and optional_space; + +/*caretequals + optional_space .and '^' .and '=' .and optional_space;*/ + +colon + optional_space .and ':' .and optional_space; + +comma + optional_space .and ',' .and optional_space; + +dot + optional_space .and '.' .and optional_space; + +equals + optional_space .and '=' .and optional_space; + +equalsequals + optional_space .and '=' .and '=' .and optional_space; + +greater + optional_space .and '>' .and optional_space; + +greaterequals + optional_space .and '>' .and '=' .and optional_space; + +/*greatergreater + optional_space .and '>' .and '>' .and optional_space;*/ + +/*greatergreaterequals + optional_space .and '>' .and '>' .and '=' .and optional_space;*/ + +lbrace + optional_space .and '{' .and optional_space; + +lbracket + optional_space .and '[' .and optional_space; + +less + optional_space .and '<' .and optional_space; + +lessequals + optional_space .and '<' .and '=' .and optional_space; + +/*lessless + optional_space .and '<' .and '<' .and optional_space;*/ + +/*lesslessequals + optional_space .and '<' .and '<' .and '=' .and optional_space;*/ + +lparen + optional_space .and '(' .and optional_space; + +minus + optional_space .and '-' .and optional_space; + +minusequals + optional_space .and '-' .and '=' .and optional_space; + +minusminus + optional_space .and '-' .and '-' .and optional_space; + +/*percent + optional_space .and '%' .and optional_space;*/ + +/*percentequals + optional_space .and '%' .and '=' .and optional_space;*/ + +plus + optional_space .and '+' .and optional_space; + +plusequals + optional_space .and '+' .and '=' .and optional_space; + +plusplus + optional_space .and '+' .and '+' .and optional_space; + +question + optional_space .and '?' .and optional_space; + +rbrace + optional_space .and '}' .and optional_space; + +rbracket + optional_space .and ']' .and optional_space; + +rparen + optional_space .and ')' .and optional_space; + +semicolon + optional_space .and ';' .and optional_space; + +slash + optional_space .and '/' .and optional_space; + +slashequals + optional_space .and '/' .and '=' .and optional_space; + +star + optional_space .and '*' .and optional_space; + +starequals + optional_space .and '*' .and '=' .and optional_space; + +/*tilde + optional_space .and '~' .and optional_space;*/ + +/* string rules - these are used internally by the parser when parsing quoted strings */ + +.string string_lexer; + +string_lexer + lex_first_identifier_character .and .loop lex_next_identifier_character; + +lex_first_identifier_character + 'a'-'z' .or 'A'-'Z' .or '_'; + +lex_next_identifier_character + 'a'-'z' .or 'A'-'Z' .or '0'-'9' .or '_'; + +/* error rules - these are used by error messages */ + +err_token + '~' .or '`' .or '!' .or '@' .or '#' .or '$' .or '%' .or '^' .or '&' .or '*' .or '(' .or ')' .or + '-' .or '+' .or '=' .or '|' .or '\\' .or '[' .or ']' .or '{' .or '}' .or ':' .or ';' .or '"' .or + '\'' .or '<' .or ',' .or '>' .or '.' .or '/' .or '?' .or err_identifier; + +err_identifier + id_character_first .and .loop id_character_next; + diff --git a/mesalib/src/mesa/shader/slang/library/slang_shader_syn.h b/mesalib/src/mesa/shader/slang/library/slang_shader_syn.h new file mode 100644 index 000000000..6a382970e --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_shader_syn.h @@ -0,0 +1,866 @@ + +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE .syn FILE */ + +".syntax translation_unit;\n" +".emtcode REVISION 5\n" +".emtcode EXTERNAL_NULL 0\n" +".emtcode EXTERNAL_FUNCTION_DEFINITION 1\n" +".emtcode EXTERNAL_DECLARATION 2\n" +".emtcode DEFAULT_PRECISION 3\n" +".emtcode INVARIANT_STMT 4\n" +".emtcode PRECISION_DEFAULT 0\n" +".emtcode PRECISION_LOW 1\n" +".emtcode PRECISION_MEDIUM 2\n" +".emtcode PRECISION_HIGH 3\n" +".emtcode DECLARATION_FUNCTION_PROTOTYPE 1\n" +".emtcode DECLARATION_INIT_DECLARATOR_LIST 2\n" +".emtcode FUNCTION_ORDINARY 0\n" +".emtcode FUNCTION_CONSTRUCTOR 1\n" +".emtcode FUNCTION_OPERATOR 2\n" +".emtcode FUNCTION_CALL_NONARRAY 0\n" +".emtcode FUNCTION_CALL_ARRAY 1\n" +".emtcode OPERATOR_ADDASSIGN 1\n" +".emtcode OPERATOR_SUBASSIGN 2\n" +".emtcode OPERATOR_MULASSIGN 3\n" +".emtcode OPERATOR_DIVASSIGN 4\n" +".emtcode OPERATOR_LOGICALXOR 11\n" +".emtcode OPERATOR_LESS 15\n" +".emtcode OPERATOR_GREATER 16\n" +".emtcode OPERATOR_LESSEQUAL 17\n" +".emtcode OPERATOR_GREATEREQUAL 18\n" +".emtcode OPERATOR_MULTIPLY 21\n" +".emtcode OPERATOR_DIVIDE 22\n" +".emtcode OPERATOR_INCREMENT 24\n" +".emtcode OPERATOR_DECREMENT 25\n" +".emtcode OPERATOR_PLUS 26\n" +".emtcode OPERATOR_MINUS 27\n" +".emtcode OPERATOR_NOT 29\n" +".emtcode DECLARATOR_NONE 0\n" +".emtcode DECLARATOR_NEXT 1\n" +".emtcode VARIABLE_NONE 0\n" +".emtcode VARIABLE_IDENTIFIER 1\n" +".emtcode VARIABLE_INITIALIZER 2\n" +".emtcode VARIABLE_ARRAY_EXPLICIT 3\n" +".emtcode VARIABLE_ARRAY_UNKNOWN 4\n" +".emtcode TYPE_QUALIFIER_NONE 0\n" +".emtcode TYPE_QUALIFIER_CONST 1\n" +".emtcode TYPE_QUALIFIER_ATTRIBUTE 2\n" +".emtcode TYPE_QUALIFIER_VARYING 3\n" +".emtcode TYPE_QUALIFIER_UNIFORM 4\n" +".emtcode TYPE_QUALIFIER_FIXEDOUTPUT 5\n" +".emtcode TYPE_QUALIFIER_FIXEDINPUT 6\n" +".emtcode TYPE_VARIANT 90\n" +".emtcode TYPE_INVARIANT 91\n" +".emtcode TYPE_CENTER 95\n" +".emtcode TYPE_CENTROID 96\n" +".emtcode TYPE_SPECIFIER_VOID 0\n" +".emtcode TYPE_SPECIFIER_BOOL 1\n" +".emtcode TYPE_SPECIFIER_BVEC2 2\n" +".emtcode TYPE_SPECIFIER_BVEC3 3\n" +".emtcode TYPE_SPECIFIER_BVEC4 4\n" +".emtcode TYPE_SPECIFIER_INT 5\n" +".emtcode TYPE_SPECIFIER_IVEC2 6\n" +".emtcode TYPE_SPECIFIER_IVEC3 7\n" +".emtcode TYPE_SPECIFIER_IVEC4 8\n" +".emtcode TYPE_SPECIFIER_FLOAT 9\n" +".emtcode TYPE_SPECIFIER_VEC2 10\n" +".emtcode TYPE_SPECIFIER_VEC3 11\n" +".emtcode TYPE_SPECIFIER_VEC4 12\n" +".emtcode TYPE_SPECIFIER_MAT2 13\n" +".emtcode TYPE_SPECIFIER_MAT3 14\n" +".emtcode TYPE_SPECIFIER_MAT4 15\n" +".emtcode TYPE_SPECIFIER_SAMPLER1D 16\n" +".emtcode TYPE_SPECIFIER_SAMPLER2D 17\n" +".emtcode TYPE_SPECIFIER_SAMPLER3D 18\n" +".emtcode TYPE_SPECIFIER_SAMPLERCUBE 19\n" +".emtcode TYPE_SPECIFIER_SAMPLER1DSHADOW 20\n" +".emtcode TYPE_SPECIFIER_SAMPLER2DSHADOW 21\n" +".emtcode TYPE_SPECIFIER_SAMPLER2DRECT 22\n" +".emtcode TYPE_SPECIFIER_SAMPLER2DRECTSHADOW 23\n" +".emtcode TYPE_SPECIFIER_STRUCT 24\n" +".emtcode TYPE_SPECIFIER_TYPENAME 25\n" +".emtcode TYPE_SPECIFIER_MAT23 26\n" +".emtcode TYPE_SPECIFIER_MAT32 27\n" +".emtcode TYPE_SPECIFIER_MAT24 28\n" +".emtcode TYPE_SPECIFIER_MAT42 29\n" +".emtcode TYPE_SPECIFIER_MAT34 30\n" +".emtcode TYPE_SPECIFIER_MAT43 31\n" +".emtcode TYPE_SPECIFIER_NONARRAY 0\n" +".emtcode TYPE_SPECIFIER_ARRAY 1\n" +".emtcode FIELD_NONE 0\n" +".emtcode FIELD_NEXT 1\n" +".emtcode FIELD_ARRAY 2\n" +".emtcode OP_END 0\n" +".emtcode OP_BLOCK_BEGIN_NO_NEW_SCOPE 1\n" +".emtcode OP_BLOCK_BEGIN_NEW_SCOPE 2\n" +".emtcode OP_DECLARE 3\n" +".emtcode OP_ASM 4\n" +".emtcode OP_BREAK 5\n" +".emtcode OP_CONTINUE 6\n" +".emtcode OP_DISCARD 7\n" +".emtcode OP_RETURN 8\n" +".emtcode OP_EXPRESSION 9\n" +".emtcode OP_IF 10\n" +".emtcode OP_WHILE 11\n" +".emtcode OP_DO 12\n" +".emtcode OP_FOR 13\n" +".emtcode OP_PUSH_VOID 14\n" +".emtcode OP_PUSH_BOOL 15\n" +".emtcode OP_PUSH_INT 16\n" +".emtcode OP_PUSH_FLOAT 17\n" +".emtcode OP_PUSH_IDENTIFIER 18\n" +".emtcode OP_SEQUENCE 19\n" +".emtcode OP_ASSIGN 20\n" +".emtcode OP_ADDASSIGN 21\n" +".emtcode OP_SUBASSIGN 22\n" +".emtcode OP_MULASSIGN 23\n" +".emtcode OP_DIVASSIGN 24\n" +".emtcode OP_SELECT 31\n" +".emtcode OP_LOGICALOR 32\n" +".emtcode OP_LOGICALXOR 33\n" +".emtcode OP_LOGICALAND 34\n" +".emtcode OP_EQUAL 38\n" +".emtcode OP_NOTEQUAL 39\n" +".emtcode OP_LESS 40\n" +".emtcode OP_GREATER 41\n" +".emtcode OP_LESSEQUAL 42\n" +".emtcode OP_GREATEREQUAL 43\n" +".emtcode OP_ADD 46\n" +".emtcode OP_SUBTRACT 47\n" +".emtcode OP_MULTIPLY 48\n" +".emtcode OP_DIVIDE 49\n" +".emtcode OP_PREINCREMENT 51\n" +".emtcode OP_PREDECREMENT 52\n" +".emtcode OP_PLUS 53\n" +".emtcode OP_MINUS 54\n" +".emtcode OP_NOT 56\n" +".emtcode OP_SUBSCRIPT 57\n" +".emtcode OP_CALL 58\n" +".emtcode OP_FIELD 59\n" +".emtcode OP_POSTINCREMENT 60\n" +".emtcode OP_POSTDECREMENT 61\n" +".emtcode OP_PRECISION 62\n" +".emtcode OP_METHOD 63\n" +".emtcode PARAM_QUALIFIER_IN 0\n" +".emtcode PARAM_QUALIFIER_OUT 1\n" +".emtcode PARAM_QUALIFIER_INOUT 2\n" +".emtcode PARAMETER_NONE 0\n" +".emtcode PARAMETER_NEXT 1\n" +".emtcode PARAMETER_ARRAY_NOT_PRESENT 0\n" +".emtcode PARAMETER_ARRAY_PRESENT 1\n" +".errtext INVALID_EXTERNAL_DECLARATION \"2001: Syntax error.\"\n" +".errtext INVALID_OPERATOR_OVERRIDE \"2002: Invalid operator override.\"\n" +".errtext LBRACE_EXPECTED \"2003: '{' expected but '$err_token$' found.\"\n" +".errtext LPAREN_EXPECTED \"2004: '(' expected but '$err_token$' found.\"\n" +".errtext RPAREN_EXPECTED \"2005: ')' expected but '$err_token$' found.\"\n" +".errtext INVALID_PRECISION \"2006: Invalid precision specifier '$err_token$'.\"\n" +".errtext INVALID_PRECISION_TYPE \"2007: Invalid precision type '$err_token$'.\"\n" +".regbyte parsing_builtin 0\n" +".regbyte shader_type 0\n" +"variable_identifier\n" +" identifier .emit OP_PUSH_IDENTIFIER;\n" +"primary_expression\n" +" floatconstant .or boolconstant .or intconstant .or variable_identifier .or primary_expression_1;\n" +"primary_expression_1\n" +" lparen .and expression .and rparen;\n" +"postfix_expression\n" +" postfix_expression_1 .and .loop postfix_expression_2;\n" +"postfix_expression_1\n" +" function_call .or primary_expression;\n" +"postfix_expression_2\n" +" postfix_expression_3 .or postfix_expression_4 .or\n" +" plusplus .emit OP_POSTINCREMENT .or\n" +" minusminus .emit OP_POSTDECREMENT;\n" +"postfix_expression_3\n" +" lbracket .and integer_expression .and rbracket .emit OP_SUBSCRIPT;\n" +"postfix_expression_4\n" +" dot .and field_selection .emit OP_FIELD;\n" +"integer_expression\n" +" expression;\n" +"function_call\n" +" function_call_or_method;\n" +"function_call_or_method\n" +" regular_function_call .or method_call;\n" +"method_call\n" +" identifier .emit OP_METHOD .and dot .and function_call_generic .and .true .emit OP_END;\n" +"regular_function_call\n" +" function_call_generic .emit OP_CALL .and .true .emit OP_END;\n" +"function_call_generic\n" +" function_call_generic_1 .or function_call_generic_2;\n" +"function_call_generic_1\n" +" function_call_header_with_parameters .and rparen .error RPAREN_EXPECTED;\n" +"function_call_generic_2\n" +" function_call_header_no_parameters .and rparen .error RPAREN_EXPECTED;\n" +"function_call_header_no_parameters\n" +" function_call_header .and function_call_header_no_parameters_1;\n" +"function_call_header_no_parameters_1\n" +" \"void\" .or .true;\n" +"function_call_header_with_parameters\n" +" function_call_header .and assignment_expression .and .true .emit OP_END .and\n" +" .loop function_call_header_with_parameters_1;\n" +"function_call_header_with_parameters_1\n" +" comma .and assignment_expression .and .true .emit OP_END;\n" +"function_call_header\n" +" function_identifier .and lparen;\n" +"function_identifier\n" +" identifier .and function_identifier_opt_array;\n" +"function_identifier_opt_array\n" +" function_identifier_array .emit FUNCTION_CALL_ARRAY .or\n" +" .true .emit FUNCTION_CALL_NONARRAY;\n" +"function_identifier_array\n" +" lbracket .and constant_expression .and rbracket;\n" +"unary_expression\n" +" postfix_expression .or unary_expression_1 .or unary_expression_2 .or unary_expression_3 .or\n" +" unary_expression_4 .or unary_expression_5;\n" +"unary_expression_1\n" +" plusplus .and unary_expression .and .true .emit OP_PREINCREMENT;\n" +"unary_expression_2\n" +" minusminus .and unary_expression .and .true .emit OP_PREDECREMENT;\n" +"unary_expression_3\n" +" plus .and unary_expression .and .true .emit OP_PLUS;\n" +"unary_expression_4\n" +" minus .and unary_expression .and .true .emit OP_MINUS;\n" +"unary_expression_5\n" +" bang .and unary_expression .and .true .emit OP_NOT;\n" +"multiplicative_expression\n" +" unary_expression .and .loop multiplicative_expression_1;\n" +"multiplicative_expression_1\n" +" multiplicative_expression_2 .or multiplicative_expression_3;\n" +"multiplicative_expression_2\n" +" star .and unary_expression .and .true .emit OP_MULTIPLY;\n" +"multiplicative_expression_3\n" +" slash .and unary_expression .and .true .emit OP_DIVIDE;\n" +"additive_expression\n" +" multiplicative_expression .and .loop additive_expression_1;\n" +"additive_expression_1\n" +" additive_expression_2 .or additive_expression_3;\n" +"additive_expression_2\n" +" plus .and multiplicative_expression .and .true .emit OP_ADD;\n" +"additive_expression_3\n" +" minus .and multiplicative_expression .and .true .emit OP_SUBTRACT;\n" +"shift_expression\n" +" additive_expression;\n" +"relational_expression\n" +" shift_expression .and .loop relational_expression_1;\n" +"relational_expression_1\n" +" relational_expression_2 .or relational_expression_3 .or relational_expression_4 .or\n" +" relational_expression_5;\n" +"relational_expression_2\n" +" lessequals .and shift_expression .and .true .emit OP_LESSEQUAL;\n" +"relational_expression_3\n" +" greaterequals .and shift_expression .and .true .emit OP_GREATEREQUAL;\n" +"relational_expression_4\n" +" less .and shift_expression .and .true .emit OP_LESS;\n" +"relational_expression_5\n" +" greater .and shift_expression .and .true .emit OP_GREATER;\n" +"equality_expression\n" +" relational_expression .and .loop equality_expression_1;\n" +"equality_expression_1\n" +" equality_expression_2 .or equality_expression_3;\n" +"equality_expression_2\n" +" equalsequals .and relational_expression .and .true .emit OP_EQUAL;\n" +"equality_expression_3\n" +" bangequals .and relational_expression .and .true .emit OP_NOTEQUAL;\n" +"and_expression\n" +" equality_expression;\n" +"exclusive_or_expression\n" +" and_expression;\n" +"inclusive_or_expression\n" +" exclusive_or_expression;\n" +"logical_and_expression\n" +" inclusive_or_expression .and .loop logical_and_expression_1;\n" +"logical_and_expression_1\n" +" ampersandampersand .and inclusive_or_expression .and .true .emit OP_LOGICALAND;\n" +"logical_xor_expression\n" +" logical_and_expression .and .loop logical_xor_expression_1;\n" +"logical_xor_expression_1\n" +" caretcaret .and logical_and_expression .and .true .emit OP_LOGICALXOR;\n" +"logical_or_expression\n" +" logical_xor_expression .and .loop logical_or_expression_1;\n" +"logical_or_expression_1\n" +" barbar .and logical_xor_expression .and .true .emit OP_LOGICALOR;\n" +"conditional_expression\n" +" logical_or_expression .and .loop conditional_expression_1;\n" +"conditional_expression_1\n" +" question .and expression .and colon .and conditional_expression .and .true .emit OP_SELECT;\n" +"assignment_expression\n" +" assignment_expression_1 .or assignment_expression_2 .or assignment_expression_3 .or\n" +" assignment_expression_4 .or assignment_expression_5 .or conditional_expression;\n" +"assignment_expression_1\n" +" unary_expression .and equals .and assignment_expression .and .true .emit OP_ASSIGN;\n" +"assignment_expression_2\n" +" unary_expression .and starequals .and assignment_expression .and .true .emit OP_MULASSIGN;\n" +"assignment_expression_3\n" +" unary_expression .and slashequals .and assignment_expression .and .true .emit OP_DIVASSIGN;\n" +"assignment_expression_4\n" +" unary_expression .and plusequals .and assignment_expression .and .true .emit OP_ADDASSIGN;\n" +"assignment_expression_5\n" +" unary_expression .and minusequals .and assignment_expression .and .true .emit OP_SUBASSIGN;\n" +"expression\n" +" assignment_expression .and .loop expression_1;\n" +"expression_1\n" +" comma .and assignment_expression .and .true .emit OP_SEQUENCE;\n" +"constant_expression\n" +" conditional_expression .and .true .emit OP_END;\n" +"declaration\n" +" declaration_1 .or declaration_2;\n" +"declaration_1\n" +" function_prototype .emit DECLARATION_FUNCTION_PROTOTYPE .and semicolon;\n" +"declaration_2\n" +" init_declarator_list .emit DECLARATION_INIT_DECLARATOR_LIST .and semicolon;\n" +"function_prototype\n" +" function_prototype_1 .or function_prototype_2;\n" +"function_prototype_1\n" +" function_header .and \"void\" .and rparen .error RPAREN_EXPECTED .emit PARAMETER_NONE;\n" +"function_prototype_2\n" +" function_declarator .and rparen .error RPAREN_EXPECTED .emit PARAMETER_NONE;\n" +"function_declarator\n" +" function_header_with_parameters .or function_header;\n" +"function_header_with_parameters\n" +" function_header .and parameter_declaration .and .loop function_header_with_parameters_1;\n" +"function_header_with_parameters_1\n" +" comma .and parameter_declaration;\n" +"function_header\n" +" function_header_nospace .or function_header_space;\n" +"function_header_space\n" +" fully_specified_type_space .and space .and function_decl_identifier .and lparen;\n" +"function_header_nospace\n" +" fully_specified_type_nospace .and function_decl_identifier .and lparen;\n" +"function_decl_identifier\n" +" .if (parsing_builtin != 0) __operator .emit FUNCTION_OPERATOR .or\n" +" .if (parsing_builtin != 0) \"__constructor\" .emit FUNCTION_CONSTRUCTOR .or\n" +" identifier .emit FUNCTION_ORDINARY;\n" +"__operator\n" +" \"__operator\" .and overriden_operator .error INVALID_OPERATOR_OVERRIDE;\n" +"overriden_operator\n" +" plusplus .emit OPERATOR_INCREMENT .or\n" +" plusequals .emit OPERATOR_ADDASSIGN .or\n" +" plus .emit OPERATOR_PLUS .or\n" +" minusminus .emit OPERATOR_DECREMENT .or\n" +" minusequals .emit OPERATOR_SUBASSIGN .or\n" +" minus .emit OPERATOR_MINUS .or\n" +" bang .emit OPERATOR_NOT .or\n" +" starequals .emit OPERATOR_MULASSIGN .or\n" +" star .emit OPERATOR_MULTIPLY .or\n" +" slashequals .emit OPERATOR_DIVASSIGN .or\n" +" slash .emit OPERATOR_DIVIDE .or\n" +" lessequals .emit OPERATOR_LESSEQUAL .or\n" +" \n" +" \n" +" less .emit OPERATOR_LESS .or\n" +" greaterequals .emit OPERATOR_GREATEREQUAL .or\n" +" \n" +" \n" +" greater .emit OPERATOR_GREATER .or\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" caretcaret .emit OPERATOR_LOGICALXOR ;\n" +"parameter_declarator\n" +" parameter_declarator_nospace .or parameter_declarator_space;\n" +"parameter_declarator_nospace\n" +" type_specifier_nospace .and identifier .and parameter_declarator_1;\n" +"parameter_declarator_space\n" +" type_specifier_space .and space .and identifier .and parameter_declarator_1;\n" +"parameter_declarator_1\n" +" parameter_declarator_2 .emit PARAMETER_ARRAY_PRESENT .or\n" +" .true .emit PARAMETER_ARRAY_NOT_PRESENT;\n" +"parameter_declarator_2\n" +" lbracket .and constant_expression .and rbracket;\n" +"parameter_declaration\n" +" parameter_declaration_1 .emit PARAMETER_NEXT;\n" +"parameter_declaration_1\n" +" parameter_declaration_2 .or parameter_declaration_3;\n" +"parameter_declaration_2\n" +" type_qualifier .and space .and parameter_qualifier .and parameter_declaration_4;\n" +"parameter_declaration_3\n" +" parameter_qualifier .emit TYPE_QUALIFIER_NONE .and parameter_declaration_4;\n" +"parameter_declaration_4\n" +" parameter_declaration_optprec .and parameter_declaration_rest;\n" +"parameter_declaration_optprec\n" +" parameter_declaration_prec .or .true .emit PRECISION_DEFAULT;\n" +"parameter_declaration_prec\n" +" precision .and space;\n" +"parameter_declaration_rest\n" +" parameter_declarator .or parameter_type_specifier;\n" +"parameter_qualifier\n" +" parameter_qualifier_1 .or .true .emit PARAM_QUALIFIER_IN;\n" +"parameter_qualifier_1\n" +" parameter_qualifier_2 .and space;\n" +"parameter_qualifier_2\n" +" \"in\" .emit PARAM_QUALIFIER_IN .or\n" +" \"out\" .emit PARAM_QUALIFIER_OUT .or\n" +" \"inout\" .emit PARAM_QUALIFIER_INOUT;\n" +"parameter_type_specifier\n" +" parameter_type_specifier_1 .and .true .emit '\\0' .and parameter_type_specifier_2;\n" +"parameter_type_specifier_1\n" +" type_specifier_nospace .or type_specifier_space;\n" +"parameter_type_specifier_2\n" +" parameter_type_specifier_3 .emit PARAMETER_ARRAY_PRESENT .or\n" +" .true .emit PARAMETER_ARRAY_NOT_PRESENT;\n" +"parameter_type_specifier_3\n" +" lbracket .and constant_expression .and rbracket;\n" +"init_declarator_list\n" +" single_declaration .and .loop init_declarator_list_1 .emit DECLARATOR_NEXT .and\n" +" .true .emit DECLARATOR_NONE;\n" +"init_declarator_list_1\n" +" comma .and identifier .emit VARIABLE_IDENTIFIER .and init_declarator_list_2;\n" +"init_declarator_list_2\n" +" init_declarator_list_3 .or init_declarator_list_4 .or .true .emit VARIABLE_NONE;\n" +"init_declarator_list_3\n" +" equals .and initializer .emit VARIABLE_INITIALIZER;\n" +"init_declarator_list_4\n" +" lbracket .and init_declarator_list_5 .and rbracket;\n" +"init_declarator_list_5\n" +" constant_expression .emit VARIABLE_ARRAY_EXPLICIT .or .true .emit VARIABLE_ARRAY_UNKNOWN;\n" +"single_declaration\n" +" single_declaration_nospace .or single_declaration_space;\n" +"single_declaration_space\n" +" fully_specified_type_space .and single_declaration_space_1;\n" +"single_declaration_nospace\n" +" fully_specified_type_nospace .and single_declaration_nospace_1;\n" +"single_declaration_space_1\n" +" single_declaration_space_2 .emit VARIABLE_IDENTIFIER .or .true .emit VARIABLE_NONE;\n" +"single_declaration_nospace_1\n" +" single_declaration_nospace_2 .emit VARIABLE_IDENTIFIER .or .true .emit VARIABLE_NONE;\n" +"single_declaration_space_2\n" +" space .and identifier .and single_declaration_3;\n" +"single_declaration_nospace_2\n" +" identifier .and single_declaration_3;\n" +"single_declaration_3\n" +" single_declaration_4 .or single_declaration_5 .or .true .emit VARIABLE_NONE;\n" +"single_declaration_4\n" +" equals .and initializer .emit VARIABLE_INITIALIZER;\n" +"single_declaration_5\n" +" lbracket .and single_declaration_6 .and rbracket;\n" +"single_declaration_6\n" +" constant_expression .emit VARIABLE_ARRAY_EXPLICIT .or .true .emit VARIABLE_ARRAY_UNKNOWN;\n" +"fully_specified_type_space\n" +" fully_specified_type_optinvariant .and fully_specified_type_optcentroid .and fully_specified_type_optqual .and fully_specified_type_optprec .and type_specifier_space;\n" +"fully_specified_type_nospace\n" +" fully_specified_type_optinvariant .and fully_specified_type_optcentroid .and fully_specified_type_optqual .and fully_specified_type_optprec .and type_specifier_nospace;\n" +"fully_specified_type_optinvariant\n" +" fully_specified_type_invariant .or .true .emit TYPE_VARIANT;\n" +"fully_specified_type_invariant\n" +" invariant_qualifier .and space;\n" +"fully_specified_type_optcentroid\n" +" fully_specified_type_centroid .or .true .emit TYPE_CENTER;\n" +"fully_specified_type_centroid\n" +" centroid_qualifier .and space;\n" +"fully_specified_type_optqual\n" +" fully_specified_type_qual .or .true .emit TYPE_QUALIFIER_NONE;\n" +"fully_specified_type_qual\n" +" type_qualifier .and space;\n" +"fully_specified_type_optprec\n" +" fully_specified_type_prec .or .true .emit PRECISION_DEFAULT;\n" +"fully_specified_type_prec\n" +" precision .and space;\n" +"invariant_qualifier\n" +" \"invariant\" .emit TYPE_INVARIANT;\n" +"centroid_qualifier\n" +" \"centroid\" .emit TYPE_CENTROID;\n" +"type_qualifier\n" +" \"const\" .emit TYPE_QUALIFIER_CONST .or\n" +" .if (shader_type == 2) \"attribute\" .emit TYPE_QUALIFIER_ATTRIBUTE .or\n" +" \"varying\" .emit TYPE_QUALIFIER_VARYING .or\n" +" \"uniform\" .emit TYPE_QUALIFIER_UNIFORM .or\n" +" .if (parsing_builtin != 0) \"__fixed_output\" .emit TYPE_QUALIFIER_FIXEDOUTPUT .or\n" +" .if (parsing_builtin != 0) \"__fixed_input\" .emit TYPE_QUALIFIER_FIXEDINPUT;\n" +"type_specifier_nonarray_space\n" +" \"void\" .emit TYPE_SPECIFIER_VOID .or\n" +" \"float\" .emit TYPE_SPECIFIER_FLOAT .or\n" +" \"int\" .emit TYPE_SPECIFIER_INT .or\n" +" \"bool\" .emit TYPE_SPECIFIER_BOOL .or\n" +" \"vec2\" .emit TYPE_SPECIFIER_VEC2 .or\n" +" \"vec3\" .emit TYPE_SPECIFIER_VEC3 .or\n" +" \"vec4\" .emit TYPE_SPECIFIER_VEC4 .or\n" +" \"bvec2\" .emit TYPE_SPECIFIER_BVEC2 .or\n" +" \"bvec3\" .emit TYPE_SPECIFIER_BVEC3 .or\n" +" \"bvec4\" .emit TYPE_SPECIFIER_BVEC4 .or\n" +" \"ivec2\" .emit TYPE_SPECIFIER_IVEC2 .or\n" +" \"ivec3\" .emit TYPE_SPECIFIER_IVEC3 .or\n" +" \"ivec4\" .emit TYPE_SPECIFIER_IVEC4 .or\n" +" \"mat2\" .emit TYPE_SPECIFIER_MAT2 .or\n" +" \"mat3\" .emit TYPE_SPECIFIER_MAT3 .or\n" +" \"mat4\" .emit TYPE_SPECIFIER_MAT4 .or\n" +" \"mat2x3\" .emit TYPE_SPECIFIER_MAT23 .or\n" +" \"mat3x2\" .emit TYPE_SPECIFIER_MAT32 .or\n" +" \"mat2x4\" .emit TYPE_SPECIFIER_MAT24 .or\n" +" \"mat4x2\" .emit TYPE_SPECIFIER_MAT42 .or\n" +" \"mat3x4\" .emit TYPE_SPECIFIER_MAT34 .or\n" +" \"mat4x3\" .emit TYPE_SPECIFIER_MAT43 .or\n" +" \"sampler1D\" .emit TYPE_SPECIFIER_SAMPLER1D .or\n" +" \"sampler2D\" .emit TYPE_SPECIFIER_SAMPLER2D .or\n" +" \"sampler3D\" .emit TYPE_SPECIFIER_SAMPLER3D .or\n" +" \"samplerCube\" .emit TYPE_SPECIFIER_SAMPLERCUBE .or\n" +" \"sampler1DShadow\" .emit TYPE_SPECIFIER_SAMPLER1DSHADOW .or\n" +" \"sampler2DShadow\" .emit TYPE_SPECIFIER_SAMPLER2DSHADOW .or\n" +" \"sampler2DRect\" .emit TYPE_SPECIFIER_SAMPLER2DRECT .or\n" +" \"sampler2DRectShadow\" .emit TYPE_SPECIFIER_SAMPLER2DRECTSHADOW .or\n" +" type_name .emit TYPE_SPECIFIER_TYPENAME;\n" +"type_specifier_nonarray_nospace\n" +" struct_specifier .emit TYPE_SPECIFIER_STRUCT;\n" +"type_specifier_nonarray\n" +" type_specifier_nonarray_nospace .or type_specifier_nonarray_space;\n" +"type_specifier_space\n" +" type_specifier_nonarray_space .and .true .emit TYPE_SPECIFIER_NONARRAY;\n" +"type_specifier_nospace\n" +" type_specifier_nospace_array .or type_specifier_nospace_1;\n" +"type_specifier_nospace_1\n" +" type_specifier_nonarray_nospace .and .true .emit TYPE_SPECIFIER_NONARRAY;\n" +"type_specifier_nospace_array\n" +" type_specifier_nonarray .and lbracket .emit TYPE_SPECIFIER_ARRAY .and constant_expression .and rbracket;\n" +"struct_specifier\n" +" \"struct\" .and struct_specifier_1 .and optional_space .and lbrace .error LBRACE_EXPECTED .and\n" +" struct_declaration_list .and rbrace .emit FIELD_NONE;\n" +"struct_specifier_1\n" +" struct_specifier_2 .or .true .emit '\\0';\n" +"struct_specifier_2\n" +" space .and identifier;\n" +"struct_declaration_list\n" +" struct_declaration .and .loop struct_declaration .emit FIELD_NEXT;\n" +"struct_declaration\n" +" struct_declaration_nospace .or struct_declaration_space;\n" +"struct_declaration_space\n" +" type_specifier_space .and space .and struct_declarator_list .and semicolon .emit FIELD_NONE;\n" +"struct_declaration_nospace\n" +" type_specifier_nospace .and struct_declarator_list .and semicolon .emit FIELD_NONE;\n" +"struct_declarator_list\n" +" struct_declarator .and .loop struct_declarator_list_1 .emit FIELD_NEXT;\n" +"struct_declarator_list_1\n" +" comma .and struct_declarator;\n" +"struct_declarator\n" +" identifier .and struct_declarator_1;\n" +"struct_declarator_1\n" +" struct_declarator_2 .emit FIELD_ARRAY .or .true .emit FIELD_NONE;\n" +"struct_declarator_2\n" +" lbracket .and constant_expression .and rbracket;\n" +"initializer\n" +" assignment_expression .and .true .emit OP_END;\n" +"declaration_statement\n" +" declaration;\n" +"statement\n" +" compound_statement .or simple_statement;\n" +"statement_space\n" +" compound_statement .or statement_space_1;\n" +"statement_space_1\n" +" space .and simple_statement;\n" +"simple_statement\n" +" .if (parsing_builtin != 0) __asm_statement .emit OP_ASM .or\n" +" selection_statement .or\n" +" iteration_statement .or\n" +" precision_stmt .emit OP_PRECISION .or\n" +" jump_statement .or\n" +" expression_statement .emit OP_EXPRESSION .or\n" +" declaration_statement .emit OP_DECLARE;\n" +"compound_statement\n" +" compound_statement_1 .emit OP_BLOCK_BEGIN_NEW_SCOPE .and .true .emit OP_END;\n" +"compound_statement_1\n" +" compound_statement_2 .or compound_statement_3;\n" +"compound_statement_2\n" +" lbrace .and rbrace;\n" +"compound_statement_3\n" +" lbrace .and statement_list .and rbrace;\n" +"compound_statement_no_new_scope\n" +" compound_statement_no_new_scope_1 .emit OP_BLOCK_BEGIN_NO_NEW_SCOPE .and .true .emit OP_END;\n" +"compound_statement_no_new_scope_1\n" +" compound_statement_no_new_scope_2 .or compound_statement_no_new_scope_3;\n" +"compound_statement_no_new_scope_2\n" +" lbrace .and rbrace;\n" +"compound_statement_no_new_scope_3\n" +" lbrace .and statement_list .and rbrace;\n" +"statement_list\n" +" statement .and .loop statement;\n" +"expression_statement\n" +" expression_statement_1 .or expression_statement_2;\n" +"expression_statement_1\n" +" semicolon .emit OP_PUSH_VOID .emit OP_END;\n" +"expression_statement_2\n" +" expression .and semicolon .emit OP_END;\n" +"selection_statement\n" +" \"if\" .emit OP_IF .and lparen .error LPAREN_EXPECTED .and expression .and\n" +" rparen .error RPAREN_EXPECTED .emit OP_END .and selection_rest_statement;\n" +"selection_rest_statement\n" +" statement .and selection_rest_statement_1;\n" +"selection_rest_statement_1\n" +" selection_rest_statement_2 .or .true .emit OP_EXPRESSION .emit OP_PUSH_VOID .emit OP_END;\n" +"selection_rest_statement_2\n" +" \"else\" .and optional_space .and statement;\n" +"condition\n" +" condition_1 .emit OP_DECLARE .emit DECLARATION_INIT_DECLARATOR_LIST .or\n" +" condition_3 .emit OP_EXPRESSION;\n" +"condition_1\n" +" condition_1_nospace .or condition_1_space;\n" +"condition_1_nospace\n" +" fully_specified_type_nospace .and condition_2;\n" +"condition_1_space\n" +" fully_specified_type_space .and space .and condition_2;\n" +"condition_2\n" +" identifier .emit VARIABLE_IDENTIFIER .and equals .emit VARIABLE_INITIALIZER .and\n" +" initializer .and .true .emit DECLARATOR_NONE;\n" +"condition_3\n" +" expression .and .true .emit OP_END;\n" +"iteration_statement\n" +" iteration_statement_1 .or iteration_statement_2 .or iteration_statement_3;\n" +"iteration_statement_1\n" +" \"while\" .emit OP_WHILE .and lparen .error LPAREN_EXPECTED .and condition .and\n" +" rparen .error RPAREN_EXPECTED .and statement;\n" +"iteration_statement_2\n" +" \"do\" .emit OP_DO .and statement_space .and \"while\" .and lparen .error LPAREN_EXPECTED .and\n" +" expression .and rparen .error RPAREN_EXPECTED .emit OP_END .and semicolon;\n" +"iteration_statement_3\n" +" \"for\" .emit OP_FOR .and lparen .error LPAREN_EXPECTED .and for_init_statement .and\n" +" for_rest_statement .and rparen .error RPAREN_EXPECTED .and statement;\n" +"for_init_statement\n" +" expression_statement .emit OP_EXPRESSION .or declaration_statement .emit OP_DECLARE;\n" +"conditionopt\n" +" condition .or\n" +" .true .emit OP_EXPRESSION .emit OP_PUSH_BOOL .emit 2 .emit '1' .emit '\\0' .emit OP_END;\n" +"for_rest_statement\n" +" conditionopt .and semicolon .and for_rest_statement_1;\n" +"for_rest_statement_1\n" +" for_rest_statement_2 .or .true .emit OP_PUSH_VOID .emit OP_END;\n" +"for_rest_statement_2\n" +" expression .and .true .emit OP_END;\n" +"jump_statement\n" +" jump_statement_1 .or jump_statement_2 .or jump_statement_3 .or jump_statement_4 .or\n" +" .if (shader_type == 1) jump_statement_5;\n" +"jump_statement_1\n" +" \"continue\" .and semicolon .emit OP_CONTINUE;\n" +"jump_statement_2\n" +" \"break\" .and semicolon .emit OP_BREAK;\n" +"jump_statement_3\n" +" \"return\" .emit OP_RETURN .and optional_space .and expression .and semicolon .emit OP_END;\n" +"jump_statement_4\n" +" \"return\" .emit OP_RETURN .and semicolon .emit OP_PUSH_VOID .emit OP_END;\n" +"jump_statement_5\n" +" \"discard\" .and semicolon .emit OP_DISCARD;\n" +"__asm_statement\n" +" \"__asm\" .and space .and identifier .and space .and asm_arguments .and semicolon .emit OP_END;\n" +"asm_arguments\n" +" asm_argument .and .true .emit OP_END .and .loop asm_arguments_1;\n" +"asm_arguments_1\n" +" comma .and asm_argument .and .true .emit OP_END;\n" +"asm_argument\n" +" var_with_field .or\n" +" variable_identifier .or\n" +" floatconstant;\n" +"var_with_field\n" +" variable_identifier .and dot .and field_selection .emit OP_FIELD;\n" +"translation_unit\n" +" optional_space .emit REVISION .and external_declaration .error INVALID_EXTERNAL_DECLARATION .and\n" +" .loop external_declaration .and optional_space .and\n" +" '\\0' .error INVALID_EXTERNAL_DECLARATION .emit EXTERNAL_NULL;\n" +"external_declaration\n" +" precision_stmt .emit DEFAULT_PRECISION .or\n" +" function_definition .emit EXTERNAL_FUNCTION_DEFINITION .or\n" +" invariant_stmt .emit INVARIANT_STMT .or\n" +" declaration .emit EXTERNAL_DECLARATION;\n" +"precision_stmt\n" +" \"precision\" .and space .and precision .error INVALID_PRECISION .and space .and prectype .error INVALID_PRECISION_TYPE .and semicolon;\n" +"precision\n" +" \"lowp\" .emit PRECISION_LOW .or\n" +" \"mediump\" .emit PRECISION_MEDIUM .or\n" +" \"highp\" .emit PRECISION_HIGH;\n" +"prectype\n" +" \"int\" .emit TYPE_SPECIFIER_INT .or\n" +" \"float\" .emit TYPE_SPECIFIER_FLOAT .or\n" +" \"sampler1D\" .emit TYPE_SPECIFIER_SAMPLER1D .or\n" +" \"sampler2D\" .emit TYPE_SPECIFIER_SAMPLER2D .or\n" +" \"sampler3D\" .emit TYPE_SPECIFIER_SAMPLER3D .or\n" +" \"samplerCube\" .emit TYPE_SPECIFIER_SAMPLERCUBE .or\n" +" \"sampler1DShadow\" .emit TYPE_SPECIFIER_SAMPLER1DSHADOW .or\n" +" \"sampler2DShadow\" .emit TYPE_SPECIFIER_SAMPLER2DSHADOW .or\n" +" \"sampler2DRect\" .emit TYPE_SPECIFIER_SAMPLER2DRECT .or\n" +" \"sampler2DRectShadow\" .emit TYPE_SPECIFIER_SAMPLER2DRECTSHADOW;\n" +"invariant_stmt\n" +" \"invariant\" .and space .and identifier .and semicolon;\n" +"function_definition\n" +" function_prototype .and compound_statement_no_new_scope;\n" +"digit_oct\n" +" '0'-'7';\n" +"digit_dec\n" +" '0'-'9';\n" +"digit_hex\n" +" '0'-'9' .or 'A'-'F' .or 'a'-'f';\n" +"id_character_first\n" +" 'a'-'z' .or 'A'-'Z' .or '_';\n" +"id_character_next\n" +" id_character_first .or digit_dec;\n" +"identifier\n" +" id_character_first .emit * .and .loop id_character_next .emit * .and .true .emit '\\0';\n" +"float\n" +" float_1 .or float_2 .or float_3;\n" +"float_1\n" +" float_fractional_constant .and float_optional_exponent_part .and optional_f_suffix;\n" +"float_2\n" +" float_digit_sequence .and .true .emit '\\0' .and float_exponent_part .and optional_f_suffix;\n" +"float_3\n" +" float_digit_sequence .and .true .emit '\\0' .and 'f' .emit '\\0';\n" +"float_fractional_constant\n" +" float_fractional_constant_1 .or float_fractional_constant_2 .or float_fractional_constant_3;\n" +"float_fractional_constant_1\n" +" float_digit_sequence .and '.' .and float_digit_sequence;\n" +"float_fractional_constant_2\n" +" float_digit_sequence .and '.' .and .true .emit '\\0';\n" +"float_fractional_constant_3\n" +" '.' .emit '\\0' .and float_digit_sequence;\n" +"float_optional_exponent_part\n" +" float_exponent_part .or .true .emit '\\0';\n" +"float_digit_sequence\n" +" digit_dec .emit * .and .loop digit_dec .emit * .and .true .emit '\\0';\n" +"float_exponent_part\n" +" float_exponent_part_1 .or float_exponent_part_2;\n" +"float_exponent_part_1\n" +" 'e' .and float_optional_sign .and float_digit_sequence;\n" +"float_exponent_part_2\n" +" 'E' .and float_optional_sign .and float_digit_sequence;\n" +"float_optional_sign\n" +" float_sign .or .true;\n" +"float_sign\n" +" '+' .or '-' .emit '-';\n" +"optional_f_suffix\n" +" 'f' .or .true;\n" +"integer\n" +" integer_hex .or integer_oct .or integer_dec;\n" +"integer_hex\n" +" '0' .and integer_hex_1 .emit 0x10 .and digit_hex .emit * .and .loop digit_hex .emit * .and\n" +" .true .emit '\\0';\n" +"integer_hex_1\n" +" 'x' .or 'X';\n" +"integer_oct\n" +" '0' .emit 8 .emit * .and .loop digit_oct .emit * .and .true .emit '\\0';\n" +"integer_dec\n" +" digit_dec .emit 10 .emit * .and .loop digit_dec .emit * .and .true .emit '\\0';\n" +"boolean\n" +" \"true\" .emit 2 .emit '1' .emit '\\0' .or\n" +" \"false\" .emit 2 .emit '0' .emit '\\0';\n" +"type_name\n" +" identifier;\n" +"field_selection\n" +" identifier;\n" +"floatconstant\n" +" float .emit OP_PUSH_FLOAT;\n" +"intconstant\n" +" integer .emit OP_PUSH_INT;\n" +"boolconstant\n" +" boolean .emit OP_PUSH_BOOL;\n" +"optional_space\n" +" .loop single_space;\n" +"space\n" +" single_space .and .loop single_space;\n" +"single_space\n" +" white_char .or c_style_comment_block .or cpp_style_comment_block;\n" +"white_char\n" +" ' ' .or '\\t' .or new_line .or '\\v' .or '\\f';\n" +"new_line\n" +" cr_lf .or lf_cr .or '\\n' .or '\\r';\n" +"cr_lf\n" +" '\\r' .and '\\n';\n" +"lf_cr\n" +" '\\n' .and '\\r';\n" +"c_style_comment_block\n" +" '/' .and '*' .and c_style_comment_rest;\n" +"c_style_comment_rest\n" +" .loop c_style_comment_char_no_star .and c_style_comment_rest_1;\n" +"c_style_comment_rest_1\n" +" c_style_comment_end .or c_style_comment_rest_2;\n" +"c_style_comment_rest_2\n" +" '*' .and c_style_comment_rest;\n" +"c_style_comment_char_no_star\n" +" '\\x2B'-'\\xFF' .or '\\x01'-'\\x29';\n" +"c_style_comment_end\n" +" '*' .and '/';\n" +"cpp_style_comment_block\n" +" '/' .and '/' .and cpp_style_comment_block_1;\n" +"cpp_style_comment_block_1\n" +" cpp_style_comment_block_2 .or cpp_style_comment_block_3;\n" +"cpp_style_comment_block_2\n" +" .loop cpp_style_comment_char .and new_line;\n" +"cpp_style_comment_block_3\n" +" .loop cpp_style_comment_char;\n" +"cpp_style_comment_char\n" +" '\\x0E'-'\\xFF' .or '\\x01'-'\\x09' .or '\\x0B'-'\\x0C';\n" +"ampersandampersand\n" +" optional_space .and '&' .and '&' .and optional_space;\n" +"barbar\n" +" optional_space .and '|' .and '|' .and optional_space;\n" +"bang\n" +" optional_space .and '!' .and optional_space;\n" +"bangequals\n" +" optional_space .and '!' .and '=' .and optional_space;\n" +"caretcaret\n" +" optional_space .and '^' .and '^' .and optional_space;\n" +"colon\n" +" optional_space .and ':' .and optional_space;\n" +"comma\n" +" optional_space .and ',' .and optional_space;\n" +"dot\n" +" optional_space .and '.' .and optional_space;\n" +"equals\n" +" optional_space .and '=' .and optional_space;\n" +"equalsequals\n" +" optional_space .and '=' .and '=' .and optional_space;\n" +"greater\n" +" optional_space .and '>' .and optional_space;\n" +"greaterequals\n" +" optional_space .and '>' .and '=' .and optional_space;\n" +"lbrace\n" +" optional_space .and '{' .and optional_space;\n" +"lbracket\n" +" optional_space .and '[' .and optional_space;\n" +"less\n" +" optional_space .and '<' .and optional_space;\n" +"lessequals\n" +" optional_space .and '<' .and '=' .and optional_space;\n" +"lparen\n" +" optional_space .and '(' .and optional_space;\n" +"minus\n" +" optional_space .and '-' .and optional_space;\n" +"minusequals\n" +" optional_space .and '-' .and '=' .and optional_space;\n" +"minusminus\n" +" optional_space .and '-' .and '-' .and optional_space;\n" +"plus\n" +" optional_space .and '+' .and optional_space;\n" +"plusequals\n" +" optional_space .and '+' .and '=' .and optional_space;\n" +"plusplus\n" +" optional_space .and '+' .and '+' .and optional_space;\n" +"question\n" +" optional_space .and '?' .and optional_space;\n" +"rbrace\n" +" optional_space .and '}' .and optional_space;\n" +"rbracket\n" +" optional_space .and ']' .and optional_space;\n" +"rparen\n" +" optional_space .and ')' .and optional_space;\n" +"semicolon\n" +" optional_space .and ';' .and optional_space;\n" +"slash\n" +" optional_space .and '/' .and optional_space;\n" +"slashequals\n" +" optional_space .and '/' .and '=' .and optional_space;\n" +"star\n" +" optional_space .and '*' .and optional_space;\n" +"starequals\n" +" optional_space .and '*' .and '=' .and optional_space;\n" +".string string_lexer;\n" +"string_lexer\n" +" lex_first_identifier_character .and .loop lex_next_identifier_character;\n" +"lex_first_identifier_character\n" +" 'a'-'z' .or 'A'-'Z' .or '_';\n" +"lex_next_identifier_character\n" +" 'a'-'z' .or 'A'-'Z' .or '0'-'9' .or '_';\n" +"err_token\n" +" '~' .or '`' .or '!' .or '@' .or '#' .or '$' .or '%' .or '^' .or '&' .or '*' .or '(' .or ')' .or\n" +" '-' .or '+' .or '=' .or '|' .or '\\\\' .or '[' .or ']' .or '{' .or '}' .or ':' .or ';' .or '\"' .or\n" +" '\\'' .or '<' .or ',' .or '>' .or '.' .or '/' .or '?' .or err_identifier;\n" +"err_identifier\n" +" id_character_first .and .loop id_character_next;\n" +"" diff --git a/mesalib/src/mesa/shader/slang/library/slang_version.syn b/mesalib/src/mesa/shader/slang/library/slang_version.syn new file mode 100644 index 000000000..aaf8bef34 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_version.syn @@ -0,0 +1,118 @@ +/* + * Mesa 3-D graphics library + * Version: 6.3 + * + * Copyright (C) 2005 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_version.syn + * slang #version directive syntax + * \author Michal Krol + */ + +.syntax version_directive; + +version_directive + version_directive_1 .and .loop version_directive_2; +version_directive_1 + prior_optional_spaces .and optional_version_directive .and .true .emit $; +version_directive_2 + prior_optional_spaces .and version_directive_body .and .true .emit $; + +optional_version_directive + version_directive_body .or .true .emit 10 .emit 1; + +version_directive_body + '#' .and optional_space .and "version" .and space .and version_number .and optional_space .and + new_line; + +version_number + version_number_110; + +version_number_110 + leading_zeroes .and "110" .emit 10 .emit 1; + +leading_zeroes + .loop zero; + +zero + '0'; + +space + single_space .and .loop single_space; + +optional_space + .loop single_space; + +single_space + ' ' .or '\t'; + +prior_optional_spaces + .loop prior_space; + +prior_space + c_style_comment_block .or cpp_style_comment_block .or space .or new_line; + +c_style_comment_block + '/' .and '*' .and c_style_comment_rest; + +c_style_comment_rest + .loop c_style_comment_char_no_star .and c_style_comment_rest_1; +c_style_comment_rest_1 + c_style_comment_end .or c_style_comment_rest_2; +c_style_comment_rest_2 + '*' .and c_style_comment_rest; + +c_style_comment_char_no_star + '\x2B'-'\xFF' .or '\x01'-'\x29'; + +c_style_comment_end + '*' .and '/'; + +cpp_style_comment_block + '/' .and '/' .and cpp_style_comment_block_1; +cpp_style_comment_block_1 + cpp_style_comment_block_2 .or cpp_style_comment_block_3; +cpp_style_comment_block_2 + .loop cpp_style_comment_char .and new_line; +cpp_style_comment_block_3 + .loop cpp_style_comment_char; + +cpp_style_comment_char + '\x0E'-'\xFF' .or '\x01'-'\x09' .or '\x0B'-'\x0C'; + +new_line + cr_lf .or lf_cr .or '\n' .or '\r'; + +cr_lf + '\r' .and '\n'; + +lf_cr + '\n' .and '\r'; + +.string __string_filter; + +__string_filter + .loop __identifier_char; + +__identifier_char + 'a'-'z' .or 'A'-'Z' .or '_' .or '0'-'9'; + diff --git a/mesalib/src/mesa/shader/slang/library/slang_vertex_builtin.gc b/mesalib/src/mesa/shader/slang/library/slang_vertex_builtin.gc new file mode 100644 index 000000000..9ad5f3542 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_vertex_builtin.gc @@ -0,0 +1,190 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// +// From Shader Spec, ver. 1.10, rev. 59 +// + +__fixed_output vec4 gl_Position; +__fixed_output float gl_PointSize; +__fixed_output vec4 gl_ClipVertex; + +attribute vec4 gl_Color; +attribute vec4 gl_SecondaryColor; +attribute vec3 gl_Normal; +attribute vec4 gl_Vertex; +attribute vec4 gl_MultiTexCoord0; +attribute vec4 gl_MultiTexCoord1; +attribute vec4 gl_MultiTexCoord2; +attribute vec4 gl_MultiTexCoord3; +attribute vec4 gl_MultiTexCoord4; +attribute vec4 gl_MultiTexCoord5; +attribute vec4 gl_MultiTexCoord6; +attribute vec4 gl_MultiTexCoord7; +attribute float gl_FogCoord; + +varying vec4 gl_FrontColor; +varying vec4 gl_BackColor; +varying vec4 gl_FrontSecondaryColor; +varying vec4 gl_BackSecondaryColor; +varying vec4 gl_TexCoord[gl_MaxTextureCoords]; +varying float gl_FogFragCoord; + +// +// Geometric Functions +// + +vec4 ftransform() +{ + __retVal = gl_ModelViewProjectionMatrix[0] * gl_Vertex.xxxx + + gl_ModelViewProjectionMatrix[1] * gl_Vertex.yyyy + + gl_ModelViewProjectionMatrix[2] * gl_Vertex.zzzz + + gl_ModelViewProjectionMatrix[3] * gl_Vertex.wwww; +} + + + +// +// 8.7 Texture Lookup Functions +// These are pretty much identical to the ones in slang_fragment_builtin.gc +// When used in a vertex program, the texture sample instructions should not +// be using a LOD term so it's effectively zero. Adding 'lod' to that does +// what we want. +// + +vec4 texture1DLod(const sampler1D sampler, const float coord, const float lod) +{ + vec4 coord4; + coord4.x = coord; + coord4.w = lod; + __asm vec4_tex_1d_bias __retVal, sampler, coord4; +} + +vec4 texture1DProjLod(const sampler1D sampler, const vec2 coord, const float lod) +{ + vec4 pcoord; + pcoord.x = coord.x / coord.y; + pcoord.w = lod; + __asm vec4_tex_1d_bias __retVal, sampler, pcoord; +} + +vec4 texture1DProjLod(const sampler1D sampler, const vec4 coord, const float lod) +{ + vec4 pcoord; + pcoord.x = coord.x / coord.z; + pcoord.w = lod; + __asm vec4_tex_1d_bias __retVal, sampler, pcoord; +} + + + +vec4 texture2DLod(const sampler2D sampler, const vec2 coord, const float lod) +{ + vec4 coord4; + coord4.xy = coord.xy; + coord4.w = lod; + __asm vec4_tex_2d_bias __retVal, sampler, coord4; +} + +vec4 texture2DProjLod(const sampler2D sampler, const vec3 coord, const float lod) +{ + vec4 pcoord; + pcoord.xy = coord.xy / coord.z; + pcoord.w = lod; + __asm vec4_tex_2d_bias __retVal, sampler, pcoord; +} + +vec4 texture2DProjLod(const sampler2D sampler, const vec4 coord, const float lod) +{ + vec4 pcoord; + pcoord.xy = coord.xy / coord.z; + pcoord.w = lod; + __asm vec4_tex_2d_bias __retVal, sampler, pcoord; +} + + +vec4 texture3DLod(const sampler3D sampler, const vec3 coord, const float lod) +{ + vec4 coord4; + coord4.xyz = coord.xyz; + coord4.w = lod; + __asm vec4_tex_3d_bias __retVal, sampler, coord4; +} + +vec4 texture3DProjLod(const sampler3D sampler, const vec4 coord, const float lod) +{ + // do projection here (there's no vec4_tex_3d_bias_proj instruction) + vec4 pcoord; + pcoord.xyz = coord.xyz / coord.w; + pcoord.w = lod; + __asm vec4_tex_3d_bias __retVal, sampler, pcoord; +} + + +vec4 textureCubeLod(const samplerCube sampler, const vec3 coord, const float lod) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = lod; + __asm vec4_tex_cube __retVal, sampler, coord4; +} + + +vec4 shadow1DLod(const sampler1DShadow sampler, const vec3 coord, const float lod) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = lod; + __asm vec4_tex_1d_bias_shadow __retVal, sampler, coord4; +} + +vec4 shadow1DProjLod(const sampler1DShadow sampler, const vec4 coord, + const float lod) +{ + vec4 pcoord; + pcoord.x = coord.x / coord.w; + pcoord.z = coord.z; + pcoord.w = lod; + __asm vec4_tex_1d_bias_shadow __retVal, sampler, pcoord; +} + + +vec4 shadow2DLod(const sampler2DShadow sampler, const vec3 coord, const float lod) +{ + vec4 coord4; + coord4.xyz = coord; + coord4.w = lod; + __asm vec4_tex_2d_bias_shadow __retVal, sampler, coord4; +} + +vec4 shadow2DProjLod(const sampler2DShadow sampler, const vec4 coord, + const float lod) +{ + vec4 pcoord; + pcoord.xy = coord.xy / coord.w; + pcoord.z = coord.z; + pcoord.w = lod; + __asm vec4_tex_2d_bias_shadow __retVal, sampler, pcoord; +} + diff --git a/mesalib/src/mesa/shader/slang/library/slang_vertex_builtin_gc.h b/mesalib/src/mesa/shader/slang/library/slang_vertex_builtin_gc.h new file mode 100644 index 000000000..e5a252b01 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/slang_vertex_builtin_gc.h @@ -0,0 +1,109 @@ + +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE FOLLOWING FILE: */ +/* slang_vertex_builtin.gc */ + +5,2,2,90,95,5,0,12,0,1,103,108,95,80,111,115,105,116,105,111,110,0,0,0,2,2,90,95,5,0,9,0,1,103,108, +95,80,111,105,110,116,83,105,122,101,0,0,0,2,2,90,95,5,0,12,0,1,103,108,95,67,108,105,112,86,101, +114,116,101,120,0,0,0,2,2,90,95,2,0,12,0,1,103,108,95,67,111,108,111,114,0,0,0,2,2,90,95,2,0,12,0, +1,103,108,95,83,101,99,111,110,100,97,114,121,67,111,108,111,114,0,0,0,2,2,90,95,2,0,11,0,1,103, +108,95,78,111,114,109,97,108,0,0,0,2,2,90,95,2,0,12,0,1,103,108,95,86,101,114,116,101,120,0,0,0,2, +2,90,95,2,0,12,0,1,103,108,95,77,117,108,116,105,84,101,120,67,111,111,114,100,48,0,0,0,2,2,90,95, +2,0,12,0,1,103,108,95,77,117,108,116,105,84,101,120,67,111,111,114,100,49,0,0,0,2,2,90,95,2,0,12,0, +1,103,108,95,77,117,108,116,105,84,101,120,67,111,111,114,100,50,0,0,0,2,2,90,95,2,0,12,0,1,103, +108,95,77,117,108,116,105,84,101,120,67,111,111,114,100,51,0,0,0,2,2,90,95,2,0,12,0,1,103,108,95, +77,117,108,116,105,84,101,120,67,111,111,114,100,52,0,0,0,2,2,90,95,2,0,12,0,1,103,108,95,77,117, +108,116,105,84,101,120,67,111,111,114,100,53,0,0,0,2,2,90,95,2,0,12,0,1,103,108,95,77,117,108,116, +105,84,101,120,67,111,111,114,100,54,0,0,0,2,2,90,95,2,0,12,0,1,103,108,95,77,117,108,116,105,84, +101,120,67,111,111,114,100,55,0,0,0,2,2,90,95,2,0,9,0,1,103,108,95,70,111,103,67,111,111,114,100,0, +0,0,2,2,90,95,3,0,12,0,1,103,108,95,70,114,111,110,116,67,111,108,111,114,0,0,0,2,2,90,95,3,0,12,0, +1,103,108,95,66,97,99,107,67,111,108,111,114,0,0,0,2,2,90,95,3,0,12,0,1,103,108,95,70,114,111,110, +116,83,101,99,111,110,100,97,114,121,67,111,108,111,114,0,0,0,2,2,90,95,3,0,12,0,1,103,108,95,66, +97,99,107,83,101,99,111,110,100,97,114,121,67,111,108,111,114,0,0,0,2,2,90,95,3,0,12,0,1,103,108, +95,84,101,120,67,111,111,114,100,0,3,18,103,108,95,77,97,120,84,101,120,116,117,114,101,67,111,111, +114,100,115,0,0,0,2,2,90,95,3,0,9,0,1,103,108,95,70,111,103,70,114,97,103,67,111,111,114,100,0,0,0, +1,90,95,0,0,12,0,0,102,116,114,97,110,115,102,111,114,109,0,0,1,9,18,95,95,114,101,116,86,97,108,0, +18,103,108,95,77,111,100,101,108,86,105,101,119,80,114,111,106,101,99,116,105,111,110,77,97,116, +114,105,120,0,16,8,48,0,57,18,103,108,95,86,101,114,116,101,120,0,59,120,120,120,120,0,48,18,103, +108,95,77,111,100,101,108,86,105,101,119,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105, +120,0,16,10,49,0,57,18,103,108,95,86,101,114,116,101,120,0,59,121,121,121,121,0,48,46,18,103,108, +95,77,111,100,101,108,86,105,101,119,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,0, +16,10,50,0,57,18,103,108,95,86,101,114,116,101,120,0,59,122,122,122,122,0,48,46,18,103,108,95,77, +111,100,101,108,86,105,101,119,80,114,111,106,101,99,116,105,111,110,77,97,116,114,105,120,0,16,10, +51,0,57,18,103,108,95,86,101,114,116,101,120,0,59,119,119,119,119,0,48,46,20,0,0,1,90,95,0,0,12,0, +0,116,101,120,116,117,114,101,49,68,76,111,100,0,1,1,0,0,16,0,115,97,109,112,108,101,114,0,0,1,1,0, +0,9,0,99,111,111,114,100,0,0,1,1,0,0,9,0,108,111,100,0,0,0,1,3,2,90,95,0,0,12,0,1,99,111,111,114, +100,52,0,0,0,9,18,99,111,111,114,100,52,0,59,120,0,18,99,111,111,114,100,0,20,0,9,18,99,111,111, +114,100,52,0,59,119,0,18,108,111,100,0,20,0,4,118,101,99,52,95,116,101,120,95,49,100,95,98,105,97, +115,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100, +52,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,49,68,80,114,111,106,76,111,100,0,1,1,0, +0,16,0,115,97,109,112,108,101,114,0,0,1,1,0,0,10,0,99,111,111,114,100,0,0,1,1,0,0,9,0,108,111,100, +0,0,0,1,3,2,90,95,0,0,12,0,1,112,99,111,111,114,100,0,0,0,9,18,112,99,111,111,114,100,0,59,120,0, +18,99,111,111,114,100,0,59,120,0,18,99,111,111,114,100,0,59,121,0,49,20,0,9,18,112,99,111,111,114, +100,0,59,119,0,18,108,111,100,0,20,0,4,118,101,99,52,95,116,101,120,95,49,100,95,98,105,97,115,0, +18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,112,99,111,111,114,100,0,0, +0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,49,68,80,114,111,106,76,111,100,0,1,1,0,0,16,0, +115,97,109,112,108,101,114,0,0,1,1,0,0,12,0,99,111,111,114,100,0,0,1,1,0,0,9,0,108,111,100,0,0,0,1, +3,2,90,95,0,0,12,0,1,112,99,111,111,114,100,0,0,0,9,18,112,99,111,111,114,100,0,59,120,0,18,99,111, +111,114,100,0,59,120,0,18,99,111,111,114,100,0,59,122,0,49,20,0,9,18,112,99,111,111,114,100,0,59, +119,0,18,108,111,100,0,20,0,4,118,101,99,52,95,116,101,120,95,49,100,95,98,105,97,115,0,18,95,95, +114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,112,99,111,111,114,100,0,0,0,0,1,90, +95,0,0,12,0,0,116,101,120,116,117,114,101,50,68,76,111,100,0,1,1,0,0,17,0,115,97,109,112,108,101, +114,0,0,1,1,0,0,10,0,99,111,111,114,100,0,0,1,1,0,0,9,0,108,111,100,0,0,0,1,3,2,90,95,0,0,12,0,1, +99,111,111,114,100,52,0,0,0,9,18,99,111,111,114,100,52,0,59,120,121,0,18,99,111,111,114,100,0,59, +120,121,0,20,0,9,18,99,111,111,114,100,52,0,59,119,0,18,108,111,100,0,20,0,4,118,101,99,52,95,116, +101,120,95,50,100,95,98,105,97,115,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101, +114,0,0,18,99,111,111,114,100,52,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,50,68,80, +114,111,106,76,111,100,0,1,1,0,0,17,0,115,97,109,112,108,101,114,0,0,1,1,0,0,11,0,99,111,111,114, +100,0,0,1,1,0,0,9,0,108,111,100,0,0,0,1,3,2,90,95,0,0,12,0,1,112,99,111,111,114,100,0,0,0,9,18,112, +99,111,111,114,100,0,59,120,121,0,18,99,111,111,114,100,0,59,120,121,0,18,99,111,111,114,100,0,59, +122,0,49,20,0,9,18,112,99,111,111,114,100,0,59,119,0,18,108,111,100,0,20,0,4,118,101,99,52,95,116, +101,120,95,50,100,95,98,105,97,115,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101, +114,0,0,18,112,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,50,68,80, +114,111,106,76,111,100,0,1,1,0,0,17,0,115,97,109,112,108,101,114,0,0,1,1,0,0,12,0,99,111,111,114, +100,0,0,1,1,0,0,9,0,108,111,100,0,0,0,1,3,2,90,95,0,0,12,0,1,112,99,111,111,114,100,0,0,0,9,18,112, +99,111,111,114,100,0,59,120,121,0,18,99,111,111,114,100,0,59,120,121,0,18,99,111,111,114,100,0,59, +122,0,49,20,0,9,18,112,99,111,111,114,100,0,59,119,0,18,108,111,100,0,20,0,4,118,101,99,52,95,116, +101,120,95,50,100,95,98,105,97,115,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101, +114,0,0,18,112,99,111,111,114,100,0,0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,51,68,76, +111,100,0,1,1,0,0,18,0,115,97,109,112,108,101,114,0,0,1,1,0,0,11,0,99,111,111,114,100,0,0,1,1,0,0, +9,0,108,111,100,0,0,0,1,3,2,90,95,0,0,12,0,1,99,111,111,114,100,52,0,0,0,9,18,99,111,111,114,100, +52,0,59,120,121,122,0,18,99,111,111,114,100,0,59,120,121,122,0,20,0,9,18,99,111,111,114,100,52,0, +59,119,0,18,108,111,100,0,20,0,4,118,101,99,52,95,116,101,120,95,51,100,95,98,105,97,115,0,18,95, +95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,52,0,0,0,0,1, +90,95,0,0,12,0,0,116,101,120,116,117,114,101,51,68,80,114,111,106,76,111,100,0,1,1,0,0,18,0,115,97, +109,112,108,101,114,0,0,1,1,0,0,12,0,99,111,111,114,100,0,0,1,1,0,0,9,0,108,111,100,0,0,0,1,3,2,90, +95,0,0,12,0,1,112,99,111,111,114,100,0,0,0,9,18,112,99,111,111,114,100,0,59,120,121,122,0,18,99, +111,111,114,100,0,59,120,121,122,0,18,99,111,111,114,100,0,59,119,0,49,20,0,9,18,112,99,111,111, +114,100,0,59,119,0,18,108,111,100,0,20,0,4,118,101,99,52,95,116,101,120,95,51,100,95,98,105,97,115, +0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,112,99,111,111,114,100,0, +0,0,0,1,90,95,0,0,12,0,0,116,101,120,116,117,114,101,67,117,98,101,76,111,100,0,1,1,0,0,19,0,115, +97,109,112,108,101,114,0,0,1,1,0,0,11,0,99,111,111,114,100,0,0,1,1,0,0,9,0,108,111,100,0,0,0,1,3,2, +90,95,0,0,12,0,1,99,111,111,114,100,52,0,0,0,9,18,99,111,111,114,100,52,0,59,120,121,122,0,18,99, +111,111,114,100,0,20,0,9,18,99,111,111,114,100,52,0,59,119,0,18,108,111,100,0,20,0,4,118,101,99,52, +95,116,101,120,95,99,117,98,101,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114, +0,0,18,99,111,111,114,100,52,0,0,0,0,1,90,95,0,0,12,0,0,115,104,97,100,111,119,49,68,76,111,100,0, +1,1,0,0,20,0,115,97,109,112,108,101,114,0,0,1,1,0,0,11,0,99,111,111,114,100,0,0,1,1,0,0,9,0,108, +111,100,0,0,0,1,3,2,90,95,0,0,12,0,1,99,111,111,114,100,52,0,0,0,9,18,99,111,111,114,100,52,0,59, +120,121,122,0,18,99,111,111,114,100,0,20,0,9,18,99,111,111,114,100,52,0,59,119,0,18,108,111,100,0, +20,0,4,118,101,99,52,95,116,101,120,95,49,100,95,98,105,97,115,95,115,104,97,100,111,119,0,18,95, +95,114,101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,99,111,111,114,100,52,0,0,0,0,1, +90,95,0,0,12,0,0,115,104,97,100,111,119,49,68,80,114,111,106,76,111,100,0,1,1,0,0,20,0,115,97,109, +112,108,101,114,0,0,1,1,0,0,12,0,99,111,111,114,100,0,0,1,1,0,0,9,0,108,111,100,0,0,0,1,3,2,90,95, +0,0,12,0,1,112,99,111,111,114,100,0,0,0,9,18,112,99,111,111,114,100,0,59,120,0,18,99,111,111,114, +100,0,59,120,0,18,99,111,111,114,100,0,59,119,0,49,20,0,9,18,112,99,111,111,114,100,0,59,122,0,18, +99,111,111,114,100,0,59,122,0,20,0,9,18,112,99,111,111,114,100,0,59,119,0,18,108,111,100,0,20,0,4, +118,101,99,52,95,116,101,120,95,49,100,95,98,105,97,115,95,115,104,97,100,111,119,0,18,95,95,114, +101,116,86,97,108,0,0,18,115,97,109,112,108,101,114,0,0,18,112,99,111,111,114,100,0,0,0,0,1,90,95, +0,0,12,0,0,115,104,97,100,111,119,50,68,76,111,100,0,1,1,0,0,21,0,115,97,109,112,108,101,114,0,0,1, +1,0,0,11,0,99,111,111,114,100,0,0,1,1,0,0,9,0,108,111,100,0,0,0,1,3,2,90,95,0,0,12,0,1,99,111,111, +114,100,52,0,0,0,9,18,99,111,111,114,100,52,0,59,120,121,122,0,18,99,111,111,114,100,0,20,0,9,18, +99,111,111,114,100,52,0,59,119,0,18,108,111,100,0,20,0,4,118,101,99,52,95,116,101,120,95,50,100,95, +98,105,97,115,95,115,104,97,100,111,119,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112,108, +101,114,0,0,18,99,111,111,114,100,52,0,0,0,0,1,90,95,0,0,12,0,0,115,104,97,100,111,119,50,68,80, +114,111,106,76,111,100,0,1,1,0,0,21,0,115,97,109,112,108,101,114,0,0,1,1,0,0,12,0,99,111,111,114, +100,0,0,1,1,0,0,9,0,108,111,100,0,0,0,1,3,2,90,95,0,0,12,0,1,112,99,111,111,114,100,0,0,0,9,18,112, +99,111,111,114,100,0,59,120,121,0,18,99,111,111,114,100,0,59,120,121,0,18,99,111,111,114,100,0,59, +119,0,49,20,0,9,18,112,99,111,111,114,100,0,59,122,0,18,99,111,111,114,100,0,59,122,0,20,0,9,18, +112,99,111,111,114,100,0,59,119,0,18,108,111,100,0,20,0,4,118,101,99,52,95,116,101,120,95,50,100, +95,98,105,97,115,95,115,104,97,100,111,119,0,18,95,95,114,101,116,86,97,108,0,0,18,115,97,109,112, +108,101,114,0,0,18,112,99,111,111,114,100,0,0,0,0,0 diff --git a/mesalib/src/mesa/shader/slang/library/syn_to_c.c b/mesalib/src/mesa/shader/slang/library/syn_to_c.c new file mode 100644 index 000000000..f997edfd8 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/library/syn_to_c.c @@ -0,0 +1,72 @@ +#include <stdio.h> + +static int was_space = 0; +static int first_char = 1; + +static void put_char (int c) +{ + if (c == '\n') { + if (!first_char) { + fputs ("\\n\"\n\"", stdout); + first_char = 1; + } + } + else { + first_char = 0; + if (c == '\\') + fputs ("\\\\", stdout); + else if (c == '\"') + fputs ("\\\"", stdout); + else if (!was_space || !(c == ' ' || c == '\t')) + fputc (c, stdout); + was_space = (c == ' ' || c == '\t'); + } +} + +int main (int argc, char *argv[]) +{ + int c; + FILE *f; + + if (argc == 1) + return 1; + f = fopen (argv[1], "r"); + if (f == NULL) + return 1; + + fputs ("\n", stdout); + fputs ("/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED FROM THE .syn FILE */\n", stdout); + fputs ("\n", stdout); + fputs ("\"", stdout); + c = getc (f); + while (c != EOF) { + if (c == '/') { + int c2 = getc (f); + if (c2 == '*') { + was_space = 0; + c = getc (f); + for (;;) { + if (c == '*') { + c2 = getc (f); + if (c2 == '/') + break; + } + c = getc (f); + } + } + else { + put_char (c); + put_char (c2); + } + } + else { + put_char (c); + } + c = getc (f); + } + fputs ("\"\n", stdout); + + fclose (f); + return 0; +} + diff --git a/mesalib/src/mesa/shader/slang/slang_builtin.c b/mesalib/src/mesa/shader/slang/slang_builtin.c new file mode 100644 index 000000000..e5809509c --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_builtin.c @@ -0,0 +1,895 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * Copyright (C) 2008 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 slang_builtin.c + * Resolve built-in uniform vars. + * \author Brian Paul + */ + +#include "main/imports.h" +#include "main/mtypes.h" +#include "shader/program.h" +#include "shader/prog_instruction.h" +#include "shader/prog_parameter.h" +#include "shader/prog_statevars.h" +#include "shader/slang/slang_ir.h" +#include "shader/slang/slang_emit.h" +#include "shader/slang/slang_builtin.h" + + +/** special state token (see below) */ +#define STATE_ARRAY ((gl_state_index) 0xfffff) + + +/** + * Lookup GL state given a variable name, 0, 1 or 2 indexes and a field. + * Allocate room for the state in the given param list and return position + * in the list. + * Yes, this is kind of ugly, but it works. + */ +static GLint +lookup_statevar(const char *var, GLint index1, GLint index2, const char *field, + GLuint *swizzleOut, + struct gl_program_parameter_list *paramList) +{ + /* + * NOTE: The ARB_vertex_program extension specified that matrices get + * loaded in registers in row-major order. With GLSL, we want column- + * major order. So, we need to transpose all matrices here... + */ + static const struct { + const char *name; + gl_state_index matrix; + gl_state_index modifier; + } matrices[] = { + { "gl_ModelViewMatrix", STATE_MODELVIEW_MATRIX, STATE_MATRIX_TRANSPOSE }, + { "gl_ModelViewMatrixInverse", STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVTRANS }, + { "gl_ModelViewMatrixTranspose", STATE_MODELVIEW_MATRIX, 0 }, + { "gl_ModelViewMatrixInverseTranspose", STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVERSE }, + + { "gl_ProjectionMatrix", STATE_PROJECTION_MATRIX, STATE_MATRIX_TRANSPOSE }, + { "gl_ProjectionMatrixInverse", STATE_PROJECTION_MATRIX, STATE_MATRIX_INVTRANS }, + { "gl_ProjectionMatrixTranspose", STATE_PROJECTION_MATRIX, 0 }, + { "gl_ProjectionMatrixInverseTranspose", STATE_PROJECTION_MATRIX, STATE_MATRIX_INVERSE }, + + { "gl_ModelViewProjectionMatrix", STATE_MVP_MATRIX, STATE_MATRIX_TRANSPOSE }, + { "gl_ModelViewProjectionMatrixInverse", STATE_MVP_MATRIX, STATE_MATRIX_INVTRANS }, + { "gl_ModelViewProjectionMatrixTranspose", STATE_MVP_MATRIX, 0 }, + { "gl_ModelViewProjectionMatrixInverseTranspose", STATE_MVP_MATRIX, STATE_MATRIX_INVERSE }, + + { "gl_TextureMatrix", STATE_TEXTURE_MATRIX, STATE_MATRIX_TRANSPOSE }, + { "gl_TextureMatrixInverse", STATE_TEXTURE_MATRIX, STATE_MATRIX_INVTRANS }, + { "gl_TextureMatrixTranspose", STATE_TEXTURE_MATRIX, 0 }, + { "gl_TextureMatrixInverseTranspose", STATE_TEXTURE_MATRIX, STATE_MATRIX_INVERSE }, + + { "gl_NormalMatrix", STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVERSE }, + + { NULL, 0, 0 } + }; + gl_state_index tokens[STATE_LENGTH]; + GLuint i; + GLboolean isMatrix = GL_FALSE; + + for (i = 0; i < STATE_LENGTH; i++) { + tokens[i] = 0; + } + *swizzleOut = SWIZZLE_NOOP; + + /* first, look if var is a pre-defined matrix */ + for (i = 0; matrices[i].name; i++) { + if (strcmp(var, matrices[i].name) == 0) { + tokens[0] = matrices[i].matrix; + /* tokens[1], [2] and [3] filled below */ + tokens[4] = matrices[i].modifier; + isMatrix = GL_TRUE; + break; + } + } + + if (isMatrix) { + if (tokens[0] == STATE_TEXTURE_MATRIX) { + /* texture_matrix[index1][index2] */ + tokens[1] = index1 >= 0 ? index1 : 0; /* which texture matrix */ + index1 = index2; /* move matrix row value to index1 */ + } + if (index1 < 0) { + /* index1 is unused: prevent extra addition at end of function */ + index1 = 0; + } + } + else if (strcmp(var, "gl_DepthRange") == 0) { + tokens[0] = STATE_DEPTH_RANGE; + if (strcmp(field, "near") == 0) { + *swizzleOut = SWIZZLE_XXXX; + } + else if (strcmp(field, "far") == 0) { + *swizzleOut = SWIZZLE_YYYY; + } + else if (strcmp(field, "diff") == 0) { + *swizzleOut = SWIZZLE_ZZZZ; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_ClipPlane") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_CLIPPLANE; + tokens[1] = index1; + } + else if (strcmp(var, "gl_Point") == 0) { + if (strcmp(field, "size") == 0) { + tokens[0] = STATE_POINT_SIZE; + *swizzleOut = SWIZZLE_XXXX; + } + else if (strcmp(field, "sizeMin") == 0) { + tokens[0] = STATE_POINT_SIZE; + *swizzleOut = SWIZZLE_YYYY; + } + else if (strcmp(field, "sizeMax") == 0) { + tokens[0] = STATE_POINT_SIZE; + *swizzleOut = SWIZZLE_ZZZZ; + } + else if (strcmp(field, "fadeThresholdSize") == 0) { + tokens[0] = STATE_POINT_SIZE; + *swizzleOut = SWIZZLE_WWWW; + } + else if (strcmp(field, "distanceConstantAttenuation") == 0) { + tokens[0] = STATE_POINT_ATTENUATION; + *swizzleOut = SWIZZLE_XXXX; + } + else if (strcmp(field, "distanceLinearAttenuation") == 0) { + tokens[0] = STATE_POINT_ATTENUATION; + *swizzleOut = SWIZZLE_YYYY; + } + else if (strcmp(field, "distanceQuadraticAttenuation") == 0) { + tokens[0] = STATE_POINT_ATTENUATION; + *swizzleOut = SWIZZLE_ZZZZ; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_FrontMaterial") == 0 || + strcmp(var, "gl_BackMaterial") == 0) { + tokens[0] = STATE_MATERIAL; + if (strcmp(var, "gl_FrontMaterial") == 0) + tokens[1] = 0; + else + tokens[1] = 1; + if (strcmp(field, "emission") == 0) { + tokens[2] = STATE_EMISSION; + } + else if (strcmp(field, "ambient") == 0) { + tokens[2] = STATE_AMBIENT; + } + else if (strcmp(field, "diffuse") == 0) { + tokens[2] = STATE_DIFFUSE; + } + else if (strcmp(field, "specular") == 0) { + tokens[2] = STATE_SPECULAR; + } + else if (strcmp(field, "shininess") == 0) { + tokens[2] = STATE_SHININESS; + *swizzleOut = SWIZZLE_XXXX; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_LightSource") == 0) { + if (!field || index1 < 0) + return -1; + + tokens[0] = STATE_LIGHT; + tokens[1] = index1; + + if (strcmp(field, "ambient") == 0) { + tokens[2] = STATE_AMBIENT; + } + else if (strcmp(field, "diffuse") == 0) { + tokens[2] = STATE_DIFFUSE; + } + else if (strcmp(field, "specular") == 0) { + tokens[2] = STATE_SPECULAR; + } + else if (strcmp(field, "position") == 0) { + tokens[2] = STATE_POSITION; + } + else if (strcmp(field, "halfVector") == 0) { + tokens[2] = STATE_HALF_VECTOR; + } + else if (strcmp(field, "spotDirection") == 0) { + tokens[2] = STATE_SPOT_DIRECTION; + } + else if (strcmp(field, "spotCosCutoff") == 0) { + tokens[2] = STATE_SPOT_DIRECTION; + *swizzleOut = SWIZZLE_WWWW; + } + else if (strcmp(field, "spotCutoff") == 0) { + tokens[2] = STATE_SPOT_CUTOFF; + *swizzleOut = SWIZZLE_XXXX; + } + else if (strcmp(field, "spotExponent") == 0) { + tokens[2] = STATE_ATTENUATION; + *swizzleOut = SWIZZLE_WWWW; + } + else if (strcmp(field, "constantAttenuation") == 0) { + tokens[2] = STATE_ATTENUATION; + *swizzleOut = SWIZZLE_XXXX; + } + else if (strcmp(field, "linearAttenuation") == 0) { + tokens[2] = STATE_ATTENUATION; + *swizzleOut = SWIZZLE_YYYY; + } + else if (strcmp(field, "quadraticAttenuation") == 0) { + tokens[2] = STATE_ATTENUATION; + *swizzleOut = SWIZZLE_ZZZZ; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_LightModel") == 0) { + if (strcmp(field, "ambient") == 0) { + tokens[0] = STATE_LIGHTMODEL_AMBIENT; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_FrontLightModelProduct") == 0) { + if (strcmp(field, "sceneColor") == 0) { + tokens[0] = STATE_LIGHTMODEL_SCENECOLOR; + tokens[1] = 0; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_BackLightModelProduct") == 0) { + if (strcmp(field, "sceneColor") == 0) { + tokens[0] = STATE_LIGHTMODEL_SCENECOLOR; + tokens[1] = 1; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_FrontLightProduct") == 0 || + strcmp(var, "gl_BackLightProduct") == 0) { + if (index1 < 0 || !field) + return -1; + + tokens[0] = STATE_LIGHTPROD; + tokens[1] = index1; /* light number */ + if (strcmp(var, "gl_FrontLightProduct") == 0) { + tokens[2] = 0; /* front */ + } + else { + tokens[2] = 1; /* back */ + } + if (strcmp(field, "ambient") == 0) { + tokens[3] = STATE_AMBIENT; + } + else if (strcmp(field, "diffuse") == 0) { + tokens[3] = STATE_DIFFUSE; + } + else if (strcmp(field, "specular") == 0) { + tokens[3] = STATE_SPECULAR; + } + else { + return -1; + } + } + else if (strcmp(var, "gl_TextureEnvColor") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXENV_COLOR; + tokens[1] = index1; + } + else if (strcmp(var, "gl_EyePlaneS") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_EYE_S; + } + else if (strcmp(var, "gl_EyePlaneT") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_EYE_T; + } + else if (strcmp(var, "gl_EyePlaneR") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_EYE_R; + } + else if (strcmp(var, "gl_EyePlaneQ") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_EYE_Q; + } + else if (strcmp(var, "gl_ObjectPlaneS") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_OBJECT_S; + } + else if (strcmp(var, "gl_ObjectPlaneT") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_OBJECT_T; + } + else if (strcmp(var, "gl_ObjectPlaneR") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_OBJECT_R; + } + else if (strcmp(var, "gl_ObjectPlaneQ") == 0) { + if (index1 < 0) + return -1; + tokens[0] = STATE_TEXGEN; + tokens[1] = index1; /* tex unit */ + tokens[2] = STATE_TEXGEN_OBJECT_Q; + } + else if (strcmp(var, "gl_Fog") == 0) { + if (strcmp(field, "color") == 0) { + tokens[0] = STATE_FOG_COLOR; + } + else if (strcmp(field, "density") == 0) { + tokens[0] = STATE_FOG_PARAMS; + *swizzleOut = SWIZZLE_XXXX; + } + else if (strcmp(field, "start") == 0) { + tokens[0] = STATE_FOG_PARAMS; + *swizzleOut = SWIZZLE_YYYY; + } + else if (strcmp(field, "end") == 0) { + tokens[0] = STATE_FOG_PARAMS; + *swizzleOut = SWIZZLE_ZZZZ; + } + else if (strcmp(field, "scale") == 0) { + tokens[0] = STATE_FOG_PARAMS; + *swizzleOut = SWIZZLE_WWWW; + } + else { + return -1; + } + } + else { + return -1; + } + + if (isMatrix) { + /* load all four columns of matrix */ + GLint pos[4]; + GLuint j; + for (j = 0; j < 4; j++) { + tokens[2] = tokens[3] = j; /* jth row of matrix */ + pos[j] = _mesa_add_state_reference(paramList, tokens); + assert(pos[j] >= 0); + ASSERT(pos[j] >= 0); + } + return pos[0] + index1; + } + else { + /* allocate a single register */ + GLint pos = _mesa_add_state_reference(paramList, tokens); + ASSERT(pos >= 0); + return pos; + } +} + + + +/** + * Given a variable name and datatype, emit uniform/constant buffer + * entries which will store that state variable. + * For example, if name="gl_LightSource" we'll emit 64 state variable + * vectors/references and return position where that data starts. This will + * allow run-time array indexing into the light source array. + * + * Note that this is a recursive function. + * + * \return -1 if error, else index of start of data in the program parameter list + */ +static GLint +emit_statevars(const char *name, int array_len, + const slang_type_specifier *type, + gl_state_index tokens[STATE_LENGTH], + struct gl_program_parameter_list *paramList) +{ + if (type->type == SLANG_SPEC_ARRAY) { + GLint i, pos = -1; + assert(array_len > 0); + if (strcmp(name, "gl_ClipPlane") == 0) { + tokens[0] = STATE_CLIPPLANE; + } + else if (strcmp(name, "gl_LightSource") == 0) { + tokens[0] = STATE_LIGHT; + } + else if (strcmp(name, "gl_FrontLightProduct") == 0) { + tokens[0] = STATE_LIGHTPROD; + tokens[2] = 0; /* front */ + } + else if (strcmp(name, "gl_BackLightProduct") == 0) { + tokens[0] = STATE_LIGHTPROD; + tokens[2] = 1; /* back */ + } + else if (strcmp(name, "gl_TextureEnvColor") == 0) { + tokens[0] = STATE_TEXENV_COLOR; + } + else if (strcmp(name, "gl_EyePlaneS") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_EYE_S; + } + else if (strcmp(name, "gl_EyePlaneT") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_EYE_T; + } + else if (strcmp(name, "gl_EyePlaneR") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_EYE_R; + } + else if (strcmp(name, "gl_EyePlaneQ") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_EYE_Q; + } + else if (strcmp(name, "gl_ObjectPlaneS") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_OBJECT_S; + } + else if (strcmp(name, "gl_ObjectPlaneT") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_OBJECT_T; + } + else if (strcmp(name, "gl_ObjectPlaneR") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_OBJECT_R; + } + else if (strcmp(name, "gl_ObjectPlaneQ") == 0) { + tokens[0] = STATE_TEXGEN; + tokens[2] = STATE_TEXGEN_OBJECT_Q; + } + else { + return -1; /* invalid array name */ + } + for (i = 0; i < array_len; i++) { + GLint p; + tokens[1] = i; + p = emit_statevars(NULL, 0, type->_array, tokens, paramList); + if (i == 0) + pos = p; + } + return pos; + } + else if (type->type == SLANG_SPEC_STRUCT) { + const slang_variable_scope *fields = type->_struct->fields; + GLuint i, pos = 0; + for (i = 0; i < fields->num_variables; i++) { + const slang_variable *var = fields->variables[i]; + GLint p = emit_statevars(var->a_name, 0, &var->type.specifier, + tokens, paramList); + if (i == 0) + pos = p; + } + return pos; + } + else { + GLint pos; + assert(type->type == SLANG_SPEC_VEC4 || + type->type == SLANG_SPEC_VEC3 || + type->type == SLANG_SPEC_VEC2 || + type->type == SLANG_SPEC_FLOAT || + type->type == SLANG_SPEC_IVEC4 || + type->type == SLANG_SPEC_IVEC3 || + type->type == SLANG_SPEC_IVEC2 || + type->type == SLANG_SPEC_INT); + if (name) { + GLint t; + + if (tokens[0] == STATE_LIGHT) + t = 2; + else if (tokens[0] == STATE_LIGHTPROD) + t = 3; + else + return -1; /* invalid array name */ + + if (strcmp(name, "ambient") == 0) { + tokens[t] = STATE_AMBIENT; + } + else if (strcmp(name, "diffuse") == 0) { + tokens[t] = STATE_DIFFUSE; + } + else if (strcmp(name, "specular") == 0) { + tokens[t] = STATE_SPECULAR; + } + else if (strcmp(name, "position") == 0) { + tokens[t] = STATE_POSITION; + } + else if (strcmp(name, "halfVector") == 0) { + tokens[t] = STATE_HALF_VECTOR; + } + else if (strcmp(name, "spotDirection") == 0) { + tokens[t] = STATE_SPOT_DIRECTION; /* xyz components */ + } + else if (strcmp(name, "spotCosCutoff") == 0) { + tokens[t] = STATE_SPOT_DIRECTION; /* w component */ + } + + else if (strcmp(name, "constantAttenuation") == 0) { + tokens[t] = STATE_ATTENUATION; /* x component */ + } + else if (strcmp(name, "linearAttenuation") == 0) { + tokens[t] = STATE_ATTENUATION; /* y component */ + } + else if (strcmp(name, "quadraticAttenuation") == 0) { + tokens[t] = STATE_ATTENUATION; /* z component */ + } + else if (strcmp(name, "spotExponent") == 0) { + tokens[t] = STATE_ATTENUATION; /* w = spot exponent */ + } + + else if (strcmp(name, "spotCutoff") == 0) { + tokens[t] = STATE_SPOT_CUTOFF; /* x component */ + } + + else { + return -1; /* invalid field name */ + } + } + + pos = _mesa_add_state_reference(paramList, tokens); + return pos; + } + + return 1; +} + + +/** + * Unroll the named built-in uniform variable into a sequence of state + * vars in the given parameter list. + */ +static GLint +alloc_state_var_array(const slang_variable *var, + struct gl_program_parameter_list *paramList) +{ + gl_state_index tokens[STATE_LENGTH]; + GLuint i; + GLint pos; + + /* Initialize the state tokens array. This is very important. + * When we call _mesa_add_state_reference() it'll searches the parameter + * list to see if the given statevar token sequence is already present. + * This is normally a good thing since it prevents redundant values in the + * constant buffer. + * + * But when we're building arrays of state this can be bad. For example, + * consider this fragment of GLSL code: + * foo = gl_LightSource[3].diffuse; + * ... + * bar = gl_LightSource[i].diffuse; + * + * When we unroll the gl_LightSource array (for "bar") we want to re-emit + * gl_LightSource[3].diffuse and not re-use the first instance (from "foo") + * since that would upset the array layout. We handle this situation by + * setting the last token in the state var token array to the special + * value STATE_ARRAY. + * This token will only be set for array state. We can hijack the last + * element in the array for this since it's never used for light, clipplane + * or texture env array state. + */ + for (i = 0; i < STATE_LENGTH; i++) + tokens[i] = 0; + tokens[STATE_LENGTH - 1] = STATE_ARRAY; + + pos = emit_statevars(var->a_name, var->array_len, &var->type.specifier, + tokens, paramList); + + return pos; +} + + + +/** + * Allocate storage for a pre-defined uniform (a GL state variable). + * As a memory-saving optimization, we try to only allocate storage for + * state vars that are actually used. + * + * Arrays such as gl_LightSource are handled specially. For an expression + * like "gl_LightSource[2].diffuse", we can allocate a single uniform/constant + * slot and return the index. In this case, we return direct=TRUE. + * + * Buf for something like "gl_LightSource[i].diffuse" we don't know the value + * of 'i' at compile time so we need to "unroll" the gl_LightSource array + * into a consecutive sequence of uniform/constant slots so it can be indexed + * at runtime. In this case, we return direct=FALSE. + * + * Currently, all pre-defined uniforms are in one of these forms: + * var + * var[i] + * var.field + * var[i].field + * var[i][j] + * + * \return -1 upon error, else position in paramList of the state variable/data + */ +GLint +_slang_alloc_statevar(slang_ir_node *n, + struct gl_program_parameter_list *paramList, + GLboolean *direct) +{ + slang_ir_node *n0 = n; + const char *field = NULL; + GLint index1 = -1, index2 = -1; + GLuint swizzle; + + *direct = GL_TRUE; + + if (n->Opcode == IR_FIELD) { + field = n->Field; + n = n->Children[0]; + } + + if (n->Opcode == IR_ELEMENT) { + if (n->Children[1]->Opcode == IR_FLOAT) { + index1 = (GLint) n->Children[1]->Value[0]; + } + else { + *direct = GL_FALSE; + } + n = n->Children[0]; + } + + if (n->Opcode == IR_ELEMENT) { + /* XXX can only handle constant indexes for now */ + if (n->Children[1]->Opcode == IR_FLOAT) { + /* two-dimensional array index: mat[i][j] */ + index2 = index1; + index1 = (GLint) n->Children[1]->Value[0]; + } + else { + *direct = GL_FALSE; + } + n = n->Children[0]; + } + + assert(n->Opcode == IR_VAR); + + if (*direct) { + const char *var = (const char *) n->Var->a_name; + GLint pos = + lookup_statevar(var, index1, index2, field, &swizzle, paramList); + if (pos >= 0) { + /* newly resolved storage for the statevar/constant/uniform */ + n0->Store->File = PROGRAM_STATE_VAR; + n0->Store->Index = pos; + n0->Store->Swizzle = swizzle; + n0->Store->Parent = NULL; + return pos; + } + } + + *direct = GL_FALSE; + return alloc_state_var_array(n->Var, paramList); +} + + + + +#define SWIZZLE_ZWWW MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W) + + +/** Predefined shader inputs */ +struct input_info +{ + const char *Name; + GLuint Attrib; + GLenum Type; + GLuint Swizzle; +}; + +/** Predefined vertex shader inputs/attributes */ +static const struct input_info vertInputs[] = { + { "gl_Vertex", VERT_ATTRIB_POS, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_Normal", VERT_ATTRIB_NORMAL, GL_FLOAT_VEC3, SWIZZLE_NOOP }, + { "gl_Color", VERT_ATTRIB_COLOR0, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_SecondaryColor", VERT_ATTRIB_COLOR1, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_FogCoord", VERT_ATTRIB_FOG, GL_FLOAT, SWIZZLE_XXXX }, + { "gl_MultiTexCoord0", VERT_ATTRIB_TEX0, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_MultiTexCoord1", VERT_ATTRIB_TEX1, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_MultiTexCoord2", VERT_ATTRIB_TEX2, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_MultiTexCoord3", VERT_ATTRIB_TEX3, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_MultiTexCoord4", VERT_ATTRIB_TEX4, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_MultiTexCoord5", VERT_ATTRIB_TEX5, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_MultiTexCoord6", VERT_ATTRIB_TEX6, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_MultiTexCoord7", VERT_ATTRIB_TEX7, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { NULL, 0, GL_NONE, SWIZZLE_NOOP } +}; + +/** Predefined fragment shader inputs */ +static const struct input_info fragInputs[] = { + { "gl_FragCoord", FRAG_ATTRIB_WPOS, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_Color", FRAG_ATTRIB_COL0, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_SecondaryColor", FRAG_ATTRIB_COL1, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + { "gl_TexCoord", FRAG_ATTRIB_TEX0, GL_FLOAT_VEC4, SWIZZLE_NOOP }, + /* note: we're packing several quantities into the fogcoord vector */ + { "gl_FogFragCoord", FRAG_ATTRIB_FOGC, GL_FLOAT, SWIZZLE_XXXX }, + { "gl_FrontFacing", FRAG_ATTRIB_FACE, GL_FLOAT, SWIZZLE_XXXX }, + { "gl_PointCoord", FRAG_ATTRIB_PNTC, GL_FLOAT_VEC2, SWIZZLE_XYZW }, + { NULL, 0, GL_NONE, SWIZZLE_NOOP } +}; + + +/** + * Return the VERT_ATTRIB_* or FRAG_ATTRIB_* value that corresponds to + * a vertex or fragment program input variable. Return -1 if the input + * name is invalid. + * XXX return size too + */ +GLint +_slang_input_index(const char *name, GLenum target, GLuint *swizzleOut) +{ + const struct input_info *inputs; + GLuint i; + + switch (target) { + case GL_VERTEX_PROGRAM_ARB: + inputs = vertInputs; + break; + case GL_FRAGMENT_PROGRAM_ARB: + inputs = fragInputs; + break; + /* XXX geom program */ + default: + _mesa_problem(NULL, "bad target in _slang_input_index"); + return -1; + } + + ASSERT(MAX_TEXTURE_COORD_UNITS == 8); /* if this fails, fix vertInputs above */ + + for (i = 0; inputs[i].Name; i++) { + if (strcmp(inputs[i].Name, name) == 0) { + /* found */ + *swizzleOut = inputs[i].Swizzle; + return inputs[i].Attrib; + } + } + return -1; +} + + +/** + * Return name of the given vertex attribute (VERT_ATTRIB_x). + */ +const char * +_slang_vert_attrib_name(GLuint attrib) +{ + GLuint i; + assert(attrib < VERT_ATTRIB_GENERIC0); + for (i = 0; vertInputs[i].Name; i++) { + if (vertInputs[i].Attrib == attrib) + return vertInputs[i].Name; + } + return NULL; +} + + +/** + * Return type (GL_FLOAT, GL_FLOAT_VEC2, etc) of the given vertex + * attribute (VERT_ATTRIB_x). + */ +GLenum +_slang_vert_attrib_type(GLuint attrib) +{ + GLuint i; + assert(attrib < VERT_ATTRIB_GENERIC0); + for (i = 0; vertInputs[i].Name; i++) { + if (vertInputs[i].Attrib == attrib) + return vertInputs[i].Type; + } + return GL_NONE; +} + + + + + +/** Predefined shader output info */ +struct output_info +{ + const char *Name; + GLuint Attrib; +}; + +/** Predefined vertex shader outputs */ +static const struct output_info vertOutputs[] = { + { "gl_Position", VERT_RESULT_HPOS }, + { "gl_FrontColor", VERT_RESULT_COL0 }, + { "gl_BackColor", VERT_RESULT_BFC0 }, + { "gl_FrontSecondaryColor", VERT_RESULT_COL1 }, + { "gl_BackSecondaryColor", VERT_RESULT_BFC1 }, + { "gl_TexCoord", VERT_RESULT_TEX0 }, + { "gl_FogFragCoord", VERT_RESULT_FOGC }, + { "gl_PointSize", VERT_RESULT_PSIZ }, + { NULL, 0 } +}; + +/** Predefined fragment shader outputs */ +static const struct output_info fragOutputs[] = { + { "gl_FragColor", FRAG_RESULT_COLOR }, + { "gl_FragDepth", FRAG_RESULT_DEPTH }, + { "gl_FragData", FRAG_RESULT_DATA0 }, + { NULL, 0 } +}; + + +/** + * Return the VERT_RESULT_* or FRAG_RESULT_* value that corresponds to + * a vertex or fragment program output variable. Return -1 for an invalid + * output name. + */ +GLint +_slang_output_index(const char *name, GLenum target) +{ + const struct output_info *outputs; + GLuint i; + + switch (target) { + case GL_VERTEX_PROGRAM_ARB: + outputs = vertOutputs; + break; + case GL_FRAGMENT_PROGRAM_ARB: + outputs = fragOutputs; + break; + /* XXX geom program */ + default: + _mesa_problem(NULL, "bad target in _slang_output_index"); + return -1; + } + + for (i = 0; outputs[i].Name; i++) { + if (strcmp(outputs[i].Name, name) == 0) { + /* found */ + return outputs[i].Attrib; + } + } + return -1; +} diff --git a/mesalib/src/mesa/shader/slang/slang_builtin.h b/mesalib/src/mesa/shader/slang/slang_builtin.h new file mode 100644 index 000000000..f814d11ac --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_builtin.h @@ -0,0 +1,54 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-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 SLANG_BUILTIN_H +#define SLANG_BUILTIN_H + +#include "shader/prog_parameter.h" +#include "slang_utility.h" +#include "slang_ir.h" + + +extern GLint +_slang_alloc_statevar(slang_ir_node *n, + struct gl_program_parameter_list *paramList, + GLboolean *direct); + + +extern GLint +_slang_input_index(const char *name, GLenum target, GLuint *swizzleOut); + +extern GLint +_slang_output_index(const char *name, GLenum target); + + +extern const char * +_slang_vert_attrib_name(GLuint attrib); + +extern GLenum +_slang_vert_attrib_type(GLuint attrib); + + +#endif /* SLANG_BUILTIN_H */ diff --git a/mesalib/src/mesa/shader/slang/slang_codegen.c b/mesalib/src/mesa/shader/slang/slang_codegen.c new file mode 100644 index 000000000..703af9f87 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_codegen.c @@ -0,0 +1,5319 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. + * Copyright (C) 2008 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 slang_codegen.c + * Generate IR tree from AST. + * \author Brian Paul + */ + + +/*** + *** NOTES: + *** The new_() functions return a new instance of a simple IR node. + *** The gen_() functions generate larger IR trees from the simple nodes. + ***/ + + + +#include "main/imports.h" +#include "main/macros.h" +#include "main/mtypes.h" +#include "shader/program.h" +#include "shader/prog_instruction.h" +#include "shader/prog_parameter.h" +#include "shader/prog_print.h" +#include "shader/prog_statevars.h" +#include "slang_typeinfo.h" +#include "slang_builtin.h" +#include "slang_codegen.h" +#include "slang_compile.h" +#include "slang_label.h" +#include "slang_mem.h" +#include "slang_simplify.h" +#include "slang_emit.h" +#include "slang_vartable.h" +#include "slang_ir.h" +#include "slang_print.h" + + +/** Max iterations to unroll */ +const GLuint MAX_FOR_LOOP_UNROLL_ITERATIONS = 32; + +/** Max for-loop body size (in slang operations) to unroll */ +const GLuint MAX_FOR_LOOP_UNROLL_BODY_SIZE = 50; + +/** Max for-loop body complexity to unroll. + * We'll compute complexity as the product of the number of iterations + * and the size of the body. So long-ish loops with very simple bodies + * can be unrolled, as well as short loops with larger bodies. + */ +const GLuint MAX_FOR_LOOP_UNROLL_COMPLEXITY = 256; + + + +static slang_ir_node * +_slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper); + +static void +slang_substitute(slang_assemble_ctx *A, slang_operation *oper, + GLuint substCount, slang_variable **substOld, + slang_operation **substNew, GLboolean isLHS); + + +/** + * Retrieves type information about an operation. + * Returns GL_TRUE on success. + * Returns GL_FALSE otherwise. + */ +static GLboolean +typeof_operation(const struct slang_assemble_ctx_ *A, + slang_operation *op, + slang_typeinfo *ti) +{ + return _slang_typeof_operation(op, &A->space, ti, A->atoms, A->log); +} + + +static GLboolean +is_sampler_type(const slang_fully_specified_type *t) +{ + switch (t->specifier.type) { + case SLANG_SPEC_SAMPLER1D: + case SLANG_SPEC_SAMPLER2D: + case SLANG_SPEC_SAMPLER3D: + case SLANG_SPEC_SAMPLERCUBE: + case SLANG_SPEC_SAMPLER1DSHADOW: + case SLANG_SPEC_SAMPLER2DSHADOW: + case SLANG_SPEC_SAMPLER2DRECT: + case SLANG_SPEC_SAMPLER2DRECTSHADOW: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Return the offset (in floats or ints) of the named field within + * the given struct. Return -1 if field not found. + * If field is NULL, return the size of the struct instead. + */ +static GLint +_slang_field_offset(const slang_type_specifier *spec, slang_atom field) +{ + GLint offset = 0; + GLuint i; + for (i = 0; i < spec->_struct->fields->num_variables; i++) { + const slang_variable *v = spec->_struct->fields->variables[i]; + const GLuint sz = _slang_sizeof_type_specifier(&v->type.specifier); + if (sz > 1) { + /* types larger than 1 float are register (4-float) aligned */ + offset = (offset + 3) & ~3; + } + if (field && v->a_name == field) { + return offset; + } + offset += sz; + } + if (field) + return -1; /* field not found */ + else + return offset; /* struct size */ +} + + +/** + * Return the size (in floats) of the given type specifier. + * If the size is greater than 4, the size should be a multiple of 4 + * so that the correct number of 4-float registers are allocated. + * For example, a mat3x2 is size 12 because we want to store the + * 3 columns in 3 float[4] registers. + */ +GLuint +_slang_sizeof_type_specifier(const slang_type_specifier *spec) +{ + GLuint sz; + switch (spec->type) { + case SLANG_SPEC_VOID: + sz = 0; + break; + case SLANG_SPEC_BOOL: + sz = 1; + break; + case SLANG_SPEC_BVEC2: + sz = 2; + break; + case SLANG_SPEC_BVEC3: + sz = 3; + break; + case SLANG_SPEC_BVEC4: + sz = 4; + break; + case SLANG_SPEC_INT: + sz = 1; + break; + case SLANG_SPEC_IVEC2: + sz = 2; + break; + case SLANG_SPEC_IVEC3: + sz = 3; + break; + case SLANG_SPEC_IVEC4: + sz = 4; + break; + case SLANG_SPEC_FLOAT: + sz = 1; + break; + case SLANG_SPEC_VEC2: + sz = 2; + break; + case SLANG_SPEC_VEC3: + sz = 3; + break; + case SLANG_SPEC_VEC4: + sz = 4; + break; + case SLANG_SPEC_MAT2: + sz = 2 * 4; /* 2 columns (regs) */ + break; + case SLANG_SPEC_MAT3: + sz = 3 * 4; + break; + case SLANG_SPEC_MAT4: + sz = 4 * 4; + break; + case SLANG_SPEC_MAT23: + sz = 2 * 4; /* 2 columns (regs) */ + break; + case SLANG_SPEC_MAT32: + sz = 3 * 4; /* 3 columns (regs) */ + break; + case SLANG_SPEC_MAT24: + sz = 2 * 4; + break; + case SLANG_SPEC_MAT42: + sz = 4 * 4; /* 4 columns (regs) */ + break; + case SLANG_SPEC_MAT34: + sz = 3 * 4; + break; + case SLANG_SPEC_MAT43: + sz = 4 * 4; /* 4 columns (regs) */ + break; + case SLANG_SPEC_SAMPLER1D: + case SLANG_SPEC_SAMPLER2D: + case SLANG_SPEC_SAMPLER3D: + case SLANG_SPEC_SAMPLERCUBE: + case SLANG_SPEC_SAMPLER1DSHADOW: + case SLANG_SPEC_SAMPLER2DSHADOW: + case SLANG_SPEC_SAMPLER2DRECT: + case SLANG_SPEC_SAMPLER2DRECTSHADOW: + sz = 1; /* a sampler is basically just an integer index */ + break; + case SLANG_SPEC_STRUCT: + sz = _slang_field_offset(spec, 0); /* special use */ + if (sz == 1) { + /* 1-float structs are actually troublesome to deal with since they + * might get placed at R.x, R.y, R.z or R.z. Return size=2 to + * ensure the object is placed at R.x + */ + sz = 2; + } + else if (sz > 4) { + sz = (sz + 3) & ~0x3; /* round up to multiple of four */ + } + break; + case SLANG_SPEC_ARRAY: + sz = _slang_sizeof_type_specifier(spec->_array); + break; + default: + _mesa_problem(NULL, "Unexpected type in _slang_sizeof_type_specifier()"); + sz = 0; + } + + if (sz > 4) { + /* if size is > 4, it should be a multiple of four */ + assert((sz & 0x3) == 0); + } + return sz; +} + + +/** + * Query variable/array length (number of elements). + * This is slightly non-trivial because there are two ways to express + * arrays: "float x[3]" vs. "float[3] x". + * \return the length of the array for the given variable, or 0 if not an array + */ +static GLint +_slang_array_length(const slang_variable *var) +{ + if (var->type.array_len > 0) { + /* Ex: float[4] x; */ + return var->type.array_len; + } + if (var->array_len > 0) { + /* Ex: float x[4]; */ + return var->array_len; + } + return 0; +} + + +/** + * Compute total size of array give size of element, number of elements. + * \return size in floats + */ +static GLint +_slang_array_size(GLint elemSize, GLint arrayLen) +{ + GLint total; + assert(elemSize > 0); + if (arrayLen > 1) { + /* round up base type to multiple of 4 */ + total = ((elemSize + 3) & ~0x3) * MAX2(arrayLen, 1); + } + else { + total = elemSize; + } + return total; +} + + +/** + * Return the TEXTURE_*_INDEX value that corresponds to a sampler type, + * or -1 if the type is not a sampler. + */ +static GLint +sampler_to_texture_index(const slang_type_specifier_type type) +{ + switch (type) { + case SLANG_SPEC_SAMPLER1D: + return TEXTURE_1D_INDEX; + case SLANG_SPEC_SAMPLER2D: + return TEXTURE_2D_INDEX; + case SLANG_SPEC_SAMPLER3D: + return TEXTURE_3D_INDEX; + case SLANG_SPEC_SAMPLERCUBE: + return TEXTURE_CUBE_INDEX; + case SLANG_SPEC_SAMPLER1DSHADOW: + return TEXTURE_1D_INDEX; /* XXX fix */ + case SLANG_SPEC_SAMPLER2DSHADOW: + return TEXTURE_2D_INDEX; /* XXX fix */ + case SLANG_SPEC_SAMPLER2DRECT: + return TEXTURE_RECT_INDEX; + case SLANG_SPEC_SAMPLER2DRECTSHADOW: + return TEXTURE_RECT_INDEX; /* XXX fix */ + default: + return -1; + } +} + + +/** helper to build a SLANG_OPER_IDENTIFIER node */ +static void +slang_operation_identifier(slang_operation *oper, + slang_assemble_ctx *A, + const char *name) +{ + oper->type = SLANG_OPER_IDENTIFIER; + oper->a_id = slang_atom_pool_atom(A->atoms, name); +} + + +/** + * Called when we begin code/IR generation for a new while/do/for loop. + */ +static void +push_loop(slang_assemble_ctx *A, slang_operation *loopOper, slang_ir_node *loopIR) +{ + A->LoopOperStack[A->LoopDepth] = loopOper; + A->LoopIRStack[A->LoopDepth] = loopIR; + A->LoopDepth++; +} + + +/** + * Called when we end code/IR generation for a new while/do/for loop. + */ +static void +pop_loop(slang_assemble_ctx *A) +{ + assert(A->LoopDepth > 0); + A->LoopDepth--; +} + + +/** + * Return pointer to slang_operation for the loop we're currently inside, + * or NULL if not in a loop. + */ +static const slang_operation * +current_loop_oper(const slang_assemble_ctx *A) +{ + if (A->LoopDepth > 0) + return A->LoopOperStack[A->LoopDepth - 1]; + else + return NULL; +} + + +/** + * Return pointer to slang_ir_node for the loop we're currently inside, + * or NULL if not in a loop. + */ +static slang_ir_node * +current_loop_ir(const slang_assemble_ctx *A) +{ + if (A->LoopDepth > 0) + return A->LoopIRStack[A->LoopDepth - 1]; + else + return NULL; +} + + +/**********************************************************************/ + + +/** + * Map "_asm foo" to IR_FOO, etc. + */ +typedef struct +{ + const char *Name; + slang_ir_opcode Opcode; + GLuint HaveRetValue, NumParams; +} slang_asm_info; + + +static slang_asm_info AsmInfo[] = { + /* vec4 binary op */ + { "vec4_add", IR_ADD, 1, 2 }, + { "vec4_subtract", IR_SUB, 1, 2 }, + { "vec4_multiply", IR_MUL, 1, 2 }, + { "vec4_dot", IR_DOT4, 1, 2 }, + { "vec3_dot", IR_DOT3, 1, 2 }, + { "vec2_dot", IR_DOT2, 1, 2 }, + { "vec3_nrm", IR_NRM3, 1, 1 }, + { "vec4_nrm", IR_NRM4, 1, 1 }, + { "vec3_cross", IR_CROSS, 1, 2 }, + { "vec4_lrp", IR_LRP, 1, 3 }, + { "vec4_min", IR_MIN, 1, 2 }, + { "vec4_max", IR_MAX, 1, 2 }, + { "vec4_clamp", IR_CLAMP, 1, 3 }, + { "vec4_seq", IR_SEQUAL, 1, 2 }, + { "vec4_sne", IR_SNEQUAL, 1, 2 }, + { "vec4_sge", IR_SGE, 1, 2 }, + { "vec4_sgt", IR_SGT, 1, 2 }, + { "vec4_sle", IR_SLE, 1, 2 }, + { "vec4_slt", IR_SLT, 1, 2 }, + /* vec4 unary */ + { "vec4_move", IR_MOVE, 1, 1 }, + { "vec4_floor", IR_FLOOR, 1, 1 }, + { "vec4_frac", IR_FRAC, 1, 1 }, + { "vec4_abs", IR_ABS, 1, 1 }, + { "vec4_negate", IR_NEG, 1, 1 }, + { "vec4_ddx", IR_DDX, 1, 1 }, + { "vec4_ddy", IR_DDY, 1, 1 }, + /* float binary op */ + { "float_power", IR_POW, 1, 2 }, + /* texture / sampler */ + { "vec4_tex_1d", IR_TEX, 1, 2 }, + { "vec4_tex_1d_bias", IR_TEXB, 1, 2 }, /* 1d w/ bias */ + { "vec4_tex_1d_proj", IR_TEXP, 1, 2 }, /* 1d w/ projection */ + { "vec4_tex_2d", IR_TEX, 1, 2 }, + { "vec4_tex_2d_bias", IR_TEXB, 1, 2 }, /* 2d w/ bias */ + { "vec4_tex_2d_proj", IR_TEXP, 1, 2 }, /* 2d w/ projection */ + { "vec4_tex_3d", IR_TEX, 1, 2 }, + { "vec4_tex_3d_bias", IR_TEXB, 1, 2 }, /* 3d w/ bias */ + { "vec4_tex_3d_proj", IR_TEXP, 1, 2 }, /* 3d w/ projection */ + { "vec4_tex_cube", IR_TEX, 1, 2 }, /* cubemap */ + { "vec4_tex_rect", IR_TEX, 1, 2 }, /* rectangle */ + { "vec4_tex_rect_bias", IR_TEX, 1, 2 }, /* rectangle w/ projection */ + + /* texture / sampler but with shadow comparison */ + { "vec4_tex_1d_shadow", IR_TEX_SH, 1, 2 }, + { "vec4_tex_1d_bias_shadow", IR_TEXB_SH, 1, 2 }, + { "vec4_tex_1d_proj_shadow", IR_TEXP_SH, 1, 2 }, + { "vec4_tex_2d_shadow", IR_TEX_SH, 1, 2 }, + { "vec4_tex_2d_bias_shadow", IR_TEXB_SH, 1, 2 }, + { "vec4_tex_2d_proj_shadow", IR_TEXP_SH, 1, 2 }, + { "vec4_tex_rect_shadow", IR_TEX_SH, 1, 2 }, + { "vec4_tex_rect_proj_shadow", IR_TEXP_SH, 1, 2 }, + + /* unary op */ + { "ivec4_to_vec4", IR_I_TO_F, 1, 1 }, /* int[4] to float[4] */ + { "vec4_to_ivec4", IR_F_TO_I, 1, 1 }, /* float[4] to int[4] */ + { "float_exp", IR_EXP, 1, 1 }, + { "float_exp2", IR_EXP2, 1, 1 }, + { "float_log2", IR_LOG2, 1, 1 }, + { "float_rsq", IR_RSQ, 1, 1 }, + { "float_rcp", IR_RCP, 1, 1 }, + { "float_sine", IR_SIN, 1, 1 }, + { "float_cosine", IR_COS, 1, 1 }, + { "float_noise1", IR_NOISE1, 1, 1}, + { "float_noise2", IR_NOISE2, 1, 1}, + { "float_noise3", IR_NOISE3, 1, 1}, + { "float_noise4", IR_NOISE4, 1, 1}, + + { NULL, IR_NOP, 0, 0 } +}; + + +static slang_ir_node * +new_node3(slang_ir_opcode op, + slang_ir_node *c0, slang_ir_node *c1, slang_ir_node *c2) +{ + slang_ir_node *n = (slang_ir_node *) _slang_alloc(sizeof(slang_ir_node)); + if (n) { + n->Opcode = op; + n->Children[0] = c0; + n->Children[1] = c1; + n->Children[2] = c2; + n->InstLocation = -1; + } + return n; +} + +static slang_ir_node * +new_node2(slang_ir_opcode op, slang_ir_node *c0, slang_ir_node *c1) +{ + return new_node3(op, c0, c1, NULL); +} + +static slang_ir_node * +new_node1(slang_ir_opcode op, slang_ir_node *c0) +{ + return new_node3(op, c0, NULL, NULL); +} + +static slang_ir_node * +new_node0(slang_ir_opcode op) +{ + return new_node3(op, NULL, NULL, NULL); +} + + +/** + * Create sequence of two nodes. + */ +static slang_ir_node * +new_seq(slang_ir_node *left, slang_ir_node *right) +{ + if (!left) + return right; + if (!right) + return left; + return new_node2(IR_SEQ, left, right); +} + +static slang_ir_node * +new_label(slang_label *label) +{ + slang_ir_node *n = new_node0(IR_LABEL); + assert(label); + if (n) + n->Label = label; + return n; +} + +static slang_ir_node * +new_float_literal(const float v[4], GLuint size) +{ + slang_ir_node *n = new_node0(IR_FLOAT); + assert(size <= 4); + COPY_4V(n->Value, v); + /* allocate a storage object, but compute actual location (Index) later */ + n->Store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, size); + return n; +} + + +static slang_ir_node * +new_not(slang_ir_node *n) +{ + return new_node1(IR_NOT, n); +} + + +/** + * Non-inlined function call. + */ +static slang_ir_node * +new_function_call(slang_ir_node *code, slang_label *name) +{ + slang_ir_node *n = new_node1(IR_CALL, code); + assert(name); + if (n) + n->Label = name; + return n; +} + + +/** + * Unconditional jump. + */ +static slang_ir_node * +new_return(slang_label *dest) +{ + slang_ir_node *n = new_node0(IR_RETURN); + assert(dest); + if (n) + n->Label = dest; + return n; +} + + +static slang_ir_node * +new_loop(slang_ir_node *body) +{ + return new_node1(IR_LOOP, body); +} + + +static slang_ir_node * +new_break(slang_ir_node *loopNode) +{ + slang_ir_node *n = new_node0(IR_BREAK); + assert(loopNode); + assert(loopNode->Opcode == IR_LOOP); + if (n) { + /* insert this node at head of linked list of cont/break instructions */ + n->List = loopNode->List; + loopNode->List = n; + } + return n; +} + + +/** + * Make new IR_BREAK_IF_TRUE. + */ +static slang_ir_node * +new_break_if_true(slang_assemble_ctx *A, slang_ir_node *cond) +{ + slang_ir_node *loopNode = current_loop_ir(A); + slang_ir_node *n; + assert(loopNode); + assert(loopNode->Opcode == IR_LOOP); + n = new_node1(IR_BREAK_IF_TRUE, cond); + if (n) { + /* insert this node at head of linked list of cont/break instructions */ + n->List = loopNode->List; + loopNode->List = n; + } + return n; +} + + +/** + * Make new IR_CONT_IF_TRUE node. + */ +static slang_ir_node * +new_cont_if_true(slang_assemble_ctx *A, slang_ir_node *cond) +{ + slang_ir_node *loopNode = current_loop_ir(A); + slang_ir_node *n; + assert(loopNode); + assert(loopNode->Opcode == IR_LOOP); + n = new_node1(IR_CONT_IF_TRUE, cond); + if (n) { + n->Parent = loopNode; /* pointer to containing loop */ + /* insert this node at head of linked list of cont/break instructions */ + n->List = loopNode->List; + loopNode->List = n; + } + return n; +} + + +static slang_ir_node * +new_cond(slang_ir_node *n) +{ + slang_ir_node *c = new_node1(IR_COND, n); + return c; +} + + +static slang_ir_node * +new_if(slang_ir_node *cond, slang_ir_node *ifPart, slang_ir_node *elsePart) +{ + return new_node3(IR_IF, cond, ifPart, elsePart); +} + + +/** + * New IR_VAR node - a reference to a previously declared variable. + */ +static slang_ir_node * +new_var(slang_assemble_ctx *A, slang_variable *var) +{ + slang_ir_node *n = new_node0(IR_VAR); + if (n) { + ASSERT(var); + ASSERT(var->store); + ASSERT(!n->Store); + ASSERT(!n->Var); + + /* Set IR node's Var and Store pointers */ + n->Var = var; + n->Store = var->store; + } + return n; +} + + +/** + * Check if the given function is really just a wrapper for a + * basic assembly instruction. + */ +static GLboolean +slang_is_asm_function(const slang_function *fun) +{ + if (fun->body->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE && + fun->body->num_children == 1 && + fun->body->children[0].type == SLANG_OPER_ASM) { + return GL_TRUE; + } + return GL_FALSE; +} + + +static GLboolean +_slang_is_noop(const slang_operation *oper) +{ + if (!oper || + oper->type == SLANG_OPER_VOID || + (oper->num_children == 1 && oper->children[0].type == SLANG_OPER_VOID)) + return GL_TRUE; + else + return GL_FALSE; +} + + +/** + * Recursively search tree for a node of the given type. + */ +#if 0 +static slang_operation * +_slang_find_node_type(slang_operation *oper, slang_operation_type type) +{ + GLuint i; + if (oper->type == type) + return oper; + for (i = 0; i < oper->num_children; i++) { + slang_operation *p = _slang_find_node_type(&oper->children[i], type); + if (p) + return p; + } + return NULL; +} +#endif + + +/** + * Count the number of operations of the given time rooted at 'oper'. + */ +static GLuint +_slang_count_node_type(const slang_operation *oper, slang_operation_type type) +{ + GLuint i, count = 0; + if (oper->type == type) { + return 1; + } + for (i = 0; i < oper->num_children; i++) { + count += _slang_count_node_type(&oper->children[i], type); + } + return count; +} + + +/** + * Check if the 'return' statement found under 'oper' is a "tail return" + * that can be no-op'd. For example: + * + * void func(void) + * { + * .. do something .. + * return; // this is a no-op + * } + * + * This is used when determining if a function can be inlined. If the + * 'return' is not the last statement, we can't inline the function since + * we still need the semantic behaviour of the 'return' but we don't want + * to accidentally return from the _calling_ function. We'd need to use an + * unconditional branch, but we don't have such a GPU instruction (not + * always, at least). + */ +static GLboolean +_slang_is_tail_return(const slang_operation *oper) +{ + GLuint k = oper->num_children; + + while (k > 0) { + const slang_operation *last = &oper->children[k - 1]; + if (last->type == SLANG_OPER_RETURN) + return GL_TRUE; + else if (last->type == SLANG_OPER_IDENTIFIER || + last->type == SLANG_OPER_LABEL) + k--; /* try prev child */ + else if (last->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE || + last->type == SLANG_OPER_BLOCK_NEW_SCOPE) + /* try sub-children */ + return _slang_is_tail_return(last); + else + break; + } + + return GL_FALSE; +} + + +/** + * Generate a variable declaration opeartion. + * I.e.: generate AST code for "bool flag = false;" + */ +static void +slang_generate_declaration(slang_assemble_ctx *A, + slang_variable_scope *scope, + slang_operation *decl, + slang_type_specifier_type type, + const char *name, + GLint initValue) +{ + slang_variable *var; + + assert(type == SLANG_SPEC_BOOL || + type == SLANG_SPEC_INT); + + decl->type = SLANG_OPER_VARIABLE_DECL; + + var = slang_variable_scope_grow(scope); + + slang_fully_specified_type_construct(&var->type); + + var->type.specifier.type = type; + var->a_name = slang_atom_pool_atom(A->atoms, name); + decl->a_id = var->a_name; + var->initializer = slang_operation_new(1); + slang_operation_literal_bool(var->initializer, initValue); +} + + +static void +slang_resolve_variable(slang_operation *oper) +{ + if (oper->type == SLANG_OPER_IDENTIFIER && !oper->var) { + oper->var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); + } +} + + +/** + * Rewrite AST code for "return expression;". + * + * We return values from functions by assinging the returned value to + * the hidden __retVal variable which is an extra 'out' parameter we add + * to the function signature. + * This code basically converts "return expr;" into "__retVal = expr; return;" + * + * \return the new AST code. + */ +static slang_operation * +gen_return_with_expression(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *blockOper, *assignOper; + + assert(oper->type == SLANG_OPER_RETURN); + + if (A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) { + slang_info_log_error(A->log, "illegal return expression"); + return NULL; + } + + blockOper = slang_operation_new(1); + blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; + blockOper->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(blockOper, 2); + + if (A->UseReturnFlag) { + /* Emit: + * { + * if (__notRetFlag) + * __retVal = expr; + * __notRetFlag = 0; + * } + */ + { + slang_operation *ifOper = slang_oper_child(blockOper, 0); + ifOper->type = SLANG_OPER_IF; + slang_operation_add_children(ifOper, 3); + { + slang_operation *cond = slang_oper_child(ifOper, 0); + cond->type = SLANG_OPER_IDENTIFIER; + cond->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); + } + { + slang_operation *elseOper = slang_oper_child(ifOper, 2); + elseOper->type = SLANG_OPER_VOID; + } + assignOper = slang_oper_child(ifOper, 1); + } + { + slang_operation *setOper = slang_oper_child(blockOper, 1); + setOper->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(setOper, 2); + { + slang_operation *lhs = slang_oper_child(setOper, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); + } + { + slang_operation *rhs = slang_oper_child(setOper, 1); + slang_operation_literal_bool(rhs, GL_FALSE); + } + } + } + else { + /* Emit: + * { + * __retVal = expr; + * return_inlined; + * } + */ + assignOper = slang_oper_child(blockOper, 0); + { + slang_operation *returnOper = slang_oper_child(blockOper, 1); + returnOper->type = SLANG_OPER_RETURN_INLINED; + assert(returnOper->num_children == 0); + } + } + + /* __retVal = expression; */ + assignOper->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(assignOper, 2); + { + slang_operation *lhs = slang_oper_child(assignOper, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__retVal"); + } + { + slang_operation *rhs = slang_oper_child(assignOper, 1); + slang_operation_copy(rhs, &oper->children[0]); + } + + ///blockOper->locals->outer_scope = oper->locals->outer_scope; + + /*slang_print_tree(blockOper, 0);*/ + + return blockOper; +} + + +/** + * Rewrite AST code for "return;" (no expression). + */ +static slang_operation * +gen_return_without_expression(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *newRet; + + assert(oper->type == SLANG_OPER_RETURN); + + if (A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) { + slang_info_log_error(A->log, "return statement requires an expression"); + return NULL; + } + + if (A->UseReturnFlag) { + /* Emit: + * __notRetFlag = 0; + */ + { + newRet = slang_operation_new(1); + newRet->locals->outer_scope = oper->locals->outer_scope; + newRet->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(newRet, 2); + { + slang_operation *lhs = slang_oper_child(newRet, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); + } + { + slang_operation *rhs = slang_oper_child(newRet, 1); + slang_operation_literal_bool(rhs, GL_FALSE); + } + } + } + else { + /* Emit: + * return_inlined; + */ + newRet = slang_operation_new(1); + newRet->locals->outer_scope = oper->locals->outer_scope; + newRet->type = SLANG_OPER_RETURN_INLINED; + } + + /*slang_print_tree(newRet, 0);*/ + + return newRet; +} + + + + +/** + * Replace particular variables (SLANG_OPER_IDENTIFIER) with new expressions. + */ +static void +slang_substitute(slang_assemble_ctx *A, slang_operation *oper, + GLuint substCount, slang_variable **substOld, + slang_operation **substNew, GLboolean isLHS) +{ + switch (oper->type) { + case SLANG_OPER_VARIABLE_DECL: + { + slang_variable *v = _slang_variable_locate(oper->locals, + oper->a_id, GL_TRUE); + assert(v); + if (v->initializer && oper->num_children == 0) { + /* set child of oper to copy of initializer */ + oper->num_children = 1; + oper->children = slang_operation_new(1); + slang_operation_copy(&oper->children[0], v->initializer); + } + if (oper->num_children == 1) { + /* the initializer */ + slang_substitute(A, &oper->children[0], substCount, + substOld, substNew, GL_FALSE); + } + } + break; + case SLANG_OPER_IDENTIFIER: + assert(oper->num_children == 0); + if (1/**!isLHS XXX FIX */) { + slang_atom id = oper->a_id; + slang_variable *v; + GLuint i; + v = _slang_variable_locate(oper->locals, id, GL_TRUE); + if (!v) { + if (_mesa_strcmp((char *) oper->a_id, "__notRetFlag")) + _mesa_problem(NULL, "var %s not found!\n", (char *) oper->a_id); + return; + } + + /* look for a substitution */ + for (i = 0; i < substCount; i++) { + if (v == substOld[i]) { + /* OK, replace this SLANG_OPER_IDENTIFIER with a new expr */ +#if 0 /* DEBUG only */ + if (substNew[i]->type == SLANG_OPER_IDENTIFIER) { + assert(substNew[i]->var); + assert(substNew[i]->var->a_name); + printf("Substitute %s with %s in id node %p\n", + (char*)v->a_name, (char*) substNew[i]->var->a_name, + (void*) oper); + } + else { + printf("Substitute %s with %f in id node %p\n", + (char*)v->a_name, substNew[i]->literal[0], + (void*) oper); + } +#endif + slang_operation_copy(oper, substNew[i]); + break; + } + } + } + break; + + case SLANG_OPER_RETURN: + { + slang_operation *newReturn; + /* generate new 'return' code' */ + if (slang_oper_child(oper, 0)->type == SLANG_OPER_VOID) + newReturn = gen_return_without_expression(A, oper); + else + newReturn = gen_return_with_expression(A, oper); + + if (!newReturn) + return; + + /* do substitutions on the new 'return' code */ + slang_substitute(A, newReturn, + substCount, substOld, substNew, GL_FALSE); + + /* install new 'return' code */ + slang_operation_copy(oper, newReturn); + slang_operation_destruct(newReturn); + } + break; + + case SLANG_OPER_ASSIGN: + case SLANG_OPER_SUBSCRIPT: + /* special case: + * child[0] can't have substitutions but child[1] can. + */ + slang_substitute(A, &oper->children[0], + substCount, substOld, substNew, GL_TRUE); + slang_substitute(A, &oper->children[1], + substCount, substOld, substNew, GL_FALSE); + break; + case SLANG_OPER_FIELD: + /* XXX NEW - test */ + slang_substitute(A, &oper->children[0], + substCount, substOld, substNew, GL_TRUE); + break; + default: + { + GLuint i; + for (i = 0; i < oper->num_children; i++) + slang_substitute(A, &oper->children[i], + substCount, substOld, substNew, GL_FALSE); + } + } +} + + +/** + * Produce inline code for a call to an assembly instruction. + * This is typically used to compile a call to a built-in function like this: + * + * vec4 mix(const vec4 x, const vec4 y, const vec4 a) + * { + * __asm vec4_lrp __retVal, a, y, x; + * } + * + * + * A call to + * r = mix(p1, p2, p3); + * + * Becomes: + * + * mov + * / \ + * r vec4_lrp + * / | \ + * p3 p2 p1 + * + * We basically translate a SLANG_OPER_CALL into a SLANG_OPER_ASM. + */ +static slang_operation * +slang_inline_asm_function(slang_assemble_ctx *A, + slang_function *fun, slang_operation *oper) +{ + const GLuint numArgs = oper->num_children; + GLuint i; + slang_operation *inlined; + const GLboolean haveRetValue = _slang_function_has_return_value(fun); + slang_variable **substOld; + slang_operation **substNew; + + ASSERT(slang_is_asm_function(fun)); + ASSERT(fun->param_count == numArgs + haveRetValue); + + /* + printf("Inline %s as %s\n", + (char*) fun->header.a_name, + (char*) fun->body->children[0].a_id); + */ + + /* + * We'll substitute formal params with actual args in the asm call. + */ + substOld = (slang_variable **) + _slang_alloc(numArgs * sizeof(slang_variable *)); + substNew = (slang_operation **) + _slang_alloc(numArgs * sizeof(slang_operation *)); + for (i = 0; i < numArgs; i++) { + substOld[i] = fun->parameters->variables[i]; + substNew[i] = oper->children + i; + } + + /* make a copy of the code to inline */ + inlined = slang_operation_new(1); + slang_operation_copy(inlined, &fun->body->children[0]); + if (haveRetValue) { + /* get rid of the __retVal child */ + inlined->num_children--; + for (i = 0; i < inlined->num_children; i++) { + inlined->children[i] = inlined->children[i + 1]; + } + } + + /* now do formal->actual substitutions */ + slang_substitute(A, inlined, numArgs, substOld, substNew, GL_FALSE); + + _slang_free(substOld); + _slang_free(substNew); + +#if 0 + printf("+++++++++++++ inlined asm function %s +++++++++++++\n", + (char *) fun->header.a_name); + slang_print_tree(inlined, 3); + printf("+++++++++++++++++++++++++++++++++++++++++++++++++++\n"); +#endif + + return inlined; +} + + +/** + * Inline the given function call operation. + * Return a new slang_operation that corresponds to the inlined code. + */ +static slang_operation * +slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun, + slang_operation *oper, slang_operation *returnOper) +{ + typedef enum { + SUBST = 1, + COPY_IN, + COPY_OUT + } ParamMode; + ParamMode *paramMode; + const GLboolean haveRetValue = _slang_function_has_return_value(fun); + const GLuint numArgs = oper->num_children; + const GLuint totalArgs = numArgs + haveRetValue; + slang_operation *args = oper->children; + slang_operation *inlined, *top; + slang_variable **substOld; + slang_operation **substNew; + GLuint substCount, numCopyIn, i; + slang_function *prevFunction; + slang_variable_scope *newScope = NULL; + + /* save / push */ + prevFunction = A->CurFunction; + A->CurFunction = fun; + + /*assert(oper->type == SLANG_OPER_CALL); (or (matrix) multiply, etc) */ + assert(fun->param_count == totalArgs); + + /* allocate temporary arrays */ + paramMode = (ParamMode *) + _slang_alloc(totalArgs * sizeof(ParamMode)); + substOld = (slang_variable **) + _slang_alloc(totalArgs * sizeof(slang_variable *)); + substNew = (slang_operation **) + _slang_alloc(totalArgs * sizeof(slang_operation *)); + +#if 0 + printf("\nInline call to %s (total vars=%d nparams=%d)\n", + (char *) fun->header.a_name, + fun->parameters->num_variables, numArgs); +#endif + + if (haveRetValue && !returnOper) { + /* Create 3-child comma sequence for inlined code: + * child[0]: declare __resultTmp + * child[1]: inlined function body + * child[2]: __resultTmp + */ + slang_operation *commaSeq; + slang_operation *declOper = NULL; + slang_variable *resultVar; + + commaSeq = slang_operation_new(1); + commaSeq->type = SLANG_OPER_SEQUENCE; + assert(commaSeq->locals); + commaSeq->locals->outer_scope = oper->locals->outer_scope; + commaSeq->num_children = 3; + commaSeq->children = slang_operation_new(3); + /* allocate the return var */ + resultVar = slang_variable_scope_grow(commaSeq->locals); + /* + printf("Alloc __resultTmp in scope %p for retval of calling %s\n", + (void*)commaSeq->locals, (char *) fun->header.a_name); + */ + + resultVar->a_name = slang_atom_pool_atom(A->atoms, "__resultTmp"); + resultVar->type = fun->header.type; /* XXX copy? */ + resultVar->isTemp = GL_TRUE; + + /* child[0] = __resultTmp declaration */ + declOper = &commaSeq->children[0]; + declOper->type = SLANG_OPER_VARIABLE_DECL; + declOper->a_id = resultVar->a_name; + declOper->locals->outer_scope = commaSeq->locals; + + /* child[1] = function body */ + inlined = &commaSeq->children[1]; + inlined->locals->outer_scope = commaSeq->locals; + + /* child[2] = __resultTmp reference */ + returnOper = &commaSeq->children[2]; + returnOper->type = SLANG_OPER_IDENTIFIER; + returnOper->a_id = resultVar->a_name; + returnOper->locals->outer_scope = commaSeq->locals; + + top = commaSeq; + } + else { + top = inlined = slang_operation_new(1); + /* XXXX this may be inappropriate!!!! */ + inlined->locals->outer_scope = oper->locals->outer_scope; + } + + + assert(inlined->locals); + + /* Examine the parameters, look for inout/out params, look for possible + * substitutions, etc: + * param type behaviour + * in copy actual to local + * const in substitute param with actual + * out copy out + */ + substCount = 0; + for (i = 0; i < totalArgs; i++) { + slang_variable *p = fun->parameters->variables[i]; + /* + printf("Param %d: %s %s \n", i, + slang_type_qual_string(p->type.qualifier), + (char *) p->a_name); + */ + if (p->type.qualifier == SLANG_QUAL_INOUT || + p->type.qualifier == SLANG_QUAL_OUT) { + /* an output param */ + slang_operation *arg; + if (i < numArgs) + arg = &args[i]; + else + arg = returnOper; + paramMode[i] = SUBST; + + if (arg->type == SLANG_OPER_IDENTIFIER) + slang_resolve_variable(arg); + + /* replace parameter 'p' with argument 'arg' */ + substOld[substCount] = p; + substNew[substCount] = arg; /* will get copied */ + substCount++; + } + else if (p->type.qualifier == SLANG_QUAL_CONST) { + /* a constant input param */ + if (args[i].type == SLANG_OPER_IDENTIFIER || + args[i].type == SLANG_OPER_LITERAL_FLOAT || + args[i].type == SLANG_OPER_SUBSCRIPT) { + /* replace all occurances of this parameter variable with the + * actual argument variable or a literal. + */ + paramMode[i] = SUBST; + slang_resolve_variable(&args[i]); + substOld[substCount] = p; + substNew[substCount] = &args[i]; /* will get copied */ + substCount++; + } + else { + paramMode[i] = COPY_IN; + } + } + else { + paramMode[i] = COPY_IN; + } + assert(paramMode[i]); + } + + /* actual code inlining: */ + slang_operation_copy(inlined, fun->body); + + /*** XXX review this */ + assert(inlined->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE || + inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE); + inlined->type = SLANG_OPER_BLOCK_NEW_SCOPE; + +#if 0 + printf("======================= orig body code ======================\n"); + printf("=== params scope = %p\n", (void*) fun->parameters); + slang_print_tree(fun->body, 8); + printf("======================= copied code =========================\n"); + slang_print_tree(inlined, 8); +#endif + + /* do parameter substitution in inlined code: */ + slang_substitute(A, inlined, substCount, substOld, substNew, GL_FALSE); + +#if 0 + printf("======================= subst code ==========================\n"); + slang_print_tree(inlined, 8); + printf("=============================================================\n"); +#endif + + /* New prolog statements: (inserted before the inlined code) + * Copy the 'in' arguments. + */ + numCopyIn = 0; + for (i = 0; i < numArgs; i++) { + if (paramMode[i] == COPY_IN) { + slang_variable *p = fun->parameters->variables[i]; + /* declare parameter 'p' */ + slang_operation *decl = slang_operation_insert(&inlined->num_children, + &inlined->children, + numCopyIn); + + decl->type = SLANG_OPER_VARIABLE_DECL; + assert(decl->locals); + decl->locals->outer_scope = inlined->locals; + decl->a_id = p->a_name; + decl->num_children = 1; + decl->children = slang_operation_new(1); + + /* child[0] is the var's initializer */ + slang_operation_copy(&decl->children[0], args + i); + + /* add parameter 'p' to the local variable scope here */ + { + slang_variable *pCopy = slang_variable_scope_grow(inlined->locals); + pCopy->type = p->type; + pCopy->a_name = p->a_name; + pCopy->array_len = p->array_len; + } + + newScope = inlined->locals; + numCopyIn++; + } + } + + /* Now add copies of the function's local vars to the new variable scope */ + for (i = totalArgs; i < fun->parameters->num_variables; i++) { + slang_variable *p = fun->parameters->variables[i]; + slang_variable *pCopy = slang_variable_scope_grow(inlined->locals); + pCopy->type = p->type; + pCopy->a_name = p->a_name; + pCopy->array_len = p->array_len; + } + + + /* New epilog statements: + * 1. Create end of function label to jump to from return statements. + * 2. Copy the 'out' parameter vars + */ + { + slang_operation *lab = slang_operation_insert(&inlined->num_children, + &inlined->children, + inlined->num_children); + lab->type = SLANG_OPER_LABEL; + lab->label = A->curFuncEndLabel; + } + + for (i = 0; i < totalArgs; i++) { + if (paramMode[i] == COPY_OUT) { + const slang_variable *p = fun->parameters->variables[i]; + /* actualCallVar = outParam */ + /*if (i > 0 || !haveRetValue)*/ + slang_operation *ass = slang_operation_insert(&inlined->num_children, + &inlined->children, + inlined->num_children); + ass->type = SLANG_OPER_ASSIGN; + ass->num_children = 2; + ass->locals->outer_scope = inlined->locals; + ass->children = slang_operation_new(2); + ass->children[0] = args[i]; /*XXX copy */ + ass->children[1].type = SLANG_OPER_IDENTIFIER; + ass->children[1].a_id = p->a_name; + ass->children[1].locals->outer_scope = ass->locals; + } + } + + _slang_free(paramMode); + _slang_free(substOld); + _slang_free(substNew); + + /* Update scoping to use the new local vars instead of the + * original function's vars. This is especially important + * for nested inlining. + */ + if (newScope) + slang_replace_scope(inlined, fun->parameters, newScope); + +#if 0 + printf("Done Inline call to %s (total vars=%d nparams=%d)\n\n", + (char *) fun->header.a_name, + fun->parameters->num_variables, numArgs); + slang_print_tree(top, 0); +#endif + + /* pop */ + A->CurFunction = prevFunction; + + return top; +} + + +/** + * Insert declaration for "bool __notRetFlag" in given block operation. + * This is used when we can't emit "early" return statements in subroutines. + */ +static void +declare_return_flag(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *decl; + + assert(oper->type == SLANG_OPER_BLOCK_NEW_SCOPE || + oper->type == SLANG_OPER_SEQUENCE); + + decl = slang_operation_insert_child(oper, 1); + + slang_generate_declaration(A, oper->locals, decl, + SLANG_SPEC_BOOL, "__notRetFlag", GL_TRUE); + + /*slang_print_tree(oper, 0);*/ +} + + +/** + * Recursively replace instances of the old node type with the new type. + */ +static void +replace_node_type(slang_operation *oper, slang_operation_type oldType, + slang_operation_type newType) +{ + GLuint i; + + if (oper->type == oldType) + oper->type = newType; + + for (i = 0; i < slang_oper_num_children(oper); i++) { + replace_node_type(slang_oper_child(oper, i), oldType, newType); + } +} + + + +/** + * Test if the given function body has an "early return". That is, there's + * a 'return' statement that's not the very last instruction in the body. + */ +static GLboolean +has_early_return(const slang_operation *funcBody) +{ + GLuint retCount = _slang_count_node_type(funcBody, SLANG_OPER_RETURN); + if (retCount == 0) + return GL_FALSE; + else if (retCount == 1 && _slang_is_tail_return(funcBody)) + return GL_FALSE; + else + return GL_TRUE; +} + + +/** + * Emit IR code for a function call. This does one of two things: + * 1. Inline the function's code + * 2. Create an IR for the function's body and create a real call to it. + */ +static slang_ir_node * +_slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, + slang_operation *oper, slang_operation *dest) +{ + slang_ir_node *n; + slang_operation *instance; + slang_label *prevFuncEndLabel; + char name[200]; + + prevFuncEndLabel = A->curFuncEndLabel; + sprintf(name, "__endOfFunc_%s_", (char *) fun->header.a_name); + A->curFuncEndLabel = _slang_label_new(name); + assert(A->curFuncEndLabel); + + /* + * 'instance' is basically a copy of the function's body with various + * transformations. + */ + + if (slang_is_asm_function(fun) && !dest) { + /* assemble assembly function - tree style */ + instance = slang_inline_asm_function(A, fun, oper); + } + else { + /* non-assembly function */ + /* We always generate an "inline-able" block of code here. + * We may either: + * 1. insert the inline code + * 2. Generate a call to the "inline" code as a subroutine + */ + const GLboolean earlyReturn = has_early_return(fun->body); + + if (earlyReturn && !A->EmitContReturn) { + A->UseReturnFlag = GL_TRUE; + } + + instance = slang_inline_function_call(A, fun, oper, dest); + if (!instance) + return NULL; + + if (earlyReturn) { + /* The function we're calling has one or more 'return' statements + * that prevent us from inlining the function's code. + * + * In this case, change the function's body type from + * SLANG_OPER_BLOCK_NEW_SCOPE to SLANG_OPER_NON_INLINED_CALL. + * During code emit this will result in a true subroutine call. + * + * Also, convert SLANG_OPER_RETURN_INLINED nodes to SLANG_OPER_RETURN. + */ + slang_operation *callOper; + + assert(instance->type == SLANG_OPER_BLOCK_NEW_SCOPE || + instance->type == SLANG_OPER_SEQUENCE); + + if (_slang_function_has_return_value(fun) && !dest) { + assert(instance->children[0].type == SLANG_OPER_VARIABLE_DECL); + assert(instance->children[2].type == SLANG_OPER_IDENTIFIER); + callOper = &instance->children[1]; + } + else { + callOper = instance; + } + + if (A->UseReturnFlag) { + /* Early returns not supported. Create a _returnFlag variable + * that's set upon 'return' and tested elsewhere to no-op any + * remaining instructions in the subroutine. + */ + assert(callOper->type == SLANG_OPER_BLOCK_NEW_SCOPE || + callOper->type == SLANG_OPER_SEQUENCE); + declare_return_flag(A, callOper); + } + else { + /* We can emit real 'return' statements. If we generated any + * 'inline return' statements during function instantiation, + * change them back to regular 'return' statements. + */ + replace_node_type(instance, SLANG_OPER_RETURN_INLINED, + SLANG_OPER_RETURN); + } + + callOper->type = SLANG_OPER_NON_INLINED_CALL; + callOper->fun = fun; + callOper->label = _slang_label_new_unique((char*) fun->header.a_name); + } + else { + /* If there are any 'return' statements remaining, they're at the + * very end of the function and can effectively become no-ops. + */ + replace_node_type(instance, SLANG_OPER_RETURN_INLINED, + SLANG_OPER_VOID); + } + } + + if (!instance) + return NULL; + + /* Replace the function call with the instance block (or new CALL stmt) */ + slang_operation_destruct(oper); + *oper = *instance; + _slang_free(instance); + +#if 0 + assert(instance->locals); + printf("*** Inlined code for call to %s:\n", (char*) fun->header.a_name); + slang_print_tree(oper, 10); + printf("\n"); +#endif + + n = _slang_gen_operation(A, oper); + + /*_slang_label_delete(A->curFuncEndLabel);*/ + A->curFuncEndLabel = prevFuncEndLabel; + + if (A->pragmas->Debug) { + char s[1000]; + _mesa_snprintf(s, sizeof(s), "Call/inline %s()", (char *) fun->header.a_name); + n->Comment = _slang_strdup(s); + } + + A->UseReturnFlag = GL_FALSE; + + return n; +} + + +static slang_asm_info * +slang_find_asm_info(const char *name) +{ + GLuint i; + for (i = 0; AsmInfo[i].Name; i++) { + if (_mesa_strcmp(AsmInfo[i].Name, name) == 0) { + return AsmInfo + i; + } + } + return NULL; +} + + +/** + * Some write-masked assignments are simple, but others are hard. + * Simple example: + * vec3 v; + * v.xy = vec2(a, b); + * Hard example: + * vec3 v; + * v.zy = vec2(a, b); + * this gets transformed/swizzled into: + * v.zy = vec2(a, b).*yx* (* = don't care) + * This function helps to determine simple vs. non-simple. + */ +static GLboolean +_slang_simple_writemask(GLuint writemask, GLuint swizzle) +{ + switch (writemask) { + case WRITEMASK_X: + return GET_SWZ(swizzle, 0) == SWIZZLE_X; + case WRITEMASK_Y: + return GET_SWZ(swizzle, 1) == SWIZZLE_Y; + case WRITEMASK_Z: + return GET_SWZ(swizzle, 2) == SWIZZLE_Z; + case WRITEMASK_W: + return GET_SWZ(swizzle, 3) == SWIZZLE_W; + case WRITEMASK_XY: + return (GET_SWZ(swizzle, 0) == SWIZZLE_X) + && (GET_SWZ(swizzle, 1) == SWIZZLE_Y); + case WRITEMASK_XYZ: + return (GET_SWZ(swizzle, 0) == SWIZZLE_X) + && (GET_SWZ(swizzle, 1) == SWIZZLE_Y) + && (GET_SWZ(swizzle, 2) == SWIZZLE_Z); + case WRITEMASK_XYZW: + return swizzle == SWIZZLE_NOOP; + default: + return GL_FALSE; + } +} + + +/** + * Convert the given swizzle into a writemask. In some cases this + * is trivial, in other cases, we'll need to also swizzle the right + * hand side to put components in the right places. + * See comment above for more info. + * XXX this function could be simplified and should probably be renamed. + * \param swizzle the incoming swizzle + * \param writemaskOut returns the writemask + * \param swizzleOut swizzle to apply to the right-hand-side + * \return GL_FALSE for simple writemasks, GL_TRUE for non-simple + */ +static GLboolean +swizzle_to_writemask(slang_assemble_ctx *A, GLuint swizzle, + GLuint *writemaskOut, GLuint *swizzleOut) +{ + GLuint mask = 0x0, newSwizzle[4]; + GLint i, size; + + /* make new dst writemask, compute size */ + for (i = 0; i < 4; i++) { + const GLuint swz = GET_SWZ(swizzle, i); + if (swz == SWIZZLE_NIL) { + /* end */ + break; + } + assert(swz >= 0 && swz <= 3); + + if (swizzle != SWIZZLE_XXXX && + swizzle != SWIZZLE_YYYY && + swizzle != SWIZZLE_ZZZZ && + swizzle != SWIZZLE_WWWW && + (mask & (1 << swz))) { + /* a channel can't be specified twice (ex: ".xyyz") */ + slang_info_log_error(A->log, "Invalid writemask '%s'", + _mesa_swizzle_string(swizzle, 0, 0)); + return GL_FALSE; + } + + mask |= (1 << swz); + } + assert(mask <= 0xf); + size = i; /* number of components in mask/swizzle */ + + *writemaskOut = mask; + + /* make new src swizzle, by inversion */ + for (i = 0; i < 4; i++) { + newSwizzle[i] = i; /*identity*/ + } + for (i = 0; i < size; i++) { + const GLuint swz = GET_SWZ(swizzle, i); + newSwizzle[swz] = i; + } + *swizzleOut = MAKE_SWIZZLE4(newSwizzle[0], + newSwizzle[1], + newSwizzle[2], + newSwizzle[3]); + + if (_slang_simple_writemask(mask, *swizzleOut)) { + if (size >= 1) + assert(GET_SWZ(*swizzleOut, 0) == SWIZZLE_X); + if (size >= 2) + assert(GET_SWZ(*swizzleOut, 1) == SWIZZLE_Y); + if (size >= 3) + assert(GET_SWZ(*swizzleOut, 2) == SWIZZLE_Z); + if (size >= 4) + assert(GET_SWZ(*swizzleOut, 3) == SWIZZLE_W); + return GL_TRUE; + } + else + return GL_FALSE; +} + + +#if 0 /* not used, but don't remove just yet */ +/** + * Recursively traverse 'oper' to produce a swizzle mask in the event + * of any vector subscripts and swizzle suffixes. + * Ex: for "vec4 v", "v[2].x" resolves to v.z + */ +static GLuint +resolve_swizzle(const slang_operation *oper) +{ + if (oper->type == SLANG_OPER_FIELD) { + /* writemask from .xyzw suffix */ + slang_swizzle swz; + if (_slang_is_swizzle((char*) oper->a_id, 4, &swz)) { + GLuint swizzle = MAKE_SWIZZLE4(swz.swizzle[0], + swz.swizzle[1], + swz.swizzle[2], + swz.swizzle[3]); + GLuint child_swizzle = resolve_swizzle(&oper->children[0]); + GLuint s = _slang_swizzle_swizzle(child_swizzle, swizzle); + return s; + } + else + return SWIZZLE_XYZW; + } + else if (oper->type == SLANG_OPER_SUBSCRIPT && + oper->children[1].type == SLANG_OPER_LITERAL_INT) { + /* writemask from [index] */ + GLuint child_swizzle = resolve_swizzle(&oper->children[0]); + GLuint i = (GLuint) oper->children[1].literal[0]; + GLuint swizzle; + GLuint s; + switch (i) { + case 0: + swizzle = SWIZZLE_XXXX; + break; + case 1: + swizzle = SWIZZLE_YYYY; + break; + case 2: + swizzle = SWIZZLE_ZZZZ; + break; + case 3: + swizzle = SWIZZLE_WWWW; + break; + default: + swizzle = SWIZZLE_XYZW; + } + s = _slang_swizzle_swizzle(child_swizzle, swizzle); + return s; + } + else { + return SWIZZLE_XYZW; + } +} +#endif + + +#if 0 +/** + * Recursively descend through swizzle nodes to find the node's storage info. + */ +static slang_ir_storage * +get_store(const slang_ir_node *n) +{ + if (n->Opcode == IR_SWIZZLE) { + return get_store(n->Children[0]); + } + return n->Store; +} +#endif + + +/** + * Generate IR tree for an asm instruction/operation such as: + * __asm vec4_dot __retVal.x, v1, v2; + */ +static slang_ir_node * +_slang_gen_asm(slang_assemble_ctx *A, slang_operation *oper, + slang_operation *dest) +{ + const slang_asm_info *info; + slang_ir_node *kids[3], *n; + GLuint j, firstOperand; + + assert(oper->type == SLANG_OPER_ASM); + + info = slang_find_asm_info((char *) oper->a_id); + if (!info) { + _mesa_problem(NULL, "undefined __asm function %s\n", + (char *) oper->a_id); + assert(info); + } + assert(info->NumParams <= 3); + + if (info->NumParams == oper->num_children) { + /* Storage for result is not specified. + * Children[0], [1], [2] are the operands. + */ + firstOperand = 0; + } + else { + /* Storage for result (child[0]) is specified. + * Children[1], [2], [3] are the operands. + */ + firstOperand = 1; + } + + /* assemble child(ren) */ + kids[0] = kids[1] = kids[2] = NULL; + for (j = 0; j < info->NumParams; j++) { + kids[j] = _slang_gen_operation(A, &oper->children[firstOperand + j]); + if (!kids[j]) + return NULL; + } + + n = new_node3(info->Opcode, kids[0], kids[1], kids[2]); + + if (firstOperand) { + /* Setup n->Store to be a particular location. Otherwise, storage + * for the result (a temporary) will be allocated later. + */ + slang_operation *dest_oper; + slang_ir_node *n0; + + dest_oper = &oper->children[0]; + + n0 = _slang_gen_operation(A, dest_oper); + if (!n0) + return NULL; + + assert(!n->Store); + n->Store = n0->Store; + + assert(n->Store->File != PROGRAM_UNDEFINED || n->Store->Parent); + + _slang_free(n0); + } + + return n; +} + + +#if 0 +static void +print_funcs(struct slang_function_scope_ *scope, const char *name) +{ + GLuint i; + for (i = 0; i < scope->num_functions; i++) { + slang_function *f = &scope->functions[i]; + if (!name || strcmp(name, (char*) f->header.a_name) == 0) + printf(" %s (%d args)\n", name, f->param_count); + + } + if (scope->outer_scope) + print_funcs(scope->outer_scope, name); +} +#endif + + +/** + * Find a function of the given name, taking 'numArgs' arguments. + * This is the function we'll try to call when there is no exact match + * between function parameters and call arguments. + * + * XXX we should really create a list of candidate functions and try + * all of them... + */ +static slang_function * +_slang_find_function_by_argc(slang_function_scope *scope, + const char *name, int numArgs) +{ + while (scope) { + GLuint i; + for (i = 0; i < scope->num_functions; i++) { + slang_function *f = &scope->functions[i]; + if (strcmp(name, (char*) f->header.a_name) == 0) { + int haveRetValue = _slang_function_has_return_value(f); + if (numArgs == f->param_count - haveRetValue) + return f; + } + } + scope = scope->outer_scope; + } + + return NULL; +} + + +static slang_function * +_slang_find_function_by_max_argc(slang_function_scope *scope, + const char *name) +{ + slang_function *maxFunc = NULL; + GLuint maxArgs = 0; + + while (scope) { + GLuint i; + for (i = 0; i < scope->num_functions; i++) { + slang_function *f = &scope->functions[i]; + if (strcmp(name, (char*) f->header.a_name) == 0) { + if (f->param_count > maxArgs) { + maxArgs = f->param_count; + maxFunc = f; + } + } + } + scope = scope->outer_scope; + } + + return maxFunc; +} + + +/** + * Generate a new slang_function which is a constructor for a user-defined + * struct type. + */ +static slang_function * +_slang_make_struct_constructor(slang_assemble_ctx *A, slang_struct *str) +{ + const GLint numFields = str->fields->num_variables; + slang_function *fun = slang_function_new(SLANG_FUNC_CONSTRUCTOR); + + /* function header (name, return type) */ + fun->header.a_name = str->a_name; + fun->header.type.qualifier = SLANG_QUAL_NONE; + fun->header.type.specifier.type = SLANG_SPEC_STRUCT; + fun->header.type.specifier._struct = str; + + /* function parameters (= struct's fields) */ + { + GLint i; + for (i = 0; i < numFields; i++) { + /* + printf("Field %d: %s\n", i, (char*) str->fields->variables[i]->a_name); + */ + slang_variable *p = slang_variable_scope_grow(fun->parameters); + *p = *str->fields->variables[i]; /* copy the variable and type */ + p->type.qualifier = SLANG_QUAL_CONST; + } + fun->param_count = fun->parameters->num_variables; + } + + /* Add __retVal to params */ + { + slang_variable *p = slang_variable_scope_grow(fun->parameters); + slang_atom a_retVal = slang_atom_pool_atom(A->atoms, "__retVal"); + assert(a_retVal); + p->a_name = a_retVal; + p->type = fun->header.type; + p->type.qualifier = SLANG_QUAL_OUT; + fun->param_count++; + } + + /* function body is: + * block: + * declare T; + * T.f1 = p1; + * T.f2 = p2; + * ... + * T.fn = pn; + * return T; + */ + { + slang_variable_scope *scope; + slang_variable *var; + GLint i; + + fun->body = slang_operation_new(1); + fun->body->type = SLANG_OPER_BLOCK_NEW_SCOPE; + fun->body->num_children = numFields + 2; + fun->body->children = slang_operation_new(numFields + 2); + + scope = fun->body->locals; + scope->outer_scope = fun->parameters; + + /* create local var 't' */ + var = slang_variable_scope_grow(scope); + var->a_name = slang_atom_pool_atom(A->atoms, "t"); + var->type = fun->header.type; + + /* declare t */ + { + slang_operation *decl; + + decl = &fun->body->children[0]; + decl->type = SLANG_OPER_VARIABLE_DECL; + decl->locals = _slang_variable_scope_new(scope); + decl->a_id = var->a_name; + } + + /* assign params to fields of t */ + for (i = 0; i < numFields; i++) { + slang_operation *assign = &fun->body->children[1 + i]; + + assign->type = SLANG_OPER_ASSIGN; + assign->locals = _slang_variable_scope_new(scope); + assign->num_children = 2; + assign->children = slang_operation_new(2); + + { + slang_operation *lhs = &assign->children[0]; + + lhs->type = SLANG_OPER_FIELD; + lhs->locals = _slang_variable_scope_new(scope); + lhs->num_children = 1; + lhs->children = slang_operation_new(1); + lhs->a_id = str->fields->variables[i]->a_name; + + lhs->children[0].type = SLANG_OPER_IDENTIFIER; + lhs->children[0].a_id = var->a_name; + lhs->children[0].locals = _slang_variable_scope_new(scope); + +#if 0 + lhs->children[1].num_children = 1; + lhs->children[1].children = slang_operation_new(1); + lhs->children[1].children[0].type = SLANG_OPER_IDENTIFIER; + lhs->children[1].children[0].a_id = str->fields->variables[i]->a_name; + lhs->children[1].children->locals = _slang_variable_scope_new(scope); +#endif + } + + { + slang_operation *rhs = &assign->children[1]; + + rhs->type = SLANG_OPER_IDENTIFIER; + rhs->locals = _slang_variable_scope_new(scope); + rhs->a_id = str->fields->variables[i]->a_name; + } + } + + /* return t; */ + { + slang_operation *ret = &fun->body->children[numFields + 1]; + + ret->type = SLANG_OPER_RETURN; + ret->locals = _slang_variable_scope_new(scope); + ret->num_children = 1; + ret->children = slang_operation_new(1); + ret->children[0].type = SLANG_OPER_IDENTIFIER; + ret->children[0].a_id = var->a_name; + ret->children[0].locals = _slang_variable_scope_new(scope); + } + } + /* + slang_print_function(fun, 1); + */ + return fun; +} + + +/** + * Find/create a function (constructor) for the given structure name. + */ +static slang_function * +_slang_locate_struct_constructor(slang_assemble_ctx *A, const char *name) +{ + unsigned int i; + for (i = 0; i < A->space.structs->num_structs; i++) { + slang_struct *str = &A->space.structs->structs[i]; + if (strcmp(name, (const char *) str->a_name) == 0) { + /* found a structure type that matches the function name */ + if (!str->constructor) { + /* create the constructor function now */ + str->constructor = _slang_make_struct_constructor(A, str); + } + return str->constructor; + } + } + return NULL; +} + + +/** + * Generate a new slang_function to satisfy a call to an array constructor. + * Ex: float[3](1., 2., 3.) + */ +static slang_function * +_slang_make_array_constructor(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_type_specifier_type baseType; + slang_function *fun; + int num_elements; + + fun = slang_function_new(SLANG_FUNC_CONSTRUCTOR); + if (!fun) + return NULL; + + baseType = slang_type_specifier_type_from_string((char *) oper->a_id); + + num_elements = oper->num_children; + + /* function header, return type */ + { + fun->header.a_name = oper->a_id; + fun->header.type.qualifier = SLANG_QUAL_NONE; + fun->header.type.specifier.type = SLANG_SPEC_ARRAY; + fun->header.type.specifier._array = + slang_type_specifier_new(baseType, NULL, NULL); + fun->header.type.array_len = num_elements; + } + + /* function parameters (= number of elements) */ + { + GLint i; + for (i = 0; i < num_elements; i++) { + /* + printf("Field %d: %s\n", i, (char*) str->fields->variables[i]->a_name); + */ + slang_variable *p = slang_variable_scope_grow(fun->parameters); + char name[10]; + _mesa_snprintf(name, sizeof(name), "p%d", i); + p->a_name = slang_atom_pool_atom(A->atoms, name); + p->type.qualifier = SLANG_QUAL_CONST; + p->type.specifier.type = baseType; + } + fun->param_count = fun->parameters->num_variables; + } + + /* Add __retVal to params */ + { + slang_variable *p = slang_variable_scope_grow(fun->parameters); + slang_atom a_retVal = slang_atom_pool_atom(A->atoms, "__retVal"); + assert(a_retVal); + p->a_name = a_retVal; + p->type = fun->header.type; + p->type.qualifier = SLANG_QUAL_OUT; + p->type.specifier.type = baseType; + fun->param_count++; + } + + /* function body is: + * block: + * declare T; + * T[0] = p0; + * T[1] = p1; + * ... + * T[n] = pn; + * return T; + */ + { + slang_variable_scope *scope; + slang_variable *var; + GLint i; + + fun->body = slang_operation_new(1); + fun->body->type = SLANG_OPER_BLOCK_NEW_SCOPE; + fun->body->num_children = num_elements + 2; + fun->body->children = slang_operation_new(num_elements + 2); + + scope = fun->body->locals; + scope->outer_scope = fun->parameters; + + /* create local var 't' */ + var = slang_variable_scope_grow(scope); + var->a_name = slang_atom_pool_atom(A->atoms, "ttt"); + var->type = fun->header.type;/*XXX copy*/ + + /* declare t */ + { + slang_operation *decl; + + decl = &fun->body->children[0]; + decl->type = SLANG_OPER_VARIABLE_DECL; + decl->locals = _slang_variable_scope_new(scope); + decl->a_id = var->a_name; + } + + /* assign params to elements of t */ + for (i = 0; i < num_elements; i++) { + slang_operation *assign = &fun->body->children[1 + i]; + + assign->type = SLANG_OPER_ASSIGN; + assign->locals = _slang_variable_scope_new(scope); + assign->num_children = 2; + assign->children = slang_operation_new(2); + + { + slang_operation *lhs = &assign->children[0]; + + lhs->type = SLANG_OPER_SUBSCRIPT; + lhs->locals = _slang_variable_scope_new(scope); + lhs->num_children = 2; + lhs->children = slang_operation_new(2); + + lhs->children[0].type = SLANG_OPER_IDENTIFIER; + lhs->children[0].a_id = var->a_name; + lhs->children[0].locals = _slang_variable_scope_new(scope); + + lhs->children[1].type = SLANG_OPER_LITERAL_INT; + lhs->children[1].literal[0] = (GLfloat) i; + } + + { + slang_operation *rhs = &assign->children[1]; + + rhs->type = SLANG_OPER_IDENTIFIER; + rhs->locals = _slang_variable_scope_new(scope); + rhs->a_id = fun->parameters->variables[i]->a_name; + } + } + + /* return t; */ + { + slang_operation *ret = &fun->body->children[num_elements + 1]; + + ret->type = SLANG_OPER_RETURN; + ret->locals = _slang_variable_scope_new(scope); + ret->num_children = 1; + ret->children = slang_operation_new(1); + ret->children[0].type = SLANG_OPER_IDENTIFIER; + ret->children[0].a_id = var->a_name; + ret->children[0].locals = _slang_variable_scope_new(scope); + } + } + + /* + slang_print_function(fun, 1); + */ + + return fun; +} + + +static GLboolean +_slang_is_vec_mat_type(const char *name) +{ + static const char *vecmat_types[] = { + "float", "int", "bool", + "vec2", "vec3", "vec4", + "ivec2", "ivec3", "ivec4", + "bvec2", "bvec3", "bvec4", + "mat2", "mat3", "mat4", + "mat2x3", "mat2x4", "mat3x2", "mat3x4", "mat4x2", "mat4x3", + NULL + }; + int i; + for (i = 0; vecmat_types[i]; i++) + if (_mesa_strcmp(name, vecmat_types[i]) == 0) + return GL_TRUE; + return GL_FALSE; +} + + +/** + * Assemble a function call, given a particular function name. + * \param name the function's name (operators like '*' are possible). + */ +static slang_ir_node * +_slang_gen_function_call_name(slang_assemble_ctx *A, const char *name, + slang_operation *oper, slang_operation *dest) +{ + slang_operation *params = oper->children; + const GLuint param_count = oper->num_children; + slang_atom atom; + slang_function *fun; + slang_ir_node *n; + + atom = slang_atom_pool_atom(A->atoms, name); + if (atom == SLANG_ATOM_NULL) + return NULL; + + if (oper->array_constructor) { + /* this needs special handling */ + fun = _slang_make_array_constructor(A, oper); + } + else { + /* Try to find function by name and exact argument type matching */ + GLboolean error = GL_FALSE; + fun = _slang_function_locate(A->space.funcs, atom, params, param_count, + &A->space, A->atoms, A->log, &error); + if (error) { + slang_info_log_error(A->log, + "Function '%s' not found (check argument types)", + name); + return NULL; + } + } + + if (!fun) { + /* Next, try locating a constructor function for a user-defined type */ + fun = _slang_locate_struct_constructor(A, name); + } + + /* + * At this point, some heuristics are used to try to find a function + * that matches the calling signature by means of casting or "unrolling" + * of constructors. + */ + + if (!fun && _slang_is_vec_mat_type(name)) { + /* Next, if this call looks like a vec() or mat() constructor call, + * try "unwinding" the args to satisfy a constructor. + */ + fun = _slang_find_function_by_max_argc(A->space.funcs, name); + if (fun) { + if (!_slang_adapt_call(oper, fun, &A->space, A->atoms, A->log)) { + slang_info_log_error(A->log, + "Function '%s' not found (check argument types)", + name); + return NULL; + } + } + } + + if (!fun && _slang_is_vec_mat_type(name)) { + /* Next, try casting args to the types of the formal parameters */ + int numArgs = oper->num_children; + fun = _slang_find_function_by_argc(A->space.funcs, name, numArgs); + if (!fun || !_slang_cast_func_params(oper, fun, &A->space, A->atoms, A->log)) { + slang_info_log_error(A->log, + "Function '%s' not found (check argument types)", + name); + return NULL; + } + assert(fun); + } + + if (!fun) { + slang_info_log_error(A->log, + "Function '%s' not found (check argument types)", + name); + return NULL; + } + + if (!fun->body) { + /* The function body may be in another compilation unit. + * We'll try concatenating the shaders and recompile at link time. + */ + A->UnresolvedRefs = GL_TRUE; + return new_node1(IR_NOP, NULL); + } + + /* type checking to be sure function's return type matches 'dest' type */ + if (dest) { + slang_typeinfo t0; + + slang_typeinfo_construct(&t0); + typeof_operation(A, dest, &t0); + + if (!slang_type_specifier_equal(&t0.spec, &fun->header.type.specifier)) { + slang_info_log_error(A->log, + "Incompatible type returned by call to '%s'", + name); + return NULL; + } + } + + n = _slang_gen_function_call(A, fun, oper, dest); + + if (n && !n->Store && !dest + && fun->header.type.specifier.type != SLANG_SPEC_VOID) { + /* setup n->Store for the result of the function call */ + GLint size = _slang_sizeof_type_specifier(&fun->header.type.specifier); + n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, size); + /*printf("Alloc storage for function result, size %d \n", size);*/ + } + + if (oper->array_constructor) { + /* free the temporary array constructor function now */ + slang_function_destruct(fun); + } + + return n; +} + + +static slang_ir_node * +_slang_gen_method_call(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_atom *a_length = slang_atom_pool_atom(A->atoms, "length"); + slang_ir_node *n; + slang_variable *var; + + /* NOTE: In GLSL 1.20, there's only one kind of method + * call: array.length(). Anything else is an error. + */ + if (oper->a_id != a_length) { + slang_info_log_error(A->log, + "Undefined method call '%s'", (char *) oper->a_id); + return NULL; + } + + /* length() takes no arguments */ + if (oper->num_children > 0) { + slang_info_log_error(A->log, "Invalid arguments to length() method"); + return NULL; + } + + /* lookup the object/variable */ + var = _slang_variable_locate(oper->locals, oper->a_obj, GL_TRUE); + if (!var || var->type.specifier.type != SLANG_SPEC_ARRAY) { + slang_info_log_error(A->log, + "Undefined object '%s'", (char *) oper->a_obj); + return NULL; + } + + /* Create a float/literal IR node encoding the array length */ + n = new_node0(IR_FLOAT); + if (n) { + n->Value[0] = (float) _slang_array_length(var); + n->Store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, 1); + } + return n; +} + + +static GLboolean +_slang_is_constant_cond(const slang_operation *oper, GLboolean *value) +{ + if (oper->type == SLANG_OPER_LITERAL_FLOAT || + oper->type == SLANG_OPER_LITERAL_INT || + oper->type == SLANG_OPER_LITERAL_BOOL) { + if (oper->literal[0]) + *value = GL_TRUE; + else + *value = GL_FALSE; + return GL_TRUE; + } + else if (oper->type == SLANG_OPER_EXPRESSION && + oper->num_children == 1) { + return _slang_is_constant_cond(&oper->children[0], value); + } + return GL_FALSE; +} + + +/** + * Test if an operation is a scalar or boolean. + */ +static GLboolean +_slang_is_scalar_or_boolean(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_typeinfo type; + GLint size; + + slang_typeinfo_construct(&type); + typeof_operation(A, oper, &type); + size = _slang_sizeof_type_specifier(&type.spec); + slang_typeinfo_destruct(&type); + return size == 1; +} + + +/** + * Test if an operation is boolean. + */ +static GLboolean +_slang_is_boolean(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_typeinfo type; + GLboolean isBool; + + slang_typeinfo_construct(&type); + typeof_operation(A, oper, &type); + isBool = (type.spec.type == SLANG_SPEC_BOOL); + slang_typeinfo_destruct(&type); + return isBool; +} + + +/** + * Check if a loop contains a 'continue' statement. + * Stop looking if we find a nested loop. + */ +static GLboolean +_slang_loop_contains_continue(const slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_CONTINUE: + return GL_TRUE; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + return GL_FALSE; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + const slang_operation *child = slang_oper_child_const(oper, i); + if (_slang_loop_contains_continue(child)) + return GL_TRUE; + } + } + return GL_FALSE; + } +} + + +/** + * Check if a loop contains a 'continue' or 'break' statement. + * Stop looking if we find a nested loop. + */ +static GLboolean +_slang_loop_contains_continue_or_break(const slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_CONTINUE: + case SLANG_OPER_BREAK: + return GL_TRUE; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + return GL_FALSE; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + const slang_operation *child = slang_oper_child_const(oper, i); + if (_slang_loop_contains_continue_or_break(child)) + return GL_TRUE; + } + } + return GL_FALSE; + } +} + + +/** + * Replace 'break' and 'continue' statements inside a do and while loops. + * This is a recursive helper function used by + * _slang_gen_do/while_without_continue(). + */ +static void +replace_break_and_cont(slang_assemble_ctx *A, slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_BREAK: + /* replace 'break' with "_notBreakFlag = false; break" */ + { + slang_operation *block = oper; + block->type = SLANG_OPER_BLOCK_NEW_SCOPE; + slang_operation_add_children(block, 2); + { + slang_operation *assign = slang_oper_child(block, 0); + assign->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(assign, 2); + { + slang_operation *lhs = slang_oper_child(assign, 0); + slang_operation_identifier(lhs, A, "_notBreakFlag"); + } + { + slang_operation *rhs = slang_oper_child(assign, 1); + slang_operation_literal_bool(rhs, GL_FALSE); + } + } + { + slang_operation *brk = slang_oper_child(block, 1); + brk->type = SLANG_OPER_BREAK; + assert(!brk->children); + } + } + break; + case SLANG_OPER_CONTINUE: + /* convert continue into a break */ + oper->type = SLANG_OPER_BREAK; + break; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + break; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + replace_break_and_cont(A, slang_oper_child(oper, i)); + } + } + } +} + + +/** + * Transform a while-loop so that continue statements are converted to breaks. + * Then do normal IR code generation. + * + * Before: + * + * while (LOOPCOND) { + * A; + * if (IFCOND) + * continue; + * B; + * break; + * C; + * } + * + * After: + * + * { + * bool _notBreakFlag = 1; + * while (_notBreakFlag && LOOPCOND) { + * do { + * A; + * if (IFCOND) { + * break; // was continue + * } + * B; + * _notBreakFlag = 0; // was + * break; // break + * C; + * } while (0) + * } + * } + */ +static slang_ir_node * +_slang_gen_while_without_continue(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *top; + slang_operation *innerBody; + + assert(oper->type == SLANG_OPER_WHILE); + + top = slang_operation_new(1); + top->type = SLANG_OPER_BLOCK_NEW_SCOPE; + top->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(top, 2); + + /* declare: bool _notBreakFlag = true */ + { + slang_operation *condDecl = slang_oper_child(top, 0); + slang_generate_declaration(A, top->locals, condDecl, + SLANG_SPEC_BOOL, "_notBreakFlag", GL_TRUE); + } + + /* build outer while-loop: while (_notBreakFlag && LOOPCOND) { ... } */ + { + slang_operation *outerWhile = slang_oper_child(top, 1); + outerWhile->type = SLANG_OPER_WHILE; + slang_operation_add_children(outerWhile, 2); + + /* _notBreakFlag && LOOPCOND */ + { + slang_operation *cond = slang_oper_child(outerWhile, 0); + cond->type = SLANG_OPER_LOGICALAND; + slang_operation_add_children(cond, 2); + { + slang_operation *notBreak = slang_oper_child(cond, 0); + slang_operation_identifier(notBreak, A, "_notBreakFlag"); + } + { + slang_operation *origCond = slang_oper_child(cond, 1); + slang_operation_copy(origCond, slang_oper_child(oper, 0)); + } + } + + /* inner loop */ + { + slang_operation *innerDo = slang_oper_child(outerWhile, 1); + innerDo->type = SLANG_OPER_DO; + slang_operation_add_children(innerDo, 2); + + /* copy original do-loop body into inner do-loop's body */ + innerBody = slang_oper_child(innerDo, 0); + slang_operation_copy(innerBody, slang_oper_child(oper, 1)); + innerBody->locals->outer_scope = innerDo->locals; + + /* inner do-loop's condition is constant/false */ + { + slang_operation *constFalse = slang_oper_child(innerDo, 1); + slang_operation_literal_bool(constFalse, GL_FALSE); + } + } + } + + /* Finally, in innerBody, + * replace "break" with "_notBreakFlag = 0; break" + * replace "continue" with "break" + */ + replace_break_and_cont(A, innerBody); + + /*slang_print_tree(top, 0);*/ + + return _slang_gen_operation(A, top); + + return NULL; +} + + +/** + * Generate loop code using high-level IR_LOOP instruction + */ +static slang_ir_node * +_slang_gen_while(slang_assemble_ctx * A, slang_operation *oper) +{ + /* + * LOOP: + * BREAK if !expr (child[0]) + * body code (child[1]) + */ + slang_ir_node *loop, *breakIf, *body; + GLboolean isConst, constTrue = GL_FALSE; + + if (!A->EmitContReturn) { + /* We don't want to emit CONT instructions. If this while-loop has + * a continue, translate it away. + */ + if (_slang_loop_contains_continue(slang_oper_child(oper, 1))) { + return _slang_gen_while_without_continue(A, oper); + } + } + + /* type-check expression */ + if (!_slang_is_boolean(A, &oper->children[0])) { + slang_info_log_error(A->log, "scalar/boolean expression expected for 'while'"); + return NULL; + } + + /* Check if loop condition is a constant */ + isConst = _slang_is_constant_cond(&oper->children[0], &constTrue); + + if (isConst && !constTrue) { + /* loop is never executed! */ + return new_node0(IR_NOP); + } + + /* Begin new loop */ + loop = new_loop(NULL); + + /* save loop state */ + push_loop(A, oper, loop); + + if (isConst && constTrue) { + /* while(nonzero constant), no conditional break */ + breakIf = NULL; + } + else { + slang_ir_node *cond + = new_cond(new_not(_slang_gen_operation(A, &oper->children[0]))); + breakIf = new_break_if_true(A, cond); + } + body = _slang_gen_operation(A, &oper->children[1]); + loop->Children[0] = new_seq(breakIf, body); + + /* Do infinite loop detection */ + /* loop->List is head of linked list of break/continue nodes */ + if (!loop->List && isConst && constTrue) { + /* infinite loop detected */ + pop_loop(A); + slang_info_log_error(A->log, "Infinite loop detected!"); + return NULL; + } + + /* restore loop state */ + pop_loop(A); + + return loop; +} + + +/** + * Transform a do-while-loop so that continue statements are converted to breaks. + * Then do normal IR code generation. + * + * Before: + * + * do { + * A; + * if (IFCOND) + * continue; + * B; + * break; + * C; + * } while (LOOPCOND); + * + * After: + * + * { + * bool _notBreakFlag = 1; + * do { + * do { + * A; + * if (IFCOND) { + * break; // was continue + * } + * B; + * _notBreakFlag = 0; // was + * break; // break + * C; + * } while (0) + * } while (_notBreakFlag && LOOPCOND); + * } + */ +static slang_ir_node * +_slang_gen_do_without_continue(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *top; + slang_operation *innerBody; + + assert(oper->type == SLANG_OPER_DO); + + top = slang_operation_new(1); + top->type = SLANG_OPER_BLOCK_NEW_SCOPE; + top->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(top, 2); + + /* declare: bool _notBreakFlag = true */ + { + slang_operation *condDecl = slang_oper_child(top, 0); + slang_generate_declaration(A, top->locals, condDecl, + SLANG_SPEC_BOOL, "_notBreakFlag", GL_TRUE); + } + + /* build outer do-loop: do { ... } while (_notBreakFlag && LOOPCOND) */ + { + slang_operation *outerDo = slang_oper_child(top, 1); + outerDo->type = SLANG_OPER_DO; + slang_operation_add_children(outerDo, 2); + + /* inner do-loop */ + { + slang_operation *innerDo = slang_oper_child(outerDo, 0); + innerDo->type = SLANG_OPER_DO; + slang_operation_add_children(innerDo, 2); + + /* copy original do-loop body into inner do-loop's body */ + innerBody = slang_oper_child(innerDo, 0); + slang_operation_copy(innerBody, slang_oper_child(oper, 0)); + innerBody->locals->outer_scope = innerDo->locals; + + /* inner do-loop's condition is constant/false */ + { + slang_operation *constFalse = slang_oper_child(innerDo, 1); + slang_operation_literal_bool(constFalse, GL_FALSE); + } + } + + /* _notBreakFlag && LOOPCOND */ + { + slang_operation *cond = slang_oper_child(outerDo, 1); + cond->type = SLANG_OPER_LOGICALAND; + slang_operation_add_children(cond, 2); + { + slang_operation *notBreak = slang_oper_child(cond, 0); + slang_operation_identifier(notBreak, A, "_notBreakFlag"); + } + { + slang_operation *origCond = slang_oper_child(cond, 1); + slang_operation_copy(origCond, slang_oper_child(oper, 1)); + } + } + } + + /* Finally, in innerBody, + * replace "break" with "_notBreakFlag = 0; break" + * replace "continue" with "break" + */ + replace_break_and_cont(A, innerBody); + + /*slang_print_tree(top, 0);*/ + + return _slang_gen_operation(A, top); +} + + +/** + * Generate IR tree for a do-while loop using high-level LOOP, IF instructions. + */ +static slang_ir_node * +_slang_gen_do(slang_assemble_ctx * A, slang_operation *oper) +{ + /* + * LOOP: + * body code (child[0]) + * tail code: + * BREAK if !expr (child[1]) + */ + slang_ir_node *loop; + GLboolean isConst, constTrue; + + if (!A->EmitContReturn) { + /* We don't want to emit CONT instructions. If this do-loop has + * a continue, translate it away. + */ + if (_slang_loop_contains_continue(slang_oper_child(oper, 0))) { + return _slang_gen_do_without_continue(A, oper); + } + } + + /* type-check expression */ + if (!_slang_is_boolean(A, &oper->children[1])) { + slang_info_log_error(A->log, "scalar/boolean expression expected for 'do/while'"); + return NULL; + } + + loop = new_loop(NULL); + + /* save loop state */ + push_loop(A, oper, loop); + + /* loop body: */ + loop->Children[0] = _slang_gen_operation(A, &oper->children[0]); + + /* Check if loop condition is a constant */ + isConst = _slang_is_constant_cond(&oper->children[1], &constTrue); + if (isConst && constTrue) { + /* do { } while(1) ==> no conditional break */ + loop->Children[1] = NULL; /* no tail code */ + } + else { + slang_ir_node *cond + = new_cond(new_not(_slang_gen_operation(A, &oper->children[1]))); + loop->Children[1] = new_break_if_true(A, cond); + } + + /* XXX we should do infinite loop detection, as above */ + + /* restore loop state */ + pop_loop(A); + + return loop; +} + + +/** + * Recursively count the number of operations rooted at 'oper'. + * This gives some kind of indication of the size/complexity of an operation. + */ +static GLuint +sizeof_operation(const slang_operation *oper) +{ + if (oper) { + GLuint count = 1; /* me */ + GLuint i; + for (i = 0; i < oper->num_children; i++) { + count += sizeof_operation(&oper->children[i]); + } + return count; + } + else { + return 0; + } +} + + +/** + * Determine if a for-loop can be unrolled. + * At this time, only a rather narrow class of for loops can be unrolled. + * See code for details. + * When a loop can't be unrolled because it's too large we'll emit a + * message to the log. + */ +static GLboolean +_slang_can_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) +{ + GLuint bodySize; + GLint start, end; + const char *varName; + slang_atom varId; + + if (oper->type != SLANG_OPER_FOR) + return GL_FALSE; + + assert(oper->num_children == 4); + + if (_slang_loop_contains_continue_or_break(slang_oper_child_const(oper, 3))) + return GL_FALSE; + + /* children[0] must be either "int i=constant" or "i=constant" */ + if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) { + slang_variable *var; + + if (oper->children[0].children[0].type != SLANG_OPER_VARIABLE_DECL) + return GL_FALSE; + + varId = oper->children[0].children[0].a_id; + + var = _slang_variable_locate(oper->children[0].children[0].locals, + varId, GL_TRUE); + if (!var) + return GL_FALSE; + if (!var->initializer) + return GL_FALSE; + if (var->initializer->type != SLANG_OPER_LITERAL_INT) + return GL_FALSE; + start = (GLint) var->initializer->literal[0]; + } + else if (oper->children[0].type == SLANG_OPER_EXPRESSION) { + if (oper->children[0].children[0].type != SLANG_OPER_ASSIGN) + return GL_FALSE; + if (oper->children[0].children[0].children[0].type != SLANG_OPER_IDENTIFIER) + return GL_FALSE; + if (oper->children[0].children[0].children[1].type != SLANG_OPER_LITERAL_INT) + return GL_FALSE; + + varId = oper->children[0].children[0].children[0].a_id; + + start = (GLint) oper->children[0].children[0].children[1].literal[0]; + } + else { + return GL_FALSE; + } + + /* children[1] must be "i<constant" */ + if (oper->children[1].type != SLANG_OPER_EXPRESSION) + return GL_FALSE; + if (oper->children[1].children[0].type != SLANG_OPER_LESS) + return GL_FALSE; + if (oper->children[1].children[0].children[0].type != SLANG_OPER_IDENTIFIER) + return GL_FALSE; + if (oper->children[1].children[0].children[1].type != SLANG_OPER_LITERAL_INT) + return GL_FALSE; + + end = (GLint) oper->children[1].children[0].children[1].literal[0]; + + /* children[2] must be "i++" or "++i" */ + if (oper->children[2].type != SLANG_OPER_POSTINCREMENT && + oper->children[2].type != SLANG_OPER_PREINCREMENT) + return GL_FALSE; + if (oper->children[2].children[0].type != SLANG_OPER_IDENTIFIER) + return GL_FALSE; + + /* make sure the same variable name is used in all places */ + if ((oper->children[1].children[0].children[0].a_id != varId) || + (oper->children[2].children[0].a_id != varId)) + return GL_FALSE; + + varName = (const char *) varId; + + /* children[3], the loop body, can't be too large */ + bodySize = sizeof_operation(&oper->children[3]); + if (bodySize > MAX_FOR_LOOP_UNROLL_BODY_SIZE) { + slang_info_log_print(A->log, + "Note: 'for (%s ... )' body is too large/complex" + " to unroll", + varName); + return GL_FALSE; + } + + if (start >= end) + return GL_FALSE; /* degenerate case */ + + if (end - start > MAX_FOR_LOOP_UNROLL_ITERATIONS) { + slang_info_log_print(A->log, + "Note: 'for (%s=%d; %s<%d; ++%s)' is too" + " many iterations to unroll", + varName, start, varName, end, varName); + return GL_FALSE; + } + + if ((end - start) * bodySize > MAX_FOR_LOOP_UNROLL_COMPLEXITY) { + slang_info_log_print(A->log, + "Note: 'for (%s=%d; %s<%d; ++%s)' will generate" + " too much code to unroll", + varName, start, varName, end, varName); + return GL_FALSE; + } + + return GL_TRUE; /* we can unroll the loop */ +} + + +/** + * Unroll a for-loop. + * First we determine the number of iterations to unroll. + * Then for each iteration: + * make a copy of the loop body + * replace instances of the loop variable with the current iteration value + * generate IR code for the body + * \return pointer to generated IR code or NULL if error, out of memory, etc. + */ +static slang_ir_node * +_slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) +{ + GLint start, end, iter; + slang_ir_node *n, *root = NULL; + slang_atom varId; + + if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) { + /* for (int i=0; ... */ + slang_variable *var; + + varId = oper->children[0].children[0].a_id; + var = _slang_variable_locate(oper->children[0].children[0].locals, + varId, GL_TRUE); + start = (GLint) var->initializer->literal[0]; + } + else { + /* for (i=0; ... */ + varId = oper->children[0].children[0].children[0].a_id; + start = (GLint) oper->children[0].children[0].children[1].literal[0]; + } + + end = (GLint) oper->children[1].children[0].children[1].literal[0]; + + for (iter = start; iter < end; iter++) { + slang_operation *body; + + /* make a copy of the loop body */ + body = slang_operation_new(1); + if (!body) + return NULL; + + if (!slang_operation_copy(body, &oper->children[3])) + return NULL; + + /* in body, replace instances of 'varId' with literal 'iter' */ + { + slang_variable *oldVar; + slang_operation *newOper; + + oldVar = _slang_variable_locate(oper->locals, varId, GL_TRUE); + if (!oldVar) { + /* undeclared loop variable */ + slang_operation_delete(body); + return NULL; + } + + newOper = slang_operation_new(1); + newOper->type = SLANG_OPER_LITERAL_INT; + newOper->literal_size = 1; + newOper->literal[0] = iter; + + /* replace instances of the loop variable with newOper */ + slang_substitute(A, body, 1, &oldVar, &newOper, GL_FALSE); + } + + /* do IR codegen for body */ + n = _slang_gen_operation(A, body); + if (!n) + return NULL; + + root = new_seq(root, n); + + slang_operation_delete(body); + } + + return root; +} + + +/** + * Replace 'continue' statement with 'break' inside a for-loop. + * This is a recursive helper function used by _slang_gen_for_without_continue(). + */ +static void +replace_continue_with_break(slang_assemble_ctx *A, slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_CONTINUE: + oper->type = SLANG_OPER_BREAK; + break; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + break; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + replace_continue_with_break(A, slang_oper_child(oper, i)); + } + } + } +} + + +/** + * Transform a for-loop so that continue statements are converted to breaks. + * Then do normal IR code generation. + * + * Before: + * + * for (INIT; LOOPCOND; INCR) { + * A; + * if (IFCOND) { + * continue; + * } + * B; + * } + * + * After: + * + * { + * bool _condFlag = 1; + * for (INIT; _condFlag; ) { + * for ( ; _condFlag = LOOPCOND; INCR) { + * A; + * if (IFCOND) { + * break; + * } + * B; + * } + * if (_condFlag) + * INCR; + * } + * } + */ +static slang_ir_node * +_slang_gen_for_without_continue(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *top; + slang_operation *outerFor, *innerFor, *init, *cond, *incr; + slang_operation *lhs, *rhs; + + assert(oper->type == SLANG_OPER_FOR); + + top = slang_operation_new(1); + top->type = SLANG_OPER_BLOCK_NEW_SCOPE; + top->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(top, 2); + + /* declare: bool _condFlag = true */ + { + slang_operation *condDecl = slang_oper_child(top, 0); + slang_generate_declaration(A, top->locals, condDecl, + SLANG_SPEC_BOOL, "_condFlag", GL_TRUE); + } + + /* build outer loop: for (INIT; _condFlag; ) { */ + outerFor = slang_oper_child(top, 1); + outerFor->type = SLANG_OPER_FOR; + slang_operation_add_children(outerFor, 4); + + init = slang_oper_child(outerFor, 0); + slang_operation_copy(init, slang_oper_child(oper, 0)); + + cond = slang_oper_child(outerFor, 1); + cond->type = SLANG_OPER_IDENTIFIER; + cond->a_id = slang_atom_pool_atom(A->atoms, "_condFlag"); + + incr = slang_oper_child(outerFor, 2); + incr->type = SLANG_OPER_VOID; + + /* body of the outer loop */ + { + slang_operation *block = slang_oper_child(outerFor, 3); + + slang_operation_add_children(block, 2); + block->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; + + /* build inner loop: for ( ; _condFlag = LOOPCOND; INCR) { */ + { + innerFor = slang_oper_child(block, 0); + + /* make copy of orig loop */ + slang_operation_copy(innerFor, oper); + assert(innerFor->type == SLANG_OPER_FOR); + innerFor->locals->outer_scope = block->locals; + + init = slang_oper_child(innerFor, 0); + init->type = SLANG_OPER_VOID; /* leak? */ + + cond = slang_oper_child(innerFor, 1); + slang_operation_destruct(cond); + cond->type = SLANG_OPER_ASSIGN; + cond->locals = _slang_variable_scope_new(innerFor->locals); + slang_operation_add_children(cond, 2); + + lhs = slang_oper_child(cond, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "_condFlag"); + + rhs = slang_oper_child(cond, 1); + slang_operation_copy(rhs, slang_oper_child(oper, 1)); + } + + /* if (_condFlag) INCR; */ + { + slang_operation *ifop = slang_oper_child(block, 1); + ifop->type = SLANG_OPER_IF; + slang_operation_add_children(ifop, 2); + + /* re-use cond node build above */ + slang_operation_copy(slang_oper_child(ifop, 0), cond); + + /* incr node from original for-loop operation */ + slang_operation_copy(slang_oper_child(ifop, 1), + slang_oper_child(oper, 2)); + } + + /* finally, replace "continue" with "break" in the inner for-loop */ + replace_continue_with_break(A, slang_oper_child(innerFor, 3)); + } + + return _slang_gen_operation(A, top); +} + + + +/** + * Generate IR for a for-loop. Unrolling will be done when possible. + */ +static slang_ir_node * +_slang_gen_for(slang_assemble_ctx * A, slang_operation *oper) +{ + GLboolean unroll; + + if (!A->EmitContReturn) { + /* We don't want to emit CONT instructions. If this for-loop has + * a continue, translate it away. + */ + if (_slang_loop_contains_continue(slang_oper_child(oper, 3))) { + return _slang_gen_for_without_continue(A, oper); + } + } + + unroll = _slang_can_unroll_for_loop(A, oper); + if (unroll) { + slang_ir_node *code = _slang_unroll_for_loop(A, oper); + if (code) + return code; + } + + assert(oper->type == SLANG_OPER_FOR); + + /* conventional for-loop code generation */ + { + /* + * init code (child[0]) + * LOOP: + * BREAK if !expr (child[1]) + * body code (child[3]) + * tail code: + * incr code (child[2]) // XXX continue here + */ + slang_ir_node *loop, *cond, *breakIf, *body, *init, *incr; + init = _slang_gen_operation(A, &oper->children[0]); + loop = new_loop(NULL); + + /* save loop state */ + push_loop(A, oper, loop); + + cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[1]))); + breakIf = new_break_if_true(A, cond); + body = _slang_gen_operation(A, &oper->children[3]); + incr = _slang_gen_operation(A, &oper->children[2]); + + loop->Children[0] = new_seq(breakIf, body); + loop->Children[1] = incr; /* tail code */ + + /* restore loop state */ + pop_loop(A); + + return new_seq(init, loop); + } +} + + +static slang_ir_node * +_slang_gen_continue(slang_assemble_ctx * A, const slang_operation *oper) +{ + slang_ir_node *n, *cont, *incr = NULL, *loopNode; + + assert(oper->type == SLANG_OPER_CONTINUE); + loopNode = current_loop_ir(A); + assert(loopNode); + assert(loopNode->Opcode == IR_LOOP); + + cont = new_node0(IR_CONT); + if (cont) { + cont->Parent = loopNode; + /* insert this node at head of linked list of cont/break instructions */ + cont->List = loopNode->List; + loopNode->List = cont; + } + + n = new_seq(incr, cont); + return n; +} + + +/** + * Determine if the given operation is of a specific type. + */ +static GLboolean +is_operation_type(const slang_operation *oper, slang_operation_type type) +{ + if (oper->type == type) + return GL_TRUE; + else if ((oper->type == SLANG_OPER_BLOCK_NEW_SCOPE || + oper->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) && + oper->num_children == 1) + return is_operation_type(&oper->children[0], type); + else + return GL_FALSE; +} + + +/** + * Generate IR tree for an if/then/else conditional using high-level + * IR_IF instruction. + */ +static slang_ir_node * +_slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper) +{ + /* + * eval expr (child[0]) + * IF expr THEN + * if-body code + * ELSE + * else-body code + * ENDIF + */ + const GLboolean haveElseClause = !_slang_is_noop(&oper->children[2]); + slang_ir_node *ifNode, *cond, *ifBody, *elseBody; + GLboolean isConst, constTrue; + + /* type-check expression */ + if (!_slang_is_boolean(A, &oper->children[0])) { + slang_info_log_error(A->log, "boolean expression expected for 'if'"); + return NULL; + } + + if (!_slang_is_scalar_or_boolean(A, &oper->children[0])) { + slang_info_log_error(A->log, "scalar/boolean expression expected for 'if'"); + return NULL; + } + + isConst = _slang_is_constant_cond(&oper->children[0], &constTrue); + if (isConst) { + if (constTrue) { + /* if (true) ... */ + return _slang_gen_operation(A, &oper->children[1]); + } + else { + /* if (false) ... */ + return _slang_gen_operation(A, &oper->children[2]); + } + } + + cond = _slang_gen_operation(A, &oper->children[0]); + cond = new_cond(cond); + + if (is_operation_type(&oper->children[1], SLANG_OPER_BREAK) + && !haveElseClause) { + /* Special case: generate a conditional break */ + ifBody = new_break_if_true(A, cond); + return ifBody; + } + else if (is_operation_type(&oper->children[1], SLANG_OPER_CONTINUE) + && !haveElseClause + && current_loop_oper(A) + && current_loop_oper(A)->type != SLANG_OPER_FOR) { + /* Special case: generate a conditional continue */ + ifBody = new_cont_if_true(A, cond); + return ifBody; + } + else { + /* general case */ + ifBody = _slang_gen_operation(A, &oper->children[1]); + if (haveElseClause) + elseBody = _slang_gen_operation(A, &oper->children[2]); + else + elseBody = NULL; + ifNode = new_if(cond, ifBody, elseBody); + return ifNode; + } +} + + + +static slang_ir_node * +_slang_gen_not(slang_assemble_ctx * A, const slang_operation *oper) +{ + slang_ir_node *n; + + assert(oper->type == SLANG_OPER_NOT); + + /* type-check expression */ + if (!_slang_is_scalar_or_boolean(A, &oper->children[0])) { + slang_info_log_error(A->log, + "scalar/boolean expression expected for '!'"); + return NULL; + } + + n = _slang_gen_operation(A, &oper->children[0]); + if (n) + return new_not(n); + else + return NULL; +} + + +static slang_ir_node * +_slang_gen_xor(slang_assemble_ctx * A, const slang_operation *oper) +{ + slang_ir_node *n1, *n2; + + assert(oper->type == SLANG_OPER_LOGICALXOR); + + if (!_slang_is_scalar_or_boolean(A, &oper->children[0]) || + !_slang_is_scalar_or_boolean(A, &oper->children[0])) { + slang_info_log_error(A->log, + "scalar/boolean expressions expected for '^^'"); + return NULL; + } + + n1 = _slang_gen_operation(A, &oper->children[0]); + if (!n1) + return NULL; + n2 = _slang_gen_operation(A, &oper->children[1]); + if (!n2) + return NULL; + return new_node2(IR_NOTEQUAL, n1, n2); +} + + +/** + * Generate IR node for storage of a temporary of given size. + */ +static slang_ir_node * +_slang_gen_temporary(GLint size) +{ + slang_ir_storage *store; + slang_ir_node *n = NULL; + + store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -2, size); + if (store) { + n = new_node0(IR_VAR_DECL); + if (n) { + n->Store = store; + } + else { + _slang_free(store); + } + } + return n; +} + + +/** + * Generate program constants for an array. + * Ex: const vec2[3] v = vec2[3](vec2(1,1), vec2(2,2), vec2(3,3)); + * This will allocate and initialize three vector constants, storing + * the array in constant memory, not temporaries like a non-const array. + * This can also be used for uniform array initializers. + * \return GL_TRUE for success, GL_FALSE if failure (semantic error, etc). + */ +static GLboolean +make_constant_array(slang_assemble_ctx *A, + slang_variable *var, + slang_operation *initializer) +{ + struct gl_program *prog = A->program; + const GLenum datatype = _slang_gltype_from_specifier(&var->type.specifier); + const char *varName = (char *) var->a_name; + const GLuint numElements = initializer->num_children; + GLint size; + GLuint i, j; + GLfloat *values; + + if (!var->store) { + var->store = _slang_new_ir_storage(PROGRAM_UNDEFINED, -6, -6); + } + size = var->store->Size; + + assert(var->type.qualifier == SLANG_QUAL_CONST || + var->type.qualifier == SLANG_QUAL_UNIFORM); + assert(initializer->type == SLANG_OPER_CALL); + assert(initializer->array_constructor); + + values = (GLfloat *) _mesa_malloc(numElements * 4 * sizeof(GLfloat)); + + /* convert constructor params into ordinary floats */ + for (i = 0; i < numElements; i++) { + const slang_operation *op = &initializer->children[i]; + if (op->type != SLANG_OPER_LITERAL_FLOAT) { + /* unsupported type for this optimization */ + free(values); + return GL_FALSE; + } + for (j = 0; j < op->literal_size; j++) { + values[i * 4 + j] = op->literal[j]; + } + for ( ; j < 4; j++) { + values[i * 4 + j] = 0.0f; + } + } + + /* slightly different paths for constants vs. uniforms */ + if (var->type.qualifier == SLANG_QUAL_UNIFORM) { + var->store->File = PROGRAM_UNIFORM; + var->store->Index = _mesa_add_uniform(prog->Parameters, varName, + size, datatype, values); + } + else { + var->store->File = PROGRAM_CONSTANT; + var->store->Index = _mesa_add_named_constant(prog->Parameters, varName, + values, size); + } + assert(var->store->Size == size); + + _mesa_free(values); + + return GL_TRUE; +} + + + +/** + * Generate IR node for allocating/declaring a variable (either a local or + * a global). + * Generally, this involves allocating an slang_ir_storage instance for the + * variable, choosing a register file (temporary, constant, etc). + * For ordinary variables we do not yet allocate storage though. We do that + * when we find the first actual use of the variable to avoid allocating temp + * regs that will never get used. + * At this time, uniforms are always allocated space in this function. + * + * \param initializer Optional initializer expression for the variable. + */ +static slang_ir_node * +_slang_gen_var_decl(slang_assemble_ctx *A, slang_variable *var, + slang_operation *initializer) +{ + const char *varName = (const char *) var->a_name; + const GLenum datatype = _slang_gltype_from_specifier(&var->type.specifier); + slang_ir_node *varDecl, *n; + slang_ir_storage *store; + GLint arrayLen, size, totalSize; /* if array then totalSize > size */ + gl_register_file file; + + /*assert(!var->declared);*/ + var->declared = GL_TRUE; + + /* determine GPU register file for simple cases */ + if (is_sampler_type(&var->type)) { + file = PROGRAM_SAMPLER; + } + else if (var->type.qualifier == SLANG_QUAL_UNIFORM) { + file = PROGRAM_UNIFORM; + } + else { + file = PROGRAM_TEMPORARY; + } + + size = _slang_sizeof_type_specifier(&var->type.specifier); + if (size <= 0) { + slang_info_log_error(A->log, "invalid declaration for '%s'", varName); + return NULL; + } + + arrayLen = _slang_array_length(var); + totalSize = _slang_array_size(size, arrayLen); + + /* Allocate IR node for the declaration */ + varDecl = new_node0(IR_VAR_DECL); + if (!varDecl) + return NULL; + + /* Allocate slang_ir_storage for this variable if needed. + * Note that we may not actually allocate a constant or temporary register + * until later. + */ + if (!var->store) { + GLint index = -7; /* TBD / unknown */ + var->store = _slang_new_ir_storage(file, index, totalSize); + if (!var->store) + return NULL; /* out of memory */ + } + + /* set the IR node's Var and Store pointers */ + varDecl->Var = var; + varDecl->Store = var->store; + + + store = var->store; + + /* if there's an initializer, generate IR for the expression */ + if (initializer) { + slang_ir_node *varRef, *init; + + if (var->type.qualifier == SLANG_QUAL_CONST) { + /* if the variable is const, the initializer must be a const + * expression as well. + */ +#if 0 + if (!_slang_is_constant_expr(initializer)) { + slang_info_log_error(A->log, + "initializer for %s not constant", varName); + return NULL; + } +#endif + } + + /* IR for the variable we're initializing */ + varRef = new_var(A, var); + if (!varRef) { + slang_info_log_error(A->log, "out of memory"); + return NULL; + } + + /* constant-folding, etc here */ + _slang_simplify(initializer, &A->space, A->atoms); + + /* look for simple constant-valued variables and uniforms */ + if (var->type.qualifier == SLANG_QUAL_CONST || + var->type.qualifier == SLANG_QUAL_UNIFORM) { + + if (initializer->type == SLANG_OPER_CALL && + initializer->array_constructor) { + /* array initializer */ + if (make_constant_array(A, var, initializer)) + return varRef; + } + else if (initializer->type == SLANG_OPER_LITERAL_FLOAT || + initializer->type == SLANG_OPER_LITERAL_INT) { + /* simple float/vector initializer */ + if (store->File == PROGRAM_UNIFORM) { + store->Index = _mesa_add_uniform(A->program->Parameters, + varName, + totalSize, datatype, + initializer->literal); + store->Swizzle = _slang_var_swizzle(size, 0); + return varRef; + } +#if 0 + else { + store->File = PROGRAM_CONSTANT; + store->Index = _mesa_add_named_constant(A->program->Parameters, + varName, + initializer->literal, + totalSize); + store->Swizzle = _slang_var_swizzle(size, 0); + return varRef; + } +#endif + } + } + + /* IR for initializer */ + init = _slang_gen_operation(A, initializer); + if (!init) + return NULL; + + /* XXX remove this when type checking is added above */ + if (init->Store && init->Store->Size != totalSize) { + slang_info_log_error(A->log, "invalid assignment (wrong types)"); + return NULL; + } + + /* assign RHS to LHS */ + n = new_node2(IR_COPY, varRef, init); + n = new_seq(varDecl, n); + } + else { + /* no initializer */ + n = varDecl; + } + + if (store->File == PROGRAM_UNIFORM && store->Index < 0) { + /* always need to allocate storage for uniforms at this point */ + store->Index = _mesa_add_uniform(A->program->Parameters, varName, + totalSize, datatype, NULL); + store->Swizzle = _slang_var_swizzle(size, 0); + } + +#if 0 + printf("%s var %p %s store=%p index=%d size=%d\n", + __FUNCTION__, (void *) var, (char *) varName, + (void *) store, store->Index, store->Size); +#endif + + return n; +} + + +/** + * Generate code for a selection expression: b ? x : y + * XXX In some cases we could implement a selection expression + * with an LRP instruction (use the boolean as the interpolant). + * Otherwise, we use an IF/ELSE/ENDIF construct. + */ +static slang_ir_node * +_slang_gen_select(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_ir_node *cond, *ifNode, *trueExpr, *falseExpr, *trueNode, *falseNode; + slang_ir_node *tmpDecl, *tmpVar, *tree; + slang_typeinfo type0, type1, type2; + int size, isBool, isEqual; + + assert(oper->type == SLANG_OPER_SELECT); + assert(oper->num_children == 3); + + /* type of children[0] must be boolean */ + slang_typeinfo_construct(&type0); + typeof_operation(A, &oper->children[0], &type0); + isBool = (type0.spec.type == SLANG_SPEC_BOOL); + slang_typeinfo_destruct(&type0); + if (!isBool) { + slang_info_log_error(A->log, "selector type is not boolean"); + return NULL; + } + + slang_typeinfo_construct(&type1); + slang_typeinfo_construct(&type2); + typeof_operation(A, &oper->children[1], &type1); + typeof_operation(A, &oper->children[2], &type2); + isEqual = slang_type_specifier_equal(&type1.spec, &type2.spec); + slang_typeinfo_destruct(&type1); + slang_typeinfo_destruct(&type2); + if (!isEqual) { + slang_info_log_error(A->log, "incompatible types for ?: operator"); + return NULL; + } + + /* size of x or y's type */ + size = _slang_sizeof_type_specifier(&type1.spec); + assert(size > 0); + + /* temporary var */ + tmpDecl = _slang_gen_temporary(size); + + /* the condition (child 0) */ + cond = _slang_gen_operation(A, &oper->children[0]); + cond = new_cond(cond); + + /* if-true body (child 1) */ + tmpVar = new_node0(IR_VAR); + tmpVar->Store = tmpDecl->Store; + trueExpr = _slang_gen_operation(A, &oper->children[1]); + trueNode = new_node2(IR_COPY, tmpVar, trueExpr); + + /* if-false body (child 2) */ + tmpVar = new_node0(IR_VAR); + tmpVar->Store = tmpDecl->Store; + falseExpr = _slang_gen_operation(A, &oper->children[2]); + falseNode = new_node2(IR_COPY, tmpVar, falseExpr); + + ifNode = new_if(cond, trueNode, falseNode); + + /* tmp var value */ + tmpVar = new_node0(IR_VAR); + tmpVar->Store = tmpDecl->Store; + + tree = new_seq(ifNode, tmpVar); + tree = new_seq(tmpDecl, tree); + + /*_slang_print_ir_tree(tree, 10);*/ + return tree; +} + + +/** + * Generate code for &&. + */ +static slang_ir_node * +_slang_gen_logical_and(slang_assemble_ctx *A, slang_operation *oper) +{ + /* rewrite "a && b" as "a ? b : false" */ + slang_operation *select; + slang_ir_node *n; + + select = slang_operation_new(1); + select->type = SLANG_OPER_SELECT; + slang_operation_add_children(select, 3); + + slang_operation_copy(slang_oper_child(select, 0), &oper->children[0]); + slang_operation_copy(slang_oper_child(select, 1), &oper->children[1]); + slang_operation_literal_bool(slang_oper_child(select, 2), GL_FALSE); + + n = _slang_gen_select(A, select); + return n; +} + + +/** + * Generate code for ||. + */ +static slang_ir_node * +_slang_gen_logical_or(slang_assemble_ctx *A, slang_operation *oper) +{ + /* rewrite "a || b" as "a ? true : b" */ + slang_operation *select; + slang_ir_node *n; + + select = slang_operation_new(1); + select->type = SLANG_OPER_SELECT; + slang_operation_add_children(select, 3); + + slang_operation_copy(slang_oper_child(select, 0), &oper->children[0]); + slang_operation_literal_bool(slang_oper_child(select, 1), GL_TRUE); + slang_operation_copy(slang_oper_child(select, 2), &oper->children[1]); + + n = _slang_gen_select(A, select); + return n; +} + + +/** + * Generate IR tree for a return statement. + */ +static slang_ir_node * +_slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) +{ + assert(oper->type == SLANG_OPER_RETURN); + return new_return(A->curFuncEndLabel); +} + + +#if 0 +/** + * Determine if the given operation/expression is const-valued. + */ +static GLboolean +_slang_is_constant_expr(const slang_operation *oper) +{ + slang_variable *var; + GLuint i; + + switch (oper->type) { + case SLANG_OPER_IDENTIFIER: + var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); + if (var && var->type.qualifier == SLANG_QUAL_CONST) + return GL_TRUE; + return GL_FALSE; + default: + for (i = 0; i < oper->num_children; i++) { + if (!_slang_is_constant_expr(&oper->children[i])) + return GL_FALSE; + } + return GL_TRUE; + } +} +#endif + + +/** + * Check if an assignment of type t1 to t0 is legal. + * XXX more cases needed. + */ +static GLboolean +_slang_assignment_compatible(slang_assemble_ctx *A, + slang_operation *op0, + slang_operation *op1) +{ + slang_typeinfo t0, t1; + GLuint sz0, sz1; + + if (op0->type == SLANG_OPER_POSTINCREMENT || + op0->type == SLANG_OPER_POSTDECREMENT) { + return GL_FALSE; + } + + slang_typeinfo_construct(&t0); + typeof_operation(A, op0, &t0); + + slang_typeinfo_construct(&t1); + typeof_operation(A, op1, &t1); + + sz0 = _slang_sizeof_type_specifier(&t0.spec); + sz1 = _slang_sizeof_type_specifier(&t1.spec); + +#if 1 + if (sz0 != sz1) { + /*printf("assignment size mismatch %u vs %u\n", sz0, sz1);*/ + return GL_FALSE; + } +#endif + + if (t0.spec.type == SLANG_SPEC_STRUCT && + t1.spec.type == SLANG_SPEC_STRUCT && + t0.spec._struct->a_name != t1.spec._struct->a_name) + return GL_FALSE; + + if (t0.spec.type == SLANG_SPEC_FLOAT && + t1.spec.type == SLANG_SPEC_BOOL) + return GL_FALSE; + +#if 0 /* not used just yet - causes problems elsewhere */ + if (t0.spec.type == SLANG_SPEC_INT && + t1.spec.type == SLANG_SPEC_FLOAT) + return GL_FALSE; +#endif + + if (t0.spec.type == SLANG_SPEC_BOOL && + t1.spec.type == SLANG_SPEC_FLOAT) + return GL_FALSE; + + if (t0.spec.type == SLANG_SPEC_BOOL && + t1.spec.type == SLANG_SPEC_INT) + return GL_FALSE; + + return GL_TRUE; +} + + +/** + * Generate IR tree for a local variable declaration. + * Basically do some error checking and call _slang_gen_var_decl(). + */ +static slang_ir_node * +_slang_gen_declaration(slang_assemble_ctx *A, slang_operation *oper) +{ + const char *varName = (char *) oper->a_id; + slang_variable *var; + slang_ir_node *varDecl; + slang_operation *initializer; + + assert(oper->type == SLANG_OPER_VARIABLE_DECL); + assert(oper->num_children <= 1); + + + /* lookup the variable by name */ + var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); + if (!var) + return NULL; /* "shouldn't happen" */ + + if (var->type.qualifier == SLANG_QUAL_ATTRIBUTE || + var->type.qualifier == SLANG_QUAL_VARYING || + var->type.qualifier == SLANG_QUAL_UNIFORM) { + /* can't declare attribute/uniform vars inside functions */ + slang_info_log_error(A->log, + "local variable '%s' cannot be an attribute/uniform/varying", + varName); + return NULL; + } + +#if 0 + if (v->declared) { + slang_info_log_error(A->log, "variable '%s' redeclared", varName); + return NULL; + } +#endif + + /* check if the var has an initializer */ + if (oper->num_children > 0) { + assert(oper->num_children == 1); + initializer = &oper->children[0]; + } + else if (var->initializer) { + initializer = var->initializer; + } + else { + initializer = NULL; + } + + if (initializer) { + /* check/compare var type and initializer type */ + if (!_slang_assignment_compatible(A, oper, initializer)) { + slang_info_log_error(A->log, "incompatible types in assignment"); + return NULL; + } + } + else { + if (var->type.qualifier == SLANG_QUAL_CONST) { + slang_info_log_error(A->log, + "const-qualified variable '%s' requires initializer", + varName); + return NULL; + } + } + + /* Generate IR node */ + varDecl = _slang_gen_var_decl(A, var, initializer); + if (!varDecl) + return NULL; + + return varDecl; +} + + +/** + * Generate IR tree for a reference to a variable (such as in an expression). + * This is different from a variable declaration. + */ +static slang_ir_node * +_slang_gen_variable(slang_assemble_ctx * A, slang_operation *oper) +{ + /* If there's a variable associated with this oper (from inlining) + * use it. Otherwise, use the oper's var id. + */ + slang_atom name = oper->var ? oper->var->a_name : oper->a_id; + slang_variable *var = _slang_variable_locate(oper->locals, name, GL_TRUE); + slang_ir_node *n; + if (!var) { + slang_info_log_error(A->log, "undefined variable '%s'", (char *) name); + return NULL; + } + assert(var->declared); + n = new_var(A, var); + return n; +} + + + +/** + * Return the number of components actually named by the swizzle. + * Recall that swizzles may have undefined/don't-care values. + */ +static GLuint +swizzle_size(GLuint swizzle) +{ + GLuint size = 0, i; + for (i = 0; i < 4; i++) { + GLuint swz = GET_SWZ(swizzle, i); + size += (swz >= 0 && swz <= 3); + } + return size; +} + + +static slang_ir_node * +_slang_gen_swizzle(slang_ir_node *child, GLuint swizzle) +{ + slang_ir_node *n = new_node1(IR_SWIZZLE, child); + assert(child); + if (n) { + assert(!n->Store); + n->Store = _slang_new_ir_storage_relative(0, + swizzle_size(swizzle), + child->Store); + n->Store->Swizzle = swizzle; + } + return n; +} + + +static GLboolean +is_store_writable(const slang_assemble_ctx *A, const slang_ir_storage *store) +{ + while (store->Parent) + store = store->Parent; + + if (!(store->File == PROGRAM_OUTPUT || + store->File == PROGRAM_TEMPORARY || + (store->File == PROGRAM_VARYING && + A->program->Target == GL_VERTEX_PROGRAM_ARB))) { + return GL_FALSE; + } + else { + return GL_TRUE; + } +} + + +/** + * Walk up an IR storage path to compute the final swizzle. + * This is used when we find an expression such as "foo.xz.yx". + */ +static GLuint +root_swizzle(const slang_ir_storage *st) +{ + GLuint swizzle = st->Swizzle; + while (st->Parent) { + st = st->Parent; + swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle); + } + return swizzle; +} + + +/** + * Generate IR tree for an assignment (=). + */ +static slang_ir_node * +_slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper) +{ + slang_operation *pred = NULL; + slang_ir_node *n = NULL; + + if (oper->children[0].type == SLANG_OPER_IDENTIFIER) { + /* Check that var is writeable */ + slang_variable *var + = _slang_variable_locate(oper->children[0].locals, + oper->children[0].a_id, GL_TRUE); + if (!var) { + slang_info_log_error(A->log, "undefined variable '%s'", + (char *) oper->children[0].a_id); + return NULL; + } + if (var->type.qualifier == SLANG_QUAL_CONST || + var->type.qualifier == SLANG_QUAL_ATTRIBUTE || + var->type.qualifier == SLANG_QUAL_UNIFORM || + (var->type.qualifier == SLANG_QUAL_VARYING && + A->program->Target == GL_FRAGMENT_PROGRAM_ARB)) { + slang_info_log_error(A->log, + "illegal assignment to read-only variable '%s'", + (char *) oper->children[0].a_id); + return NULL; + } + + /* check if we need to predicate this assignment based on __notRetFlag */ + if ((var->is_global || + var->type.qualifier == SLANG_QUAL_OUT || + var->type.qualifier == SLANG_QUAL_INOUT) && A->UseReturnFlag) { + /* create predicate, used below */ + pred = slang_operation_new(1); + pred->type = SLANG_OPER_IDENTIFIER; + pred->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); + pred->locals->outer_scope = oper->locals->outer_scope; + } + } + + if (oper->children[0].type == SLANG_OPER_IDENTIFIER && + oper->children[1].type == SLANG_OPER_CALL) { + /* Special case of: x = f(a, b) + * Replace with f(a, b, x) (where x == hidden __retVal out param) + * + * XXX this could be even more effective if we could accomodate + * cases such as "v.x = f();" - would help with typical vertex + * transformation. + */ + n = _slang_gen_function_call_name(A, + (const char *) oper->children[1].a_id, + &oper->children[1], &oper->children[0]); + } + else { + slang_ir_node *lhs, *rhs; + + /* lhs and rhs type checking */ + if (!_slang_assignment_compatible(A, + &oper->children[0], + &oper->children[1])) { + slang_info_log_error(A->log, "incompatible types in assignment"); + return NULL; + } + + lhs = _slang_gen_operation(A, &oper->children[0]); + if (!lhs) { + return NULL; + } + + if (!lhs->Store) { + slang_info_log_error(A->log, + "invalid left hand side for assignment"); + return NULL; + } + + /* check that lhs is writable */ + if (!is_store_writable(A, lhs->Store)) { + slang_info_log_error(A->log, + "illegal assignment to read-only l-value"); + return NULL; + } + + rhs = _slang_gen_operation(A, &oper->children[1]); + if (lhs && rhs) { + /* convert lhs swizzle into writemask */ + const GLuint swizzle = root_swizzle(lhs->Store); + GLuint writemask, newSwizzle = 0x0; + if (!swizzle_to_writemask(A, swizzle, &writemask, &newSwizzle)) { + /* Non-simple writemask, need to swizzle right hand side in + * order to put components into the right place. + */ + rhs = _slang_gen_swizzle(rhs, newSwizzle); + } + n = new_node2(IR_COPY, lhs, rhs); + } + else { + return NULL; + } + } + + if (n && pred) { + /* predicate the assignment code on __notRetFlag */ + slang_ir_node *top, *cond; + + cond = _slang_gen_operation(A, pred); + top = new_if(cond, n, NULL); + return top; + } + return n; +} + + +/** + * Generate IR tree for referencing a field in a struct (or basic vector type) + */ +static slang_ir_node * +_slang_gen_struct_field(slang_assemble_ctx * A, slang_operation *oper) +{ + slang_typeinfo ti; + + /* type of struct */ + slang_typeinfo_construct(&ti); + typeof_operation(A, &oper->children[0], &ti); + + if (_slang_type_is_vector(ti.spec.type)) { + /* the field should be a swizzle */ + const GLuint rows = _slang_type_dim(ti.spec.type); + slang_swizzle swz; + slang_ir_node *n; + GLuint swizzle; + if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) { + slang_info_log_error(A->log, "Bad swizzle"); + return NULL; + } + swizzle = MAKE_SWIZZLE4(swz.swizzle[0], + swz.swizzle[1], + swz.swizzle[2], + swz.swizzle[3]); + + n = _slang_gen_operation(A, &oper->children[0]); + /* create new parent node with swizzle */ + if (n) + n = _slang_gen_swizzle(n, swizzle); + return n; + } + else if ( ti.spec.type == SLANG_SPEC_FLOAT + || ti.spec.type == SLANG_SPEC_INT + || ti.spec.type == SLANG_SPEC_BOOL) { + const GLuint rows = 1; + slang_swizzle swz; + slang_ir_node *n; + GLuint swizzle; + if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) { + slang_info_log_error(A->log, "Bad swizzle"); + } + swizzle = MAKE_SWIZZLE4(swz.swizzle[0], + swz.swizzle[1], + swz.swizzle[2], + swz.swizzle[3]); + n = _slang_gen_operation(A, &oper->children[0]); + /* create new parent node with swizzle */ + n = _slang_gen_swizzle(n, swizzle); + return n; + } + else { + /* the field is a structure member (base.field) */ + /* oper->children[0] is the base */ + /* oper->a_id is the field name */ + slang_ir_node *base, *n; + slang_typeinfo field_ti; + GLint fieldSize, fieldOffset = -1; + + /* type of field */ + slang_typeinfo_construct(&field_ti); + typeof_operation(A, oper, &field_ti); + + fieldSize = _slang_sizeof_type_specifier(&field_ti.spec); + if (fieldSize > 0) + fieldOffset = _slang_field_offset(&ti.spec, oper->a_id); + + if (fieldSize == 0 || fieldOffset < 0) { + const char *structName; + if (ti.spec._struct) + structName = (char *) ti.spec._struct->a_name; + else + structName = "unknown"; + slang_info_log_error(A->log, + "\"%s\" is not a member of struct \"%s\"", + (char *) oper->a_id, structName); + return NULL; + } + assert(fieldSize >= 0); + + base = _slang_gen_operation(A, &oper->children[0]); + if (!base) { + /* error msg should have already been logged */ + return NULL; + } + + n = new_node1(IR_FIELD, base); + if (!n) + return NULL; + + n->Field = (char *) oper->a_id; + + /* Store the field's offset in storage->Index */ + n->Store = _slang_new_ir_storage(base->Store->File, + fieldOffset, + fieldSize); + + return n; + } +} + + +/** + * Gen code for array indexing. + */ +static slang_ir_node * +_slang_gen_array_element(slang_assemble_ctx * A, slang_operation *oper) +{ + slang_typeinfo array_ti; + + /* get array's type info */ + slang_typeinfo_construct(&array_ti); + typeof_operation(A, &oper->children[0], &array_ti); + + if (_slang_type_is_vector(array_ti.spec.type)) { + /* indexing a simple vector type: "vec4 v; v[0]=p;" */ + /* translate the index into a swizzle/writemask: "v.x=p" */ + const GLuint max = _slang_type_dim(array_ti.spec.type); + GLint index; + slang_ir_node *n; + + index = (GLint) oper->children[1].literal[0]; + if (oper->children[1].type != SLANG_OPER_LITERAL_INT || + index >= (GLint) max) { +#if 0 + slang_info_log_error(A->log, "Invalid array index for vector type"); + printf("type = %d\n", oper->children[1].type); + printf("index = %d, max = %d\n", index, max); + printf("array = %s\n", (char*)oper->children[0].a_id); + printf("index = %s\n", (char*)oper->children[1].a_id); + return NULL; +#else + index = 0; +#endif + } + + n = _slang_gen_operation(A, &oper->children[0]); + if (n) { + /* use swizzle to access the element */ + GLuint swizzle = MAKE_SWIZZLE4(SWIZZLE_X + index, + SWIZZLE_NIL, + SWIZZLE_NIL, + SWIZZLE_NIL); + n = _slang_gen_swizzle(n, swizzle); + } + assert(n->Store); + return n; + } + else { + /* conventional array */ + slang_typeinfo elem_ti; + slang_ir_node *elem, *array, *index; + GLint elemSize, arrayLen; + + /* size of array element */ + slang_typeinfo_construct(&elem_ti); + typeof_operation(A, oper, &elem_ti); + elemSize = _slang_sizeof_type_specifier(&elem_ti.spec); + + if (_slang_type_is_matrix(array_ti.spec.type)) + arrayLen = _slang_type_dim(array_ti.spec.type); + else + arrayLen = array_ti.array_len; + + slang_typeinfo_destruct(&array_ti); + slang_typeinfo_destruct(&elem_ti); + + if (elemSize <= 0) { + /* unknown var or type */ + slang_info_log_error(A->log, "Undefined variable or type"); + return NULL; + } + + array = _slang_gen_operation(A, &oper->children[0]); + index = _slang_gen_operation(A, &oper->children[1]); + if (array && index) { + /* bounds check */ + GLint constIndex = -1; + if (index->Opcode == IR_FLOAT) { + constIndex = (int) index->Value[0]; + if (constIndex < 0 || constIndex >= arrayLen) { + slang_info_log_error(A->log, + "Array index out of bounds (index=%d size=%d)", + constIndex, arrayLen); + _slang_free_ir_tree(array); + _slang_free_ir_tree(index); + return NULL; + } + } + + if (!array->Store) { + slang_info_log_error(A->log, "Invalid array"); + return NULL; + } + + elem = new_node2(IR_ELEMENT, array, index); + + /* The storage info here will be updated during code emit */ + elem->Store = _slang_new_ir_storage(array->Store->File, + array->Store->Index, + elemSize); + elem->Store->Swizzle = _slang_var_swizzle(elemSize, 0); + return elem; + } + else { + _slang_free_ir_tree(array); + _slang_free_ir_tree(index); + return NULL; + } + } +} + + +static slang_ir_node * +_slang_gen_compare(slang_assemble_ctx *A, slang_operation *oper, + slang_ir_opcode opcode) +{ + slang_typeinfo t0, t1; + slang_ir_node *n; + + slang_typeinfo_construct(&t0); + typeof_operation(A, &oper->children[0], &t0); + + slang_typeinfo_construct(&t1); + typeof_operation(A, &oper->children[0], &t1); + + if (t0.spec.type == SLANG_SPEC_ARRAY || + t1.spec.type == SLANG_SPEC_ARRAY) { + slang_info_log_error(A->log, "Illegal array comparison"); + return NULL; + } + + if (oper->type != SLANG_OPER_EQUAL && + oper->type != SLANG_OPER_NOTEQUAL) { + /* <, <=, >, >= can only be used with scalars */ + if ((t0.spec.type != SLANG_SPEC_INT && + t0.spec.type != SLANG_SPEC_FLOAT) || + (t1.spec.type != SLANG_SPEC_INT && + t1.spec.type != SLANG_SPEC_FLOAT)) { + slang_info_log_error(A->log, "Incompatible type(s) for inequality operator"); + return NULL; + } + } + + n = new_node2(opcode, + _slang_gen_operation(A, &oper->children[0]), + _slang_gen_operation(A, &oper->children[1])); + + /* result is a bool (size 1) */ + n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1); + + return n; +} + + +#if 0 +static void +print_vars(slang_variable_scope *s) +{ + int i; + printf("vars: "); + for (i = 0; i < s->num_variables; i++) { + printf("%s %d, \n", + (char*) s->variables[i]->a_name, + s->variables[i]->declared); + } + + printf("\n"); +} +#endif + + +#if 0 +static void +_slang_undeclare_vars(slang_variable_scope *locals) +{ + if (locals->num_variables > 0) { + int i; + for (i = 0; i < locals->num_variables; i++) { + slang_variable *v = locals->variables[i]; + printf("undeclare %s at %p\n", (char*) v->a_name, v); + v->declared = GL_FALSE; + } + } +} +#endif + + +/** + * Generate IR tree for a slang_operation (AST node) + */ +static slang_ir_node * +_slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_BLOCK_NEW_SCOPE: + { + slang_ir_node *n; + + _slang_push_var_table(A->vartable); + + oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; /* temp change */ + n = _slang_gen_operation(A, oper); + oper->type = SLANG_OPER_BLOCK_NEW_SCOPE; /* restore */ + + _slang_pop_var_table(A->vartable); + + /*_slang_undeclare_vars(oper->locals);*/ + /*print_vars(oper->locals);*/ + + if (n) + n = new_node1(IR_SCOPE, n); + return n; + } + break; + + case SLANG_OPER_BLOCK_NO_NEW_SCOPE: + /* list of operations */ + if (oper->num_children > 0) + { + slang_ir_node *n, *tree = NULL; + GLuint i; + + for (i = 0; i < oper->num_children; i++) { + n = _slang_gen_operation(A, &oper->children[i]); + if (!n) { + _slang_free_ir_tree(tree); + return NULL; /* error must have occured */ + } + tree = new_seq(tree, n); + } + + return tree; + } + else { + return new_node0(IR_NOP); + } + + case SLANG_OPER_EXPRESSION: + return _slang_gen_operation(A, &oper->children[0]); + + case SLANG_OPER_FOR: + return _slang_gen_for(A, oper); + case SLANG_OPER_DO: + return _slang_gen_do(A, oper); + case SLANG_OPER_WHILE: + return _slang_gen_while(A, oper); + case SLANG_OPER_BREAK: + if (!current_loop_oper(A)) { + slang_info_log_error(A->log, "'break' not in loop"); + return NULL; + } + return new_break(current_loop_ir(A)); + case SLANG_OPER_CONTINUE: + if (!current_loop_oper(A)) { + slang_info_log_error(A->log, "'continue' not in loop"); + return NULL; + } + return _slang_gen_continue(A, oper); + case SLANG_OPER_DISCARD: + return new_node0(IR_KILL); + + case SLANG_OPER_EQUAL: + return _slang_gen_compare(A, oper, IR_EQUAL); + case SLANG_OPER_NOTEQUAL: + return _slang_gen_compare(A, oper, IR_NOTEQUAL); + case SLANG_OPER_GREATER: + return _slang_gen_compare(A, oper, IR_SGT); + case SLANG_OPER_LESS: + return _slang_gen_compare(A, oper, IR_SLT); + case SLANG_OPER_GREATEREQUAL: + return _slang_gen_compare(A, oper, IR_SGE); + case SLANG_OPER_LESSEQUAL: + return _slang_gen_compare(A, oper, IR_SLE); + case SLANG_OPER_ADD: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "+", oper, NULL); + return n; + } + case SLANG_OPER_SUBTRACT: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "-", oper, NULL); + return n; + } + case SLANG_OPER_MULTIPLY: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "*", oper, NULL); + return n; + } + case SLANG_OPER_DIVIDE: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "/", oper, NULL); + return n; + } + case SLANG_OPER_MINUS: + { + slang_ir_node *n; + assert(oper->num_children == 1); + n = _slang_gen_function_call_name(A, "-", oper, NULL); + return n; + } + case SLANG_OPER_PLUS: + /* +expr --> do nothing */ + return _slang_gen_operation(A, &oper->children[0]); + case SLANG_OPER_VARIABLE_DECL: + return _slang_gen_declaration(A, oper); + case SLANG_OPER_ASSIGN: + return _slang_gen_assignment(A, oper); + case SLANG_OPER_ADDASSIGN: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "+=", oper, NULL); + return n; + } + case SLANG_OPER_SUBASSIGN: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "-=", oper, NULL); + return n; + } + break; + case SLANG_OPER_MULASSIGN: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "*=", oper, NULL); + return n; + } + case SLANG_OPER_DIVASSIGN: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_function_call_name(A, "/=", oper, NULL); + return n; + } + case SLANG_OPER_LOGICALAND: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_logical_and(A, oper); + return n; + } + case SLANG_OPER_LOGICALOR: + { + slang_ir_node *n; + assert(oper->num_children == 2); + n = _slang_gen_logical_or(A, oper); + return n; + } + case SLANG_OPER_LOGICALXOR: + return _slang_gen_xor(A, oper); + case SLANG_OPER_NOT: + return _slang_gen_not(A, oper); + case SLANG_OPER_SELECT: /* b ? x : y */ + { + slang_ir_node *n; + assert(oper->num_children == 3); + n = _slang_gen_select(A, oper); + return n; + } + + case SLANG_OPER_ASM: + return _slang_gen_asm(A, oper, NULL); + case SLANG_OPER_CALL: + return _slang_gen_function_call_name(A, (const char *) oper->a_id, + oper, NULL); + case SLANG_OPER_METHOD: + return _slang_gen_method_call(A, oper); + case SLANG_OPER_RETURN: + return _slang_gen_return(A, oper); + case SLANG_OPER_RETURN_INLINED: + return _slang_gen_return(A, oper); + case SLANG_OPER_LABEL: + return new_label(oper->label); + case SLANG_OPER_IDENTIFIER: + return _slang_gen_variable(A, oper); + case SLANG_OPER_IF: + return _slang_gen_if(A, oper); + case SLANG_OPER_FIELD: + return _slang_gen_struct_field(A, oper); + case SLANG_OPER_SUBSCRIPT: + return _slang_gen_array_element(A, oper); + case SLANG_OPER_LITERAL_FLOAT: + /* fall-through */ + case SLANG_OPER_LITERAL_INT: + /* fall-through */ + case SLANG_OPER_LITERAL_BOOL: + return new_float_literal(oper->literal, oper->literal_size); + + case SLANG_OPER_POSTINCREMENT: /* var++ */ + { + slang_ir_node *n; + assert(oper->num_children == 1); + n = _slang_gen_function_call_name(A, "__postIncr", oper, NULL); + return n; + } + case SLANG_OPER_POSTDECREMENT: /* var-- */ + { + slang_ir_node *n; + assert(oper->num_children == 1); + n = _slang_gen_function_call_name(A, "__postDecr", oper, NULL); + return n; + } + case SLANG_OPER_PREINCREMENT: /* ++var */ + { + slang_ir_node *n; + assert(oper->num_children == 1); + n = _slang_gen_function_call_name(A, "++", oper, NULL); + return n; + } + case SLANG_OPER_PREDECREMENT: /* --var */ + { + slang_ir_node *n; + assert(oper->num_children == 1); + n = _slang_gen_function_call_name(A, "--", oper, NULL); + return n; + } + + case SLANG_OPER_NON_INLINED_CALL: + case SLANG_OPER_SEQUENCE: + { + slang_ir_node *tree = NULL; + GLuint i; + for (i = 0; i < oper->num_children; i++) { + slang_ir_node *n = _slang_gen_operation(A, &oper->children[i]); + tree = new_seq(tree, n); + if (n) + tree->Store = n->Store; + } + if (oper->type == SLANG_OPER_NON_INLINED_CALL) { + tree = new_function_call(tree, oper->label); + } + return tree; + } + + case SLANG_OPER_NONE: + case SLANG_OPER_VOID: + /* returning NULL here would generate an error */ + return new_node0(IR_NOP); + + default: + _mesa_problem(NULL, "bad node type %d in _slang_gen_operation", + oper->type); + return new_node0(IR_NOP); + } + + return NULL; +} + + +/** + * Check if the given type specifier is a rectangular texture sampler. + */ +static GLboolean +is_rect_sampler_spec(const slang_type_specifier *spec) +{ + while (spec->_array) { + spec = spec->_array; + } + return spec->type == SLANG_SPEC_SAMPLER2DRECT || + spec->type == SLANG_SPEC_SAMPLER2DRECTSHADOW; +} + + + +/** + * Called by compiler when a global variable has been parsed/compiled. + * Here we examine the variable's type to determine what kind of register + * storage will be used. + * + * A uniform such as "gl_Position" will become the register specification + * (PROGRAM_OUTPUT, VERT_RESULT_HPOS). Or, uniform "gl_FogFragCoord" + * will be (PROGRAM_INPUT, FRAG_ATTRIB_FOGC). + * + * Samplers are interesting. For "uniform sampler2D tex;" we'll specify + * (PROGRAM_SAMPLER, index) where index is resolved at link-time to an + * actual texture unit (as specified by the user calling glUniform1i()). + */ +GLboolean +_slang_codegen_global_variable(slang_assemble_ctx *A, slang_variable *var, + slang_unit_type type) +{ + struct gl_program *prog = A->program; + const char *varName = (char *) var->a_name; + GLboolean success = GL_TRUE; + slang_ir_storage *store = NULL; + int dbg = 0; + const GLenum datatype = _slang_gltype_from_specifier(&var->type.specifier); + const GLint size = _slang_sizeof_type_specifier(&var->type.specifier); + const GLint arrayLen = _slang_array_length(var); + const GLint totalSize = _slang_array_size(size, arrayLen); + GLint texIndex = sampler_to_texture_index(var->type.specifier.type); + + var->is_global = GL_TRUE; + + /* check for sampler2D arrays */ + if (texIndex == -1 && var->type.specifier._array) + texIndex = sampler_to_texture_index(var->type.specifier._array->type); + + if (texIndex != -1) { + /* This is a texture sampler variable... + * store->File = PROGRAM_SAMPLER + * store->Index = sampler number (0..7, typically) + * store->Size = texture type index (1D, 2D, 3D, cube, etc) + */ + if (var->initializer) { + slang_info_log_error(A->log, "illegal assignment to '%s'", varName); + return GL_FALSE; + } +#if FEATURE_es2_glsl /* XXX should use FEATURE_texture_rect */ + /* disallow rect samplers */ + if (is_rect_sampler_spec(&var->type.specifier)) { + slang_info_log_error(A->log, "invalid sampler type for '%s'", varName); + return GL_FALSE; + } +#else + (void) is_rect_sampler_spec; /* silence warning */ +#endif + { + GLint sampNum = _mesa_add_sampler(prog->Parameters, varName, datatype); + store = _slang_new_ir_storage_sampler(sampNum, texIndex, totalSize); + + /* If we have a sampler array, then we need to allocate the + * additional samplers to ensure we don't allocate them elsewhere. + * We can't directly use _mesa_add_sampler() as that checks the + * varName and gets a match, so we call _mesa_add_parameter() + * directly and use the last sampler number from the call above. + */ + if (arrayLen > 0) { + GLint a = arrayLen - 1; + GLint i; + for (i = 0; i < a; i++) { + GLfloat value = (GLfloat)(i + sampNum + 1); + (void) _mesa_add_parameter(prog->Parameters, PROGRAM_SAMPLER, + varName, 1, datatype, &value, NULL, 0x0); + } + } + } + if (dbg) printf("SAMPLER "); + } + else if (var->type.qualifier == SLANG_QUAL_UNIFORM) { + /* Uniform variable */ + const GLuint swizzle = _slang_var_swizzle(totalSize, 0); + + if (prog) { + /* user-defined uniform */ + if (datatype == GL_NONE) { + if ((var->type.specifier.type == SLANG_SPEC_ARRAY && + var->type.specifier._array->type == SLANG_SPEC_STRUCT) || + (var->type.specifier.type == SLANG_SPEC_STRUCT)) { + /* temporary work-around */ + GLenum datatype = GL_FLOAT; + GLint uniformLoc = _mesa_add_uniform(prog->Parameters, varName, + totalSize, datatype, NULL); + store = _slang_new_ir_storage_swz(PROGRAM_UNIFORM, uniformLoc, + totalSize, swizzle); + + if (arrayLen > 0) { + GLint a = arrayLen - 1; + GLint i; + for (i = 0; i < a; i++) { + GLfloat value = (GLfloat)(i + uniformLoc + 1); + (void) _mesa_add_parameter(prog->Parameters, PROGRAM_UNIFORM, + varName, 1, datatype, &value, NULL, 0x0); + } + } + + /* XXX what we need to do is unroll the struct into its + * basic types, creating a uniform variable for each. + * For example: + * struct foo { + * vec3 a; + * vec4 b; + * }; + * uniform foo f; + * + * Should produce uniforms: + * "f.a" (GL_FLOAT_VEC3) + * "f.b" (GL_FLOAT_VEC4) + */ + + if (var->initializer) { + slang_info_log_error(A->log, + "unsupported initializer for uniform '%s'", varName); + return GL_FALSE; + } + } + else { + slang_info_log_error(A->log, + "invalid datatype for uniform variable %s", + varName); + return GL_FALSE; + } + } + else { + /* non-struct uniform */ + if (!_slang_gen_var_decl(A, var, var->initializer)) + return GL_FALSE; + store = var->store; + } + } + else { + /* pre-defined uniform, like gl_ModelviewMatrix */ + /* We know it's a uniform, but don't allocate storage unless + * it's really used. + */ + store = _slang_new_ir_storage_swz(PROGRAM_STATE_VAR, -1, + totalSize, swizzle); + } + if (dbg) printf("UNIFORM (sz %d) ", totalSize); + } + else if (var->type.qualifier == SLANG_QUAL_VARYING) { + /* varyings must be float, vec or mat */ + if (!_slang_type_is_float_vec_mat(var->type.specifier.type) && + var->type.specifier.type != SLANG_SPEC_ARRAY) { + slang_info_log_error(A->log, + "varying '%s' must be float/vector/matrix", + varName); + return GL_FALSE; + } + + if (var->initializer) { + slang_info_log_error(A->log, "illegal initializer for varying '%s'", + varName); + return GL_FALSE; + } + + if (prog) { + /* user-defined varying */ + GLbitfield flags; + GLint varyingLoc; + GLuint swizzle; + + flags = 0x0; + if (var->type.centroid == SLANG_CENTROID) + flags |= PROG_PARAM_BIT_CENTROID; + if (var->type.variant == SLANG_INVARIANT) + flags |= PROG_PARAM_BIT_INVARIANT; + + varyingLoc = _mesa_add_varying(prog->Varying, varName, + totalSize, flags); + swizzle = _slang_var_swizzle(size, 0); + store = _slang_new_ir_storage_swz(PROGRAM_VARYING, varyingLoc, + totalSize, swizzle); + } + else { + /* pre-defined varying, like gl_Color or gl_TexCoord */ + if (type == SLANG_UNIT_FRAGMENT_BUILTIN) { + /* fragment program input */ + GLuint swizzle; + GLint index = _slang_input_index(varName, GL_FRAGMENT_PROGRAM_ARB, + &swizzle); + assert(index >= 0); + assert(index < FRAG_ATTRIB_MAX); + store = _slang_new_ir_storage_swz(PROGRAM_INPUT, index, + size, swizzle); + } + else { + /* vertex program output */ + GLint index = _slang_output_index(varName, GL_VERTEX_PROGRAM_ARB); + GLuint swizzle = _slang_var_swizzle(size, 0); + assert(index >= 0); + assert(index < VERT_RESULT_MAX); + assert(type == SLANG_UNIT_VERTEX_BUILTIN); + store = _slang_new_ir_storage_swz(PROGRAM_OUTPUT, index, + size, swizzle); + } + if (dbg) printf("V/F "); + } + if (dbg) printf("VARYING "); + } + else if (var->type.qualifier == SLANG_QUAL_ATTRIBUTE) { + GLuint swizzle; + GLint index; + /* attributes must be float, vec or mat */ + if (!_slang_type_is_float_vec_mat(var->type.specifier.type)) { + slang_info_log_error(A->log, + "attribute '%s' must be float/vector/matrix", + varName); + return GL_FALSE; + } + + if (prog) { + /* user-defined vertex attribute */ + const GLint attr = -1; /* unknown */ + swizzle = _slang_var_swizzle(size, 0); + index = _mesa_add_attribute(prog->Attributes, varName, + size, datatype, attr); + assert(index >= 0); + index = VERT_ATTRIB_GENERIC0 + index; + } + else { + /* pre-defined vertex attrib */ + index = _slang_input_index(varName, GL_VERTEX_PROGRAM_ARB, &swizzle); + assert(index >= 0); + } + store = _slang_new_ir_storage_swz(PROGRAM_INPUT, index, size, swizzle); + if (dbg) printf("ATTRIB "); + } + else if (var->type.qualifier == SLANG_QUAL_FIXEDINPUT) { + GLuint swizzle = SWIZZLE_XYZW; /* silence compiler warning */ + GLint index = _slang_input_index(varName, GL_FRAGMENT_PROGRAM_ARB, + &swizzle); + store = _slang_new_ir_storage_swz(PROGRAM_INPUT, index, size, swizzle); + if (dbg) printf("INPUT "); + } + else if (var->type.qualifier == SLANG_QUAL_FIXEDOUTPUT) { + if (type == SLANG_UNIT_VERTEX_BUILTIN) { + GLint index = _slang_output_index(varName, GL_VERTEX_PROGRAM_ARB); + store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, size); + } + else { + GLint index = _slang_output_index(varName, GL_FRAGMENT_PROGRAM_ARB); + GLint specialSize = 4; /* treat all fragment outputs as float[4] */ + assert(type == SLANG_UNIT_FRAGMENT_BUILTIN); + store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, specialSize); + } + if (dbg) printf("OUTPUT "); + } + else if (var->type.qualifier == SLANG_QUAL_CONST && !prog) { + /* pre-defined global constant, like gl_MaxLights */ + store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, size); + if (dbg) printf("CONST "); + } + else { + /* ordinary variable (may be const) */ + slang_ir_node *n; + + /* IR node to declare the variable */ + n = _slang_gen_var_decl(A, var, var->initializer); + + /* emit GPU instructions */ + success = _slang_emit_code(n, A->vartable, A->program, A->pragmas, GL_FALSE, A->log); + + _slang_free_ir_tree(n); + } + + if (dbg) printf("GLOBAL VAR %s idx %d\n", (char*) var->a_name, + store ? store->Index : -2); + + if (store) + var->store = store; /* save var's storage info */ + + var->declared = GL_TRUE; + + return success; +} + + +/** + * Produce an IR tree from a function AST (fun->body). + * Then call the code emitter to convert the IR tree into gl_program + * instructions. + */ +GLboolean +_slang_codegen_function(slang_assemble_ctx * A, slang_function * fun) +{ + slang_ir_node *n; + GLboolean success = GL_TRUE; + + if (_mesa_strcmp((char *) fun->header.a_name, "main") != 0) { + /* we only really generate code for main, all other functions get + * inlined or codegen'd upon an actual call. + */ +#if 0 + /* do some basic error checking though */ + if (fun->header.type.specifier.type != SLANG_SPEC_VOID) { + /* check that non-void functions actually return something */ + slang_operation *op + = _slang_find_node_type(fun->body, SLANG_OPER_RETURN); + if (!op) { + slang_info_log_error(A->log, + "function \"%s\" has no return statement", + (char *) fun->header.a_name); + printf( + "function \"%s\" has no return statement\n", + (char *) fun->header.a_name); + return GL_FALSE; + } + } +#endif + return GL_TRUE; /* not an error */ + } + +#if 0 + printf("\n*********** codegen_function %s\n", (char *) fun->header.a_name); + slang_print_function(fun, 1); +#endif + + /* should have been allocated earlier: */ + assert(A->program->Parameters ); + assert(A->program->Varying); + assert(A->vartable); + + A->LoopDepth = 0; + A->UseReturnFlag = GL_FALSE; + A->CurFunction = fun; + + /* fold constant expressions, etc. */ + _slang_simplify(fun->body, &A->space, A->atoms); + +#if 0 + printf("\n*********** simplified %s\n", (char *) fun->header.a_name); + slang_print_function(fun, 1); +#endif + + /* Create an end-of-function label */ + A->curFuncEndLabel = _slang_label_new("__endOfFunc__main"); + + /* push new vartable scope */ + _slang_push_var_table(A->vartable); + + /* Generate IR tree for the function body code */ + n = _slang_gen_operation(A, fun->body); + if (n) + n = new_node1(IR_SCOPE, n); + + /* pop vartable, restore previous */ + _slang_pop_var_table(A->vartable); + + if (!n) { + /* XXX record error */ + return GL_FALSE; + } + + /* append an end-of-function-label to IR tree */ + n = new_seq(n, new_label(A->curFuncEndLabel)); + + /*_slang_label_delete(A->curFuncEndLabel);*/ + A->curFuncEndLabel = NULL; + +#if 0 + printf("************* New AST for %s *****\n", (char*)fun->header.a_name); + slang_print_function(fun, 1); +#endif +#if 0 + printf("************* IR for %s *******\n", (char*)fun->header.a_name); + _slang_print_ir_tree(n, 0); +#endif +#if 0 + printf("************* End codegen function ************\n\n"); +#endif + + if (A->UnresolvedRefs) { + /* Can't codegen at this time. + * At link time we'll concatenate all the vertex shaders and/or all + * the fragment shaders and try recompiling. + */ + return GL_TRUE; + } + + /* Emit program instructions */ + success = _slang_emit_code(n, A->vartable, A->program, A->pragmas, GL_TRUE, A->log); + _slang_free_ir_tree(n); + + /* free codegen context */ + /* + _mesa_free(A->codegen); + */ + + return success; +} + diff --git a/mesalib/src/mesa/shader/slang/slang_codegen.h b/mesalib/src/mesa/shader/slang/slang_codegen.h new file mode 100644 index 000000000..ee3be55a4 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_codegen.h @@ -0,0 +1,72 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-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 SLANG_CODEGEN_H +#define SLANG_CODEGEN_H + + +#include "main/imports.h" +#include "slang_compile.h" + + +#define MAX_LOOP_DEPTH 30 + + +typedef struct slang_assemble_ctx_ +{ + slang_atom_pool *atoms; + slang_name_space space; + struct gl_program *program; + struct gl_sl_pragmas *pragmas; + slang_var_table *vartable; + slang_info_log *log; + + /* current loop stack */ + const slang_operation *LoopOperStack[MAX_LOOP_DEPTH]; + struct slang_ir_node_ *LoopIRStack[MAX_LOOP_DEPTH]; + GLuint LoopDepth; + + /* current function */ + struct slang_function_ *CurFunction; + struct slang_label_ *curFuncEndLabel; + GLboolean UseReturnFlag; + + GLboolean UnresolvedRefs; + GLboolean EmitContReturn; +} slang_assemble_ctx; + + +extern GLuint +_slang_sizeof_type_specifier(const slang_type_specifier *spec); + +extern GLboolean +_slang_codegen_function(slang_assemble_ctx *A , struct slang_function_ *fun); + +extern GLboolean +_slang_codegen_global_variable(slang_assemble_ctx *A, slang_variable *var, + slang_unit_type type); + + +#endif /* SLANG_CODEGEN_H */ diff --git a/mesalib/src/mesa/shader/slang/slang_compile.c b/mesalib/src/mesa/shader/slang/slang_compile.c new file mode 100644 index 000000000..c1b97c7cb --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_compile.c @@ -0,0 +1,2825 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * Copyright (C) 2008 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 slang_compile.c + * slang front-end compiler + * \author Michal Krol + */ + +#include "main/imports.h" +#include "main/context.h" +#include "shader/program.h" +#include "shader/programopt.h" +#include "shader/prog_optimize.h" +#include "shader/prog_print.h" +#include "shader/prog_parameter.h" +#include "shader/grammar/grammar_mesa.h" +#include "slang_codegen.h" +#include "slang_compile.h" +#include "slang_preprocess.h" +#include "slang_storage.h" +#include "slang_emit.h" +#include "slang_log.h" +#include "slang_mem.h" +#include "slang_vartable.h" +#include "slang_simplify.h" + +#include "slang_print.h" + +/* + * This is a straightforward implementation of the slang front-end + * compiler. Lots of error-checking functionality is missing but + * every well-formed shader source should compile successfully and + * execute as expected. However, some semantically ill-formed shaders + * may be accepted resulting in undefined behaviour. + */ + + +/** re-defined below, should be the same though */ +#define TYPE_SPECIFIER_COUNT 32 + + +/** + * Check if the given identifier is legal. + */ +static GLboolean +legal_identifier(slang_atom name) +{ + /* "gl_" is a reserved prefix */ + if (_mesa_strncmp((char *) name, "gl_", 3) == 0) { + return GL_FALSE; + } + return GL_TRUE; +} + + +/* + * slang_code_unit + */ + +GLvoid +_slang_code_unit_ctr(slang_code_unit * self, + struct slang_code_object_ * object) +{ + _slang_variable_scope_ctr(&self->vars); + _slang_function_scope_ctr(&self->funs); + _slang_struct_scope_ctr(&self->structs); + self->object = object; +} + +GLvoid +_slang_code_unit_dtr(slang_code_unit * self) +{ + slang_variable_scope_destruct(&self->vars); + slang_function_scope_destruct(&self->funs); + slang_struct_scope_destruct(&self->structs); +} + +/* + * slang_code_object + */ + +GLvoid +_slang_code_object_ctr(slang_code_object * self) +{ + GLuint i; + + for (i = 0; i < SLANG_BUILTIN_TOTAL; i++) + _slang_code_unit_ctr(&self->builtin[i], self); + _slang_code_unit_ctr(&self->unit, self); + slang_atom_pool_construct(&self->atompool); +} + +GLvoid +_slang_code_object_dtr(slang_code_object * self) +{ + GLuint i; + + for (i = 0; i < SLANG_BUILTIN_TOTAL; i++) + _slang_code_unit_dtr(&self->builtin[i]); + _slang_code_unit_dtr(&self->unit); + slang_atom_pool_destruct(&self->atompool); +} + + +/* slang_parse_ctx */ + +typedef struct slang_parse_ctx_ +{ + const byte *I; + slang_info_log *L; + int parsing_builtin; + GLboolean global_scope; /**< Is object being declared a global? */ + slang_atom_pool *atoms; + slang_unit_type type; /**< Vertex vs. Fragment */ + GLuint version; /**< user-specified (or default) #version */ +} slang_parse_ctx; + +/* slang_output_ctx */ + +typedef struct slang_output_ctx_ +{ + slang_variable_scope *vars; + slang_function_scope *funs; + slang_struct_scope *structs; + struct gl_program *program; + struct gl_sl_pragmas *pragmas; + slang_var_table *vartable; + GLuint default_precision[TYPE_SPECIFIER_COUNT]; + GLboolean allow_precision; + GLboolean allow_invariant; + GLboolean allow_centroid; + GLboolean allow_array_types; /* float[] syntax */ +} slang_output_ctx; + +/* _slang_compile() */ + + +/* Debugging aid, print file/line where parsing error is detected */ +#define RETURN0 \ + do { \ + if (0) \ + printf("slang error at %s:%d\n", __FILE__, __LINE__); \ + return 0; \ + } while (0) + + +static void +parse_identifier_str(slang_parse_ctx * C, char **id) +{ + *id = (char *) C->I; + C->I += _mesa_strlen(*id) + 1; +} + +static slang_atom +parse_identifier(slang_parse_ctx * C) +{ + const char *id; + + id = (const char *) C->I; + C->I += _mesa_strlen(id) + 1; + return slang_atom_pool_atom(C->atoms, id); +} + +static int +parse_number(slang_parse_ctx * C, int *number) +{ + const int radix = (int) (*C->I++); + *number = 0; + while (*C->I != '\0') { + int digit; + if (*C->I >= '0' && *C->I <= '9') + digit = (int) (*C->I - '0'); + else if (*C->I >= 'A' && *C->I <= 'Z') + digit = (int) (*C->I - 'A') + 10; + else + digit = (int) (*C->I - 'a') + 10; + *number = *number * radix + digit; + C->I++; + } + C->I++; + if (*number > 65535) + slang_info_log_warning(C->L, "%d: literal integer overflow.", *number); + return 1; +} + +static int +parse_float(slang_parse_ctx * C, float *number) +{ + char *integral = NULL; + char *fractional = NULL; + char *exponent = NULL; + char *whole = NULL; + + parse_identifier_str(C, &integral); + parse_identifier_str(C, &fractional); + parse_identifier_str(C, &exponent); + + whole = (char *) _slang_alloc((_mesa_strlen(integral) + + _mesa_strlen(fractional) + + _mesa_strlen(exponent) + 3) * sizeof(char)); + if (whole == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + + slang_string_copy(whole, integral); + slang_string_concat(whole, "."); + slang_string_concat(whole, fractional); + slang_string_concat(whole, "E"); + slang_string_concat(whole, exponent); + + *number = (float) (_mesa_strtod(whole, (char **) NULL)); + + _slang_free(whole); + + return 1; +} + +/* revision number - increment after each change affecting emitted output */ +#define REVISION 5 + +static int +check_revision(slang_parse_ctx * C) +{ + if (*C->I != REVISION) { + slang_info_log_error(C->L, "Internal compiler error."); + RETURN0; + } + C->I++; + return 1; +} + +static int parse_statement(slang_parse_ctx *, slang_output_ctx *, + slang_operation *); +static int parse_expression(slang_parse_ctx *, slang_output_ctx *, + slang_operation *); +static int parse_type_specifier(slang_parse_ctx *, slang_output_ctx *, + slang_type_specifier *); +static int +parse_type_array_size(slang_parse_ctx *C, + slang_output_ctx *O, + GLint *array_len); + +static GLboolean +parse_array_len(slang_parse_ctx * C, slang_output_ctx * O, GLuint * len) +{ + slang_operation array_size; + slang_name_space space; + GLboolean result; + + if (!slang_operation_construct(&array_size)) + return GL_FALSE; + if (!parse_expression(C, O, &array_size)) { + slang_operation_destruct(&array_size); + return GL_FALSE; + } + + space.funcs = O->funs; + space.structs = O->structs; + space.vars = O->vars; + + /* evaluate compile-time expression which is array size */ + _slang_simplify(&array_size, &space, C->atoms); + + if (array_size.type == SLANG_OPER_LITERAL_INT) { + result = GL_TRUE; + *len = (GLint) array_size.literal[0]; + } else if (array_size.type == SLANG_OPER_IDENTIFIER) { + slang_variable *var = _slang_variable_locate(array_size.locals, array_size.a_id, GL_TRUE); + if (!var) { + slang_info_log_error(C->L, "undefined variable '%s'", + (char *) array_size.a_id); + result = GL_FALSE; + } else if (var->type.qualifier == SLANG_QUAL_CONST && + var->type.specifier.type == SLANG_SPEC_INT) { + if (var->initializer && + var->initializer->type == SLANG_OPER_LITERAL_INT) { + *len = (GLint) var->initializer->literal[0]; + result = GL_TRUE; + } else { + slang_info_log_error(C->L, "unable to parse array size declaration"); + result = GL_FALSE; + } + } else { + slang_info_log_error(C->L, "unable to parse array size declaration"); + result = GL_FALSE; + } + } else { + result = GL_FALSE; + } + + slang_operation_destruct(&array_size); + return result; +} + +static GLboolean +calculate_var_size(slang_parse_ctx * C, slang_output_ctx * O, + slang_variable * var) +{ + slang_storage_aggregate agg; + + if (!slang_storage_aggregate_construct(&agg)) + return GL_FALSE; + if (!_slang_aggregate_variable(&agg, &var->type.specifier, var->array_len, + O->funs, O->structs, O->vars, C->atoms)) { + slang_storage_aggregate_destruct(&agg); + return GL_FALSE; + } + var->size = _slang_sizeof_aggregate(&agg); + slang_storage_aggregate_destruct(&agg); + return GL_TRUE; +} + +static void +promote_type_to_array(slang_parse_ctx *C, + slang_fully_specified_type *type, + GLint array_len) +{ + slang_type_specifier *baseType = + slang_type_specifier_new(type->specifier.type, NULL, NULL); + + type->specifier.type = SLANG_SPEC_ARRAY; + type->specifier._array = baseType; + type->array_len = array_len; +} + + +static GLboolean +convert_to_array(slang_parse_ctx * C, slang_variable * var, + const slang_type_specifier * sp) +{ + /* sized array - mark it as array, copy the specifier to the array element + * and parse the expression */ + var->type.specifier.type = SLANG_SPEC_ARRAY; + var->type.specifier._array = (slang_type_specifier *) + _slang_alloc(sizeof(slang_type_specifier)); + if (var->type.specifier._array == NULL) { + slang_info_log_memory(C->L); + return GL_FALSE; + } + slang_type_specifier_ctr(var->type.specifier._array); + return slang_type_specifier_copy(var->type.specifier._array, sp); +} + +/* structure field */ +#define FIELD_NONE 0 +#define FIELD_NEXT 1 +#define FIELD_ARRAY 2 + +static GLboolean +parse_struct_field_var(slang_parse_ctx * C, slang_output_ctx * O, + slang_variable * var, slang_atom a_name, + const slang_type_specifier * sp, + GLuint array_len) +{ + var->a_name = a_name; + if (var->a_name == SLANG_ATOM_NULL) + return GL_FALSE; + + switch (*C->I++) { + case FIELD_NONE: + if (array_len != -1) { + if (!convert_to_array(C, var, sp)) + return GL_FALSE; + var->array_len = array_len; + } + else { + if (!slang_type_specifier_copy(&var->type.specifier, sp)) + return GL_FALSE; + } + break; + case FIELD_ARRAY: + if (array_len != -1) + return GL_FALSE; + if (!convert_to_array(C, var, sp)) + return GL_FALSE; + if (!parse_array_len(C, O, &var->array_len)) + return GL_FALSE; + break; + default: + return GL_FALSE; + } + + return calculate_var_size(C, O, var); +} + +static int +parse_struct_field(slang_parse_ctx * C, slang_output_ctx * O, + slang_struct * st, slang_type_specifier * sp) +{ + slang_output_ctx o = *O; + GLint array_len; + + o.structs = st->structs; + if (!parse_type_specifier(C, &o, sp)) + RETURN0; + if (!parse_type_array_size(C, &o, &array_len)) + RETURN0; + + do { + slang_atom a_name; + slang_variable *var = slang_variable_scope_grow(st->fields); + if (!var) { + slang_info_log_memory(C->L); + RETURN0; + } + a_name = parse_identifier(C); + if (_slang_variable_locate(st->fields, a_name, GL_FALSE)) { + slang_info_log_error(C->L, "duplicate field '%s'", (char *) a_name); + RETURN0; + } + + if (!parse_struct_field_var(C, &o, var, a_name, sp, array_len)) + RETURN0; + } + while (*C->I++ != FIELD_NONE); + + return 1; +} + +static int +parse_struct(slang_parse_ctx * C, slang_output_ctx * O, slang_struct ** st) +{ + slang_atom a_name; + const char *name; + + /* parse struct name (if any) and make sure it is unique in current scope */ + a_name = parse_identifier(C); + if (a_name == SLANG_ATOM_NULL) + RETURN0; + + name = slang_atom_pool_id(C->atoms, a_name); + if (name[0] != '\0' + && slang_struct_scope_find(O->structs, a_name, 0) != NULL) { + slang_info_log_error(C->L, "%s: duplicate type name.", name); + RETURN0; + } + + /* set-up a new struct */ + *st = (slang_struct *) _slang_alloc(sizeof(slang_struct)); + if (*st == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + if (!slang_struct_construct(*st)) { + _slang_free(*st); + *st = NULL; + slang_info_log_memory(C->L); + RETURN0; + } + (**st).a_name = a_name; + (**st).structs->outer_scope = O->structs; + + /* parse individual struct fields */ + do { + slang_type_specifier sp; + + slang_type_specifier_ctr(&sp); + if (!parse_struct_field(C, O, *st, &sp)) { + slang_type_specifier_dtr(&sp); + RETURN0; + } + slang_type_specifier_dtr(&sp); + } + while (*C->I++ != FIELD_NONE); + + /* if named struct, copy it to current scope */ + if (name[0] != '\0') { + slang_struct *s; + + O->structs->structs = + (slang_struct *) _slang_realloc(O->structs->structs, + O->structs->num_structs + * sizeof(slang_struct), + (O->structs->num_structs + 1) + * sizeof(slang_struct)); + if (O->structs->structs == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + s = &O->structs->structs[O->structs->num_structs]; + if (!slang_struct_construct(s)) + RETURN0; + O->structs->num_structs++; + if (!slang_struct_copy(s, *st)) + RETURN0; + } + + return 1; +} + + +/* invariant qualifer */ +#define TYPE_VARIANT 90 +#define TYPE_INVARIANT 91 + +static int +parse_type_variant(slang_parse_ctx * C, slang_type_variant *variant) +{ + GLuint invariant = *C->I++; + switch (invariant) { + case TYPE_VARIANT: + *variant = SLANG_VARIANT; + return 1; + case TYPE_INVARIANT: + *variant = SLANG_INVARIANT; + return 1; + default: + RETURN0; + } +} + + +/* centroid qualifer */ +#define TYPE_CENTER 95 +#define TYPE_CENTROID 96 + +static int +parse_type_centroid(slang_parse_ctx * C, slang_type_centroid *centroid) +{ + GLuint c = *C->I++; + switch (c) { + case TYPE_CENTER: + *centroid = SLANG_CENTER; + return 1; + case TYPE_CENTROID: + *centroid = SLANG_CENTROID; + return 1; + default: + RETURN0; + } +} + + +/* type qualifier */ +#define TYPE_QUALIFIER_NONE 0 +#define TYPE_QUALIFIER_CONST 1 +#define TYPE_QUALIFIER_ATTRIBUTE 2 +#define TYPE_QUALIFIER_VARYING 3 +#define TYPE_QUALIFIER_UNIFORM 4 +#define TYPE_QUALIFIER_FIXEDOUTPUT 5 +#define TYPE_QUALIFIER_FIXEDINPUT 6 + +static int +parse_type_qualifier(slang_parse_ctx * C, slang_type_qualifier * qual) +{ + GLuint qualifier = *C->I++; + switch (qualifier) { + case TYPE_QUALIFIER_NONE: + *qual = SLANG_QUAL_NONE; + break; + case TYPE_QUALIFIER_CONST: + *qual = SLANG_QUAL_CONST; + break; + case TYPE_QUALIFIER_ATTRIBUTE: + *qual = SLANG_QUAL_ATTRIBUTE; + break; + case TYPE_QUALIFIER_VARYING: + *qual = SLANG_QUAL_VARYING; + break; + case TYPE_QUALIFIER_UNIFORM: + *qual = SLANG_QUAL_UNIFORM; + break; + case TYPE_QUALIFIER_FIXEDOUTPUT: + *qual = SLANG_QUAL_FIXEDOUTPUT; + break; + case TYPE_QUALIFIER_FIXEDINPUT: + *qual = SLANG_QUAL_FIXEDINPUT; + break; + default: + RETURN0; + } + return 1; +} + +/* type specifier */ +#define TYPE_SPECIFIER_VOID 0 +#define TYPE_SPECIFIER_BOOL 1 +#define TYPE_SPECIFIER_BVEC2 2 +#define TYPE_SPECIFIER_BVEC3 3 +#define TYPE_SPECIFIER_BVEC4 4 +#define TYPE_SPECIFIER_INT 5 +#define TYPE_SPECIFIER_IVEC2 6 +#define TYPE_SPECIFIER_IVEC3 7 +#define TYPE_SPECIFIER_IVEC4 8 +#define TYPE_SPECIFIER_FLOAT 9 +#define TYPE_SPECIFIER_VEC2 10 +#define TYPE_SPECIFIER_VEC3 11 +#define TYPE_SPECIFIER_VEC4 12 +#define TYPE_SPECIFIER_MAT2 13 +#define TYPE_SPECIFIER_MAT3 14 +#define TYPE_SPECIFIER_MAT4 15 +#define TYPE_SPECIFIER_SAMPLER1D 16 +#define TYPE_SPECIFIER_SAMPLER2D 17 +#define TYPE_SPECIFIER_SAMPLER3D 18 +#define TYPE_SPECIFIER_SAMPLERCUBE 19 +#define TYPE_SPECIFIER_SAMPLER1DSHADOW 20 +#define TYPE_SPECIFIER_SAMPLER2DSHADOW 21 +#define TYPE_SPECIFIER_SAMPLER2DRECT 22 +#define TYPE_SPECIFIER_SAMPLER2DRECTSHADOW 23 +#define TYPE_SPECIFIER_STRUCT 24 +#define TYPE_SPECIFIER_TYPENAME 25 +#define TYPE_SPECIFIER_MAT23 26 +#define TYPE_SPECIFIER_MAT32 27 +#define TYPE_SPECIFIER_MAT24 28 +#define TYPE_SPECIFIER_MAT42 29 +#define TYPE_SPECIFIER_MAT34 30 +#define TYPE_SPECIFIER_MAT43 31 +#define TYPE_SPECIFIER_COUNT 32 + +static int +parse_type_specifier(slang_parse_ctx * C, slang_output_ctx * O, + slang_type_specifier * spec) +{ + switch (*C->I++) { + case TYPE_SPECIFIER_VOID: + spec->type = SLANG_SPEC_VOID; + break; + case TYPE_SPECIFIER_BOOL: + spec->type = SLANG_SPEC_BOOL; + break; + case TYPE_SPECIFIER_BVEC2: + spec->type = SLANG_SPEC_BVEC2; + break; + case TYPE_SPECIFIER_BVEC3: + spec->type = SLANG_SPEC_BVEC3; + break; + case TYPE_SPECIFIER_BVEC4: + spec->type = SLANG_SPEC_BVEC4; + break; + case TYPE_SPECIFIER_INT: + spec->type = SLANG_SPEC_INT; + break; + case TYPE_SPECIFIER_IVEC2: + spec->type = SLANG_SPEC_IVEC2; + break; + case TYPE_SPECIFIER_IVEC3: + spec->type = SLANG_SPEC_IVEC3; + break; + case TYPE_SPECIFIER_IVEC4: + spec->type = SLANG_SPEC_IVEC4; + break; + case TYPE_SPECIFIER_FLOAT: + spec->type = SLANG_SPEC_FLOAT; + break; + case TYPE_SPECIFIER_VEC2: + spec->type = SLANG_SPEC_VEC2; + break; + case TYPE_SPECIFIER_VEC3: + spec->type = SLANG_SPEC_VEC3; + break; + case TYPE_SPECIFIER_VEC4: + spec->type = SLANG_SPEC_VEC4; + break; + case TYPE_SPECIFIER_MAT2: + spec->type = SLANG_SPEC_MAT2; + break; + case TYPE_SPECIFIER_MAT3: + spec->type = SLANG_SPEC_MAT3; + break; + case TYPE_SPECIFIER_MAT4: + spec->type = SLANG_SPEC_MAT4; + break; + case TYPE_SPECIFIER_MAT23: + spec->type = SLANG_SPEC_MAT23; + break; + case TYPE_SPECIFIER_MAT32: + spec->type = SLANG_SPEC_MAT32; + break; + case TYPE_SPECIFIER_MAT24: + spec->type = SLANG_SPEC_MAT24; + break; + case TYPE_SPECIFIER_MAT42: + spec->type = SLANG_SPEC_MAT42; + break; + case TYPE_SPECIFIER_MAT34: + spec->type = SLANG_SPEC_MAT34; + break; + case TYPE_SPECIFIER_MAT43: + spec->type = SLANG_SPEC_MAT43; + break; + case TYPE_SPECIFIER_SAMPLER1D: + spec->type = SLANG_SPEC_SAMPLER1D; + break; + case TYPE_SPECIFIER_SAMPLER2D: + spec->type = SLANG_SPEC_SAMPLER2D; + break; + case TYPE_SPECIFIER_SAMPLER3D: + spec->type = SLANG_SPEC_SAMPLER3D; + break; + case TYPE_SPECIFIER_SAMPLERCUBE: + spec->type = SLANG_SPEC_SAMPLERCUBE; + break; + case TYPE_SPECIFIER_SAMPLER2DRECT: + spec->type = SLANG_SPEC_SAMPLER2DRECT; + break; + case TYPE_SPECIFIER_SAMPLER1DSHADOW: + spec->type = SLANG_SPEC_SAMPLER1DSHADOW; + break; + case TYPE_SPECIFIER_SAMPLER2DSHADOW: + spec->type = SLANG_SPEC_SAMPLER2DSHADOW; + break; + case TYPE_SPECIFIER_SAMPLER2DRECTSHADOW: + spec->type = SLANG_SPEC_SAMPLER2DRECTSHADOW; + break; + case TYPE_SPECIFIER_STRUCT: + spec->type = SLANG_SPEC_STRUCT; + if (!parse_struct(C, O, &spec->_struct)) + RETURN0; + break; + case TYPE_SPECIFIER_TYPENAME: + spec->type = SLANG_SPEC_STRUCT; + { + slang_atom a_name; + slang_struct *stru; + + a_name = parse_identifier(C); + if (a_name == NULL) + RETURN0; + + stru = slang_struct_scope_find(O->structs, a_name, 1); + if (stru == NULL) { + slang_info_log_error(C->L, "undeclared type name '%s'", + slang_atom_pool_id(C->atoms, a_name)); + RETURN0; + } + + spec->_struct = (slang_struct *) _slang_alloc(sizeof(slang_struct)); + if (spec->_struct == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + if (!slang_struct_construct(spec->_struct)) { + _slang_free(spec->_struct); + spec->_struct = NULL; + RETURN0; + } + if (!slang_struct_copy(spec->_struct, stru)) + RETURN0; + } + break; + default: + RETURN0; + } + return 1; +} + +#define TYPE_SPECIFIER_NONARRAY 0 +#define TYPE_SPECIFIER_ARRAY 1 + +static int +parse_type_array_size(slang_parse_ctx *C, + slang_output_ctx *O, + GLint *array_len) +{ + GLuint size; + + switch (*C->I++) { + case TYPE_SPECIFIER_NONARRAY: + *array_len = -1; /* -1 = not an array */ + break; + case TYPE_SPECIFIER_ARRAY: + if (!parse_array_len(C, O, &size)) + RETURN0; + *array_len = (GLint) size; + break; + default: + assert(0); + RETURN0; + } + return 1; +} + +#define PRECISION_DEFAULT 0 +#define PRECISION_LOW 1 +#define PRECISION_MEDIUM 2 +#define PRECISION_HIGH 3 + +static int +parse_type_precision(slang_parse_ctx *C, + slang_type_precision *precision) +{ + GLint prec = *C->I++; + switch (prec) { + case PRECISION_DEFAULT: + *precision = SLANG_PREC_DEFAULT; + return 1; + case PRECISION_LOW: + *precision = SLANG_PREC_LOW; + return 1; + case PRECISION_MEDIUM: + *precision = SLANG_PREC_MEDIUM; + return 1; + case PRECISION_HIGH: + *precision = SLANG_PREC_HIGH; + return 1; + default: + RETURN0; + } +} + +static int +parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O, + slang_fully_specified_type * type) +{ + if (!parse_type_variant(C, &type->variant)) + RETURN0; + + if (!parse_type_centroid(C, &type->centroid)) + RETURN0; + + if (!parse_type_qualifier(C, &type->qualifier)) + RETURN0; + + if (!parse_type_precision(C, &type->precision)) + RETURN0; + + if (!parse_type_specifier(C, O, &type->specifier)) + RETURN0; + + if (!parse_type_array_size(C, O, &type->array_len)) + RETURN0; + + if (!O->allow_invariant && type->variant == SLANG_INVARIANT) { + slang_info_log_error(C->L, + "'invariant' keyword not allowed (perhaps set #version 120)"); + RETURN0; + } + + if (!O->allow_centroid && type->centroid == SLANG_CENTROID) { + slang_info_log_error(C->L, + "'centroid' keyword not allowed (perhaps set #version 120)"); + RETURN0; + } + else if (type->centroid == SLANG_CENTROID && + type->qualifier != SLANG_QUAL_VARYING) { + slang_info_log_error(C->L, + "'centroid' keyword only allowed for varying vars"); + RETURN0; + } + + + /* need this? + if (type->qualifier != SLANG_QUAL_VARYING && + type->variant == SLANG_INVARIANT) { + slang_info_log_error(C->L, + "invariant qualifer only allowed for varying vars"); + RETURN0; + } + */ + + if (O->allow_precision) { + if (type->precision == SLANG_PREC_DEFAULT) { + assert(type->specifier.type < TYPE_SPECIFIER_COUNT); + /* use the default precision for this datatype */ + type->precision = O->default_precision[type->specifier.type]; + } + } + else { + /* only default is allowed */ + if (type->precision != SLANG_PREC_DEFAULT) { + slang_info_log_error(C->L, "precision qualifiers not allowed"); + RETURN0; + } + } + + if (!O->allow_array_types && type->array_len >= 0) { + slang_info_log_error(C->L, "first-class array types not allowed"); + RETURN0; + } + + if (type->array_len >= 0) { + /* convert type to array type (ex: convert "int" to "array of int" */ + promote_type_to_array(C, type, type->array_len); + } + + return 1; +} + +/* operation */ +#define OP_END 0 +#define OP_BLOCK_BEGIN_NO_NEW_SCOPE 1 +#define OP_BLOCK_BEGIN_NEW_SCOPE 2 +#define OP_DECLARE 3 +#define OP_ASM 4 +#define OP_BREAK 5 +#define OP_CONTINUE 6 +#define OP_DISCARD 7 +#define OP_RETURN 8 +#define OP_EXPRESSION 9 +#define OP_IF 10 +#define OP_WHILE 11 +#define OP_DO 12 +#define OP_FOR 13 +#define OP_PUSH_VOID 14 +#define OP_PUSH_BOOL 15 +#define OP_PUSH_INT 16 +#define OP_PUSH_FLOAT 17 +#define OP_PUSH_IDENTIFIER 18 +#define OP_SEQUENCE 19 +#define OP_ASSIGN 20 +#define OP_ADDASSIGN 21 +#define OP_SUBASSIGN 22 +#define OP_MULASSIGN 23 +#define OP_DIVASSIGN 24 +/*#define OP_MODASSIGN 25*/ +/*#define OP_LSHASSIGN 26*/ +/*#define OP_RSHASSIGN 27*/ +/*#define OP_ORASSIGN 28*/ +/*#define OP_XORASSIGN 29*/ +/*#define OP_ANDASSIGN 30*/ +#define OP_SELECT 31 +#define OP_LOGICALOR 32 +#define OP_LOGICALXOR 33 +#define OP_LOGICALAND 34 +/*#define OP_BITOR 35*/ +/*#define OP_BITXOR 36*/ +/*#define OP_BITAND 37*/ +#define OP_EQUAL 38 +#define OP_NOTEQUAL 39 +#define OP_LESS 40 +#define OP_GREATER 41 +#define OP_LESSEQUAL 42 +#define OP_GREATEREQUAL 43 +/*#define OP_LSHIFT 44*/ +/*#define OP_RSHIFT 45*/ +#define OP_ADD 46 +#define OP_SUBTRACT 47 +#define OP_MULTIPLY 48 +#define OP_DIVIDE 49 +/*#define OP_MODULUS 50*/ +#define OP_PREINCREMENT 51 +#define OP_PREDECREMENT 52 +#define OP_PLUS 53 +#define OP_MINUS 54 +/*#define OP_COMPLEMENT 55*/ +#define OP_NOT 56 +#define OP_SUBSCRIPT 57 +#define OP_CALL 58 +#define OP_FIELD 59 +#define OP_POSTINCREMENT 60 +#define OP_POSTDECREMENT 61 +#define OP_PRECISION 62 +#define OP_METHOD 63 + + +/** + * When parsing a compound production, this function is used to parse the + * children. + * For example, a while-loop compound will have two children, the + * while condition expression and the loop body. So, this function will + * be called twice to parse those two sub-expressions. + * \param C the parsing context + * \param O the output context + * \param oper the operation we're parsing + * \param statement indicates whether parsing a statement, or expression + * \return 1 if success, 0 if error + */ +static int +parse_child_operation(slang_parse_ctx * C, slang_output_ctx * O, + slang_operation * oper, GLboolean statement) +{ + slang_operation *ch; + + /* grow child array */ + ch = slang_operation_grow(&oper->num_children, &oper->children); + if (statement) + return parse_statement(C, O, ch); + return parse_expression(C, O, ch); +} + +static int parse_declaration(slang_parse_ctx * C, slang_output_ctx * O); + +static int +parse_statement(slang_parse_ctx * C, slang_output_ctx * O, + slang_operation * oper) +{ + int op; + + oper->locals->outer_scope = O->vars; + + op = *C->I++; + switch (op) { + case OP_BLOCK_BEGIN_NO_NEW_SCOPE: + /* parse child statements, do not create new variable scope */ + oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; + while (*C->I != OP_END) + if (!parse_child_operation(C, O, oper, GL_TRUE)) + RETURN0; + C->I++; + break; + case OP_BLOCK_BEGIN_NEW_SCOPE: + /* parse child statements, create new variable scope */ + { + slang_output_ctx o = *O; + + oper->type = SLANG_OPER_BLOCK_NEW_SCOPE; + o.vars = oper->locals; + while (*C->I != OP_END) + if (!parse_child_operation(C, &o, oper, GL_TRUE)) + RETURN0; + C->I++; + } + break; + case OP_DECLARE: + /* local variable declaration, individual declarators are stored as + * children identifiers + */ + oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; + { + const unsigned int first_var = O->vars->num_variables; + + /* parse the declaration, note that there can be zero or more + * than one declarators + */ + if (!parse_declaration(C, O)) + RETURN0; + if (first_var < O->vars->num_variables) { + const unsigned int num_vars = O->vars->num_variables - first_var; + unsigned int i; + assert(oper->num_children == 0); + oper->num_children = num_vars; + oper->children = slang_operation_new(num_vars); + if (oper->children == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + for (i = first_var; i < O->vars->num_variables; i++) { + slang_operation *o = &oper->children[i - first_var]; + slang_variable *var = O->vars->variables[i]; + o->type = SLANG_OPER_VARIABLE_DECL; + o->locals->outer_scope = O->vars; + o->a_id = var->a_name; + + /* new/someday... + calculate_var_size(C, O, var); + */ + + if (!legal_identifier(o->a_id)) { + slang_info_log_error(C->L, "illegal variable name '%s'", + (char *) o->a_id); + RETURN0; + } + } + } + } + break; + case OP_ASM: + /* the __asm statement, parse the mnemonic and all its arguments + * as expressions + */ + oper->type = SLANG_OPER_ASM; + oper->a_id = parse_identifier(C); + if (oper->a_id == SLANG_ATOM_NULL) + RETURN0; + while (*C->I != OP_END) { + if (!parse_child_operation(C, O, oper, GL_FALSE)) + RETURN0; + } + C->I++; + break; + case OP_BREAK: + oper->type = SLANG_OPER_BREAK; + break; + case OP_CONTINUE: + oper->type = SLANG_OPER_CONTINUE; + break; + case OP_DISCARD: + oper->type = SLANG_OPER_DISCARD; + break; + case OP_RETURN: + oper->type = SLANG_OPER_RETURN; + if (!parse_child_operation(C, O, oper, GL_FALSE)) + RETURN0; + break; + case OP_EXPRESSION: + oper->type = SLANG_OPER_EXPRESSION; + if (!parse_child_operation(C, O, oper, GL_FALSE)) + RETURN0; + break; + case OP_IF: + oper->type = SLANG_OPER_IF; + if (!parse_child_operation(C, O, oper, GL_FALSE)) + RETURN0; + if (!parse_child_operation(C, O, oper, GL_TRUE)) + RETURN0; + if (!parse_child_operation(C, O, oper, GL_TRUE)) + RETURN0; + break; + case OP_WHILE: + { + slang_output_ctx o = *O; + + oper->type = SLANG_OPER_WHILE; + o.vars = oper->locals; + if (!parse_child_operation(C, &o, oper, GL_TRUE)) + RETURN0; + if (!parse_child_operation(C, &o, oper, GL_TRUE)) + RETURN0; + } + break; + case OP_DO: + oper->type = SLANG_OPER_DO; + if (!parse_child_operation(C, O, oper, GL_TRUE)) + RETURN0; + if (!parse_child_operation(C, O, oper, GL_FALSE)) + RETURN0; + break; + case OP_FOR: + { + slang_output_ctx o = *O; + + oper->type = SLANG_OPER_FOR; + o.vars = oper->locals; + if (!parse_child_operation(C, &o, oper, GL_TRUE)) + RETURN0; + if (!parse_child_operation(C, &o, oper, GL_TRUE)) + RETURN0; + if (!parse_child_operation(C, &o, oper, GL_FALSE)) + RETURN0; + if (!parse_child_operation(C, &o, oper, GL_TRUE)) + RETURN0; + } + break; + case OP_PRECISION: + { + /* set default precision for a type in this scope */ + /* ignored at this time */ + int prec_qual = *C->I++; + int datatype = *C->I++; + (void) prec_qual; + (void) datatype; + } + break; + default: + /*printf("Unexpected operation %d\n", op);*/ + RETURN0; + } + return 1; +} + +static int +handle_nary_expression(slang_parse_ctx * C, slang_operation * op, + slang_operation ** ops, unsigned int *total_ops, + unsigned int n) +{ + unsigned int i; + + op->children = slang_operation_new(n); + if (op->children == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + op->num_children = n; + + for (i = 0; i < n; i++) { + slang_operation_destruct(&op->children[i]); + op->children[i] = (*ops)[*total_ops - (n + 1 - i)]; + } + + (*ops)[*total_ops - (n + 1)] = (*ops)[*total_ops - 1]; + *total_ops -= n; + + *ops = (slang_operation *) + _slang_realloc(*ops, + (*total_ops + n) * sizeof(slang_operation), + *total_ops * sizeof(slang_operation)); + if (*ops == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + return 1; +} + +static int +is_constructor_name(const char *name, slang_atom a_name, + slang_struct_scope * structs) +{ + if (slang_type_specifier_type_from_string(name) != SLANG_SPEC_VOID) + return 1; + return slang_struct_scope_find(structs, a_name, 1) != NULL; +} + +#define FUNCTION_CALL_NONARRAY 0 +#define FUNCTION_CALL_ARRAY 1 + +static int +parse_expression(slang_parse_ctx * C, slang_output_ctx * O, + slang_operation * oper) +{ + slang_operation *ops = NULL; + unsigned int num_ops = 0; + int number; + + while (*C->I != OP_END) { + slang_operation *op; + const unsigned int op_code = *C->I++; + + /* allocate default operation, becomes a no-op if not used */ + ops = (slang_operation *) + _slang_realloc(ops, + num_ops * sizeof(slang_operation), + (num_ops + 1) * sizeof(slang_operation)); + if (ops == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + op = &ops[num_ops]; + if (!slang_operation_construct(op)) { + slang_info_log_memory(C->L); + RETURN0; + } + num_ops++; + op->locals->outer_scope = O->vars; + + switch (op_code) { + case OP_PUSH_VOID: + op->type = SLANG_OPER_VOID; + break; + case OP_PUSH_BOOL: + op->type = SLANG_OPER_LITERAL_BOOL; + if (!parse_number(C, &number)) + RETURN0; + op->literal[0] = + op->literal[1] = + op->literal[2] = + op->literal[3] = (GLfloat) number; + op->literal_size = 1; + break; + case OP_PUSH_INT: + op->type = SLANG_OPER_LITERAL_INT; + if (!parse_number(C, &number)) + RETURN0; + op->literal[0] = + op->literal[1] = + op->literal[2] = + op->literal[3] = (GLfloat) number; + op->literal_size = 1; + break; + case OP_PUSH_FLOAT: + op->type = SLANG_OPER_LITERAL_FLOAT; + if (!parse_float(C, &op->literal[0])) + RETURN0; + op->literal[1] = + op->literal[2] = + op->literal[3] = op->literal[0]; + op->literal_size = 1; + break; + case OP_PUSH_IDENTIFIER: + op->type = SLANG_OPER_IDENTIFIER; + op->a_id = parse_identifier(C); + if (op->a_id == SLANG_ATOM_NULL) + RETURN0; + break; + case OP_SEQUENCE: + op->type = SLANG_OPER_SEQUENCE; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_ASSIGN: + op->type = SLANG_OPER_ASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_ADDASSIGN: + op->type = SLANG_OPER_ADDASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_SUBASSIGN: + op->type = SLANG_OPER_SUBASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_MULASSIGN: + op->type = SLANG_OPER_MULASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_DIVASSIGN: + op->type = SLANG_OPER_DIVASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + /*case OP_MODASSIGN: */ + /*case OP_LSHASSIGN: */ + /*case OP_RSHASSIGN: */ + /*case OP_ORASSIGN: */ + /*case OP_XORASSIGN: */ + /*case OP_ANDASSIGN: */ + case OP_SELECT: + op->type = SLANG_OPER_SELECT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 3)) + RETURN0; + break; + case OP_LOGICALOR: + op->type = SLANG_OPER_LOGICALOR; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_LOGICALXOR: + op->type = SLANG_OPER_LOGICALXOR; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_LOGICALAND: + op->type = SLANG_OPER_LOGICALAND; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + /*case OP_BITOR: */ + /*case OP_BITXOR: */ + /*case OP_BITAND: */ + case OP_EQUAL: + op->type = SLANG_OPER_EQUAL; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_NOTEQUAL: + op->type = SLANG_OPER_NOTEQUAL; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_LESS: + op->type = SLANG_OPER_LESS; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_GREATER: + op->type = SLANG_OPER_GREATER; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_LESSEQUAL: + op->type = SLANG_OPER_LESSEQUAL; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_GREATEREQUAL: + op->type = SLANG_OPER_GREATEREQUAL; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + /*case OP_LSHIFT: */ + /*case OP_RSHIFT: */ + case OP_ADD: + op->type = SLANG_OPER_ADD; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_SUBTRACT: + op->type = SLANG_OPER_SUBTRACT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_MULTIPLY: + op->type = SLANG_OPER_MULTIPLY; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_DIVIDE: + op->type = SLANG_OPER_DIVIDE; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + /*case OP_MODULUS: */ + case OP_PREINCREMENT: + op->type = SLANG_OPER_PREINCREMENT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + case OP_PREDECREMENT: + op->type = SLANG_OPER_PREDECREMENT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + case OP_PLUS: + op->type = SLANG_OPER_PLUS; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + case OP_MINUS: + op->type = SLANG_OPER_MINUS; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + case OP_NOT: + op->type = SLANG_OPER_NOT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + /*case OP_COMPLEMENT: */ + case OP_SUBSCRIPT: + op->type = SLANG_OPER_SUBSCRIPT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + RETURN0; + break; + case OP_METHOD: + op->type = SLANG_OPER_METHOD; + op->a_obj = parse_identifier(C); + if (op->a_obj == SLANG_ATOM_NULL) + RETURN0; + + op->a_id = parse_identifier(C); + if (op->a_id == SLANG_ATOM_NULL) + RETURN0; + + assert(*C->I == OP_END); + C->I++; + + while (*C->I != OP_END) + if (!parse_child_operation(C, O, op, GL_FALSE)) + RETURN0; + C->I++; +#if 0 + /* don't lookup the method (not yet anyway) */ + if (!C->parsing_builtin + && !slang_function_scope_find_by_name(O->funs, op->a_id, 1)) { + const char *id; + + id = slang_atom_pool_id(C->atoms, op->a_id); + if (!is_constructor_name(id, op->a_id, O->structs)) { + slang_info_log_error(C->L, "%s: undeclared function name.", id); + RETURN0; + } + } +#endif + break; + case OP_CALL: + { + GLboolean array_constructor = GL_FALSE; + GLint array_constructor_size = 0; + + op->type = SLANG_OPER_CALL; + op->a_id = parse_identifier(C); + if (op->a_id == SLANG_ATOM_NULL) + RETURN0; + switch (*C->I++) { + case FUNCTION_CALL_NONARRAY: + /* Nothing to do. */ + break; + case FUNCTION_CALL_ARRAY: + /* Calling an array constructor. For example: + * float[3](1.1, 2.2, 3.3); + */ + if (!O->allow_array_types) { + slang_info_log_error(C->L, + "array constructors not allowed " + "in this GLSL version"); + RETURN0; + } + else { + /* parse the array constructor size */ + slang_operation array_size; + array_constructor = GL_TRUE; + slang_operation_construct(&array_size); + if (!parse_expression(C, O, &array_size)) { + slang_operation_destruct(&array_size); + return GL_FALSE; + } + if (array_size.type != SLANG_OPER_LITERAL_INT) { + slang_info_log_error(C->L, + "constructor array size is not an integer"); + slang_operation_destruct(&array_size); + RETURN0; + } + array_constructor_size = (int) array_size.literal[0]; + op->array_constructor = GL_TRUE; + slang_operation_destruct(&array_size); + } + break; + default: + assert(0); + RETURN0; + } + while (*C->I != OP_END) + if (!parse_child_operation(C, O, op, GL_FALSE)) + RETURN0; + C->I++; + + if (array_constructor && + array_constructor_size != op->num_children) { + slang_info_log_error(C->L, "number of parameters to array" + " constructor does not match array size"); + RETURN0; + } + + if (!C->parsing_builtin + && !slang_function_scope_find_by_name(O->funs, op->a_id, 1)) { + const char *id; + + id = slang_atom_pool_id(C->atoms, op->a_id); + if (!is_constructor_name(id, op->a_id, O->structs)) { + slang_info_log_error(C->L, "%s: undeclared function name.", id); + RETURN0; + } + } + } + break; + case OP_FIELD: + op->type = SLANG_OPER_FIELD; + op->a_id = parse_identifier(C); + if (op->a_id == SLANG_ATOM_NULL) + RETURN0; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + case OP_POSTINCREMENT: + op->type = SLANG_OPER_POSTINCREMENT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + case OP_POSTDECREMENT: + op->type = SLANG_OPER_POSTDECREMENT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + RETURN0; + break; + default: + RETURN0; + } + } + C->I++; + + slang_operation_destruct(oper); + *oper = *ops; /* struct copy */ + _slang_free(ops); + + return 1; +} + +/* parameter qualifier */ +#define PARAM_QUALIFIER_IN 0 +#define PARAM_QUALIFIER_OUT 1 +#define PARAM_QUALIFIER_INOUT 2 + +/* function parameter array presence */ +#define PARAMETER_ARRAY_NOT_PRESENT 0 +#define PARAMETER_ARRAY_PRESENT 1 + +static int +parse_parameter_declaration(slang_parse_ctx * C, slang_output_ctx * O, + slang_variable * param) +{ + int param_qual, precision_qual; + + /* parse and validate the parameter's type qualifiers (there can be + * two at most) because not all combinations are valid + */ + if (!parse_type_qualifier(C, ¶m->type.qualifier)) + RETURN0; + + param_qual = *C->I++; + switch (param_qual) { + case PARAM_QUALIFIER_IN: + if (param->type.qualifier != SLANG_QUAL_CONST + && param->type.qualifier != SLANG_QUAL_NONE) { + slang_info_log_error(C->L, "Invalid type qualifier."); + RETURN0; + } + break; + case PARAM_QUALIFIER_OUT: + if (param->type.qualifier == SLANG_QUAL_NONE) + param->type.qualifier = SLANG_QUAL_OUT; + else { + slang_info_log_error(C->L, "Invalid type qualifier."); + RETURN0; + } + break; + case PARAM_QUALIFIER_INOUT: + if (param->type.qualifier == SLANG_QUAL_NONE) + param->type.qualifier = SLANG_QUAL_INOUT; + else { + slang_info_log_error(C->L, "Invalid type qualifier."); + RETURN0; + } + break; + default: + RETURN0; + } + + /* parse precision qualifier (lowp, mediump, highp */ + precision_qual = *C->I++; + /* ignored at this time */ + (void) precision_qual; + + /* parse parameter's type specifier and name */ + if (!parse_type_specifier(C, O, ¶m->type.specifier)) + RETURN0; + if (!parse_type_array_size(C, O, ¶m->type.array_len)) + RETURN0; + param->a_name = parse_identifier(C); + if (param->a_name == SLANG_ATOM_NULL) + RETURN0; + + /* first-class array + */ + if (param->type.array_len >= 0) { + slang_type_specifier p; + + slang_type_specifier_ctr(&p); + if (!slang_type_specifier_copy(&p, ¶m->type.specifier)) { + slang_type_specifier_dtr(&p); + RETURN0; + } + if (!convert_to_array(C, param, &p)) { + slang_type_specifier_dtr(&p); + RETURN0; + } + slang_type_specifier_dtr(&p); + param->array_len = param->type.array_len; + } + + /* if the parameter is an array, parse its size (the size must be + * explicitly defined + */ + if (*C->I++ == PARAMETER_ARRAY_PRESENT) { + slang_type_specifier p; + + if (param->type.array_len >= 0) { + slang_info_log_error(C->L, "multi-dimensional arrays not allowed"); + RETURN0; + } + slang_type_specifier_ctr(&p); + if (!slang_type_specifier_copy(&p, ¶m->type.specifier)) { + slang_type_specifier_dtr(&p); + RETURN0; + } + if (!convert_to_array(C, param, &p)) { + slang_type_specifier_dtr(&p); + RETURN0; + } + slang_type_specifier_dtr(&p); + if (!parse_array_len(C, O, ¶m->array_len)) + RETURN0; + } + +#if 0 + /* calculate the parameter size */ + if (!calculate_var_size(C, O, param)) + RETURN0; +#endif + /* TODO: allocate the local address here? */ + return 1; +} + +/* function type */ +#define FUNCTION_ORDINARY 0 +#define FUNCTION_CONSTRUCTOR 1 +#define FUNCTION_OPERATOR 2 + +/* function parameter */ +#define PARAMETER_NONE 0 +#define PARAMETER_NEXT 1 + +/* operator type */ +#define OPERATOR_ADDASSIGN 1 +#define OPERATOR_SUBASSIGN 2 +#define OPERATOR_MULASSIGN 3 +#define OPERATOR_DIVASSIGN 4 +/*#define OPERATOR_MODASSIGN 5*/ +/*#define OPERATOR_LSHASSIGN 6*/ +/*#define OPERATOR_RSHASSIGN 7*/ +/*#define OPERATOR_ANDASSIGN 8*/ +/*#define OPERATOR_XORASSIGN 9*/ +/*#define OPERATOR_ORASSIGN 10*/ +#define OPERATOR_LOGICALXOR 11 +/*#define OPERATOR_BITOR 12*/ +/*#define OPERATOR_BITXOR 13*/ +/*#define OPERATOR_BITAND 14*/ +#define OPERATOR_LESS 15 +#define OPERATOR_GREATER 16 +#define OPERATOR_LESSEQUAL 17 +#define OPERATOR_GREATEREQUAL 18 +/*#define OPERATOR_LSHIFT 19*/ +/*#define OPERATOR_RSHIFT 20*/ +#define OPERATOR_MULTIPLY 21 +#define OPERATOR_DIVIDE 22 +/*#define OPERATOR_MODULUS 23*/ +#define OPERATOR_INCREMENT 24 +#define OPERATOR_DECREMENT 25 +#define OPERATOR_PLUS 26 +#define OPERATOR_MINUS 27 +/*#define OPERATOR_COMPLEMENT 28*/ +#define OPERATOR_NOT 29 + +static const struct +{ + unsigned int o_code; + const char *o_name; +} operator_names[] = { + {OPERATOR_INCREMENT, "++"}, + {OPERATOR_ADDASSIGN, "+="}, + {OPERATOR_PLUS, "+"}, + {OPERATOR_DECREMENT, "--"}, + {OPERATOR_SUBASSIGN, "-="}, + {OPERATOR_MINUS, "-"}, + {OPERATOR_NOT, "!"}, + {OPERATOR_MULASSIGN, "*="}, + {OPERATOR_MULTIPLY, "*"}, + {OPERATOR_DIVASSIGN, "/="}, + {OPERATOR_DIVIDE, "/"}, + {OPERATOR_LESSEQUAL, "<="}, + /*{ OPERATOR_LSHASSIGN, "<<=" }, */ + /*{ OPERATOR_LSHIFT, "<<" }, */ + {OPERATOR_LESS, "<"}, + {OPERATOR_GREATEREQUAL, ">="}, + /*{ OPERATOR_RSHASSIGN, ">>=" }, */ + /*{ OPERATOR_RSHIFT, ">>" }, */ + {OPERATOR_GREATER, ">"}, + /*{ OPERATOR_MODASSIGN, "%=" }, */ + /*{ OPERATOR_MODULUS, "%" }, */ + /*{ OPERATOR_ANDASSIGN, "&=" }, */ + /*{ OPERATOR_BITAND, "&" }, */ + /*{ OPERATOR_ORASSIGN, "|=" }, */ + /*{ OPERATOR_BITOR, "|" }, */ + /*{ OPERATOR_COMPLEMENT, "~" }, */ + /*{ OPERATOR_XORASSIGN, "^=" }, */ + {OPERATOR_LOGICALXOR, "^^"}, + /*{ OPERATOR_BITXOR, "^" } */ +}; + +static slang_atom +parse_operator_name(slang_parse_ctx * C) +{ + unsigned int i; + + for (i = 0; i < sizeof(operator_names) / sizeof(*operator_names); i++) { + if (operator_names[i].o_code == (unsigned int) (*C->I)) { + slang_atom atom = + slang_atom_pool_atom(C->atoms, operator_names[i].o_name); + if (atom == SLANG_ATOM_NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + C->I++; + return atom; + } + } + RETURN0; +} + + +static int +parse_function_prototype(slang_parse_ctx * C, slang_output_ctx * O, + slang_function * func) +{ + GLuint functype; + /* parse function type and name */ + if (!parse_fully_specified_type(C, O, &func->header.type)) + RETURN0; + + functype = *C->I++; + switch (functype) { + case FUNCTION_ORDINARY: + func->kind = SLANG_FUNC_ORDINARY; + func->header.a_name = parse_identifier(C); + if (func->header.a_name == SLANG_ATOM_NULL) + RETURN0; + break; + case FUNCTION_CONSTRUCTOR: + func->kind = SLANG_FUNC_CONSTRUCTOR; + if (func->header.type.specifier.type == SLANG_SPEC_STRUCT) + RETURN0; + func->header.a_name = + slang_atom_pool_atom(C->atoms, + slang_type_specifier_type_to_string + (func->header.type.specifier.type)); + if (func->header.a_name == SLANG_ATOM_NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + break; + case FUNCTION_OPERATOR: + func->kind = SLANG_FUNC_OPERATOR; + func->header.a_name = parse_operator_name(C); + if (func->header.a_name == SLANG_ATOM_NULL) + RETURN0; + break; + default: + RETURN0; + } + + if (!legal_identifier(func->header.a_name)) { + slang_info_log_error(C->L, "illegal function name '%s'", + (char *) func->header.a_name); + RETURN0; + } + + /* parse function parameters */ + while (*C->I++ == PARAMETER_NEXT) { + slang_variable *p = slang_variable_scope_grow(func->parameters); + if (!p) { + slang_info_log_memory(C->L); + RETURN0; + } + if (!parse_parameter_declaration(C, O, p)) + RETURN0; + } + + /* if the function returns a value, append a hidden __retVal 'out' + * parameter that corresponds to the return value. + */ + if (_slang_function_has_return_value(func)) { + slang_variable *p = slang_variable_scope_grow(func->parameters); + slang_atom a_retVal = slang_atom_pool_atom(C->atoms, "__retVal"); + assert(a_retVal); + p->a_name = a_retVal; + p->type = func->header.type; + p->type.qualifier = SLANG_QUAL_OUT; + } + + /* function formal parameters and local variables share the same + * scope, so save the information about param count in a seperate + * place also link the scope to the global variable scope so when a + * given identifier is not found here, the search process continues + * in the global space + */ + func->param_count = func->parameters->num_variables; + func->parameters->outer_scope = O->vars; + + return 1; +} + +static int +parse_function_definition(slang_parse_ctx * C, slang_output_ctx * O, + slang_function * func) +{ + slang_output_ctx o = *O; + + if (!parse_function_prototype(C, O, func)) + RETURN0; + + /* create function's body operation */ + func->body = (slang_operation *) _slang_alloc(sizeof(slang_operation)); + if (func->body == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + if (!slang_operation_construct(func->body)) { + _slang_free(func->body); + func->body = NULL; + slang_info_log_memory(C->L); + RETURN0; + } + + /* to parse the body the parse context is modified in order to + * capture parsed variables into function's local variable scope + */ + C->global_scope = GL_FALSE; + o.vars = func->parameters; + if (!parse_statement(C, &o, func->body)) + RETURN0; + + C->global_scope = GL_TRUE; + return 1; +} + +static GLboolean +initialize_global(slang_assemble_ctx * A, slang_variable * var) +{ + slang_operation op_id, op_assign; + GLboolean result; + + /* construct the left side of assignment */ + if (!slang_operation_construct(&op_id)) + return GL_FALSE; + op_id.type = SLANG_OPER_IDENTIFIER; + op_id.a_id = var->a_name; + + /* put the variable into operation's scope */ + op_id.locals->variables = + (slang_variable **) _slang_alloc(sizeof(slang_variable *)); + if (op_id.locals->variables == NULL) { + slang_operation_destruct(&op_id); + return GL_FALSE; + } + op_id.locals->num_variables = 1; + op_id.locals->variables[0] = var; + + /* construct the assignment expression */ + if (!slang_operation_construct(&op_assign)) { + op_id.locals->num_variables = 0; + slang_operation_destruct(&op_id); + return GL_FALSE; + } + op_assign.type = SLANG_OPER_ASSIGN; + op_assign.children = + (slang_operation *) _slang_alloc(2 * sizeof(slang_operation)); + if (op_assign.children == NULL) { + slang_operation_destruct(&op_assign); + op_id.locals->num_variables = 0; + slang_operation_destruct(&op_id); + return GL_FALSE; + } + op_assign.num_children = 2; + op_assign.children[0] = op_id; + op_assign.children[1] = *var->initializer; + + result = 1; + + /* carefully destroy the operations */ + op_assign.num_children = 0; + _slang_free(op_assign.children); + op_assign.children = NULL; + slang_operation_destruct(&op_assign); + op_id.locals->num_variables = 0; + slang_operation_destruct(&op_id); + + if (!result) + return GL_FALSE; + + return GL_TRUE; +} + +/* init declarator list */ +#define DECLARATOR_NONE 0 +#define DECLARATOR_NEXT 1 + +/* variable declaration */ +#define VARIABLE_NONE 0 +#define VARIABLE_IDENTIFIER 1 +#define VARIABLE_INITIALIZER 2 +#define VARIABLE_ARRAY_EXPLICIT 3 +#define VARIABLE_ARRAY_UNKNOWN 4 + + +/** + * Parse the initializer for a variable declaration. + */ +static int +parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, + const slang_fully_specified_type * type) +{ + GET_CURRENT_CONTEXT(ctx); /* a hack */ + slang_variable *var; + slang_atom a_name; + + /* empty init declatator (without name, e.g. "float ;") */ + if (*C->I++ == VARIABLE_NONE) + return 1; + + a_name = parse_identifier(C); + + /* check if name is already in this scope */ + if (_slang_variable_locate(O->vars, a_name, GL_FALSE)) { + slang_info_log_error(C->L, + "declaration of '%s' conflicts with previous declaration", + (char *) a_name); + RETURN0; + } + + /* make room for the new variable and initialize it */ + var = slang_variable_scope_grow(O->vars); + if (!var) { + slang_info_log_memory(C->L); + RETURN0; + } + + /* copy the declarator type qualifier/etc info, parse the identifier */ + var->type.qualifier = type->qualifier; + var->type.centroid = type->centroid; + var->type.precision = type->precision; + var->type.variant = type->variant; + var->type.array_len = type->array_len; + var->a_name = a_name; + if (var->a_name == SLANG_ATOM_NULL) + RETURN0; + + switch (*C->I++) { + case VARIABLE_NONE: + /* simple variable declarator - just copy the specifier */ + if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier)) + RETURN0; + break; + case VARIABLE_INITIALIZER: + /* initialized variable - copy the specifier and parse the expression */ + if (0 && type->array_len >= 0) { + /* The type was something like "float[4]" */ + convert_to_array(C, var, &type->specifier); + var->array_len = type->array_len; + } + else { + if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier)) + RETURN0; + } + var->initializer = + (slang_operation *) _slang_alloc(sizeof(slang_operation)); + if (var->initializer == NULL) { + slang_info_log_memory(C->L); + RETURN0; + } + if (!slang_operation_construct(var->initializer)) { + _slang_free(var->initializer); + var->initializer = NULL; + slang_info_log_memory(C->L); + RETURN0; + } + if (!parse_expression(C, O, var->initializer)) + RETURN0; + break; + case VARIABLE_ARRAY_UNKNOWN: + /* unsized array - mark it as array and copy the specifier to + * the array element + */ + if (type->array_len >= 0) { + slang_info_log_error(C->L, "multi-dimensional arrays not allowed"); + RETURN0; + } + if (!convert_to_array(C, var, &type->specifier)) + return GL_FALSE; + break; + case VARIABLE_ARRAY_EXPLICIT: + if (type->array_len >= 0) { + /* the user is trying to do something like: float[2] x[3]; */ + slang_info_log_error(C->L, "multi-dimensional arrays not allowed"); + RETURN0; + } + if (!convert_to_array(C, var, &type->specifier)) + return GL_FALSE; + if (!parse_array_len(C, O, &var->array_len)) + return GL_FALSE; + break; + default: + RETURN0; + } + + /* allocate global address space for a variable with a known size */ + if (C->global_scope + && !(var->type.specifier.type == SLANG_SPEC_ARRAY + && var->array_len == 0)) { + if (!calculate_var_size(C, O, var)) + return GL_FALSE; + } + + /* emit code for global var decl */ + if (C->global_scope) { + slang_assemble_ctx A; + memset(&A, 0, sizeof(slang_assemble_ctx)); + A.atoms = C->atoms; + A.space.funcs = O->funs; + A.space.structs = O->structs; + A.space.vars = O->vars; + A.program = O->program; + A.pragmas = O->pragmas; + A.vartable = O->vartable; + A.log = C->L; + A.curFuncEndLabel = NULL; + A.EmitContReturn = ctx->Shader.EmitContReturn; + if (!_slang_codegen_global_variable(&A, var, C->type)) + RETURN0; + } + + /* initialize global variable */ + if (C->global_scope) { + if (var->initializer != NULL) { + slang_assemble_ctx A; + memset(&A, 0, sizeof(slang_assemble_ctx)); + A.atoms = C->atoms; + A.space.funcs = O->funs; + A.space.structs = O->structs; + A.space.vars = O->vars; + if (!initialize_global(&A, var)) + RETURN0; + } + } + return 1; +} + +/** + * Parse a list of variable declarations. Each variable may have an + * initializer. + */ +static int +parse_init_declarator_list(slang_parse_ctx * C, slang_output_ctx * O) +{ + slang_fully_specified_type type; + + /* parse the fully specified type, common to all declarators */ + if (!slang_fully_specified_type_construct(&type)) + RETURN0; + if (!parse_fully_specified_type(C, O, &type)) { + slang_fully_specified_type_destruct(&type); + RETURN0; + } + + /* parse declarators, pass-in the parsed type */ + do { + if (!parse_init_declarator(C, O, &type)) { + slang_fully_specified_type_destruct(&type); + RETURN0; + } + } + while (*C->I++ == DECLARATOR_NEXT); + + slang_fully_specified_type_destruct(&type); + return 1; +} + + +/** + * Parse a function definition or declaration. + * \param C parsing context + * \param O output context + * \param definition if non-zero expect a definition, else a declaration + * \param parsed_func_ret returns the parsed function + * \return GL_TRUE if success, GL_FALSE if failure + */ +static GLboolean +parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition, + slang_function ** parsed_func_ret) +{ + slang_function parsed_func, *found_func; + + /* parse function definition/declaration */ + if (!slang_function_construct(&parsed_func)) + return GL_FALSE; + if (definition) { + if (!parse_function_definition(C, O, &parsed_func)) { + slang_function_destruct(&parsed_func); + return GL_FALSE; + } + } + else { + if (!parse_function_prototype(C, O, &parsed_func)) { + slang_function_destruct(&parsed_func); + return GL_FALSE; + } + } + + /* find a function with a prototype matching the parsed one - only + * the current scope is being searched to allow built-in function + * overriding + */ + found_func = slang_function_scope_find(O->funs, &parsed_func, 0); + if (found_func == NULL) { + /* New function, add it to the function list */ + O->funs->functions = + (slang_function *) _slang_realloc(O->funs->functions, + O->funs->num_functions + * sizeof(slang_function), + (O->funs->num_functions + 1) + * sizeof(slang_function)); + if (O->funs->functions == NULL) { + /* Make sure that there are no functions marked, as the + * allocation is currently NULL, in order to avoid + * a potental segfault as we clean up later. + */ + O->funs->num_functions = 0; + + slang_info_log_memory(C->L); + slang_function_destruct(&parsed_func); + return GL_FALSE; + } + O->funs->functions[O->funs->num_functions] = parsed_func; + O->funs->num_functions++; + + /* return the newly parsed function */ + *parsed_func_ret = &O->funs->functions[O->funs->num_functions - 1]; + } + else { + /* previously defined or declared */ + /* TODO: check function return type qualifiers and specifiers */ + if (definition) { + if (found_func->body != NULL) { + slang_info_log_error(C->L, "%s: function already has a body.", + slang_atom_pool_id(C->atoms, + parsed_func.header. + a_name)); + slang_function_destruct(&parsed_func); + return GL_FALSE; + } + + /* destroy the existing function declaration and replace it + * with the new one + */ + slang_function_destruct(found_func); + *found_func = parsed_func; + } + else { + /* another declaration of the same function prototype - ignore it */ + slang_function_destruct(&parsed_func); + } + + /* return the found function */ + *parsed_func_ret = found_func; + } + + return GL_TRUE; +} + +/* declaration */ +#define DECLARATION_FUNCTION_PROTOTYPE 1 +#define DECLARATION_INIT_DECLARATOR_LIST 2 + +static int +parse_declaration(slang_parse_ctx * C, slang_output_ctx * O) +{ + switch (*C->I++) { + case DECLARATION_INIT_DECLARATOR_LIST: + if (!parse_init_declarator_list(C, O)) + RETURN0; + break; + case DECLARATION_FUNCTION_PROTOTYPE: + { + slang_function *dummy_func; + + if (!parse_function(C, O, 0, &dummy_func)) + RETURN0; + } + break; + default: + RETURN0; + } + return 1; +} + +static int +parse_default_precision(slang_parse_ctx * C, slang_output_ctx * O) +{ + int precision, type; + + if (!O->allow_precision) { + slang_info_log_error(C->L, "syntax error at \"precision\""); + RETURN0; + } + + precision = *C->I++; + switch (precision) { + case PRECISION_LOW: + case PRECISION_MEDIUM: + case PRECISION_HIGH: + /* OK */ + break; + default: + _mesa_problem(NULL, "unexpected precision %d at %s:%d\n", + precision, __FILE__, __LINE__); + RETURN0; + } + + type = *C->I++; + switch (type) { + case TYPE_SPECIFIER_FLOAT: + case TYPE_SPECIFIER_INT: + case TYPE_SPECIFIER_SAMPLER1D: + case TYPE_SPECIFIER_SAMPLER2D: + case TYPE_SPECIFIER_SAMPLER3D: + case TYPE_SPECIFIER_SAMPLERCUBE: + case TYPE_SPECIFIER_SAMPLER1DSHADOW: + case TYPE_SPECIFIER_SAMPLER2DSHADOW: + case TYPE_SPECIFIER_SAMPLER2DRECT: + case TYPE_SPECIFIER_SAMPLER2DRECTSHADOW: + /* OK */ + break; + default: + _mesa_problem(NULL, "unexpected type %d at %s:%d\n", + type, __FILE__, __LINE__); + RETURN0; + } + + assert(type < TYPE_SPECIFIER_COUNT); + O->default_precision[type] = precision; + + return 1; +} + + +/** + * Initialize the default precision for all types. + * XXX this info isn't used yet. + */ +static void +init_default_precision(slang_output_ctx *O, slang_unit_type type) +{ + GLuint i; + for (i = 0; i < TYPE_SPECIFIER_COUNT; i++) { +#if FEATURE_es2_glsl + O->default_precision[i] = PRECISION_LOW; +#else + O->default_precision[i] = PRECISION_HIGH; +#endif + } + + if (type == SLANG_UNIT_VERTEX_SHADER) { + O->default_precision[TYPE_SPECIFIER_FLOAT] = PRECISION_HIGH; + O->default_precision[TYPE_SPECIFIER_INT] = PRECISION_HIGH; + } + else { + O->default_precision[TYPE_SPECIFIER_INT] = PRECISION_MEDIUM; + } +} + + +static int +parse_invariant(slang_parse_ctx * C, slang_output_ctx * O) +{ + if (O->allow_invariant) { + slang_atom *a = parse_identifier(C); + /* XXX not doing anything with this var yet */ + /*printf("ID: %s\n", (char*) a);*/ + return a ? 1 : 0; + } + else { + slang_info_log_error(C->L, "syntax error at \"invariant\""); + RETURN0; + } +} + + +/* external declaration or default precision specifier */ +#define EXTERNAL_NULL 0 +#define EXTERNAL_FUNCTION_DEFINITION 1 +#define EXTERNAL_DECLARATION 2 +#define DEFAULT_PRECISION 3 +#define INVARIANT_STMT 4 + + +static GLboolean +parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit, + struct gl_shader *shader) +{ + GET_CURRENT_CONTEXT(ctx); + slang_output_ctx o; + GLboolean success; + GLuint maxRegs; + slang_function *mainFunc = NULL; + + if (unit->type == SLANG_UNIT_FRAGMENT_BUILTIN || + unit->type == SLANG_UNIT_FRAGMENT_SHADER) { + maxRegs = ctx->Const.FragmentProgram.MaxTemps; + } + else { + assert(unit->type == SLANG_UNIT_VERTEX_BUILTIN || + unit->type == SLANG_UNIT_VERTEX_SHADER); + maxRegs = ctx->Const.VertexProgram.MaxTemps; + } + + /* setup output context */ + o.funs = &unit->funs; + o.structs = &unit->structs; + o.vars = &unit->vars; + o.program = shader ? shader->Program : NULL; + o.pragmas = shader ? &shader->Pragmas : NULL; + o.vartable = _slang_new_var_table(maxRegs); + _slang_push_var_table(o.vartable); + + /* allow 'invariant' keyword? */ +#if FEATURE_es2_glsl + o.allow_invariant = GL_TRUE; +#else + o.allow_invariant = (C->version >= 120) ? GL_TRUE : GL_FALSE; +#endif + + /* allow 'centroid' keyword? */ + o.allow_centroid = (C->version >= 120) ? GL_TRUE : GL_FALSE; + + /* allow 'lowp/mediump/highp' keywords? */ +#if FEATURE_es2_glsl + o.allow_precision = GL_TRUE; +#else + o.allow_precision = (C->version >= 120) ? GL_TRUE : GL_FALSE; +#endif + init_default_precision(&o, unit->type); + + /* allow 'float[]' keyword? */ + o.allow_array_types = (C->version >= 120) ? GL_TRUE : GL_FALSE; + + /* parse individual functions and declarations */ + while (*C->I != EXTERNAL_NULL) { + switch (*C->I++) { + case EXTERNAL_FUNCTION_DEFINITION: + { + slang_function *func; + success = parse_function(C, &o, 1, &func); + if (success && + _mesa_strcmp((char *) func->header.a_name, "main") == 0) { + /* found main() */ + mainFunc = func; + } + } + break; + case EXTERNAL_DECLARATION: + success = parse_declaration(C, &o); + break; + case DEFAULT_PRECISION: + success = parse_default_precision(C, &o); + break; + case INVARIANT_STMT: + success = parse_invariant(C, &o); + break; + default: + success = GL_FALSE; + } + + if (!success) { + /* xxx free codegen */ + _slang_pop_var_table(o.vartable); + return GL_FALSE; + } + } + C->I++; + + if (mainFunc) { + /* assemble (generate code) for main() */ + slang_assemble_ctx A; + memset(&A, 0, sizeof(slang_assemble_ctx)); + A.atoms = C->atoms; + A.space.funcs = o.funs; + A.space.structs = o.structs; + A.space.vars = o.vars; + A.program = o.program; + A.pragmas = &shader->Pragmas; + A.vartable = o.vartable; + A.EmitContReturn = ctx->Shader.EmitContReturn; + A.log = C->L; + + /* main() takes no parameters */ + if (mainFunc->param_count > 0) { + slang_info_log_error(A.log, "main() takes no arguments"); + return GL_FALSE; + } + + _slang_codegen_function(&A, mainFunc); + + shader->Main = GL_TRUE; /* this shader defines main() */ + + shader->UnresolvedRefs = A.UnresolvedRefs; + } + + _slang_pop_var_table(o.vartable); + _slang_delete_var_table(o.vartable); + + return GL_TRUE; +} + +static GLboolean +compile_binary(const byte * prod, slang_code_unit * unit, + GLuint version, + slang_unit_type type, slang_info_log * infolog, + slang_code_unit * builtin, slang_code_unit * downlink, + struct gl_shader *shader) +{ + slang_parse_ctx C; + + unit->type = type; + + /* setup parse context */ + C.I = prod; + C.L = infolog; + C.parsing_builtin = (builtin == NULL); + C.global_scope = GL_TRUE; + C.atoms = &unit->object->atompool; + C.type = type; + C.version = version; + + if (!check_revision(&C)) + return GL_FALSE; + + if (downlink != NULL) { + unit->vars.outer_scope = &downlink->vars; + unit->funs.outer_scope = &downlink->funs; + unit->structs.outer_scope = &downlink->structs; + } + + /* parse translation unit */ + return parse_code_unit(&C, unit, shader); +} + +static GLboolean +compile_with_grammar(grammar id, const char *source, slang_code_unit * unit, + slang_unit_type type, slang_info_log * infolog, + slang_code_unit * builtin, + struct gl_shader *shader, + const struct gl_extensions *extensions, + struct gl_sl_pragmas *pragmas) +{ + byte *prod; + GLuint size, start, version; + slang_string preprocessed; + GLuint maxVersion; + +#if FEATURE_ARB_shading_language_120 + maxVersion = 120; +#elif FEATURE_es2_glsl + maxVersion = 100; +#else + maxVersion = 110; +#endif + + /* First retrieve the version number. */ + if (!_slang_preprocess_version(source, &version, &start, infolog)) + return GL_FALSE; + + if (version > maxVersion) { + slang_info_log_error(infolog, + "language version %.2f is not supported.", + version * 0.01); + return GL_FALSE; + } + + /* Now preprocess the source string. */ + slang_string_init(&preprocessed); + if (!_slang_preprocess_directives(&preprocessed, &source[start], + infolog, extensions, pragmas)) { + slang_string_free(&preprocessed); + slang_info_log_error(infolog, "failed to preprocess the source."); + return GL_FALSE; + } + + /* Finally check the syntax and generate its binary representation. */ + if (!grammar_fast_check(id, + (const byte *) (slang_string_cstr(&preprocessed)), + &prod, &size, 65536)) { + char buf[1024]; + GLint pos; + + slang_string_free(&preprocessed); + grammar_get_last_error((byte *) (buf), sizeof(buf), &pos); + slang_info_log_error(infolog, buf); + /* syntax error (possibly in library code) */ +#if 0 + { + int line, col; + char *s; + s = (char *) _mesa_find_line_column((const GLubyte *) source, + (const GLubyte *) source + pos, + &line, &col); + printf("Error on line %d, col %d: %s\n", line, col, s); + } +#endif + return GL_FALSE; + } + slang_string_free(&preprocessed); + + /* Syntax is okay - translate it to internal representation. */ + if (!compile_binary(prod, unit, version, type, infolog, builtin, + &builtin[SLANG_BUILTIN_TOTAL - 1], + shader)) { + grammar_alloc_free(prod); + return GL_FALSE; + } + grammar_alloc_free(prod); + return GL_TRUE; +} + +LONGSTRING static const char *slang_shader_syn = +#include "library/slang_shader_syn.h" + ; + +static const byte slang_core_gc[] = { +#include "library/slang_core_gc.h" +}; + +static const byte slang_120_core_gc[] = { +#include "library/slang_120_core_gc.h" +}; + +static const byte slang_120_fragment_gc[] = { +#include "library/slang_builtin_120_fragment_gc.h" +}; + +static const byte slang_common_builtin_gc[] = { +#include "library/slang_common_builtin_gc.h" +}; + +static const byte slang_fragment_builtin_gc[] = { +#include "library/slang_fragment_builtin_gc.h" +}; + +static const byte slang_vertex_builtin_gc[] = { +#include "library/slang_vertex_builtin_gc.h" +}; + +static GLboolean +compile_object(grammar * id, const char *source, slang_code_object * object, + slang_unit_type type, slang_info_log * infolog, + struct gl_shader *shader, + const struct gl_extensions *extensions, + struct gl_sl_pragmas *pragmas) +{ + slang_code_unit *builtins = NULL; + GLuint base_version = 110; + + /* load GLSL grammar */ + *id = grammar_load_from_text((const byte *) (slang_shader_syn)); + if (*id == 0) { + byte buf[1024]; + int pos; + + grammar_get_last_error(buf, 1024, &pos); + slang_info_log_error(infolog, (const char *) (buf)); + return GL_FALSE; + } + + /* set shader type - the syntax is slightly different for different shaders */ + if (type == SLANG_UNIT_FRAGMENT_SHADER + || type == SLANG_UNIT_FRAGMENT_BUILTIN) + grammar_set_reg8(*id, (const byte *) "shader_type", 1); + else + grammar_set_reg8(*id, (const byte *) "shader_type", 2); + + /* enable language extensions */ + grammar_set_reg8(*id, (const byte *) "parsing_builtin", 1); + + /* if parsing user-specified shader, load built-in library */ + if (type == SLANG_UNIT_FRAGMENT_SHADER || type == SLANG_UNIT_VERTEX_SHADER) { + /* compile core functionality first */ + if (!compile_binary(slang_core_gc, + &object->builtin[SLANG_BUILTIN_CORE], + base_version, + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, + NULL, NULL, NULL)) + return GL_FALSE; + +#if FEATURE_ARB_shading_language_120 + if (!compile_binary(slang_120_core_gc, + &object->builtin[SLANG_BUILTIN_120_CORE], + 120, + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, + NULL, &object->builtin[SLANG_BUILTIN_CORE], NULL)) + return GL_FALSE; +#endif + + /* compile common functions and variables, link to core */ + if (!compile_binary(slang_common_builtin_gc, + &object->builtin[SLANG_BUILTIN_COMMON], +#if FEATURE_ARB_shading_language_120 + 120, +#else + base_version, +#endif + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, +#if FEATURE_ARB_shading_language_120 + &object->builtin[SLANG_BUILTIN_120_CORE], +#else + &object->builtin[SLANG_BUILTIN_CORE], +#endif + NULL)) + return GL_FALSE; + + /* compile target-specific functions and variables, link to common */ + if (type == SLANG_UNIT_FRAGMENT_SHADER) { + if (!compile_binary(slang_fragment_builtin_gc, + &object->builtin[SLANG_BUILTIN_TARGET], + base_version, + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, + &object->builtin[SLANG_BUILTIN_COMMON], NULL)) + return GL_FALSE; +#if FEATURE_ARB_shading_language_120 + if (!compile_binary(slang_120_fragment_gc, + &object->builtin[SLANG_BUILTIN_TARGET], + 120, + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, + &object->builtin[SLANG_BUILTIN_COMMON], NULL)) + return GL_FALSE; +#endif + } + else if (type == SLANG_UNIT_VERTEX_SHADER) { + if (!compile_binary(slang_vertex_builtin_gc, + &object->builtin[SLANG_BUILTIN_TARGET], + base_version, + SLANG_UNIT_VERTEX_BUILTIN, infolog, NULL, + &object->builtin[SLANG_BUILTIN_COMMON], NULL)) + return GL_FALSE; + } + + /* disable language extensions */ +#if NEW_SLANG /* allow-built-ins */ + grammar_set_reg8(*id, (const byte *) "parsing_builtin", 1); +#else + grammar_set_reg8(*id, (const byte *) "parsing_builtin", 0); +#endif + builtins = object->builtin; + } + + /* compile the actual shader - pass-in built-in library for external shader */ + return compile_with_grammar(*id, source, &object->unit, type, infolog, + builtins, shader, extensions, pragmas); +} + + +static GLboolean +compile_shader(GLcontext *ctx, slang_code_object * object, + slang_unit_type type, slang_info_log * infolog, + struct gl_shader *shader) +{ + GLboolean success; + grammar id = 0; + +#if 0 /* for debug */ + _mesa_printf("********* COMPILE SHADER ***********\n"); + _mesa_printf("%s\n", shader->Source); + _mesa_printf("************************************\n"); +#endif + + assert(shader->Program); + + _slang_code_object_dtr(object); + _slang_code_object_ctr(object); + + success = compile_object(&id, shader->Source, object, type, infolog, shader, + &ctx->Extensions, &shader->Pragmas); + if (id != 0) + grammar_destroy(id); + if (!success) + return GL_FALSE; + + return GL_TRUE; +} + + + +GLboolean +_slang_compile(GLcontext *ctx, struct gl_shader *shader) +{ + GLboolean success; + slang_info_log info_log; + slang_code_object obj; + slang_unit_type type; + + if (shader->Type == GL_VERTEX_SHADER) { + type = SLANG_UNIT_VERTEX_SHADER; + } + else { + assert(shader->Type == GL_FRAGMENT_SHADER); + type = SLANG_UNIT_FRAGMENT_SHADER; + } + + if (!shader->Source) + return GL_FALSE; + + ctx->Shader.MemPool = _slang_new_mempool(1024*1024); + + shader->Main = GL_FALSE; + + if (!shader->Program) { + GLenum progTarget; + if (shader->Type == GL_VERTEX_SHADER) + progTarget = GL_VERTEX_PROGRAM_ARB; + else + progTarget = GL_FRAGMENT_PROGRAM_ARB; + shader->Program = ctx->Driver.NewProgram(ctx, progTarget, 1); + shader->Program->Parameters = _mesa_new_parameter_list(); + shader->Program->Varying = _mesa_new_parameter_list(); + shader->Program->Attributes = _mesa_new_parameter_list(); + } + + slang_info_log_construct(&info_log); + _slang_code_object_ctr(&obj); + + success = compile_shader(ctx, &obj, type, &info_log, shader); + + /* free shader's prev info log */ + if (shader->InfoLog) { + _mesa_free(shader->InfoLog); + shader->InfoLog = NULL; + } + + if (info_log.text) { + /* copy info-log string to shader object */ + shader->InfoLog = _mesa_strdup(info_log.text); + } + + if (info_log.error_flag) { + success = GL_FALSE; + } + + slang_info_log_destruct(&info_log); + _slang_code_object_dtr(&obj); + + _slang_delete_mempool((slang_mempool *) ctx->Shader.MemPool); + ctx->Shader.MemPool = NULL; + + /* remove any reads of output registers */ +#if 0 + printf("Pre-remove output reads:\n"); + _mesa_print_program(shader->Program); +#endif + _mesa_remove_output_reads(shader->Program, PROGRAM_OUTPUT); + if (shader->Type == GL_VERTEX_SHADER) { + /* and remove writes to varying vars in vertex programs */ + _mesa_remove_output_reads(shader->Program, PROGRAM_VARYING); + } +#if 0 + printf("Post-remove output reads:\n"); + _mesa_print_program(shader->Program); +#endif + + shader->CompileStatus = success; + + if (success) { + if (shader->Pragmas.Optimize && + (ctx->Shader.Flags & GLSL_NO_OPT) == 0) { + _mesa_optimize_program(ctx, shader->Program); + } + } + + if (ctx->Shader.Flags & GLSL_LOG) { + _mesa_write_shader_to_file(shader); + } + + return success; +} + diff --git a/mesalib/src/mesa/shader/slang/slang_compile.h b/mesalib/src/mesa/shader/slang/slang_compile.h new file mode 100644 index 000000000..7fb549d33 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_compile.h @@ -0,0 +1,100 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#if !defined SLANG_COMPILE_H +#define SLANG_COMPILE_H + +#include "main/imports.h" +#include "main/mtypes.h" +#include "slang_typeinfo.h" +#include "slang_compile_variable.h" +#include "slang_compile_struct.h" +#include "slang_compile_operation.h" +#include "slang_compile_function.h" + +#if defined __cplusplus +extern "C" { +#endif + +typedef struct slang_name_space_ +{ + struct slang_function_scope_ *funcs; + struct slang_struct_scope_ *structs; + struct slang_variable_scope_ *vars; +} slang_name_space; + +typedef enum slang_unit_type_ +{ + SLANG_UNIT_FRAGMENT_SHADER, + SLANG_UNIT_VERTEX_SHADER, + SLANG_UNIT_FRAGMENT_BUILTIN, + SLANG_UNIT_VERTEX_BUILTIN +} slang_unit_type; + + +typedef struct slang_code_unit_ +{ + slang_variable_scope vars; + slang_function_scope funs; + slang_struct_scope structs; + slang_unit_type type; + struct slang_code_object_ *object; +} slang_code_unit; + + +extern GLvoid +_slang_code_unit_ctr (slang_code_unit *, struct slang_code_object_ *); + +extern GLvoid +_slang_code_unit_dtr (slang_code_unit *); + +#define SLANG_BUILTIN_CORE 0 +#define SLANG_BUILTIN_120_CORE 1 +#define SLANG_BUILTIN_COMMON 2 +#define SLANG_BUILTIN_TARGET 3 + +#define SLANG_BUILTIN_TOTAL 4 + +typedef struct slang_code_object_ +{ + slang_code_unit builtin[SLANG_BUILTIN_TOTAL]; + slang_code_unit unit; + slang_atom_pool atompool; +} slang_code_object; + +extern GLvoid +_slang_code_object_ctr (slang_code_object *); + +extern GLvoid +_slang_code_object_dtr (slang_code_object *); + +extern GLboolean +_slang_compile (GLcontext *ctx, struct gl_shader *shader); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/mesalib/src/mesa/shader/slang/slang_compile_function.c b/mesalib/src/mesa/shader/slang/slang_compile_function.c new file mode 100644 index 000000000..4dd885176 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_compile_function.c @@ -0,0 +1,262 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_compile_function.c + * slang front-end compiler + * \author Michal Krol + */ + +#include "main/imports.h" +#include "slang_compile.h" +#include "slang_mem.h" + + +int +slang_function_construct(slang_function * func) +{ + func->kind = SLANG_FUNC_ORDINARY; + if (!slang_variable_construct(&func->header)) + return 0; + + func->parameters = (slang_variable_scope *) + _slang_alloc(sizeof(slang_variable_scope)); + if (func->parameters == NULL) { + slang_variable_destruct(&func->header); + return 0; + } + + _slang_variable_scope_ctr(func->parameters); + func->param_count = 0; + func->body = NULL; + return 1; +} + +void +slang_function_destruct(slang_function * func) +{ + slang_variable_destruct(&func->header); + slang_variable_scope_destruct(func->parameters); + _slang_free(func->parameters); + if (func->body != NULL) { + slang_operation_destruct(func->body); + _slang_free(func->body); + } +} + + +slang_function * +slang_function_new(slang_function_kind kind) +{ + slang_function *fun = (slang_function *) + _slang_alloc(sizeof(slang_function)); + if (fun) { + slang_function_construct(fun); + fun->kind = kind; + } + return fun; +} + + +/* + * slang_function_scope + */ + +GLvoid +_slang_function_scope_ctr(slang_function_scope * self) +{ + self->functions = NULL; + self->num_functions = 0; + self->outer_scope = NULL; +} + +void +slang_function_scope_destruct(slang_function_scope * scope) +{ + unsigned int i; + + for (i = 0; i < scope->num_functions; i++) + slang_function_destruct(scope->functions + i); + _slang_free(scope->functions); +} + + +/** + * Does this function have a non-void return value? + */ +GLboolean +_slang_function_has_return_value(const slang_function *fun) +{ + return fun->header.type.specifier.type != SLANG_SPEC_VOID; +} + + +/** + * Search a list of functions for a particular function by name. + * \param funcs the list of functions to search + * \param a_name the name to search for + * \param all_scopes if non-zero, search containing scopes too. + * \return pointer to found function, or NULL. + */ +int +slang_function_scope_find_by_name(slang_function_scope * funcs, + slang_atom a_name, int all_scopes) +{ + unsigned int i; + + for (i = 0; i < funcs->num_functions; i++) + if (a_name == funcs->functions[i].header.a_name) + return 1; + if (all_scopes && funcs->outer_scope != NULL) + return slang_function_scope_find_by_name(funcs->outer_scope, a_name, 1); + return 0; +} + + +/** + * Search a list of functions for a particular function (for implementing + * function calls. Matching is done by first comparing the function's name, + * then the function's parameter list. + * + * \param funcs the list of functions to search + * \param fun the function to search for + * \param all_scopes if non-zero, search containing scopes too. + * \return pointer to found function, or NULL. + */ +slang_function * +slang_function_scope_find(slang_function_scope * funcs, slang_function * fun, + int all_scopes) +{ + unsigned int i; + + for (i = 0; i < funcs->num_functions; i++) { + slang_function *f = &funcs->functions[i]; + const GLuint haveRetValue = 0; +#if 0 + = (f->header.type.specifier.type != SLANG_SPEC_VOID); +#endif + unsigned int j; + + /* + printf("Compare name %s to %s (ret %u, %d, %d)\n", + (char *) fun->header.a_name, (char *) f->header.a_name, + haveRetValue, + fun->param_count, f->param_count); + */ + + if (fun->header.a_name != f->header.a_name) + continue; + if (fun->param_count != f->param_count) + continue; + for (j = haveRetValue; j < fun->param_count; j++) { + if (!slang_type_specifier_equal + (&fun->parameters->variables[j]->type.specifier, + &f->parameters->variables[j]->type.specifier)) + break; + } + if (j == fun->param_count) { + /* + printf("Found match\n"); + */ + return f; + } + } + /* + printf("Not found\n"); + */ + if (all_scopes && funcs->outer_scope != NULL) + return slang_function_scope_find(funcs->outer_scope, fun, 1); + return NULL; +} + + +/** + * Lookup a function according to name and parameter count/types. + */ +slang_function * +_slang_function_locate(const slang_function_scope * funcs, slang_atom a_name, + slang_operation * args, GLuint num_args, + const slang_name_space * space, slang_atom_pool * atoms, + slang_info_log *log, GLboolean *error) +{ + slang_typeinfo arg_ti[100]; + GLuint i; + + *error = GL_FALSE; + + /* determine type of each argument */ + assert(num_args < 100); + for (i = 0; i < num_args; i++) { + if (!slang_typeinfo_construct(&arg_ti[i])) + return NULL; + if (!_slang_typeof_operation(&args[i], space, &arg_ti[i], atoms, log)) { + return NULL; + } + } + + /* loop over function scopes */ + while (funcs) { + + /* look for function with matching name and argument/param types */ + for (i = 0; i < funcs->num_functions; i++) { + slang_function *f = &funcs->functions[i]; + const GLuint haveRetValue = _slang_function_has_return_value(f); + GLuint j; + + if (a_name != f->header.a_name) + continue; + if (f->param_count - haveRetValue != num_args) + continue; + + /* compare parameter / argument types */ + for (j = 0; j < num_args; j++) { + if (!slang_type_specifier_compatible(&arg_ti[j].spec, + &f->parameters->variables[j]->type.specifier)) { + /* param/arg types don't match */ + break; + } + + /* "out" and "inout" formal parameter requires the actual + * argument to be an l-value. + */ + if (!arg_ti[j].can_be_referenced && + (f->parameters->variables[j]->type.qualifier == SLANG_QUAL_OUT || + f->parameters->variables[j]->type.qualifier == SLANG_QUAL_INOUT)) { + /* param is not an lvalue! */ + *error = GL_TRUE; + return NULL; + } + } + + if (j == num_args) { + /* name and args match! */ + return f; + } + } + + funcs = funcs->outer_scope; + } + + return NULL; +} diff --git a/mesalib/src/mesa/shader/slang/slang_compile_function.h b/mesalib/src/mesa/shader/slang/slang_compile_function.h new file mode 100644 index 000000000..a5445ec25 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_compile_function.h @@ -0,0 +1,92 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLANG_COMPILE_FUNCTION_H +#define SLANG_COMPILE_FUNCTION_H + + +/** + * Types of functions. + */ +typedef enum slang_function_kind_ +{ + SLANG_FUNC_ORDINARY, + SLANG_FUNC_CONSTRUCTOR, + SLANG_FUNC_OPERATOR +} slang_function_kind; + + +/** + * Description of a compiled shader function. + */ +typedef struct slang_function_ +{ + slang_function_kind kind; + slang_variable header; /**< The function's name and return type */ + slang_variable_scope *parameters; /**< formal parameters AND local vars */ + unsigned int param_count; /**< number of formal params (no locals) */ + slang_operation *body; /**< The instruction tree */ +} slang_function; + +extern int slang_function_construct(slang_function *); +extern void slang_function_destruct(slang_function *); +extern slang_function *slang_function_new(slang_function_kind kind); + +extern GLboolean +_slang_function_has_return_value(const slang_function *fun); + + +/** + * Basically, a list of compiled functions. + */ +typedef struct slang_function_scope_ +{ + slang_function *functions; + GLuint num_functions; + struct slang_function_scope_ *outer_scope; +} slang_function_scope; + + +extern GLvoid +_slang_function_scope_ctr(slang_function_scope *); + +extern void +slang_function_scope_destruct(slang_function_scope *); + +extern int +slang_function_scope_find_by_name(slang_function_scope *, slang_atom, int); + +extern slang_function * +slang_function_scope_find(slang_function_scope *, slang_function *, int); + +extern struct slang_function_ * +_slang_function_locate(const struct slang_function_scope_ *funcs, + slang_atom name, struct slang_operation_ *params, + GLuint num_params, + const struct slang_name_space_ *space, + slang_atom_pool *atoms, slang_info_log *log, + GLboolean *error); + + +#endif /* SLANG_COMPILE_FUNCTION_H */ diff --git a/mesalib/src/mesa/shader/slang/slang_compile_operation.c b/mesalib/src/mesa/shader/slang/slang_compile_operation.c new file mode 100644 index 000000000..3e2bdbc91 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_compile_operation.c @@ -0,0 +1,332 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_compile_operation.c + * slang front-end compiler + * \author Michal Krol + */ + +#include "main/imports.h" +#include "slang_compile.h" +#include "slang_mem.h" + + +/** + * Init a slang_operation object + */ +GLboolean +slang_operation_construct(slang_operation * oper) +{ + oper->type = SLANG_OPER_NONE; + oper->children = NULL; + oper->num_children = 0; + oper->literal[0] = 0.0; + oper->literal_size = 1; + oper->array_constructor = GL_FALSE; + oper->a_id = SLANG_ATOM_NULL; + oper->locals = _slang_variable_scope_new(NULL); + if (oper->locals == NULL) + return GL_FALSE; + _slang_variable_scope_ctr(oper->locals); + oper->fun = NULL; + oper->var = NULL; + return GL_TRUE; +} + +void +slang_operation_destruct(slang_operation * oper) +{ + GLuint i; + + for (i = 0; i < oper->num_children; i++) + slang_operation_destruct(oper->children + i); + _slang_free(oper->children); + slang_variable_scope_destruct(oper->locals); + _slang_free(oper->locals); + oper->children = NULL; + oper->num_children = 0; + oper->locals = NULL; +} + + +/** + * Recursively traverse 'oper', replacing occurances of 'oldScope' with + * 'newScope' in the oper->locals->outer_scope field. + */ +void +slang_replace_scope(slang_operation *oper, + slang_variable_scope *oldScope, + slang_variable_scope *newScope) +{ + GLuint i; + + if (oper->locals != newScope && + oper->locals->outer_scope == oldScope) { + /* found. replace old w/ new */ + oper->locals->outer_scope = newScope; + } + + if (oper->type == SLANG_OPER_VARIABLE_DECL) { + /* search/replace in the initializer */ + slang_variable *var; + var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); + if (var && var->initializer) { + slang_replace_scope(var->initializer, oldScope, newScope); + } + } + + /* search/replace in children */ + for (i = 0; i < oper->num_children; i++) { + slang_replace_scope(&oper->children[i], oldScope, newScope); + } +} + + +/** + * Recursively copy a slang_operation node. + * \param x copy target + * \param y copy source + * \return GL_TRUE for success, GL_FALSE if failure + */ +GLboolean +slang_operation_copy(slang_operation * x, const slang_operation * y) +{ + slang_operation z; + GLuint i; + + if (!slang_operation_construct(&z)) + return GL_FALSE; + z.type = y->type; + if (y->num_children > 0) { + z.children = (slang_operation *) + _slang_alloc(y->num_children * sizeof(slang_operation)); + if (z.children == NULL) { + slang_operation_destruct(&z); + return GL_FALSE; + } + } + for (z.num_children = 0; z.num_children < y->num_children; + z.num_children++) { + if (!slang_operation_construct(&z.children[z.num_children])) { + slang_operation_destruct(&z); + return GL_FALSE; + } + } + for (i = 0; i < z.num_children; i++) { + if (!slang_operation_copy(&z.children[i], &y->children[i])) { + slang_operation_destruct(&z); + return GL_FALSE; + } + } + z.literal[0] = y->literal[0]; + z.literal[1] = y->literal[1]; + z.literal[2] = y->literal[2]; + z.literal[3] = y->literal[3]; + z.literal_size = y->literal_size; + assert(y->literal_size >= 1); + assert(y->literal_size <= 4); + z.a_id = y->a_id; + if (y->locals) { + if (!slang_variable_scope_copy(z.locals, y->locals)) { + slang_operation_destruct(&z); + return GL_FALSE; + } + } + + /* update scoping for children */ + for (i = 0; i < y->num_children; i++) { + if (y->children[i].locals && + y->children[i].locals->outer_scope == y->locals) { + z.children[i].locals->outer_scope = z.locals; + } + } + +#if 0 + z.var = y->var; + z.fun = y->fun; +#endif + slang_operation_destruct(x); + *x = z; + + /* If this operation declares a new scope, we need to make sure + * all children point to it, not the original operation's scope! + */ + if (x->type == SLANG_OPER_BLOCK_NEW_SCOPE || + x->type == SLANG_OPER_WHILE || + x->type == SLANG_OPER_FOR) { + slang_replace_scope(x, y->locals, x->locals); + } + + return GL_TRUE; +} + + +slang_operation * +slang_operation_new(GLuint count) +{ + slang_operation *ops + = (slang_operation *) _slang_alloc(count * sizeof(slang_operation)); + assert(count > 0); + if (ops) { + GLuint i; + for (i = 0; i < count; i++) + slang_operation_construct(ops + i); + } + return ops; +} + + +/** + * Delete operation and all children + */ +void +slang_operation_delete(slang_operation *oper) +{ + slang_operation_destruct(oper); + _slang_free(oper); +} + + +void +slang_operation_free_children(slang_operation *oper) +{ + GLuint i; + for (i = 0; i < slang_oper_num_children(oper); i++) { + slang_operation *child = slang_oper_child(oper, i); + slang_operation_destruct(child); + } + _slang_free(oper->children); + oper->children = NULL; + oper->num_children = 0; +} + + +slang_operation * +slang_operation_grow(GLuint *numChildren, slang_operation **children) +{ + slang_operation *ops; + + ops = (slang_operation *) + _slang_realloc(*children, + *numChildren * sizeof(slang_operation), + (*numChildren + 1) * sizeof(slang_operation)); + if (ops) { + slang_operation *newOp = ops + *numChildren; + if (!slang_operation_construct(newOp)) { + _slang_free(ops); + *children = NULL; + return NULL; + } + *children = ops; + (*numChildren)++; + return newOp; + } + return NULL; +} + +/** + * Insert a new slang_operation into an array. + * \param numElements pointer to current array size (in/out) + * \param array address of the array (in/out) + * \param pos position to insert new element + * \return pointer to the new operation/element + */ +slang_operation * +slang_operation_insert(GLuint *numElements, slang_operation **array, + GLuint pos) +{ + slang_operation *ops; + + assert(pos <= *numElements); + + ops = (slang_operation *) + _slang_alloc((*numElements + 1) * sizeof(slang_operation)); + if (ops) { + slang_operation *newOp; + newOp = ops + pos; + if (pos > 0) + _mesa_memcpy(ops, *array, pos * sizeof(slang_operation)); + if (pos < *numElements) + _mesa_memcpy(newOp + 1, (*array) + pos, + (*numElements - pos) * sizeof(slang_operation)); + + if (!slang_operation_construct(newOp)) { + _slang_free(ops); + *numElements = 0; + *array = NULL; + return NULL; + } + if (*array) + _slang_free(*array); + *array = ops; + (*numElements)++; + return newOp; + } + return NULL; +} + + +/** + * Add/insert new child into given node at given position. + * \return pointer to the new child node + */ +slang_operation * +slang_operation_insert_child(slang_operation *oper, GLuint pos) +{ + slang_operation *newOp; + + newOp = slang_operation_insert(&oper->num_children, + &oper->children, + pos); + if (newOp) { + newOp->locals->outer_scope = oper->locals; + } + + return newOp; +} + + +void +_slang_operation_swap(slang_operation *oper0, slang_operation *oper1) +{ + slang_operation tmp = *oper0; + *oper0 = *oper1; + *oper1 = tmp; +} + + +void +slang_operation_add_children(slang_operation *oper, GLuint num_children) +{ + GLuint i; + assert(oper->num_children == 0); + assert(oper->children == NULL); + oper->num_children = num_children; + oper->children = slang_operation_new(num_children); + for (i = 0; i < num_children; i++) { + oper->children[i].locals = _slang_variable_scope_new(oper->locals); + } +} + diff --git a/mesalib/src/mesa/shader/slang/slang_compile_operation.h b/mesalib/src/mesa/shader/slang/slang_compile_operation.h new file mode 100644 index 000000000..58f1edeed --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_compile_operation.h @@ -0,0 +1,226 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLANG_COMPILE_OPERATION_H +#define SLANG_COMPILE_OPERATION_H + + +/** + * Types of slang operations. + * These are the types of the AST (abstract syntax tree) nodes. + * [foo] indicates a sub-tree or reference to another type of node + */ +typedef enum slang_operation_type_ +{ + SLANG_OPER_NONE, + SLANG_OPER_BLOCK_NO_NEW_SCOPE, /* "{" sequence "}" */ + SLANG_OPER_BLOCK_NEW_SCOPE, /* "{" sequence "}" */ + SLANG_OPER_VARIABLE_DECL, /* [type] [var] or [var] = [expr] */ + SLANG_OPER_ASM, + SLANG_OPER_BREAK, /* "break" statement */ + SLANG_OPER_CONTINUE, /* "continue" statement */ + SLANG_OPER_DISCARD, /* "discard" (kill fragment) statement */ + SLANG_OPER_RETURN, /* "return" [expr] */ + SLANG_OPER_RETURN_INLINED, /* "return" [expr] from inlined function */ + SLANG_OPER_LABEL, /* a jump target */ + SLANG_OPER_EXPRESSION, /* [expr] */ + SLANG_OPER_IF, /* "if" [0] then [1] else [2] */ + SLANG_OPER_WHILE, /* "while" [cond] [body] */ + SLANG_OPER_DO, /* "do" [body] "while" [cond] */ + SLANG_OPER_FOR, /* "for" [init] [while] [incr] [body] */ + SLANG_OPER_VOID, /* nop */ + SLANG_OPER_LITERAL_BOOL, /* "true" or "false" */ + SLANG_OPER_LITERAL_INT, /* integer literal */ + SLANG_OPER_LITERAL_FLOAT, /* float literal */ + SLANG_OPER_IDENTIFIER, /* var name, func name, etc */ + SLANG_OPER_SEQUENCE, /* [expr] "," [expr] "," etc */ + SLANG_OPER_ASSIGN, /* [var] "=" [expr] */ + SLANG_OPER_ADDASSIGN, /* [var] "+=" [expr] */ + SLANG_OPER_SUBASSIGN, /* [var] "-=" [expr] */ + SLANG_OPER_MULASSIGN, /* [var] "*=" [expr] */ + SLANG_OPER_DIVASSIGN, /* [var] "/=" [expr] */ + /*SLANG_OPER_MODASSIGN, */ + /*SLANG_OPER_LSHASSIGN, */ + /*SLANG_OPER_RSHASSIGN, */ + /*SLANG_OPER_ORASSIGN, */ + /*SLANG_OPER_XORASSIGN, */ + /*SLANG_OPER_ANDASSIGN, */ + SLANG_OPER_SELECT, /* [expr] "?" [expr] ":" [expr] */ + SLANG_OPER_LOGICALOR, /* [expr] "||" [expr] */ + SLANG_OPER_LOGICALXOR, /* [expr] "^^" [expr] */ + SLANG_OPER_LOGICALAND, /* [expr] "&&" [expr] */ + /*SLANG_OPER_BITOR, */ + /*SLANG_OPER_BITXOR, */ + /*SLANG_OPER_BITAND, */ + SLANG_OPER_EQUAL, /* [expr] "==" [expr] */ + SLANG_OPER_NOTEQUAL, /* [expr] "!=" [expr] */ + SLANG_OPER_LESS, /* [expr] "<" [expr] */ + SLANG_OPER_GREATER, /* [expr] ">" [expr] */ + SLANG_OPER_LESSEQUAL, /* [expr] "<=" [expr] */ + SLANG_OPER_GREATEREQUAL, /* [expr] ">=" [expr] */ + /*SLANG_OPER_LSHIFT, */ + /*SLANG_OPER_RSHIFT, */ + SLANG_OPER_ADD, /* [expr] "+" [expr] */ + SLANG_OPER_SUBTRACT, /* [expr] "-" [expr] */ + SLANG_OPER_MULTIPLY, /* [expr] "*" [expr] */ + SLANG_OPER_DIVIDE, /* [expr] "/" [expr] */ + /*SLANG_OPER_MODULUS, */ + SLANG_OPER_PREINCREMENT, /* "++" [var] */ + SLANG_OPER_PREDECREMENT, /* "--" [var] */ + SLANG_OPER_PLUS, /* "-" [expr] */ + SLANG_OPER_MINUS, /* "+" [expr] */ + /*SLANG_OPER_COMPLEMENT, */ + SLANG_OPER_NOT, /* "!" [expr] */ + SLANG_OPER_SUBSCRIPT, /* [expr] "[" [expr] "]" */ + SLANG_OPER_CALL, /* [func name] [param] [param] [...] */ + SLANG_OPER_NON_INLINED_CALL, /* a real function call */ + SLANG_OPER_METHOD, /* method call, such as v.length() */ + SLANG_OPER_FIELD, /* i.e.: ".next" or ".xzy" or ".xxx" etc */ + SLANG_OPER_POSTINCREMENT, /* [var] "++" */ + SLANG_OPER_POSTDECREMENT /* [var] "--" */ +} slang_operation_type; + + +/** + * A slang_operation is basically a compiled instruction (such as assignment, + * a while-loop, a conditional, a multiply, a function call, etc). + * The AST (abstract syntax tree) is built from these nodes. + * NOTE: This structure could have been implemented as a union of simpler + * structs which would correspond to the operation types above. + */ +typedef struct slang_operation_ +{ + slang_operation_type type; + struct slang_operation_ *children; + GLuint num_children; + GLfloat literal[4]; /**< Used for float, int and bool values */ + GLuint literal_size; /**< 1, 2, 3, or 4 */ + slang_atom a_id; /**< type: asm, identifier, call, field */ + slang_atom a_obj; /**< object in a method call */ + slang_variable_scope *locals; /**< local vars for scope */ + struct slang_function_ *fun; /**< If type == SLANG_OPER_CALL */ + struct slang_variable_ *var; /**< If type == slang_oper_identier */ + struct slang_label_ *label; /**< If type == SLANG_OPER_LABEL */ + /** If type==SLANG_OPER_CALL and we're calling an array constructor, + * for which there's no real function, we need to have a flag to + * indicate such. num_children indicates number of elements. + */ + GLboolean array_constructor; + double x; +} slang_operation; + + +extern GLboolean +slang_operation_construct(slang_operation *); + +extern void +slang_operation_destruct(slang_operation *); + +extern void +slang_replace_scope(slang_operation *oper, + slang_variable_scope *oldScope, + slang_variable_scope *newScope); + +extern GLboolean +slang_operation_copy(slang_operation *, const slang_operation *); + +extern slang_operation * +slang_operation_new(GLuint count); + +extern void +slang_operation_delete(slang_operation *oper); + +extern void +slang_operation_free_children(slang_operation *oper); + +extern slang_operation * +slang_operation_grow(GLuint *numChildren, slang_operation **children); + +extern slang_operation * +slang_operation_insert(GLuint *numChildren, slang_operation **children, + GLuint pos); + +extern slang_operation * +slang_operation_insert_child(slang_operation *oper, GLuint pos); + +extern void +_slang_operation_swap(slang_operation *oper0, slang_operation *oper1); + + +extern void +slang_operation_add_children(slang_operation *oper, GLuint num_children); + + +/** Return number of children of given node */ +static INLINE GLuint +slang_oper_num_children(const slang_operation *oper) +{ + return oper->num_children; +} + +/** Return child of given operation node */ +static INLINE slang_operation * +slang_oper_child(slang_operation *oper, GLuint child) +{ + assert(child < oper->num_children); + return &oper->children[child]; +} + + +/** Return child of given operation node, const version */ +static INLINE const slang_operation * +slang_oper_child_const(const slang_operation *oper, GLuint child) +{ + assert(child < oper->num_children); + return &oper->children[child]; +} + + +/** Init oper to a boolean literal. */ +static INLINE void +slang_operation_literal_bool(slang_operation *oper, GLboolean value) +{ + oper->type = SLANG_OPER_LITERAL_BOOL; + oper->literal[0] = + oper->literal[1] = + oper->literal[2] = + oper->literal[3] = (float) value; + oper->literal_size = 1; +} + + +/** Init oper to an int literal. */ +static INLINE void +slang_operation_literal_int(slang_operation *oper, GLint value) +{ + oper->type = SLANG_OPER_LITERAL_INT; + oper->literal[0] = + oper->literal[1] = + oper->literal[2] = + oper->literal[3] = (float) value; + oper->literal_size = 1; +} + + +#endif /* SLANG_COMPILE_OPERATION_H */ diff --git a/mesalib/src/mesa/shader/slang/slang_compile_struct.c b/mesalib/src/mesa/shader/slang/slang_compile_struct.c new file mode 100644 index 000000000..e6c38730d --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_compile_struct.c @@ -0,0 +1,174 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-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 slang_compile_struct.c + * slang front-end compiler + * \author Michal Krol + */ + +#include "main/imports.h" +#include "slang_mem.h" +#include "slang_compile.h" + + +GLvoid +_slang_struct_scope_ctr(slang_struct_scope * self) +{ + self->structs = NULL; + self->num_structs = 0; + self->outer_scope = NULL; +} + +void +slang_struct_scope_destruct(slang_struct_scope * scope) +{ + GLuint i; + + for (i = 0; i < scope->num_structs; i++) + slang_struct_destruct(scope->structs + i); + _slang_free(scope->structs); + /* do not free scope->outer_scope */ +} + +int +slang_struct_scope_copy(slang_struct_scope * x, const slang_struct_scope * y) +{ + slang_struct_scope z; + GLuint i; + + _slang_struct_scope_ctr(&z); + z.structs = (slang_struct *) + _slang_alloc(y->num_structs * sizeof(slang_struct)); + if (z.structs == NULL) { + slang_struct_scope_destruct(&z); + return 0; + } + for (z.num_structs = 0; z.num_structs < y->num_structs; z.num_structs++) + if (!slang_struct_construct(&z.structs[z.num_structs])) { + slang_struct_scope_destruct(&z); + return 0; + } + for (i = 0; i < z.num_structs; i++) + if (!slang_struct_copy(&z.structs[i], &y->structs[i])) { + slang_struct_scope_destruct(&z); + return 0; + } + z.outer_scope = y->outer_scope; + slang_struct_scope_destruct(x); + *x = z; + return 1; +} + +slang_struct * +slang_struct_scope_find(slang_struct_scope * stru, slang_atom a_name, + int all_scopes) +{ + GLuint i; + + for (i = 0; i < stru->num_structs; i++) + if (a_name == stru->structs[i].a_name) + return &stru->structs[i]; + if (all_scopes && stru->outer_scope != NULL) + return slang_struct_scope_find(stru->outer_scope, a_name, 1); + return NULL; +} + +/* slang_struct */ + +int +slang_struct_construct(slang_struct * stru) +{ + stru->a_name = SLANG_ATOM_NULL; + stru->fields = (slang_variable_scope *) + _slang_alloc(sizeof(slang_variable_scope)); + if (stru->fields == NULL) + return 0; + _slang_variable_scope_ctr(stru->fields); + + stru->structs = + (slang_struct_scope *) _slang_alloc(sizeof(slang_struct_scope)); + if (stru->structs == NULL) { + slang_variable_scope_destruct(stru->fields); + _slang_free(stru->fields); + return 0; + } + _slang_struct_scope_ctr(stru->structs); + stru->constructor = NULL; + return 1; +} + +void +slang_struct_destruct(slang_struct * stru) +{ + slang_variable_scope_destruct(stru->fields); + _slang_free(stru->fields); + slang_struct_scope_destruct(stru->structs); + _slang_free(stru->structs); +} + +int +slang_struct_copy(slang_struct * x, const slang_struct * y) +{ + slang_struct z; + + if (!slang_struct_construct(&z)) + return 0; + z.a_name = y->a_name; + if (!slang_variable_scope_copy(z.fields, y->fields)) { + slang_struct_destruct(&z); + return 0; + } + if (!slang_struct_scope_copy(z.structs, y->structs)) { + slang_struct_destruct(&z); + return 0; + } + slang_struct_destruct(x); + *x = z; + return 1; +} + +int +slang_struct_equal(const slang_struct * x, const slang_struct * y) +{ + GLuint i; + + if (x->fields->num_variables != y->fields->num_variables) + return 0; + + for (i = 0; i < x->fields->num_variables; i++) { + const slang_variable *varx = x->fields->variables[i]; + const slang_variable *vary = y->fields->variables[i]; + + if (varx->a_name != vary->a_name) + return 0; + if (!slang_type_specifier_equal(&varx->type.specifier, + &vary->type.specifier)) + return 0; + if (varx->type.specifier.type == SLANG_SPEC_ARRAY) + if (varx->array_len != vary->array_len) + return GL_FALSE; + } + return 1; +} diff --git a/mesalib/src/mesa/shader/slang/slang_compile_struct.h b/mesalib/src/mesa/shader/slang/slang_compile_struct.h new file mode 100644 index 000000000..90c5512f4 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_compile_struct.h @@ -0,0 +1,66 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#if !defined SLANG_COMPILE_STRUCT_H +#define SLANG_COMPILE_STRUCT_H + +#if defined __cplusplus +extern "C" { +#endif + +struct slang_function_; + +typedef struct slang_struct_scope_ +{ + struct slang_struct_ *structs; + GLuint num_structs; + struct slang_struct_scope_ *outer_scope; +} slang_struct_scope; + +extern GLvoid +_slang_struct_scope_ctr (slang_struct_scope *); + +void slang_struct_scope_destruct (slang_struct_scope *); +int slang_struct_scope_copy (slang_struct_scope *, const slang_struct_scope *); +struct slang_struct_ *slang_struct_scope_find (slang_struct_scope *, slang_atom, int); + +typedef struct slang_struct_ +{ + slang_atom a_name; + struct slang_variable_scope_ *fields; + slang_struct_scope *structs; + struct slang_function_ *constructor; +} slang_struct; + +int slang_struct_construct (slang_struct *); +void slang_struct_destruct (slang_struct *); +int slang_struct_copy (slang_struct *, const slang_struct *); +int slang_struct_equal (const slang_struct *, const slang_struct *); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/mesalib/src/mesa/shader/slang/slang_compile_variable.c b/mesalib/src/mesa/shader/slang/slang_compile_variable.c new file mode 100644 index 000000000..eab912710 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_compile_variable.c @@ -0,0 +1,247 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-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 slang_compile_variable.c + * slang front-end compiler + * \author Michal Krol + */ + +#include "main/imports.h" +#include "slang_compile.h" +#include "slang_mem.h" + + +static slang_variable * +slang_variable_new(void) +{ + slang_variable *v = (slang_variable *) _slang_alloc(sizeof(slang_variable)); + if (v) { + if (!slang_variable_construct(v)) { + _slang_free(v); + v = NULL; + } + } + return v; +} + + +static void +slang_variable_delete(slang_variable * var) +{ + slang_variable_destruct(var); + _slang_free(var); +} + + +/* + * slang_variable_scope + */ + +slang_variable_scope * +_slang_variable_scope_new(slang_variable_scope *parent) +{ + slang_variable_scope *s; + s = (slang_variable_scope *) _slang_alloc(sizeof(slang_variable_scope)); + if (s) + s->outer_scope = parent; + return s; +} + + +GLvoid +_slang_variable_scope_ctr(slang_variable_scope * self) +{ + self->variables = NULL; + self->num_variables = 0; + self->outer_scope = NULL; +} + +void +slang_variable_scope_destruct(slang_variable_scope * scope) +{ + unsigned int i; + + if (!scope) + return; + for (i = 0; i < scope->num_variables; i++) { + if (scope->variables[i]) + slang_variable_delete(scope->variables[i]); + } + _slang_free(scope->variables); + /* do not free scope->outer_scope */ +} + +int +slang_variable_scope_copy(slang_variable_scope * x, + const slang_variable_scope * y) +{ + slang_variable_scope z; + unsigned int i; + + _slang_variable_scope_ctr(&z); + z.variables = (slang_variable **) + _slang_alloc(y->num_variables * sizeof(slang_variable *)); + if (z.variables == NULL) { + slang_variable_scope_destruct(&z); + return 0; + } + for (z.num_variables = 0; z.num_variables < y->num_variables; + z.num_variables++) { + z.variables[z.num_variables] = slang_variable_new(); + if (!z.variables[z.num_variables]) { + slang_variable_scope_destruct(&z); + return 0; + } + } + for (i = 0; i < z.num_variables; i++) { + if (!slang_variable_copy(z.variables[i], y->variables[i])) { + slang_variable_scope_destruct(&z); + return 0; + } + } + z.outer_scope = y->outer_scope; + slang_variable_scope_destruct(x); + *x = z; + return 1; +} + + +/** + * Grow the variable list by one. + * \return pointer to space for the new variable (will be initialized) + */ +slang_variable * +slang_variable_scope_grow(slang_variable_scope *scope) +{ + const int n = scope->num_variables; + scope->variables = (slang_variable **) + _slang_realloc(scope->variables, + n * sizeof(slang_variable *), + (n + 1) * sizeof(slang_variable *)); + if (!scope->variables) + return NULL; + + scope->num_variables++; + + scope->variables[n] = slang_variable_new(); + if (!scope->variables[n]) + return NULL; + + return scope->variables[n]; +} + + + +/* slang_variable */ + +int +slang_variable_construct(slang_variable * var) +{ + if (!slang_fully_specified_type_construct(&var->type)) + return 0; + var->a_name = SLANG_ATOM_NULL; + var->array_len = 0; + var->initializer = NULL; + var->size = 0; + var->isTemp = GL_FALSE; + var->store = NULL; + var->declared = 0; + return 1; +} + + +void +slang_variable_destruct(slang_variable * var) +{ + slang_fully_specified_type_destruct(&var->type); + if (var->initializer != NULL) { + slang_operation_destruct(var->initializer); + _slang_free(var->initializer); + } +#if 0 + if (var->aux) { + _mesa_free(var->aux); + } +#endif +} + + +int +slang_variable_copy(slang_variable * x, const slang_variable * y) +{ + slang_variable z; + + if (!slang_variable_construct(&z)) + return 0; + if (!slang_fully_specified_type_copy(&z.type, &y->type)) { + slang_variable_destruct(&z); + return 0; + } + z.a_name = y->a_name; + z.array_len = y->array_len; + if (y->initializer != NULL) { + z.initializer + = (slang_operation *) _slang_alloc(sizeof(slang_operation)); + if (z.initializer == NULL) { + slang_variable_destruct(&z); + return 0; + } + if (!slang_operation_construct(z.initializer)) { + _slang_free(z.initializer); + slang_variable_destruct(&z); + return 0; + } + if (!slang_operation_copy(z.initializer, y->initializer)) { + slang_variable_destruct(&z); + return 0; + } + } + z.size = y->size; + slang_variable_destruct(x); + *x = z; + return 1; +} + + +/** + * Search for named variable in given scope. + * \param all if true, search parent scopes too. + */ +slang_variable * +_slang_variable_locate(const slang_variable_scope * scope, + const slang_atom a_name, GLboolean all) +{ + while (scope) { + GLuint i; + for (i = 0; i < scope->num_variables; i++) + if (a_name == scope->variables[i]->a_name) + return scope->variables[i]; + if (all) + scope = scope->outer_scope; + else + scope = NULL; + } + return NULL; +} diff --git a/mesalib/src/mesa/shader/slang/slang_compile_variable.h b/mesalib/src/mesa/shader/slang/slang_compile_variable.h new file mode 100644 index 000000000..b4585599f --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_compile_variable.h @@ -0,0 +1,90 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.2 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLANG_COMPILE_VARIABLE_H +#define SLANG_COMPILE_VARIABLE_H + + +struct slang_ir_storage_; + + +/** + * A shading language program variable. + */ +typedef struct slang_variable_ +{ + slang_fully_specified_type type; /**< Variable's data type */ + slang_atom a_name; /**< The variable's name (char *) */ + GLuint array_len; /**< only if type == SLANG_SPEC_ARRAy */ + struct slang_operation_ *initializer; /**< Optional initializer code */ + GLuint size; /**< Variable's size in bytes */ + GLboolean is_global; + GLboolean isTemp; /**< a named temporary (__resultTmp) */ + GLboolean declared; /**< for debug */ + struct slang_ir_storage_ *store; /**< Storage for this var */ +} slang_variable; + + +/** + * Basically a list of variables, with a pointer to the parent scope. + */ +typedef struct slang_variable_scope_ +{ + slang_variable **variables; /**< Array [num_variables] of ptrs to vars */ + GLuint num_variables; + struct slang_variable_scope_ *outer_scope; +} slang_variable_scope; + + +extern slang_variable_scope * +_slang_variable_scope_new(slang_variable_scope *parent); + +extern GLvoid +_slang_variable_scope_ctr(slang_variable_scope *); + +extern void +slang_variable_scope_destruct(slang_variable_scope *); + +extern int +slang_variable_scope_copy(slang_variable_scope *, + const slang_variable_scope *); + +extern slang_variable * +slang_variable_scope_grow(slang_variable_scope *); + +extern int +slang_variable_construct(slang_variable *); + +extern void +slang_variable_destruct(slang_variable *); + +extern int +slang_variable_copy(slang_variable *, const slang_variable *); + +extern slang_variable * +_slang_variable_locate(const slang_variable_scope *, const slang_atom a_name, + GLboolean all); + + +#endif /* SLANG_COMPILE_VARIABLE_H */ diff --git a/mesalib/src/mesa/shader/slang/slang_emit.c b/mesalib/src/mesa/shader/slang/slang_emit.c new file mode 100644 index 000000000..3f455e064 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_emit.c @@ -0,0 +1,2518 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2008 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 slang_emit.c + * Emit program instructions (PI code) from IR trees. + * \author Brian Paul + */ + +/*** + *** NOTES + *** + *** To emit GPU instructions, we basically just do an in-order traversal + *** of the IR tree. + ***/ + + +#include "main/imports.h" +#include "main/context.h" +#include "main/macros.h" +#include "shader/program.h" +#include "shader/prog_instruction.h" +#include "shader/prog_parameter.h" +#include "shader/prog_print.h" +#include "slang_builtin.h" +#include "slang_emit.h" +#include "slang_mem.h" + + +#define PEEPHOLE_OPTIMIZATIONS 1 +#define ANNOTATE 0 + + +typedef struct +{ + slang_info_log *log; + slang_var_table *vt; + struct gl_program *prog; + struct gl_program **Subroutines; + GLuint NumSubroutines; + + GLuint MaxInstructions; /**< size of prog->Instructions[] buffer */ + + GLboolean UnresolvedFunctions; + + /* code-gen options */ + GLboolean EmitHighLevelInstructions; + GLboolean EmitCondCodes; + GLboolean EmitComments; + GLboolean EmitBeginEndSub; /* XXX TEMPORARY */ +} slang_emit_info; + + + +static struct gl_program * +new_subroutine(slang_emit_info *emitInfo, GLuint *id) +{ + GET_CURRENT_CONTEXT(ctx); + const GLuint n = emitInfo->NumSubroutines; + + emitInfo->Subroutines = (struct gl_program **) + _mesa_realloc(emitInfo->Subroutines, + n * sizeof(struct gl_program), + (n + 1) * sizeof(struct gl_program)); + emitInfo->Subroutines[n] = ctx->Driver.NewProgram(ctx, emitInfo->prog->Target, 0); + emitInfo->Subroutines[n]->Parameters = emitInfo->prog->Parameters; + emitInfo->NumSubroutines++; + *id = n; + return emitInfo->Subroutines[n]; +} + + +/** + * Convert a writemask to a swizzle. Used for testing cond codes because + * we only want to test the cond code component(s) that was set by the + * previous instruction. + */ +static GLuint +writemask_to_swizzle(GLuint writemask) +{ + if (writemask == WRITEMASK_X) + return SWIZZLE_XXXX; + if (writemask == WRITEMASK_Y) + return SWIZZLE_YYYY; + if (writemask == WRITEMASK_Z) + return SWIZZLE_ZZZZ; + if (writemask == WRITEMASK_W) + return SWIZZLE_WWWW; + return SWIZZLE_XYZW; /* shouldn't be hit */ +} + + +/** + * Convert a swizzle mask to a writemask. + * Note that the slang_ir_storage->Swizzle field can represent either a + * swizzle mask or a writemask, depending on how it's used. For example, + * when we parse "direction.yz" alone, we don't know whether .yz is a + * writemask or a swizzle. In this case, we encode ".yz" in store->Swizzle + * as a swizzle mask (.yz?? actually). Later, if direction.yz is used as + * an R-value, we use store->Swizzle as-is. Otherwise, if direction.yz is + * used as an L-value, we convert it to a writemask. + */ +static GLuint +swizzle_to_writemask(GLuint swizzle) +{ + GLuint i, writemask = 0x0; + for (i = 0; i < 4; i++) { + GLuint swz = GET_SWZ(swizzle, i); + if (swz <= SWIZZLE_W) { + writemask |= (1 << swz); + } + } + return writemask; +} + + +/** + * Swizzle a swizzle (function composition). + * That is, return swz2(swz1), or said another way: swz1.szw2 + * Example: swizzle_swizzle(".zwxx", ".xxyw") yields ".zzwx" + */ +GLuint +_slang_swizzle_swizzle(GLuint swz1, GLuint swz2) +{ + GLuint i, swz, s[4]; + for (i = 0; i < 4; i++) { + GLuint c = GET_SWZ(swz2, i); + if (c <= SWIZZLE_W) + s[i] = GET_SWZ(swz1, c); + else + s[i] = c; + } + swz = MAKE_SWIZZLE4(s[0], s[1], s[2], s[3]); + return swz; +} + + +/** + * Return the default swizzle mask for accessing a variable of the + * given size (in floats). If size = 1, comp is used to identify + * which component [0..3] of the register holds the variable. + */ +GLuint +_slang_var_swizzle(GLint size, GLint comp) +{ + switch (size) { + case 1: + return MAKE_SWIZZLE4(comp, SWIZZLE_NIL, SWIZZLE_NIL, SWIZZLE_NIL); + case 2: + return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_NIL, SWIZZLE_NIL); + case 3: + return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_NIL); + default: + return SWIZZLE_XYZW; + } +} + + + +/** + * Allocate storage for the given node (if it hasn't already been allocated). + * + * Typically this is temporary storage for an intermediate result (such as + * for a multiply or add, etc). + * + * If n->Store does not exist it will be created and will be of the size + * specified by defaultSize. + */ +static GLboolean +alloc_node_storage(slang_emit_info *emitInfo, slang_ir_node *n, + GLint defaultSize) +{ + assert(!n->Var); + if (!n->Store) { + assert(defaultSize > 0); + n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, defaultSize); + } + + /* now allocate actual register(s). I.e. set n->Store->Index >= 0 */ + if (n->Store->Index < 0) { + if (!_slang_alloc_temp(emitInfo->vt, n->Store)) { + slang_info_log_error(emitInfo->log, + "Ran out of registers, too many temporaries"); + _slang_free(n->Store); + n->Store = NULL; + return GL_FALSE; + } + } + return GL_TRUE; +} + + +/** + * Free temporary storage, if n->Store is, in fact, temp storage. + * Otherwise, no-op. + */ +static void +free_node_storage(slang_var_table *vt, slang_ir_node *n) +{ + if (n->Store->File == PROGRAM_TEMPORARY && + n->Store->Index >= 0 && + n->Opcode != IR_SWIZZLE) { + if (_slang_is_temp(vt, n->Store)) { + _slang_free_temp(vt, n->Store); + n->Store->Index = -1; + n->Store = NULL; /* XXX this may not be needed */ + } + } +} + + +/** + * Helper function to allocate a short-term temporary. + * Free it with _slang_free_temp(). + */ +static GLboolean +alloc_local_temp(slang_emit_info *emitInfo, slang_ir_storage *temp, GLint size) +{ + assert(size >= 1); + assert(size <= 4); + _mesa_bzero(temp, sizeof(*temp)); + temp->Size = size; + temp->File = PROGRAM_TEMPORARY; + temp->Index = -1; + return _slang_alloc_temp(emitInfo->vt, temp); +} + + +/** + * Remove any SWIZZLE_NIL terms from given swizzle mask. + * For a swizzle like .z??? generate .zzzz (replicate single component). + * Else, for .wx?? generate .wxzw (insert default component for the position). + */ +static GLuint +fix_swizzle(GLuint swizzle) +{ + GLuint c0 = GET_SWZ(swizzle, 0), + c1 = GET_SWZ(swizzle, 1), + c2 = GET_SWZ(swizzle, 2), + c3 = GET_SWZ(swizzle, 3); + if (c1 == SWIZZLE_NIL && c2 == SWIZZLE_NIL && c3 == SWIZZLE_NIL) { + /* smear first component across all positions */ + c1 = c2 = c3 = c0; + } + else { + /* insert default swizzle components */ + if (c0 == SWIZZLE_NIL) + c0 = SWIZZLE_X; + if (c1 == SWIZZLE_NIL) + c1 = SWIZZLE_Y; + if (c2 == SWIZZLE_NIL) + c2 = SWIZZLE_Z; + if (c3 == SWIZZLE_NIL) + c3 = SWIZZLE_W; + } + return MAKE_SWIZZLE4(c0, c1, c2, c3); +} + + + +/** + * Convert IR storage to an instruction dst register. + */ +static void +storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st) +{ + const GLboolean relAddr = st->RelAddr; + const GLint size = st->Size; + GLint index = st->Index; + GLuint swizzle = st->Swizzle; + + assert(index >= 0); + /* if this is storage relative to some parent storage, walk up the tree */ + while (st->Parent) { + st = st->Parent; + assert(st->Index >= 0); + index += st->Index; + swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle); + } + + assert(st->File != PROGRAM_UNDEFINED); + dst->File = st->File; + + assert(index >= 0); + dst->Index = index; + + assert(size >= 1); + assert(size <= 4); + + if (swizzle != SWIZZLE_XYZW) { + dst->WriteMask = swizzle_to_writemask(swizzle); + } + else { + switch (size) { + case 1: + dst->WriteMask = WRITEMASK_X << GET_SWZ(st->Swizzle, 0); + break; + case 2: + dst->WriteMask = WRITEMASK_XY; + break; + case 3: + dst->WriteMask = WRITEMASK_XYZ; + break; + case 4: + dst->WriteMask = WRITEMASK_XYZW; + break; + default: + ; /* error would have been caught above */ + } + } + + dst->RelAddr = relAddr; +} + + +/** + * Convert IR storage to an instruction src register. + */ +static void +storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st) +{ + const GLboolean relAddr = st->RelAddr; + GLint index = st->Index; + GLuint swizzle = st->Swizzle; + + /* if this is storage relative to some parent storage, walk up the tree */ + assert(index >= 0); + while (st->Parent) { + st = st->Parent; + if (st->Index < 0) { + /* an error should have been reported already */ + return; + } + assert(st->Index >= 0); + index += st->Index; + swizzle = _slang_swizzle_swizzle(fix_swizzle(st->Swizzle), swizzle); + } + + assert(st->File >= 0); +#if 1 /* XXX temporary */ + if (st->File == PROGRAM_UNDEFINED) { + slang_ir_storage *st0 = (slang_ir_storage *) st; + st0->File = PROGRAM_TEMPORARY; + } +#endif + assert(st->File < PROGRAM_UNDEFINED); + src->File = st->File; + + assert(index >= 0); + src->Index = index; + + swizzle = fix_swizzle(swizzle); + assert(GET_SWZ(swizzle, 0) <= SWIZZLE_W); + assert(GET_SWZ(swizzle, 1) <= SWIZZLE_W); + assert(GET_SWZ(swizzle, 2) <= SWIZZLE_W); + assert(GET_SWZ(swizzle, 3) <= SWIZZLE_W); + src->Swizzle = swizzle; + + src->RelAddr = relAddr; +} + + +/* + * Setup storage pointing to a scalar constant/literal. + */ +static void +constant_to_storage(slang_emit_info *emitInfo, + GLfloat val, + slang_ir_storage *store) +{ + GLuint swizzle; + GLint reg; + GLfloat value[4]; + + value[0] = val; + reg = _mesa_add_unnamed_constant(emitInfo->prog->Parameters, + value, 1, &swizzle); + + memset(store, 0, sizeof(*store)); + store->File = PROGRAM_CONSTANT; + store->Index = reg; + store->Swizzle = swizzle; +} + + +/** + * Add new instruction at end of given program. + * \param prog the program to append instruction onto + * \param opcode opcode for the new instruction + * \return pointer to the new instruction + */ +static struct prog_instruction * +new_instruction(slang_emit_info *emitInfo, gl_inst_opcode opcode) +{ + struct gl_program *prog = emitInfo->prog; + struct prog_instruction *inst; + +#if 0 + /* print prev inst */ + if (prog->NumInstructions > 0) { + _mesa_print_instruction(prog->Instructions + prog->NumInstructions - 1); + } +#endif + assert(prog->NumInstructions <= emitInfo->MaxInstructions); + + if (prog->NumInstructions == emitInfo->MaxInstructions) { + /* grow the instruction buffer */ + emitInfo->MaxInstructions += 20; + prog->Instructions = + _mesa_realloc_instructions(prog->Instructions, + prog->NumInstructions, + emitInfo->MaxInstructions); + } + + inst = prog->Instructions + prog->NumInstructions; + prog->NumInstructions++; + _mesa_init_instructions(inst, 1); + inst->Opcode = opcode; + inst->BranchTarget = -1; /* invalid */ + /* + printf("New inst %d: %p %s\n", prog->NumInstructions-1,(void*)inst, + _mesa_opcode_string(inst->Opcode)); + */ + return inst; +} + + +static struct prog_instruction * +emit_arl_load(slang_emit_info *emitInfo, + gl_register_file file, GLint index, GLuint swizzle) +{ + struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_ARL); + inst->SrcReg[0].File = file; + inst->SrcReg[0].Index = index; + inst->SrcReg[0].Swizzle = fix_swizzle(swizzle); + inst->DstReg.File = PROGRAM_ADDRESS; + inst->DstReg.Index = 0; + inst->DstReg.WriteMask = WRITEMASK_X; + return inst; +} + + +/** + * Emit a new instruction with given opcode, operands. + * At this point the instruction may have multiple indirect register + * loads/stores. We convert those into ARL loads and address-relative + * operands. See comments inside. + * At some point in the future we could directly emit indirectly addressed + * registers in Mesa GPU instructions. + */ +static struct prog_instruction * +emit_instruction(slang_emit_info *emitInfo, + gl_inst_opcode opcode, + const slang_ir_storage *dst, + const slang_ir_storage *src0, + const slang_ir_storage *src1, + const slang_ir_storage *src2) +{ + struct prog_instruction *inst; + GLuint numIndirect = 0; + const slang_ir_storage *src[3]; + slang_ir_storage newSrc[3], newDst; + GLuint i; + GLboolean isTemp[3]; + + isTemp[0] = isTemp[1] = isTemp[2] = GL_FALSE; + + src[0] = src0; + src[1] = src1; + src[2] = src2; + + /* count up how many operands are indirect loads */ + for (i = 0; i < 3; i++) { + if (src[i] && src[i]->IsIndirect) + numIndirect++; + } + if (dst && dst->IsIndirect) + numIndirect++; + + /* Take special steps for indirect register loads. + * If we had multiple address registers this would be simpler. + * For example, this GLSL code: + * x[i] = y[j] + z[k]; + * would translate into something like: + * ARL ADDR.x, i; + * ARL ADDR.y, j; + * ARL ADDR.z, k; + * ADD TEMP[ADDR.x+5], TEMP[ADDR.y+9], TEMP[ADDR.z+4]; + * But since we currently only have one address register we have to do this: + * ARL ADDR.x, i; + * MOV t1, TEMP[ADDR.x+9]; + * ARL ADDR.x, j; + * MOV t2, TEMP[ADDR.x+4]; + * ARL ADDR.x, k; + * ADD TEMP[ADDR.x+5], t1, t2; + * The code here figures this out... + */ + if (numIndirect > 0) { + for (i = 0; i < 3; i++) { + if (src[i] && src[i]->IsIndirect) { + /* load the ARL register with the indirect register */ + emit_arl_load(emitInfo, + src[i]->IndirectFile, + src[i]->IndirectIndex, + src[i]->IndirectSwizzle); + + if (numIndirect > 1) { + /* Need to load src[i] into a temporary register */ + slang_ir_storage srcRelAddr; + alloc_local_temp(emitInfo, &newSrc[i], src[i]->Size); + isTemp[i] = GL_TRUE; + + /* set RelAddr flag on src register */ + srcRelAddr = *src[i]; + srcRelAddr.RelAddr = GL_TRUE; + srcRelAddr.IsIndirect = GL_FALSE; /* not really needed */ + + /* MOV newSrc, srcRelAddr; */ + inst = emit_instruction(emitInfo, + OPCODE_MOV, + &newSrc[i], + &srcRelAddr, + NULL, + NULL); + + src[i] = &newSrc[i]; + } + else { + /* just rewrite the src[i] storage to be ARL-relative */ + newSrc[i] = *src[i]; + newSrc[i].RelAddr = GL_TRUE; + newSrc[i].IsIndirect = GL_FALSE; /* not really needed */ + src[i] = &newSrc[i]; + } + } + } + } + + /* Take special steps for indirect dest register write */ + if (dst && dst->IsIndirect) { + /* load the ARL register with the indirect register */ + emit_arl_load(emitInfo, + dst->IndirectFile, + dst->IndirectIndex, + dst->IndirectSwizzle); + newDst = *dst; + newDst.RelAddr = GL_TRUE; + newDst.IsIndirect = GL_FALSE; + dst = &newDst; + } + + /* OK, emit the instruction and its dst, src regs */ + inst = new_instruction(emitInfo, opcode); + if (!inst) + return NULL; + + if (dst) + storage_to_dst_reg(&inst->DstReg, dst); + + for (i = 0; i < 3; i++) { + if (src[i]) + storage_to_src_reg(&inst->SrcReg[i], src[i]); + } + + /* Free any temp registers that we allocated above */ + for (i = 0; i < 3; i++) { + if (isTemp[i]) + _slang_free_temp(emitInfo->vt, &newSrc[i]); + } + + return inst; +} + + + +/** + * Put a comment on the given instruction. + */ +static void +inst_comment(struct prog_instruction *inst, const char *comment) +{ + if (inst) + inst->Comment = _mesa_strdup(comment); +} + + + +/** + * Return pointer to last instruction in program. + */ +static struct prog_instruction * +prev_instruction(slang_emit_info *emitInfo) +{ + struct gl_program *prog = emitInfo->prog; + if (prog->NumInstructions == 0) + return NULL; + else + return prog->Instructions + prog->NumInstructions - 1; +} + + +static struct prog_instruction * +emit(slang_emit_info *emitInfo, slang_ir_node *n); + + +/** + * Return an annotation string for given node's storage. + */ +static char * +storage_annotation(const slang_ir_node *n, const struct gl_program *prog) +{ +#if ANNOTATE + const slang_ir_storage *st = n->Store; + static char s[100] = ""; + + if (!st) + return _mesa_strdup(""); + + switch (st->File) { + case PROGRAM_CONSTANT: + if (st->Index >= 0) { + const GLfloat *val = prog->Parameters->ParameterValues[st->Index]; + if (st->Swizzle == SWIZZLE_NOOP) + sprintf(s, "{%g, %g, %g, %g}", val[0], val[1], val[2], val[3]); + else { + sprintf(s, "%g", val[GET_SWZ(st->Swizzle, 0)]); + } + } + break; + case PROGRAM_TEMPORARY: + if (n->Var) + sprintf(s, "%s", (char *) n->Var->a_name); + else + sprintf(s, "t[%d]", st->Index); + break; + case PROGRAM_STATE_VAR: + case PROGRAM_UNIFORM: + sprintf(s, "%s", prog->Parameters->Parameters[st->Index].Name); + break; + case PROGRAM_VARYING: + sprintf(s, "%s", prog->Varying->Parameters[st->Index].Name); + break; + case PROGRAM_INPUT: + sprintf(s, "input[%d]", st->Index); + break; + case PROGRAM_OUTPUT: + sprintf(s, "output[%d]", st->Index); + break; + default: + s[0] = 0; + } + return _mesa_strdup(s); +#else + return NULL; +#endif +} + + +/** + * Return an annotation string for an instruction. + */ +static char * +instruction_annotation(gl_inst_opcode opcode, char *dstAnnot, + char *srcAnnot0, char *srcAnnot1, char *srcAnnot2) +{ +#if ANNOTATE + const char *operator; + char *s; + int len = 50; + + if (dstAnnot) + len += strlen(dstAnnot); + else + dstAnnot = _mesa_strdup(""); + + if (srcAnnot0) + len += strlen(srcAnnot0); + else + srcAnnot0 = _mesa_strdup(""); + + if (srcAnnot1) + len += strlen(srcAnnot1); + else + srcAnnot1 = _mesa_strdup(""); + + if (srcAnnot2) + len += strlen(srcAnnot2); + else + srcAnnot2 = _mesa_strdup(""); + + switch (opcode) { + case OPCODE_ADD: + operator = "+"; + break; + case OPCODE_SUB: + operator = "-"; + break; + case OPCODE_MUL: + operator = "*"; + break; + case OPCODE_DP2: + operator = "DP2"; + break; + case OPCODE_DP3: + operator = "DP3"; + break; + case OPCODE_DP4: + operator = "DP4"; + break; + case OPCODE_XPD: + operator = "XPD"; + break; + case OPCODE_RSQ: + operator = "RSQ"; + break; + case OPCODE_SGT: + operator = ">"; + break; + default: + operator = ","; + } + + s = (char *) malloc(len); + sprintf(s, "%s = %s %s %s %s", dstAnnot, + srcAnnot0, operator, srcAnnot1, srcAnnot2); + assert(_mesa_strlen(s) < len); + + free(dstAnnot); + free(srcAnnot0); + free(srcAnnot1); + free(srcAnnot2); + + return s; +#else + return NULL; +#endif +} + + +/** + * Emit an instruction that's just a comment. + */ +static struct prog_instruction * +emit_comment(slang_emit_info *emitInfo, const char *comment) +{ + struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_NOP); + inst_comment(inst, comment); + return inst; +} + + +/** + * Generate code for a simple arithmetic instruction. + * Either 1, 2 or 3 operands. + */ +static struct prog_instruction * +emit_arith(slang_emit_info *emitInfo, slang_ir_node *n) +{ + const slang_ir_info *info = _slang_ir_info(n->Opcode); + struct prog_instruction *inst; + GLuint i; + + assert(info); + assert(info->InstOpcode != OPCODE_NOP); + +#if PEEPHOLE_OPTIMIZATIONS + /* Look for MAD opportunity */ + if (info->NumParams == 2 && + n->Opcode == IR_ADD && n->Children[0]->Opcode == IR_MUL) { + /* found pattern IR_ADD(IR_MUL(A, B), C) */ + emit(emitInfo, n->Children[0]->Children[0]); /* A */ + emit(emitInfo, n->Children[0]->Children[1]); /* B */ + emit(emitInfo, n->Children[1]); /* C */ + alloc_node_storage(emitInfo, n, -1); /* dest */ + + inst = emit_instruction(emitInfo, + OPCODE_MAD, + n->Store, + n->Children[0]->Children[0]->Store, + n->Children[0]->Children[1]->Store, + n->Children[1]->Store); + + free_node_storage(emitInfo->vt, n->Children[0]->Children[0]); + free_node_storage(emitInfo->vt, n->Children[0]->Children[1]); + free_node_storage(emitInfo->vt, n->Children[1]); + return inst; + } + + if (info->NumParams == 2 && + n->Opcode == IR_ADD && n->Children[1]->Opcode == IR_MUL) { + /* found pattern IR_ADD(A, IR_MUL(B, C)) */ + emit(emitInfo, n->Children[0]); /* A */ + emit(emitInfo, n->Children[1]->Children[0]); /* B */ + emit(emitInfo, n->Children[1]->Children[1]); /* C */ + alloc_node_storage(emitInfo, n, -1); /* dest */ + + inst = emit_instruction(emitInfo, + OPCODE_MAD, + n->Store, + n->Children[1]->Children[0]->Store, + n->Children[1]->Children[1]->Store, + n->Children[0]->Store); + + free_node_storage(emitInfo->vt, n->Children[1]->Children[0]); + free_node_storage(emitInfo->vt, n->Children[1]->Children[1]); + free_node_storage(emitInfo->vt, n->Children[0]); + return inst; + } +#endif + + /* gen code for children, may involve temp allocation */ + for (i = 0; i < info->NumParams; i++) { + emit(emitInfo, n->Children[i]); + if (!n->Children[i] || !n->Children[i]->Store) { + /* error recovery */ + return NULL; + } + } + + /* result storage */ + alloc_node_storage(emitInfo, n, -1); + + inst = emit_instruction(emitInfo, + info->InstOpcode, + n->Store, /* dest */ + (info->NumParams > 0 ? n->Children[0]->Store : NULL), + (info->NumParams > 1 ? n->Children[1]->Store : NULL), + (info->NumParams > 2 ? n->Children[2]->Store : NULL) + ); + + /* free temps */ + for (i = 0; i < info->NumParams; i++) + free_node_storage(emitInfo->vt, n->Children[i]); + + return inst; +} + + +/** + * Emit code for == and != operators. These could normally be handled + * by emit_arith() except we need to be able to handle structure comparisons. + */ +static struct prog_instruction * +emit_compare(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst = NULL; + GLint size; + + assert(n->Opcode == IR_EQUAL || n->Opcode == IR_NOTEQUAL); + + /* gen code for children */ + emit(emitInfo, n->Children[0]); + emit(emitInfo, n->Children[1]); + + if (n->Children[0]->Store->Size != n->Children[1]->Store->Size) { + /* XXX this error should have been caught in slang_codegen.c */ + slang_info_log_error(emitInfo->log, "invalid operands to == or !="); + n->Store = NULL; + return NULL; + } + + /* final result is 1 bool */ + if (!alloc_node_storage(emitInfo, n, 1)) + return NULL; + + size = n->Children[0]->Store->Size; + + if (size == 1) { + gl_inst_opcode opcode = n->Opcode == IR_EQUAL ? OPCODE_SEQ : OPCODE_SNE; + inst = emit_instruction(emitInfo, + opcode, + n->Store, /* dest */ + n->Children[0]->Store, + n->Children[1]->Store, + NULL); + } + else if (size <= 4) { + /* compare two vectors. + * Unfortunately, there's no instruction to compare vectors and + * return a scalar result. Do it with some compare and dot product + * instructions... + */ + GLuint swizzle; + gl_inst_opcode dotOp; + slang_ir_storage tempStore; + + if (!alloc_local_temp(emitInfo, &tempStore, 4)) { + n->Store = NULL; + return NULL; + /* out of temps */ + } + + if (size == 4) { + dotOp = OPCODE_DP4; + swizzle = SWIZZLE_XYZW; + } + else if (size == 3) { + dotOp = OPCODE_DP3; + swizzle = SWIZZLE_XYZW; + } + else { + assert(size == 2); + dotOp = OPCODE_DP3; /* XXX use OPCODE_DP2 eventually */ + swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y); + } + + /* Compute inequality (temp = (A != B)) */ + inst = emit_instruction(emitInfo, + OPCODE_SNE, + &tempStore, + n->Children[0]->Store, + n->Children[1]->Store, + NULL); + inst_comment(inst, "Compare values"); + + /* Compute val = DOT(temp, temp) (reduction) */ + inst = emit_instruction(emitInfo, + dotOp, + n->Store, + &tempStore, + &tempStore, + NULL); + inst->SrcReg[0].Swizzle = inst->SrcReg[1].Swizzle = swizzle; /*override*/ + inst_comment(inst, "Reduce vec to bool"); + + _slang_free_temp(emitInfo->vt, &tempStore); /* free temp */ + + if (n->Opcode == IR_EQUAL) { + /* compute val = !val.x with SEQ val, val, 0; */ + slang_ir_storage zero; + constant_to_storage(emitInfo, 0.0, &zero); + inst = emit_instruction(emitInfo, + OPCODE_SEQ, + n->Store, /* dest */ + n->Store, + &zero, + NULL); + inst_comment(inst, "Invert true/false"); + } + } + else { + /* size > 4, struct or array compare. + * XXX this won't work reliably for structs with padding!! + */ + GLint i, num = (n->Children[0]->Store->Size + 3) / 4; + slang_ir_storage accTemp, sneTemp; + + if (!alloc_local_temp(emitInfo, &accTemp, 4)) + return NULL; + + if (!alloc_local_temp(emitInfo, &sneTemp, 4)) + return NULL; + + for (i = 0; i < num; i++) { + slang_ir_storage srcStore0 = *n->Children[0]->Store; + slang_ir_storage srcStore1 = *n->Children[1]->Store; + srcStore0.Index += i; + srcStore1.Index += i; + + if (i == 0) { + /* SNE accTemp, left[i], right[i] */ + inst = emit_instruction(emitInfo, OPCODE_SNE, + &accTemp, /* dest */ + &srcStore0, + &srcStore1, + NULL); + inst_comment(inst, "Begin struct/array comparison"); + } + else { + /* SNE sneTemp, left[i], right[i] */ + inst = emit_instruction(emitInfo, OPCODE_SNE, + &sneTemp, /* dest */ + &srcStore0, + &srcStore1, + NULL); + /* ADD accTemp, accTemp, sneTemp; # like logical-OR */ + inst = emit_instruction(emitInfo, OPCODE_ADD, + &accTemp, /* dest */ + &accTemp, + &sneTemp, + NULL); + } + } + + /* compute accTemp.x || accTemp.y || accTemp.z || accTemp.w with DOT4 */ + inst = emit_instruction(emitInfo, OPCODE_DP4, + n->Store, + &accTemp, + &accTemp, + NULL); + inst_comment(inst, "End struct/array comparison"); + + if (n->Opcode == IR_EQUAL) { + /* compute tmp.x = !tmp.x via tmp.x = (tmp.x == 0) */ + slang_ir_storage zero; + constant_to_storage(emitInfo, 0.0, &zero); + inst = emit_instruction(emitInfo, OPCODE_SEQ, + n->Store, /* dest */ + n->Store, + &zero, + NULL); + inst_comment(inst, "Invert true/false"); + } + + _slang_free_temp(emitInfo->vt, &accTemp); + _slang_free_temp(emitInfo->vt, &sneTemp); + } + + /* free temps */ + free_node_storage(emitInfo->vt, n->Children[0]); + free_node_storage(emitInfo->vt, n->Children[1]); + + return inst; +} + + + +/** + * Generate code for an IR_CLAMP instruction. + */ +static struct prog_instruction * +emit_clamp(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + slang_ir_node tmpNode; + + assert(n->Opcode == IR_CLAMP); + /* ch[0] = value + * ch[1] = min limit + * ch[2] = max limit + */ + + inst = emit(emitInfo, n->Children[0]); + + /* If lower limit == 0.0 and upper limit == 1.0, + * set prev instruction's SaturateMode field to SATURATE_ZERO_ONE. + * Else, + * emit OPCODE_MIN, OPCODE_MAX sequence. + */ +#if 0 + /* XXX this isn't quite finished yet */ + if (n->Children[1]->Opcode == IR_FLOAT && + n->Children[1]->Value[0] == 0.0 && + n->Children[1]->Value[1] == 0.0 && + n->Children[1]->Value[2] == 0.0 && + n->Children[1]->Value[3] == 0.0 && + n->Children[2]->Opcode == IR_FLOAT && + n->Children[2]->Value[0] == 1.0 && + n->Children[2]->Value[1] == 1.0 && + n->Children[2]->Value[2] == 1.0 && + n->Children[2]->Value[3] == 1.0) { + if (!inst) { + inst = prev_instruction(prog); + } + if (inst && inst->Opcode != OPCODE_NOP) { + /* and prev instruction's DstReg matches n->Children[0]->Store */ + inst->SaturateMode = SATURATE_ZERO_ONE; + n->Store = n->Children[0]->Store; + return inst; + } + } +#endif + + if (!alloc_node_storage(emitInfo, n, n->Children[0]->Store->Size)) + return NULL; + + emit(emitInfo, n->Children[1]); + emit(emitInfo, n->Children[2]); + + /* Some GPUs don't allow reading from output registers. So if the + * dest for this clamp() is an output reg, we can't use that reg for + * the intermediate result. Use a temp register instead. + */ + _mesa_bzero(&tmpNode, sizeof(tmpNode)); + alloc_node_storage(emitInfo, &tmpNode, n->Store->Size); + + /* tmp = max(ch[0], ch[1]) */ + inst = emit_instruction(emitInfo, OPCODE_MAX, + tmpNode.Store, /* dest */ + n->Children[0]->Store, + n->Children[1]->Store, + NULL); + + /* n->dest = min(tmp, ch[2]) */ + inst = emit_instruction(emitInfo, OPCODE_MIN, + n->Store, /* dest */ + tmpNode.Store, + n->Children[2]->Store, + NULL); + + free_node_storage(emitInfo->vt, &tmpNode); + + return inst; +} + + +static struct prog_instruction * +emit_negation(slang_emit_info *emitInfo, slang_ir_node *n) +{ + /* Implement as MOV dst, -src; */ + /* XXX we could look at the previous instruction and in some circumstances + * modify it to accomplish the negation. + */ + struct prog_instruction *inst; + + emit(emitInfo, n->Children[0]); + + if (!alloc_node_storage(emitInfo, n, n->Children[0]->Store->Size)) + return NULL; + + inst = emit_instruction(emitInfo, + OPCODE_MOV, + n->Store, /* dest */ + n->Children[0]->Store, + NULL, + NULL); + inst->SrcReg[0].Negate = NEGATE_XYZW; + return inst; +} + + +static struct prog_instruction * +emit_label(slang_emit_info *emitInfo, const slang_ir_node *n) +{ + assert(n->Label); +#if 0 + /* XXX this fails in loop tail code - investigate someday */ + assert(_slang_label_get_location(n->Label) < 0); + _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, + emitInfo->prog); +#else + if (_slang_label_get_location(n->Label) < 0) + _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, + emitInfo->prog); +#endif + return NULL; +} + + +/** + * Emit code for a function call. + * Note that for each time a function is called, we emit the function's + * body code again because the set of available registers may be different. + */ +static struct prog_instruction * +emit_fcall(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct gl_program *progSave; + struct prog_instruction *inst; + GLuint subroutineId; + GLuint maxInstSave; + + assert(n->Opcode == IR_CALL); + assert(n->Label); + + /* save/push cur program */ + maxInstSave = emitInfo->MaxInstructions; + progSave = emitInfo->prog; + + emitInfo->prog = new_subroutine(emitInfo, &subroutineId); + emitInfo->MaxInstructions = emitInfo->prog->NumInstructions; + + _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, + emitInfo->prog); + + if (emitInfo->EmitBeginEndSub) { + /* BGNSUB isn't a real instruction. + * We require a label (i.e. "foobar:") though, if we're going to + * print the program in the NV format. The BNGSUB instruction is + * really just a NOP to attach the label to. + */ + inst = new_instruction(emitInfo, OPCODE_BGNSUB); + inst_comment(inst, n->Label->Name); + } + + /* body of function: */ + emit(emitInfo, n->Children[0]); + n->Store = n->Children[0]->Store; + + /* add RET instruction now, if needed */ + inst = prev_instruction(emitInfo); + if (inst && inst->Opcode != OPCODE_RET) { + inst = new_instruction(emitInfo, OPCODE_RET); + } + + if (emitInfo->EmitBeginEndSub) { + inst = new_instruction(emitInfo, OPCODE_ENDSUB); + inst_comment(inst, n->Label->Name); + } + + /* pop/restore cur program */ + emitInfo->prog = progSave; + emitInfo->MaxInstructions = maxInstSave; + + /* emit the function call */ + inst = new_instruction(emitInfo, OPCODE_CAL); + /* The branch target is just the subroutine number (changed later) */ + inst->BranchTarget = subroutineId; + inst_comment(inst, n->Label->Name); + assert(inst->BranchTarget >= 0); + + return inst; +} + + +/** + * Emit code for a 'return' statement. + */ +static struct prog_instruction * +emit_return(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + assert(n); + assert(n->Opcode == IR_RETURN); + assert(n->Label); + inst = new_instruction(emitInfo, OPCODE_RET); + inst->DstReg.CondMask = COND_TR; /* always return */ + return inst; +} + + +static struct prog_instruction * +emit_kill(slang_emit_info *emitInfo) +{ + struct gl_fragment_program *fp; + struct prog_instruction *inst; + /* NV-KILL - discard fragment depending on condition code. + * Note that ARB-KILL depends on sign of vector operand. + */ + inst = new_instruction(emitInfo, OPCODE_KIL_NV); + inst->DstReg.CondMask = COND_TR; /* always kill */ + + assert(emitInfo->prog->Target == GL_FRAGMENT_PROGRAM_ARB); + fp = (struct gl_fragment_program *) emitInfo->prog; + fp->UsesKill = GL_TRUE; + + return inst; +} + + +static struct prog_instruction * +emit_tex(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + gl_inst_opcode opcode; + GLboolean shadow = GL_FALSE; + + switch (n->Opcode) { + case IR_TEX: + opcode = OPCODE_TEX; + break; + case IR_TEX_SH: + opcode = OPCODE_TEX; + shadow = GL_TRUE; + break; + case IR_TEXB: + opcode = OPCODE_TXB; + break; + case IR_TEXB_SH: + opcode = OPCODE_TXB; + shadow = GL_TRUE; + break; + case IR_TEXP: + opcode = OPCODE_TXP; + break; + case IR_TEXP_SH: + opcode = OPCODE_TXP; + shadow = GL_TRUE; + break; + default: + _mesa_problem(NULL, "Bad IR TEX code"); + return NULL; + } + + if (n->Children[0]->Opcode == IR_ELEMENT) { + /* array is the sampler (a uniform which'll indicate the texture unit) */ + assert(n->Children[0]->Children[0]->Store); + assert(n->Children[0]->Children[0]->Store->File == PROGRAM_SAMPLER); + + emit(emitInfo, n->Children[0]); + + n->Children[0]->Var = n->Children[0]->Children[0]->Var; + } else { + /* this is the sampler (a uniform which'll indicate the texture unit) */ + assert(n->Children[0]->Store); + assert(n->Children[0]->Store->File == PROGRAM_SAMPLER); + } + + /* emit code for the texcoord operand */ + (void) emit(emitInfo, n->Children[1]); + + /* alloc storage for result of texture fetch */ + if (!alloc_node_storage(emitInfo, n, 4)) + return NULL; + + /* emit TEX instruction; Child[1] is the texcoord */ + inst = emit_instruction(emitInfo, + opcode, + n->Store, + n->Children[1]->Store, + NULL, + NULL); + + inst->TexShadow = shadow; + + /* Store->Index is the uniform/sampler index */ + assert(n->Children[0]->Store->Index >= 0); + inst->TexSrcUnit = n->Children[0]->Store->Index; + inst->TexSrcTarget = n->Children[0]->Store->TexTarget; + + /* mark the sampler as being used */ + _mesa_use_uniform(emitInfo->prog->Parameters, + (char *) n->Children[0]->Var->a_name); + + return inst; +} + + +/** + * Assignment/copy + */ +static struct prog_instruction * +emit_copy(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + + assert(n->Opcode == IR_COPY); + + /* lhs */ + emit(emitInfo, n->Children[0]); + if (!n->Children[0]->Store || n->Children[0]->Store->Index < 0) { + /* an error should have been already recorded */ + return NULL; + } + + /* rhs */ + assert(n->Children[1]); + inst = emit(emitInfo, n->Children[1]); + + if (!n->Children[1]->Store || n->Children[1]->Store->Index < 0) { + if (!emitInfo->log->text && !emitInfo->UnresolvedFunctions) { + /* XXX this error should have been caught in slang_codegen.c */ + slang_info_log_error(emitInfo->log, "invalid assignment"); + } + return NULL; + } + + assert(n->Children[1]->Store->Index >= 0); + + /*assert(n->Children[0]->Store->Size == n->Children[1]->Store->Size);*/ + + n->Store = n->Children[0]->Store; + + if (n->Store->File == PROGRAM_SAMPLER) { + /* no code generated for sampler assignments, + * just copy the sampler index/target at compile time. + */ + n->Store->Index = n->Children[1]->Store->Index; + n->Store->TexTarget = n->Children[1]->Store->TexTarget; + return NULL; + } + +#if PEEPHOLE_OPTIMIZATIONS + if (inst && + (n->Children[1]->Opcode != IR_SWIZZLE) && + _slang_is_temp(emitInfo->vt, n->Children[1]->Store) && + (inst->DstReg.File == n->Children[1]->Store->File) && + (inst->DstReg.Index == n->Children[1]->Store->Index) && + !n->Children[0]->Store->IsIndirect && + n->Children[0]->Store->Size <= 4) { + /* Peephole optimization: + * The Right-Hand-Side has its results in a temporary place. + * Modify the RHS (and the prev instruction) to store its results + * in the destination specified by n->Children[0]. + * Then, this MOVE is a no-op. + * Ex: + * MUL tmp, x, y; + * MOV a, tmp; + * becomes: + * MUL a, x, y; + */ + + /* fixup the previous instruction (which stored the RHS result) */ + assert(n->Children[0]->Store->Index >= 0); + storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store); + return inst; + } + else +#endif + { + if (n->Children[0]->Store->Size > 4) { + /* move matrix/struct etc (block of registers) */ + slang_ir_storage dstStore = *n->Children[0]->Store; + slang_ir_storage srcStore = *n->Children[1]->Store; + GLint size = srcStore.Size; + ASSERT(n->Children[1]->Store->Swizzle == SWIZZLE_NOOP); + dstStore.Size = 4; + srcStore.Size = 4; + while (size >= 4) { + inst = emit_instruction(emitInfo, OPCODE_MOV, + &dstStore, + &srcStore, + NULL, + NULL); + inst_comment(inst, "IR_COPY block"); + srcStore.Index++; + dstStore.Index++; + size -= 4; + } + } + else { + /* single register move */ + char *srcAnnot, *dstAnnot; + assert(n->Children[0]->Store->Index >= 0); + inst = emit_instruction(emitInfo, OPCODE_MOV, + n->Children[0]->Store, /* dest */ + n->Children[1]->Store, + NULL, + NULL); + dstAnnot = storage_annotation(n->Children[0], emitInfo->prog); + srcAnnot = storage_annotation(n->Children[1], emitInfo->prog); + inst->Comment = instruction_annotation(inst->Opcode, dstAnnot, + srcAnnot, NULL, NULL); + } + free_node_storage(emitInfo->vt, n->Children[1]); + return inst; + } +} + + +/** + * An IR_COND node wraps a boolean expression which is used by an + * IF or WHILE test. This is where we'll set condition codes, if needed. + */ +static struct prog_instruction * +emit_cond(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + + assert(n->Opcode == IR_COND); + + if (!n->Children[0]) + return NULL; + + /* emit code for the expression */ + inst = emit(emitInfo, n->Children[0]); + + if (!n->Children[0]->Store) { + /* error recovery */ + return NULL; + } + + assert(n->Children[0]->Store); + /*assert(n->Children[0]->Store->Size == 1);*/ + + if (emitInfo->EmitCondCodes) { + if (inst && + n->Children[0]->Store && + inst->DstReg.File == n->Children[0]->Store->File && + inst->DstReg.Index == n->Children[0]->Store->Index) { + /* The previous instruction wrote to the register who's value + * we're testing. Just fix that instruction so that the + * condition codes are computed. + */ + inst->CondUpdate = GL_TRUE; + n->Store = n->Children[0]->Store; + return inst; + } + else { + /* This'll happen for things like "if (i) ..." where no code + * is normally generated for the expression "i". + * Generate a move instruction just to set condition codes. + */ + if (!alloc_node_storage(emitInfo, n, 1)) + return NULL; + inst = emit_instruction(emitInfo, OPCODE_MOV, + n->Store, /* dest */ + n->Children[0]->Store, + NULL, + NULL); + inst->CondUpdate = GL_TRUE; + inst_comment(inst, "COND expr"); + _slang_free_temp(emitInfo->vt, n->Store); + return inst; + } + } + else { + /* No-op: the boolean result of the expression is in a regular reg */ + n->Store = n->Children[0]->Store; + return inst; + } +} + + +/** + * Logical-NOT + */ +static struct prog_instruction * +emit_not(slang_emit_info *emitInfo, slang_ir_node *n) +{ + static const struct { + gl_inst_opcode op, opNot; + } operators[] = { + { OPCODE_SLT, OPCODE_SGE }, + { OPCODE_SLE, OPCODE_SGT }, + { OPCODE_SGT, OPCODE_SLE }, + { OPCODE_SGE, OPCODE_SLT }, + { OPCODE_SEQ, OPCODE_SNE }, + { OPCODE_SNE, OPCODE_SEQ }, + { 0, 0 } + }; + struct prog_instruction *inst; + slang_ir_storage zero; + GLuint i; + + /* child expr */ + inst = emit(emitInfo, n->Children[0]); + +#if PEEPHOLE_OPTIMIZATIONS + if (inst) { + /* if the prev instruction was a comparison instruction, invert it */ + for (i = 0; operators[i].op; i++) { + if (inst->Opcode == operators[i].op) { + inst->Opcode = operators[i].opNot; + n->Store = n->Children[0]->Store; + return inst; + } + } + } +#endif + + /* else, invert using SEQ (v = v == 0) */ + if (!alloc_node_storage(emitInfo, n, n->Children[0]->Store->Size)) + return NULL; + + constant_to_storage(emitInfo, 0.0, &zero); + inst = emit_instruction(emitInfo, + OPCODE_SEQ, + n->Store, + n->Children[0]->Store, + &zero, + NULL); + inst_comment(inst, "NOT"); + + free_node_storage(emitInfo->vt, n->Children[0]); + + return inst; +} + + +static struct prog_instruction * +emit_if(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct gl_program *prog = emitInfo->prog; + GLuint ifInstLoc, elseInstLoc = 0; + GLuint condWritemask = 0; + + /* emit condition expression code */ + { + struct prog_instruction *inst; + inst = emit(emitInfo, n->Children[0]); + if (emitInfo->EmitCondCodes) { + if (!inst) { + /* error recovery */ + return NULL; + } + condWritemask = inst->DstReg.WriteMask; + } + } + + if (!n->Children[0]->Store) + return NULL; + +#if 0 + assert(n->Children[0]->Store->Size == 1); /* a bool! */ +#endif + + ifInstLoc = prog->NumInstructions; + if (emitInfo->EmitHighLevelInstructions) { + if (emitInfo->EmitCondCodes) { + /* IF condcode THEN ... */ + struct prog_instruction *ifInst; + ifInst = new_instruction(emitInfo, OPCODE_IF); + ifInst->DstReg.CondMask = COND_NE; /* if cond is non-zero */ + /* only test the cond code (1 of 4) that was updated by the + * previous instruction. + */ + ifInst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); + } + else { + /* IF src[0] THEN ... */ + emit_instruction(emitInfo, OPCODE_IF, + NULL, /* dst */ + n->Children[0]->Store, /* op0 */ + NULL, + NULL); + } + } + else { + /* conditional jump to else, or endif */ + struct prog_instruction *ifInst = new_instruction(emitInfo, OPCODE_BRA); + ifInst->DstReg.CondMask = COND_EQ; /* BRA if cond is zero */ + inst_comment(ifInst, "if zero"); + ifInst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); + } + + /* if body */ + emit(emitInfo, n->Children[1]); + + if (n->Children[2]) { + /* have else body */ + elseInstLoc = prog->NumInstructions; + if (emitInfo->EmitHighLevelInstructions) { + (void) new_instruction(emitInfo, OPCODE_ELSE); + } + else { + /* jump to endif instruction */ + struct prog_instruction *inst; + inst = new_instruction(emitInfo, OPCODE_BRA); + inst_comment(inst, "else"); + inst->DstReg.CondMask = COND_TR; /* always branch */ + } + prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions; + emit(emitInfo, n->Children[2]); + } + else { + /* no else body */ + prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions; + } + + if (emitInfo->EmitHighLevelInstructions) { + (void) new_instruction(emitInfo, OPCODE_ENDIF); + } + + if (n->Children[2]) { + prog->Instructions[elseInstLoc].BranchTarget = prog->NumInstructions; + } + return NULL; +} + + +static struct prog_instruction * +emit_loop(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct gl_program *prog = emitInfo->prog; + struct prog_instruction *endInst; + GLuint beginInstLoc, tailInstLoc, endInstLoc; + slang_ir_node *ir; + + /* emit OPCODE_BGNLOOP */ + beginInstLoc = prog->NumInstructions; + if (emitInfo->EmitHighLevelInstructions) { + (void) new_instruction(emitInfo, OPCODE_BGNLOOP); + } + + /* body */ + emit(emitInfo, n->Children[0]); + + /* tail */ + tailInstLoc = prog->NumInstructions; + if (n->Children[1]) { + if (emitInfo->EmitComments) + emit_comment(emitInfo, "Loop tail code:"); + emit(emitInfo, n->Children[1]); + } + + endInstLoc = prog->NumInstructions; + if (emitInfo->EmitHighLevelInstructions) { + /* emit OPCODE_ENDLOOP */ + endInst = new_instruction(emitInfo, OPCODE_ENDLOOP); + } + else { + /* emit unconditional BRA-nch */ + endInst = new_instruction(emitInfo, OPCODE_BRA); + endInst->DstReg.CondMask = COND_TR; /* always true */ + } + /* ENDLOOP's BranchTarget points to the BGNLOOP inst */ + endInst->BranchTarget = beginInstLoc; + + if (emitInfo->EmitHighLevelInstructions) { + /* BGNLOOP's BranchTarget points to the ENDLOOP inst */ + prog->Instructions[beginInstLoc].BranchTarget = prog->NumInstructions -1; + } + + /* Done emitting loop code. Now walk over the loop's linked list of + * BREAK and CONT nodes, filling in their BranchTarget fields (which + * will point to the ENDLOOP+1 or BGNLOOP instructions, respectively). + */ + for (ir = n->List; ir; ir = ir->List) { + struct prog_instruction *inst = prog->Instructions + ir->InstLocation; + assert(inst->BranchTarget < 0); + if (ir->Opcode == IR_BREAK || + ir->Opcode == IR_BREAK_IF_TRUE) { + assert(inst->Opcode == OPCODE_BRK || + inst->Opcode == OPCODE_BRA); + /* go to instruction after end of loop */ + inst->BranchTarget = endInstLoc + 1; + } + else { + assert(ir->Opcode == IR_CONT || + ir->Opcode == IR_CONT_IF_TRUE); + assert(inst->Opcode == OPCODE_CONT || + inst->Opcode == OPCODE_BRA); + /* go to instruction at tail of loop */ + inst->BranchTarget = endInstLoc; + } + } + return NULL; +} + + +/** + * Unconditional "continue" or "break" statement. + * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted. + */ +static struct prog_instruction * +emit_cont_break(slang_emit_info *emitInfo, slang_ir_node *n) +{ + gl_inst_opcode opcode; + struct prog_instruction *inst; + + if (n->Opcode == IR_CONT) { + /* we need to execute the loop's tail code before doing CONT */ + assert(n->Parent); + assert(n->Parent->Opcode == IR_LOOP); + if (n->Parent->Children[1]) { + /* emit tail code */ + if (emitInfo->EmitComments) { + emit_comment(emitInfo, "continue - tail code:"); + } + emit(emitInfo, n->Parent->Children[1]); + } + } + + /* opcode selection */ + if (emitInfo->EmitHighLevelInstructions) { + opcode = (n->Opcode == IR_CONT) ? OPCODE_CONT : OPCODE_BRK; + } + else { + opcode = OPCODE_BRA; + } + n->InstLocation = emitInfo->prog->NumInstructions; + inst = new_instruction(emitInfo, opcode); + inst->DstReg.CondMask = COND_TR; /* always true */ + return inst; +} + + +/** + * Conditional "continue" or "break" statement. + * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted. + */ +static struct prog_instruction * +emit_cont_break_if_true(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + + assert(n->Opcode == IR_CONT_IF_TRUE || + n->Opcode == IR_BREAK_IF_TRUE); + + /* evaluate condition expr, setting cond codes */ + inst = emit(emitInfo, n->Children[0]); + if (emitInfo->EmitCondCodes) { + assert(inst); + inst->CondUpdate = GL_TRUE; + } + + n->InstLocation = emitInfo->prog->NumInstructions; + + /* opcode selection */ + if (emitInfo->EmitHighLevelInstructions) { + const gl_inst_opcode opcode + = (n->Opcode == IR_CONT_IF_TRUE) ? OPCODE_CONT : OPCODE_BRK; + if (emitInfo->EmitCondCodes) { + /* Get the writemask from the previous instruction which set + * the condcodes. Use that writemask as the CondSwizzle. + */ + const GLuint condWritemask = inst->DstReg.WriteMask; + inst = new_instruction(emitInfo, opcode); + inst->DstReg.CondMask = COND_NE; + inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); + return inst; + } + else { + /* IF reg + * BRK/CONT; + * ENDIF + */ + GLint ifInstLoc; + ifInstLoc = emitInfo->prog->NumInstructions; + inst = emit_instruction(emitInfo, OPCODE_IF, + NULL, /* dest */ + n->Children[0]->Store, + NULL, + NULL); + n->InstLocation = emitInfo->prog->NumInstructions; + + inst = new_instruction(emitInfo, opcode); + inst = new_instruction(emitInfo, OPCODE_ENDIF); + + emitInfo->prog->Instructions[ifInstLoc].BranchTarget + = emitInfo->prog->NumInstructions; + return inst; + } + } + else { + const GLuint condWritemask = inst->DstReg.WriteMask; + assert(emitInfo->EmitCondCodes); + inst = new_instruction(emitInfo, OPCODE_BRA); + inst->DstReg.CondMask = COND_NE; + inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); + return inst; + } +} + + +/** + * Return the size of a swizzle mask given that some swizzle components + * may be NIL/undefined. For example: + * swizzle_size(".zzxx") = 4 + * swizzle_size(".xy??") = 2 + * swizzle_size(".w???") = 1 + */ +static GLuint +swizzle_size(GLuint swizzle) +{ + GLuint i; + for (i = 0; i < 4; i++) { + if (GET_SWZ(swizzle, i) == SWIZZLE_NIL) + return i; + } + return 4; +} + + +static struct prog_instruction * +emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + + inst = emit(emitInfo, n->Children[0]); + + if (!n->Store->Parent) { + /* this covers a case such as "(b ? p : q).x" */ + n->Store->Parent = n->Children[0]->Store; + assert(n->Store->Parent); + } + + { + const GLuint swizzle = n->Store->Swizzle; + /* new storage is parent storage with updated Swizzle + Size fields */ + _slang_copy_ir_storage(n->Store, n->Store->Parent); + /* Apply this node's swizzle to parent's storage */ + n->Store->Swizzle = _slang_swizzle_swizzle(n->Store->Swizzle, swizzle); + /* Update size */ + n->Store->Size = swizzle_size(n->Store->Swizzle); + } + + assert(!n->Store->Parent); + assert(n->Store->Index >= 0); + + return inst; +} + + +/** + * Dereference array element: element == array[index] + * This basically involves emitting code for computing the array index + * and updating the node/element's storage info. + */ +static struct prog_instruction * +emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n) +{ + slang_ir_storage *arrayStore, *indexStore; + const int elemSize = n->Store->Size; /* number of floats */ + const GLint elemSizeVec = (elemSize + 3) / 4; /* number of vec4 */ + struct prog_instruction *inst; + + assert(n->Opcode == IR_ELEMENT); + assert(elemSize > 0); + + /* special case for built-in state variables, like light state */ + { + slang_ir_storage *root = n->Store; + assert(!root->Parent); + while (root->Parent) + root = root->Parent; + + if (root->File == PROGRAM_STATE_VAR) { + GLboolean direct; + GLint index = + _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct); + if (index < 0) { + /* error */ + return NULL; + } + if (direct) { + n->Store->Index = index; + return NULL; /* all done */ + } + } + } + + /* do codegen for array itself */ + emit(emitInfo, n->Children[0]); + arrayStore = n->Children[0]->Store; + + /* The initial array element storage is the array's storage, + * then modified below. + */ + _slang_copy_ir_storage(n->Store, arrayStore); + + + if (n->Children[1]->Opcode == IR_FLOAT) { + /* Constant array index */ + const GLint element = (GLint) n->Children[1]->Value[0]; + + /* this element's storage is the array's storage, plus constant offset */ + n->Store->Index += elemSizeVec * element; + } + else { + /* Variable array index */ + + /* do codegen for array index expression */ + emit(emitInfo, n->Children[1]); + indexStore = n->Children[1]->Store; + + if (indexStore->IsIndirect) { + /* need to put the array index into a temporary since we can't + * directly support a[b[i]] constructs. + */ + + + /*indexStore = tempstore();*/ + } + + + if (elemSize > 4) { + /* need to multiply array index by array element size */ + struct prog_instruction *inst; + slang_ir_storage *indexTemp; + slang_ir_storage elemSizeStore; + + /* allocate 1 float indexTemp */ + indexTemp = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1); + _slang_alloc_temp(emitInfo->vt, indexTemp); + + /* allocate a constant containing the element size */ + constant_to_storage(emitInfo, (float) elemSizeVec, &elemSizeStore); + + /* multiply array index by element size */ + inst = emit_instruction(emitInfo, + OPCODE_MUL, + indexTemp, /* dest */ + indexStore, /* the index */ + &elemSizeStore, + NULL); + + indexStore = indexTemp; + } + + if (arrayStore->IsIndirect) { + /* ex: in a[i][j], a[i] (the arrayStore) is indirect */ + /* Need to add indexStore to arrayStore->Indirect store */ + slang_ir_storage indirectArray; + slang_ir_storage *indexTemp; + + _slang_init_ir_storage(&indirectArray, + arrayStore->IndirectFile, + arrayStore->IndirectIndex, + 1, + arrayStore->IndirectSwizzle); + + /* allocate 1 float indexTemp */ + indexTemp = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1); + _slang_alloc_temp(emitInfo->vt, indexTemp); + + inst = emit_instruction(emitInfo, + OPCODE_ADD, + indexTemp, /* dest */ + indexStore, /* the index */ + &indirectArray, /* indirect array base */ + NULL); + + indexStore = indexTemp; + } + + /* update the array element storage info */ + n->Store->IsIndirect = GL_TRUE; + n->Store->IndirectFile = indexStore->File; + n->Store->IndirectIndex = indexStore->Index; + n->Store->IndirectSwizzle = indexStore->Swizzle; + } + + n->Store->Size = elemSize; + n->Store->Swizzle = _slang_var_swizzle(elemSize, 0); + + return NULL; /* no instruction */ +} + + +/** + * Resolve storage for accessing a structure field. + */ +static struct prog_instruction * +emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n) +{ + slang_ir_storage *root = n->Store; + GLint fieldOffset, fieldSize; + + assert(n->Opcode == IR_FIELD); + + assert(!root->Parent); + while (root->Parent) + root = root->Parent; + + /* If this is the field of a state var, allocate constant/uniform + * storage for it now if we haven't already. + * Note that we allocate storage (uniform/constant slots) for state + * variables here rather than at declaration time so we only allocate + * space for the ones that we actually use! + */ + if (root->File == PROGRAM_STATE_VAR) { + GLboolean direct; + GLint index = _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct); + if (index < 0) { + slang_info_log_error(emitInfo->log, "Error parsing state variable"); + return NULL; + } + if (direct) { + root->Index = index; + return NULL; /* all done */ + } + } + + /* do codegen for struct */ + emit(emitInfo, n->Children[0]); + assert(n->Children[0]->Store->Index >= 0); + + + fieldOffset = n->Store->Index; + fieldSize = n->Store->Size; + + _slang_copy_ir_storage(n->Store, n->Children[0]->Store); + + n->Store->Index = n->Children[0]->Store->Index + fieldOffset / 4; + n->Store->Size = fieldSize; + + switch (fieldSize) { + case 1: + { + GLint swz = fieldOffset % 4; + n->Store->Swizzle = MAKE_SWIZZLE4(swz, swz, swz, swz); + } + break; + case 2: + n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, + SWIZZLE_NIL, SWIZZLE_NIL); + break; + case 3: + n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, + SWIZZLE_Z, SWIZZLE_NIL); + break; + default: + n->Store->Swizzle = SWIZZLE_XYZW; + } + + assert(n->Store->Index >= 0); + + return NULL; /* no instruction */ +} + + +/** + * Emit code for a variable declaration. + * This usually doesn't result in any code generation, but just + * memory allocation. + */ +static struct prog_instruction * +emit_var_decl(slang_emit_info *emitInfo, slang_ir_node *n) +{ + assert(n->Store); + assert(n->Store->File != PROGRAM_UNDEFINED); + assert(n->Store->Size > 0); + /*assert(n->Store->Index < 0);*/ + + if (!n->Var || n->Var->isTemp) { + /* a nameless/temporary variable, will be freed after first use */ + /*NEW*/ + if (n->Store->Index < 0 && !_slang_alloc_temp(emitInfo->vt, n->Store)) { + slang_info_log_error(emitInfo->log, + "Ran out of registers, too many temporaries"); + return NULL; + } + } + else { + /* a regular variable */ + _slang_add_variable(emitInfo->vt, n->Var); + if (!_slang_alloc_var(emitInfo->vt, n->Store)) { + slang_info_log_error(emitInfo->log, + "Ran out of registers, too many variables"); + return NULL; + } + /* + printf("IR_VAR_DECL %s %d store %p\n", + (char*) n->Var->a_name, n->Store->Index, (void*) n->Store); + */ + assert(n->Var->store == n->Store); + } + if (emitInfo->EmitComments) { + /* emit NOP with comment describing the variable's storage location */ + char s[1000]; + sprintf(s, "TEMP[%d]%s = variable %s (size %d)", + n->Store->Index, + _mesa_swizzle_string(n->Store->Swizzle, 0, GL_FALSE), + (n->Var ? (char *) n->Var->a_name : "anonymous"), + n->Store->Size); + emit_comment(emitInfo, s); + } + return NULL; +} + + +/** + * Emit code for a reference to a variable. + * Actually, no code is generated but we may do some memory allocation. + * In particular, state vars (uniforms) are allocated on an as-needed basis. + */ +static struct prog_instruction * +emit_var_ref(slang_emit_info *emitInfo, slang_ir_node *n) +{ + assert(n->Store); + assert(n->Store->File != PROGRAM_UNDEFINED); + + if (n->Store->File == PROGRAM_STATE_VAR && n->Store->Index < 0) { + GLboolean direct; + GLint index = _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct); + if (index < 0) { + /* error */ + char s[100]; + /* XXX isn't this really an out of memory/resources error? */ + _mesa_snprintf(s, sizeof(s), "Undefined variable '%s'", + (char *) n->Var->a_name); + slang_info_log_error(emitInfo->log, s); + return NULL; + } + + n->Store->Index = index; + } + else if (n->Store->File == PROGRAM_UNIFORM || + n->Store->File == PROGRAM_SAMPLER) { + /* mark var as used */ + _mesa_use_uniform(emitInfo->prog->Parameters, (char *) n->Var->a_name); + } + else if (n->Store->File == PROGRAM_INPUT) { + assert(n->Store->Index >= 0); + emitInfo->prog->InputsRead |= (1 << n->Store->Index); + } + + if (n->Store->Index < 0) { + /* probably ran out of registers */ + return NULL; + } + assert(n->Store->Size > 0); + + return NULL; +} + + +static struct prog_instruction * +emit(slang_emit_info *emitInfo, slang_ir_node *n) +{ + struct prog_instruction *inst; + if (!n) + return NULL; + + if (emitInfo->log->error_flag) { + return NULL; + } + + if (n->Comment) { + inst = new_instruction(emitInfo, OPCODE_NOP); + inst->Comment = _mesa_strdup(n->Comment); + inst = NULL; + } + + switch (n->Opcode) { + case IR_SEQ: + /* sequence of two sub-trees */ + assert(n->Children[0]); + assert(n->Children[1]); + emit(emitInfo, n->Children[0]); + if (emitInfo->log->error_flag) + return NULL; + inst = emit(emitInfo, n->Children[1]); +#if 0 + assert(!n->Store); +#endif + n->Store = n->Children[1]->Store; + return inst; + + case IR_SCOPE: + /* new variable scope */ + _slang_push_var_table(emitInfo->vt); + inst = emit(emitInfo, n->Children[0]); + _slang_pop_var_table(emitInfo->vt); + return inst; + + case IR_VAR_DECL: + /* Variable declaration - allocate a register for it */ + inst = emit_var_decl(emitInfo, n); + return inst; + + case IR_VAR: + /* Reference to a variable + * Storage should have already been resolved/allocated. + */ + return emit_var_ref(emitInfo, n); + + case IR_ELEMENT: + return emit_array_element(emitInfo, n); + case IR_FIELD: + return emit_struct_field(emitInfo, n); + case IR_SWIZZLE: + return emit_swizzle(emitInfo, n); + + /* Simple arithmetic */ + /* unary */ + case IR_MOVE: + case IR_RSQ: + case IR_RCP: + case IR_FLOOR: + case IR_FRAC: + case IR_F_TO_I: + case IR_I_TO_F: + case IR_ABS: + case IR_SIN: + case IR_COS: + case IR_DDX: + case IR_DDY: + case IR_EXP: + case IR_EXP2: + case IR_LOG2: + case IR_NOISE1: + case IR_NOISE2: + case IR_NOISE3: + case IR_NOISE4: + case IR_NRM4: + case IR_NRM3: + /* binary */ + case IR_ADD: + case IR_SUB: + case IR_MUL: + case IR_DOT4: + case IR_DOT3: + case IR_DOT2: + case IR_CROSS: + case IR_MIN: + case IR_MAX: + case IR_SEQUAL: + case IR_SNEQUAL: + case IR_SGE: + case IR_SGT: + case IR_SLE: + case IR_SLT: + case IR_POW: + /* trinary operators */ + case IR_LRP: + return emit_arith(emitInfo, n); + + case IR_EQUAL: + case IR_NOTEQUAL: + return emit_compare(emitInfo, n); + + case IR_CLAMP: + return emit_clamp(emitInfo, n); + case IR_TEX: + case IR_TEXB: + case IR_TEXP: + case IR_TEX_SH: + case IR_TEXB_SH: + case IR_TEXP_SH: + return emit_tex(emitInfo, n); + case IR_NEG: + return emit_negation(emitInfo, n); + case IR_FLOAT: + /* find storage location for this float constant */ + n->Store->Index = _mesa_add_unnamed_constant(emitInfo->prog->Parameters, + n->Value, + n->Store->Size, + &n->Store->Swizzle); + if (n->Store->Index < 0) { + slang_info_log_error(emitInfo->log, "Ran out of space for constants"); + return NULL; + } + return NULL; + + case IR_COPY: + return emit_copy(emitInfo, n); + + case IR_COND: + return emit_cond(emitInfo, n); + + case IR_NOT: + return emit_not(emitInfo, n); + + case IR_LABEL: + return emit_label(emitInfo, n); + + case IR_KILL: + return emit_kill(emitInfo); + + case IR_CALL: + /* new variable scope for subroutines/function calls */ + _slang_push_var_table(emitInfo->vt); + inst = emit_fcall(emitInfo, n); + _slang_pop_var_table(emitInfo->vt); + return inst; + + case IR_IF: + return emit_if(emitInfo, n); + + case IR_LOOP: + return emit_loop(emitInfo, n); + case IR_BREAK_IF_TRUE: + case IR_CONT_IF_TRUE: + return emit_cont_break_if_true(emitInfo, n); + case IR_BREAK: + /* fall-through */ + case IR_CONT: + return emit_cont_break(emitInfo, n); + + case IR_BEGIN_SUB: + return new_instruction(emitInfo, OPCODE_BGNSUB); + case IR_END_SUB: + return new_instruction(emitInfo, OPCODE_ENDSUB); + case IR_RETURN: + return emit_return(emitInfo, n); + + case IR_NOP: + return NULL; + + default: + _mesa_problem(NULL, "Unexpected IR opcode in emit()\n"); + } + return NULL; +} + + +/** + * After code generation, any subroutines will be in separate program + * objects. This function appends all the subroutines onto the main + * program and resolves the linking of all the branch/call instructions. + * XXX this logic should really be part of the linking process... + */ +static void +_slang_resolve_subroutines(slang_emit_info *emitInfo) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_program *mainP = emitInfo->prog; + GLuint *subroutineLoc, i, total; + + subroutineLoc + = (GLuint *) _mesa_malloc(emitInfo->NumSubroutines * sizeof(GLuint)); + + /* total number of instructions */ + total = mainP->NumInstructions; + for (i = 0; i < emitInfo->NumSubroutines; i++) { + subroutineLoc[i] = total; + total += emitInfo->Subroutines[i]->NumInstructions; + } + + /* adjust BranchTargets within the functions */ + for (i = 0; i < emitInfo->NumSubroutines; i++) { + struct gl_program *sub = emitInfo->Subroutines[i]; + GLuint j; + for (j = 0; j < sub->NumInstructions; j++) { + struct prog_instruction *inst = sub->Instructions + j; + if (inst->Opcode != OPCODE_CAL && inst->BranchTarget >= 0) { + inst->BranchTarget += subroutineLoc[i]; + } + } + } + + /* append subroutines' instructions after main's instructions */ + mainP->Instructions = _mesa_realloc_instructions(mainP->Instructions, + mainP->NumInstructions, + total); + mainP->NumInstructions = total; + for (i = 0; i < emitInfo->NumSubroutines; i++) { + struct gl_program *sub = emitInfo->Subroutines[i]; + _mesa_copy_instructions(mainP->Instructions + subroutineLoc[i], + sub->Instructions, + sub->NumInstructions); + /* delete subroutine code */ + sub->Parameters = NULL; /* prevent double-free */ + _mesa_reference_program(ctx, &emitInfo->Subroutines[i], NULL); + } + + /* free subroutine list */ + if (emitInfo->Subroutines) { + _mesa_free(emitInfo->Subroutines); + emitInfo->Subroutines = NULL; + } + emitInfo->NumSubroutines = 0; + + /* Examine CAL instructions. + * At this point, the BranchTarget field of the CAL instruction is + * the number/id of the subroutine to call (an index into the + * emitInfo->Subroutines list). + * Translate that into an actual instruction location now. + */ + for (i = 0; i < mainP->NumInstructions; i++) { + struct prog_instruction *inst = mainP->Instructions + i; + if (inst->Opcode == OPCODE_CAL) { + const GLuint f = inst->BranchTarget; + inst->BranchTarget = subroutineLoc[f]; + } + } + + _mesa_free(subroutineLoc); +} + + + +/** + * Convert the IR tree into GPU instructions. + * \param n root of IR tree + * \param vt variable table + * \param prog program to put GPU instructions into + * \param pragmas controls codegen options + * \param withEnd if true, emit END opcode at end + * \param log log for emitting errors/warnings/info + */ +GLboolean +_slang_emit_code(slang_ir_node *n, slang_var_table *vt, + struct gl_program *prog, + const struct gl_sl_pragmas *pragmas, + GLboolean withEnd, + slang_info_log *log) +{ + GET_CURRENT_CONTEXT(ctx); + GLboolean success; + slang_emit_info emitInfo; + GLuint maxUniforms; + + emitInfo.log = log; + emitInfo.vt = vt; + emitInfo.prog = prog; + emitInfo.Subroutines = NULL; + emitInfo.NumSubroutines = 0; + emitInfo.MaxInstructions = prog->NumInstructions; + + emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions; + emitInfo.EmitCondCodes = ctx->Shader.EmitCondCodes; + emitInfo.EmitComments = ctx->Shader.EmitComments || pragmas->Debug; + emitInfo.EmitBeginEndSub = GL_TRUE; + + if (!emitInfo.EmitCondCodes) { + emitInfo.EmitHighLevelInstructions = GL_TRUE; + } + + /* Check uniform/constant limits */ + if (prog->Target == GL_FRAGMENT_PROGRAM_ARB) { + maxUniforms = ctx->Const.FragmentProgram.MaxUniformComponents / 4; + } + else { + assert(prog->Target == GL_VERTEX_PROGRAM_ARB); + maxUniforms = ctx->Const.VertexProgram.MaxUniformComponents / 4; + } + if (prog->Parameters->NumParameters > maxUniforms) { + slang_info_log_error(log, "Constant/uniform register limit exceeded " + "(max=%u vec4)", maxUniforms); + + return GL_FALSE; + } + + (void) emit(&emitInfo, n); + + /* finish up by adding the END opcode to program */ + if (withEnd) { + struct prog_instruction *inst; + inst = new_instruction(&emitInfo, OPCODE_END); + } + + _slang_resolve_subroutines(&emitInfo); + + success = GL_TRUE; + +#if 0 + printf("*********** End emit code (%u inst):\n", prog->NumInstructions); + _mesa_print_program(prog); + _mesa_print_program_parameters(ctx,prog); +#endif + + return success; +} diff --git a/mesalib/src/mesa/shader/slang/slang_emit.h b/mesalib/src/mesa/shader/slang/slang_emit.h new file mode 100644 index 000000000..ab4c202d6 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_emit.h @@ -0,0 +1,51 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 2005-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. + */ + +#ifndef SLANG_EMIT_H +#define SLANG_EMIT_H + + +#include "main/imports.h" +#include "slang_compile.h" +#include "slang_ir.h" +#include "main/mtypes.h" + + +extern GLuint +_slang_swizzle_swizzle(GLuint swz1, GLuint swz2); + + +extern GLuint +_slang_var_swizzle(GLint size, GLint comp); + + +extern GLboolean +_slang_emit_code(slang_ir_node *n, slang_var_table *vartable, + struct gl_program *prog, + const struct gl_sl_pragmas *pragmas, + GLboolean withEnd, + slang_info_log *log); + + +#endif /* SLANG_EMIT_H */ diff --git a/mesalib/src/mesa/shader/slang/slang_ir.c b/mesalib/src/mesa/shader/slang/slang_ir.c new file mode 100644 index 000000000..1c7f7474e --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_ir.c @@ -0,0 +1,497 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2005-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. + */ + + +#include "main/imports.h" +#include "main/context.h" +#include "slang_ir.h" +#include "slang_mem.h" +#include "shader/prog_instruction.h" +#include "shader/prog_print.h" + + +static const slang_ir_info IrInfo[] = { + /* binary ops */ + { IR_ADD, "IR_ADD", OPCODE_ADD, 4, 2 }, + { IR_SUB, "IR_SUB", OPCODE_SUB, 4, 2 }, + { IR_MUL, "IR_MUL", OPCODE_MUL, 4, 2 }, + { IR_DIV, "IR_DIV", OPCODE_NOP, 0, 2 }, /* XXX broke */ + { IR_DOT4, "IR_DOT4", OPCODE_DP4, 1, 2 }, + { IR_DOT3, "IR_DOT3", OPCODE_DP3, 1, 2 }, + { IR_DOT2, "IR_DOT2", OPCODE_DP2, 1, 2 }, + { IR_NRM4, "IR_NRM4", OPCODE_NRM4, 1, 1 }, + { IR_NRM3, "IR_NRM3", OPCODE_NRM3, 1, 1 }, + { IR_CROSS, "IR_CROSS", OPCODE_XPD, 3, 2 }, + { IR_LRP, "IR_LRP", OPCODE_LRP, 4, 3 }, + { IR_MIN, "IR_MIN", OPCODE_MIN, 4, 2 }, + { IR_MAX, "IR_MAX", OPCODE_MAX, 4, 2 }, + { IR_CLAMP, "IR_CLAMP", OPCODE_NOP, 4, 3 }, /* special case: emit_clamp() */ + { IR_SEQUAL, "IR_SEQUAL", OPCODE_SEQ, 4, 2 }, + { IR_SNEQUAL, "IR_SNEQUAL", OPCODE_SNE, 4, 2 }, + { IR_SGE, "IR_SGE", OPCODE_SGE, 4, 2 }, + { IR_SGT, "IR_SGT", OPCODE_SGT, 4, 2 }, + { IR_SLE, "IR_SLE", OPCODE_SLE, 4, 2 }, + { IR_SLT, "IR_SLT", OPCODE_SLT, 4, 2 }, + { IR_POW, "IR_POW", OPCODE_POW, 1, 2 }, + { IR_EQUAL, "IR_EQUAL", OPCODE_NOP, 1, 2 }, + { IR_NOTEQUAL, "IR_NOTEQUAL", OPCODE_NOP, 1, 2 }, + + /* unary ops */ + { IR_MOVE, "IR_MOVE", OPCODE_MOV, 4, 1 }, + { IR_I_TO_F, "IR_I_TO_F", OPCODE_MOV, 4, 1 }, /* int[4] to float[4] */ + { IR_F_TO_I, "IR_F_TO_I", OPCODE_TRUNC, 4, 1 }, + { IR_EXP, "IR_EXP", OPCODE_EXP, 1, 1 }, + { IR_EXP2, "IR_EXP2", OPCODE_EX2, 1, 1 }, + { IR_LOG2, "IR_LOG2", OPCODE_LG2, 1, 1 }, + { IR_RSQ, "IR_RSQ", OPCODE_RSQ, 1, 1 }, + { IR_RCP, "IR_RCP", OPCODE_RCP, 1, 1 }, + { IR_FLOOR, "IR_FLOOR", OPCODE_FLR, 4, 1 }, + { IR_FRAC, "IR_FRAC", OPCODE_FRC, 4, 1 }, + { IR_ABS, "IR_ABS", OPCODE_ABS, 4, 1 }, + { IR_NEG, "IR_NEG", OPCODE_NOP, 4, 1 }, /* special case: emit_negation() */ + { IR_DDX, "IR_DDX", OPCODE_DDX, 4, 1 }, + { IR_DDY, "IR_DDY", OPCODE_DDY, 4, 1 }, + { IR_SIN, "IR_SIN", OPCODE_SIN, 1, 1 }, + { IR_COS, "IR_COS", OPCODE_COS, 1, 1 }, + { IR_NOISE1, "IR_NOISE1", OPCODE_NOISE1, 1, 1 }, + { IR_NOISE2, "IR_NOISE2", OPCODE_NOISE2, 1, 1 }, + { IR_NOISE3, "IR_NOISE3", OPCODE_NOISE3, 1, 1 }, + { IR_NOISE4, "IR_NOISE4", OPCODE_NOISE4, 1, 1 }, + + /* other */ + { IR_SEQ, "IR_SEQ", OPCODE_NOP, 0, 0 }, + { IR_SCOPE, "IR_SCOPE", OPCODE_NOP, 0, 0 }, + { IR_LABEL, "IR_LABEL", OPCODE_NOP, 0, 0 }, + { IR_IF, "IR_IF", OPCODE_NOP, 0, 0 }, + { IR_KILL, "IR_KILL", OPCODE_NOP, 0, 0 }, + { IR_COND, "IR_COND", OPCODE_NOP, 0, 0 }, + { IR_CALL, "IR_CALL", OPCODE_NOP, 0, 0 }, + { IR_COPY, "IR_COPY", OPCODE_NOP, 0, 1 }, + { IR_NOT, "IR_NOT", OPCODE_NOP, 1, 1 }, + { IR_VAR, "IR_VAR", OPCODE_NOP, 0, 0 }, + { IR_VAR_DECL, "IR_VAR_DECL", OPCODE_NOP, 0, 0 }, + { IR_TEX, "IR_TEX", OPCODE_TEX, 4, 1 }, + { IR_TEXB, "IR_TEXB", OPCODE_TXB, 4, 1 }, + { IR_TEXP, "IR_TEXP", OPCODE_TXP, 4, 1 }, + { IR_TEX_SH, "IR_TEX_SH", OPCODE_TEX, 4, 1 }, + { IR_TEXB_SH, "IR_TEXB_SH", OPCODE_TXB, 4, 1 }, + { IR_TEXP_SH, "IR_TEXP_SH", OPCODE_TXP, 4, 1 }, + { IR_FLOAT, "IR_FLOAT", OPCODE_NOP, 0, 0 }, /* float literal */ + { IR_FIELD, "IR_FIELD", OPCODE_NOP, 0, 0 }, + { IR_ELEMENT, "IR_ELEMENT", OPCODE_NOP, 0, 0 }, + { IR_SWIZZLE, "IR_SWIZZLE", OPCODE_NOP, 0, 0 }, + { IR_NOP, "IR_NOP", OPCODE_NOP, 0, 0 }, + { 0, NULL, 0, 0, 0 } +}; + + +const slang_ir_info * +_slang_ir_info(slang_ir_opcode opcode) +{ + GLuint i; + for (i = 0; IrInfo[i].IrName; i++) { + if (IrInfo[i].IrOpcode == opcode) { + return IrInfo + i; + } + } + return NULL; +} + + +void +_slang_init_ir_storage(slang_ir_storage *st, + gl_register_file file, GLint index, GLint size, + GLuint swizzle) +{ + st->File = file; + st->Index = index; + st->Size = size; + st->Swizzle = swizzle; + st->Parent = NULL; + st->IsIndirect = GL_FALSE; +} + + +/** + * Return a new slang_ir_storage object. + */ +slang_ir_storage * +_slang_new_ir_storage(gl_register_file file, GLint index, GLint size) +{ + slang_ir_storage *st; + st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); + if (st) { + st->File = file; + st->Index = index; + st->Size = size; + st->Swizzle = SWIZZLE_NOOP; + st->Parent = NULL; + st->IsIndirect = GL_FALSE; + } + return st; +} + + +/** + * Return a new slang_ir_storage object. + */ +slang_ir_storage * +_slang_new_ir_storage_swz(gl_register_file file, GLint index, GLint size, + GLuint swizzle) +{ + slang_ir_storage *st; + st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); + if (st) { + st->File = file; + st->Index = index; + st->Size = size; + st->Swizzle = swizzle; + st->Parent = NULL; + st->IsIndirect = GL_FALSE; + } + return st; +} + + +/** + * Return a new slang_ir_storage object. + */ +slang_ir_storage * +_slang_new_ir_storage_relative(GLint index, GLint size, + slang_ir_storage *parent) +{ + slang_ir_storage *st; + st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); + if (st) { + st->File = PROGRAM_UNDEFINED; + st->Index = index; + st->Size = size; + st->Swizzle = SWIZZLE_NOOP; + st->Parent = parent; + st->IsIndirect = GL_FALSE; + } + return st; +} + + +slang_ir_storage * +_slang_new_ir_storage_indirect(gl_register_file file, + GLint index, + GLint size, + gl_register_file indirectFile, + GLint indirectIndex, + GLuint indirectSwizzle) +{ + slang_ir_storage *st; + st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); + if (st) { + st->File = file; + st->Index = index; + st->Size = size; + st->Swizzle = SWIZZLE_NOOP; + st->IsIndirect = GL_TRUE; + st->IndirectFile = indirectFile; + st->IndirectIndex = indirectIndex; + st->IndirectSwizzle = indirectSwizzle; + } + return st; +} + + +/** + * Allocate IR storage for a texture sampler. + * \param sampNum the sampler number/index + * \param texTarget one of TEXTURE_x_INDEX values + * \param size number of samplers (in case of sampler array) + */ +slang_ir_storage * +_slang_new_ir_storage_sampler(GLint sampNum, GLuint texTarget, GLint size) +{ + slang_ir_storage *st; + assert(texTarget < NUM_TEXTURE_TARGETS); + st = _slang_new_ir_storage(PROGRAM_SAMPLER, sampNum, size); + if (st) { + st->TexTarget = texTarget; + } + return st; +} + + + +/* XXX temporary function */ +void +_slang_copy_ir_storage(slang_ir_storage *dst, const slang_ir_storage *src) +{ + *dst = *src; + dst->Parent = NULL; +} + + + +static const char * +_slang_ir_name(slang_ir_opcode opcode) +{ + return _slang_ir_info(opcode)->IrName; +} + + + +#if 0 /* no longer needed with mempool */ +/** + * Since many IR nodes might point to the same IR storage info, we need + * to be careful when deleting things. + * Before deleting an IR tree, traverse it and do refcounting on the + * IR storage nodes. Use the refcount info during delete to free things + * properly. + */ +static void +_slang_refcount_storage(slang_ir_node *n) +{ + GLuint i; + if (!n) + return; + if (n->Store) + n->Store->RefCount++; + for (i = 0; i < 3; i++) + _slang_refcount_storage(n->Children[i]); +} +#endif + + +static void +_slang_free_ir(slang_ir_node *n) +{ + GLuint i; + if (!n) + return; + +#if 0 + if (n->Store) { + n->Store->RefCount--; + if (n->Store->RefCount == 0) { + _slang_free(n->Store); + n->Store = NULL; + } + } +#endif + + for (i = 0; i < 3; i++) + _slang_free_ir(n->Children[i]); + /* Do not free n->List since it's a child elsewhere */ + _slang_free(n); +} + + +/** + * Recursively free an IR tree. + */ +void +_slang_free_ir_tree(slang_ir_node *n) +{ +#if 0 + _slang_refcount_storage(n); +#endif + _slang_free_ir(n); +} + + +static const char * +storage_string(const slang_ir_storage *st) +{ + static const char *files[] = { + "TEMP", + "LOCAL_PARAM", + "ENV_PARAM", + "STATE", + "INPUT", + "OUTPUT", + "NAMED_PARAM", + "CONSTANT", + "UNIFORM", + "VARYING", + "WRITE_ONLY", + "ADDRESS", + "SAMPLER", + "UNDEFINED" + }; + static char s[100]; + assert(Elements(files) == PROGRAM_FILE_MAX); +#if 0 + if (st->Size == 1) + sprintf(s, "%s[%d]", files[st->File], st->Index); + else + sprintf(s, "%s[%d..%d]", files[st->File], st->Index, + st->Index + st->Size - 1); +#endif + assert(st->File < (GLint) (sizeof(files) / sizeof(files[0]))); + sprintf(s, "%s[%d]", files[st->File], st->Index); + return s; +} + + +static void +spaces(int n) +{ + while (n-- > 0) { + printf(" "); + } +} + + +void +_slang_print_ir_tree(const slang_ir_node *n, int indent) +{ +#define IND 0 + + if (!n) + return; +#if !IND + if (n->Opcode != IR_SEQ) +#else + printf("%3d:", indent); +#endif + spaces(indent); + + switch (n->Opcode) { + case IR_SEQ: +#if IND + printf("SEQ at %p\n", (void*) n); +#endif + assert(n->Children[0]); + assert(n->Children[1]); + _slang_print_ir_tree(n->Children[0], indent + IND); + _slang_print_ir_tree(n->Children[1], indent + IND); + break; + case IR_SCOPE: + printf("NEW SCOPE\n"); + assert(!n->Children[1]); + _slang_print_ir_tree(n->Children[0], indent + 3); + break; + case IR_COPY: + printf("COPY\n"); + _slang_print_ir_tree(n->Children[0], indent+3); + _slang_print_ir_tree(n->Children[1], indent+3); + break; + case IR_LABEL: + printf("LABEL: %s\n", n->Label->Name); + break; + case IR_COND: + printf("COND\n"); + _slang_print_ir_tree(n->Children[0], indent + 3); + break; + + case IR_IF: + printf("IF \n"); + _slang_print_ir_tree(n->Children[0], indent+3); + spaces(indent); + printf("THEN\n"); + _slang_print_ir_tree(n->Children[1], indent+3); + if (n->Children[2]) { + spaces(indent); + printf("ELSE\n"); + _slang_print_ir_tree(n->Children[2], indent+3); + } + spaces(indent); + printf("ENDIF\n"); + break; + + case IR_BEGIN_SUB: + printf("BEGIN_SUB\n"); + break; + case IR_END_SUB: + printf("END_SUB\n"); + break; + case IR_RETURN: + printf("RETURN\n"); + break; + case IR_CALL: + printf("CALL %s\n", n->Label->Name); + break; + + case IR_LOOP: + printf("LOOP\n"); + _slang_print_ir_tree(n->Children[0], indent+3); + if (n->Children[1]) { + spaces(indent); + printf("TAIL:\n"); + _slang_print_ir_tree(n->Children[1], indent+3); + } + spaces(indent); + printf("ENDLOOP\n"); + break; + case IR_CONT: + printf("CONT\n"); + break; + case IR_BREAK: + printf("BREAK\n"); + break; + case IR_BREAK_IF_TRUE: + printf("BREAK_IF_TRUE\n"); + _slang_print_ir_tree(n->Children[0], indent+3); + break; + case IR_CONT_IF_TRUE: + printf("CONT_IF_TRUE\n"); + _slang_print_ir_tree(n->Children[0], indent+3); + break; + + case IR_VAR: + printf("VAR %s%s at %s store %p\n", + (n->Var ? (char *) n->Var->a_name : "TEMP"), + _mesa_swizzle_string(n->Store->Swizzle, 0, 0), + storage_string(n->Store), (void*) n->Store); + break; + case IR_VAR_DECL: + printf("VAR_DECL %s (%p) at %s store %p\n", + (n->Var ? (char *) n->Var->a_name : "TEMP"), + (void*) n->Var, storage_string(n->Store), + (void*) n->Store); + break; + case IR_FIELD: + printf("FIELD %s of\n", n->Field); + _slang_print_ir_tree(n->Children[0], indent+3); + break; + case IR_FLOAT: + printf("FLOAT %g %g %g %g\n", + n->Value[0], n->Value[1], n->Value[2], n->Value[3]); + break; + case IR_I_TO_F: + printf("INT_TO_FLOAT\n"); + _slang_print_ir_tree(n->Children[0], indent+3); + break; + case IR_F_TO_I: + printf("FLOAT_TO_INT\n"); + _slang_print_ir_tree(n->Children[0], indent+3); + break; + case IR_SWIZZLE: + printf("SWIZZLE %s of (store %p) \n", + _mesa_swizzle_string(n->Store->Swizzle, 0, 0), (void*) n->Store); + _slang_print_ir_tree(n->Children[0], indent + 3); + break; + default: + printf("%s (%p, %p) (store %p)\n", _slang_ir_name(n->Opcode), + (void*) n->Children[0], (void*) n->Children[1], (void*) n->Store); + _slang_print_ir_tree(n->Children[0], indent+3); + _slang_print_ir_tree(n->Children[1], indent+3); + } +} diff --git a/mesalib/src/mesa/shader/slang/slang_ir.h b/mesalib/src/mesa/shader/slang/slang_ir.h new file mode 100644 index 000000000..e796693ed --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_ir.h @@ -0,0 +1,279 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2005-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 slang_ir.h + * Mesa GLSL Intermediate Representation tree types and constants. + * \author Brian Paul + */ + + +#ifndef SLANG_IR_H +#define SLANG_IR_H + + +#include "main/imports.h" +#include "slang_compile.h" +#include "slang_label.h" +#include "main/mtypes.h" + + +/** + * Intermediate Representation opcodes + */ +typedef enum +{ + IR_NOP = 0, + IR_SEQ, /* sequence (eval left, then right) */ + IR_SCOPE, /* new variable scope (one child) */ + + IR_LABEL, /* target of a jump or cjump */ + + IR_COND, /* conditional expression/predicate */ + + IR_IF, /* high-level IF/then/else */ + /* Children[0] = conditional expression */ + /* Children[1] = if-true part */ + /* Children[2] = if-else part, or NULL */ + + IR_BEGIN_SUB, /* begin subroutine */ + IR_END_SUB, /* end subroutine */ + IR_RETURN, /* return from subroutine */ + IR_CALL, /* call subroutine */ + + IR_LOOP, /* high-level loop-begin / loop-end */ + /* Children[0] = loop body */ + /* Children[1] = loop tail code, or NULL */ + + IR_CONT, /* continue loop */ + /* n->Parent = ptr to parent IR_LOOP Node */ + IR_BREAK, /* break loop */ + + IR_BREAK_IF_TRUE, /**< Children[0] = the condition expression */ + IR_CONT_IF_TRUE, + + IR_COPY, /**< assignment/copy */ + IR_MOVE, /**< assembly MOV instruction */ + + /* vector ops: */ + IR_ADD, /**< assembly ADD instruction */ + IR_SUB, + IR_MUL, + IR_DIV, + IR_DOT4, + IR_DOT3, + IR_DOT2, + IR_NRM4, + IR_NRM3, + IR_CROSS, /* vec3 cross product */ + IR_LRP, + IR_CLAMP, + IR_MIN, + IR_MAX, + IR_SEQUAL, /* Set if args are equal (vector) */ + IR_SNEQUAL, /* Set if args are not equal (vector) */ + IR_SGE, /* Set if greater or equal (vector) */ + IR_SGT, /* Set if greater than (vector) */ + IR_SLE, /* Set if less or equal (vector) */ + IR_SLT, /* Set if less than (vector) */ + IR_POW, /* x^y */ + IR_EXP, /* e^x */ + IR_EXP2, /* 2^x */ + IR_LOG2, /* log base 2 */ + IR_RSQ, /* 1/sqrt() */ + IR_RCP, /* reciprocol */ + IR_FLOOR, + IR_FRAC, + IR_ABS, /* absolute value */ + IR_NEG, /* negate */ + IR_DDX, /* derivative w.r.t. X */ + IR_DDY, /* derivative w.r.t. Y */ + IR_SIN, /* sine */ + IR_COS, /* cosine */ + IR_NOISE1, /* noise(x) */ + IR_NOISE2, /* noise(x, y) */ + IR_NOISE3, /* noise(x, y, z) */ + IR_NOISE4, /* noise(x, y, z, w) */ + + IR_EQUAL, /* boolean equality */ + IR_NOTEQUAL,/* boolean inequality */ + IR_NOT, /* boolean not */ + + IR_VAR, /* variable reference */ + IR_VAR_DECL,/* var declaration */ + + IR_ELEMENT, /* array element */ + IR_FIELD, /* struct field */ + IR_SWIZZLE, /* swizzled storage access */ + + IR_TEX, /* texture lookup */ + IR_TEXB, /* texture lookup with LOD bias */ + IR_TEXP, /* texture lookup with projection */ + + IR_TEX_SH, /* texture lookup, shadow compare */ + IR_TEXB_SH, /* texture lookup with LOD bias, shadow compare */ + IR_TEXP_SH, /* texture lookup with projection, shadow compare */ + + IR_FLOAT, + IR_I_TO_F, /* int[4] to float[4] conversion */ + IR_F_TO_I, /* float[4] to int[4] conversion */ + + IR_KILL /* fragment kill/discard */ +} slang_ir_opcode; + + +/** + * Describes where data/variables are stored in the various register files. + * + * In the simple case, the File, Index and Size fields indicate where + * a variable is stored. For example, a vec3 variable may be stored + * as (File=PROGRAM_TEMPORARY, Index=6, Size=3). Or, File[Index]. + * Or, a program input like color may be stored as + * (File=PROGRAM_INPUT,Index=3,Size=4); + * + * For single-float values, the Swizzle field indicates which component + * of the vector contains the float. + * + * If IsIndirect is set, the storage is accessed through an indirect + * register lookup. The value in question will be located at: + * File[Index + IndirectFile[IndirectIndex]] + * + * This is primary used for indexing arrays. For example, consider this + * GLSL code: + * uniform int i; + * float a[10]; + * float x = a[i]; + * + * here, storage for a[i] would be described by (File=PROGRAM_TEMPORAY, + * Index=aPos, IndirectFile=PROGRAM_UNIFORM, IndirectIndex=iPos), which + * would mean TEMP[aPos + UNIFORM[iPos]] + */ +struct slang_ir_storage_ +{ + gl_register_file File; /**< PROGRAM_TEMPORARY, PROGRAM_INPUT, etc */ + GLint Index; /**< -1 means unallocated */ + GLint Size; /**< number of floats or ints */ + GLuint Swizzle; /**< Swizzle AND writemask info */ + GLint RefCount; /**< Used during IR tree delete */ + + GLboolean RelAddr; /* we'll remove this eventually */ + + GLboolean IsIndirect; + gl_register_file IndirectFile; + GLint IndirectIndex; + GLuint IndirectSwizzle; + GLuint TexTarget; /**< If File==PROGRAM_SAMPLER, one of TEXTURE_x_INDEX */ + + /** If Parent is non-null, Index is relative to parent. + * The other fields are ignored. + */ + struct slang_ir_storage_ *Parent; +}; + +typedef struct slang_ir_storage_ slang_ir_storage; + + +/** + * Intermediate Representation (IR) tree node + * Basically a binary tree, but IR_LRP and IR_CLAMP have three children. + */ +typedef struct slang_ir_node_ +{ + slang_ir_opcode Opcode; + struct slang_ir_node_ *Children[3]; + slang_ir_storage *Store; /**< location of result of this operation */ + GLint InstLocation; /**< Location of instruction emitted for this node */ + + /** special fields depending on Opcode: */ + const char *Field; /**< If Opcode == IR_FIELD */ + GLfloat Value[4]; /**< If Opcode == IR_FLOAT */ + slang_variable *Var; /**< If Opcode == IR_VAR or IR_VAR_DECL */ + struct slang_ir_node_ *List; /**< For various linked lists */ + struct slang_ir_node_ *Parent; /**< Pointer to logical parent (ie. loop) */ + slang_label *Label; /**< Used for branches */ + const char *Comment; /**< If Opcode == IR_COMMENT */ +} slang_ir_node; + + + +/** + * Assembly and IR info + */ +typedef struct +{ + slang_ir_opcode IrOpcode; + const char *IrName; + gl_inst_opcode InstOpcode; + GLuint ResultSize, NumParams; +} slang_ir_info; + + + +extern const slang_ir_info * +_slang_ir_info(slang_ir_opcode opcode); + + +extern void +_slang_init_ir_storage(slang_ir_storage *st, + gl_register_file file, GLint index, GLint size, + GLuint swizzle); + +extern slang_ir_storage * +_slang_new_ir_storage(gl_register_file file, GLint index, GLint size); + + +extern slang_ir_storage * +_slang_new_ir_storage_swz(gl_register_file file, GLint index, GLint size, + GLuint swizzle); + +extern slang_ir_storage * +_slang_new_ir_storage_relative(GLint index, GLint size, + slang_ir_storage *parent); + + +extern slang_ir_storage * +_slang_new_ir_storage_indirect(gl_register_file file, + GLint index, + GLint size, + gl_register_file indirectFile, + GLint indirectIndex, + GLuint indirectSwizzle); + +extern slang_ir_storage * +_slang_new_ir_storage_sampler(GLint sampNum, GLuint texTarget, GLint size); + + +extern void +_slang_copy_ir_storage(slang_ir_storage *dst, const slang_ir_storage *src); + + +extern void +_slang_free_ir_tree(slang_ir_node *n); + + +extern void +_slang_print_ir_tree(const slang_ir_node *n, int indent); + + +#endif /* SLANG_IR_H */ diff --git a/mesalib/src/mesa/shader/slang/slang_label.c b/mesalib/src/mesa/shader/slang/slang_label.c new file mode 100644 index 000000000..1ca1ef0c7 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_label.c @@ -0,0 +1,104 @@ + + +/** + * Functions for managing instruction labels. + * Basically, this is used to manage the problem of forward branches where + * we have a branch instruciton but don't know the target address yet. + */ + + +#include "slang_label.h" +#include "slang_mem.h" + + + +slang_label * +_slang_label_new(const char *name) +{ + slang_label *l = (slang_label *) _slang_alloc(sizeof(slang_label)); + if (l) { + l->Name = _slang_strdup(name); + l->Location = -1; + } + return l; +} + +/** + * As above, but suffix the name with a unique number. + */ +slang_label * +_slang_label_new_unique(const char *name) +{ + static int id = 1; + slang_label *l = (slang_label *) _slang_alloc(sizeof(slang_label)); + if (l) { + l->Name = (char *) _slang_alloc(_mesa_strlen(name) + 10); + if (!l->Name) { + _mesa_free(l); + return NULL; + } + _mesa_sprintf(l->Name, "%s_%d", name, id); + id++; + l->Location = -1; + } + return l; +} + +void +_slang_label_delete(slang_label *l) +{ + if (l->Name) { + _slang_free(l->Name); + l->Name = NULL; + } + if (l->References) { + _slang_free(l->References); + l->References = NULL; + } + _slang_free(l); +} + + +void +_slang_label_add_reference(slang_label *l, GLuint inst) +{ + const GLuint oldSize = l->NumReferences * sizeof(GLuint); + assert(l->Location < 0); + l->References = _slang_realloc(l->References, + oldSize, oldSize + sizeof(GLuint)); + if (l->References) { + l->References[l->NumReferences] = inst; + l->NumReferences++; + } +} + + +GLint +_slang_label_get_location(const slang_label *l) +{ + return l->Location; +} + + +void +_slang_label_set_location(slang_label *l, GLint location, + struct gl_program *prog) +{ + GLuint i; + + assert(l->Location < 0); + assert(location >= 0); + + l->Location = location; + + /* for the instructions that were waiting to learn the label's location: */ + for (i = 0; i < l->NumReferences; i++) { + const GLuint j = l->References[i]; + prog->Instructions[j].BranchTarget = location; + } + + if (l->References) { + _slang_free(l->References); + l->References = NULL; + } +} diff --git a/mesalib/src/mesa/shader/slang/slang_label.h b/mesalib/src/mesa/shader/slang/slang_label.h new file mode 100644 index 000000000..87068ae7a --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_label.h @@ -0,0 +1,45 @@ +#ifndef SLANG_LABEL_H +#define SLANG_LABEL_H 1 + +#include "main/imports.h" +#include "main/mtypes.h" +#include "shader/prog_instruction.h" + + +struct slang_label_ +{ + char *Name; + GLint Location; + /** + * List of instruction references (numbered starting at zero) which need + * their BranchTarget field filled in with the location eventually + * assigned to the label. + */ + GLuint NumReferences; + GLuint *References; /** Array [NumReferences] */ +}; + +typedef struct slang_label_ slang_label; + + +extern slang_label * +_slang_label_new(const char *name); + +extern slang_label * +_slang_label_new_unique(const char *name); + +extern void +_slang_label_delete(slang_label *l); + +extern void +_slang_label_add_reference(slang_label *l, GLuint inst); + +extern GLint +_slang_label_get_location(const slang_label *l); + +extern void +_slang_label_set_location(slang_label *l, GLint location, + struct gl_program *prog); + + +#endif /* SLANG_LABEL_H */ diff --git a/mesalib/src/mesa/shader/slang/slang_link.c b/mesalib/src/mesa/shader/slang/slang_link.c new file mode 100644 index 000000000..8f2b40d5d --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_link.c @@ -0,0 +1,898 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 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 slang_link.c + * GLSL linker + * \author Brian Paul + */ + +#include "main/imports.h" +#include "main/context.h" +#include "main/hash.h" +#include "main/macros.h" +#include "shader/program.h" +#include "shader/prog_instruction.h" +#include "shader/prog_parameter.h" +#include "shader/prog_print.h" +#include "shader/prog_statevars.h" +#include "shader/prog_uniform.h" +#include "shader/shader_api.h" +#include "slang_builtin.h" +#include "slang_link.h" + + +/** cast wrapper */ +static struct gl_vertex_program * +vertex_program(struct gl_program *prog) +{ + assert(prog->Target == GL_VERTEX_PROGRAM_ARB); + return (struct gl_vertex_program *) prog; +} + + +/** cast wrapper */ +static struct gl_fragment_program * +fragment_program(struct gl_program *prog) +{ + assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB); + return (struct gl_fragment_program *) prog; +} + + +/** + * Record a linking error. + */ +static void +link_error(struct gl_shader_program *shProg, const char *msg) +{ + if (shProg->InfoLog) { + _mesa_free(shProg->InfoLog); + } + shProg->InfoLog = _mesa_strdup(msg); + shProg->LinkStatus = GL_FALSE; +} + + + +/** + * Check if the given bit is either set or clear in both bitfields. + */ +static GLboolean +bits_agree(GLbitfield flags1, GLbitfield flags2, GLbitfield bit) +{ + return (flags1 & bit) == (flags2 & bit); +} + + +/** + * Linking varying vars involves rearranging varying vars so that the + * vertex program's output varyings matches the order of the fragment + * program's input varyings. + * We'll then rewrite instructions to replace PROGRAM_VARYING with either + * PROGRAM_INPUT or PROGRAM_OUTPUT depending on whether it's a vertex or + * fragment shader. + * This is also where we set program Input/OutputFlags to indicate + * which inputs are centroid-sampled, invariant, etc. + */ +static GLboolean +link_varying_vars(GLcontext *ctx, + struct gl_shader_program *shProg, struct gl_program *prog) +{ + GLuint *map, i, firstVarying, newFile; + GLbitfield *inOutFlags; + + map = (GLuint *) malloc(prog->Varying->NumParameters * sizeof(GLuint)); + if (!map) + return GL_FALSE; + + /* Varying variables are treated like other vertex program outputs + * (and like other fragment program inputs). The position of the + * first varying differs for vertex/fragment programs... + * Also, replace File=PROGRAM_VARYING with File=PROGRAM_INPUT/OUTPUT. + */ + if (prog->Target == GL_VERTEX_PROGRAM_ARB) { + firstVarying = VERT_RESULT_VAR0; + newFile = PROGRAM_OUTPUT; + inOutFlags = prog->OutputFlags; + } + else { + assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB); + firstVarying = FRAG_ATTRIB_VAR0; + newFile = PROGRAM_INPUT; + inOutFlags = prog->InputFlags; + } + + for (i = 0; i < prog->Varying->NumParameters; i++) { + /* see if this varying is in the linked varying list */ + const struct gl_program_parameter *var = prog->Varying->Parameters + i; + GLint j = _mesa_lookup_parameter_index(shProg->Varying, -1, var->Name); + if (j >= 0) { + /* varying is already in list, do some error checking */ + const struct gl_program_parameter *v = + &shProg->Varying->Parameters[j]; + if (var->Size != v->Size) { + link_error(shProg, "mismatched varying variable types"); + return GL_FALSE; + } + if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_CENTROID)) { + char msg[100]; + _mesa_snprintf(msg, sizeof(msg), + "centroid modifier mismatch for '%s'", var->Name); + link_error(shProg, msg); + return GL_FALSE; + } + if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_INVARIANT)) { + char msg[100]; + _mesa_snprintf(msg, sizeof(msg), + "invariant modifier mismatch for '%s'", var->Name); + link_error(shProg, msg); + return GL_FALSE; + } + } + else { + /* not already in linked list */ + j = _mesa_add_varying(shProg->Varying, var->Name, var->Size, + var->Flags); + } + + if (shProg->Varying->NumParameters > ctx->Const.MaxVarying) { + link_error(shProg, "Too many varying variables"); + return GL_FALSE; + } + + /* Map varying[i] to varying[j]. + * Note: the loop here takes care of arrays or large (sz>4) vars. + */ + { + GLint sz = var->Size; + while (sz > 0) { + inOutFlags[firstVarying + j] = var->Flags; + /*printf("Link varying from %d to %d\n", i, j);*/ + map[i++] = j++; + sz -= 4; + } + i--; /* go back one */ + } + } + + + /* OK, now scan the program/shader instructions looking for varying vars, + * replacing the old index with the new index. + */ + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + GLuint j; + + if (inst->DstReg.File == PROGRAM_VARYING) { + inst->DstReg.File = newFile; + inst->DstReg.Index = map[ inst->DstReg.Index ] + firstVarying; + } + + for (j = 0; j < 3; j++) { + if (inst->SrcReg[j].File == PROGRAM_VARYING) { + inst->SrcReg[j].File = newFile; + inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ] + firstVarying; + } + } + } + + free(map); + + /* these will get recomputed before linking is completed */ + prog->InputsRead = 0x0; + prog->OutputsWritten = 0x0; + + return GL_TRUE; +} + + +/** + * Build the shProg->Uniforms list. + * This is basically a list/index of all uniforms found in either/both of + * the vertex and fragment shaders. + * + * About uniforms: + * Each uniform has two indexes, one that points into the vertex + * program's parameter array and another that points into the fragment + * program's parameter array. When the user changes a uniform's value + * we have to change the value in the vertex and/or fragment program's + * parameter array. + * + * This function will be called twice to set up the two uniform->parameter + * mappings. + * + * If a uniform is only present in the vertex program OR fragment program + * then the fragment/vertex parameter index, respectively, will be -1. + */ +static GLboolean +link_uniform_vars(GLcontext *ctx, + struct gl_shader_program *shProg, + struct gl_program *prog, + GLuint *numSamplers) +{ + GLuint samplerMap[200]; /* max number of samplers declared, not used */ + GLuint i; + + for (i = 0; i < prog->Parameters->NumParameters; i++) { + const struct gl_program_parameter *p = prog->Parameters->Parameters + i; + + /* + * XXX FIX NEEDED HERE + * We should also be adding a uniform if p->Type == PROGRAM_STATE_VAR. + * For example, modelview matrix, light pos, etc. + * Also, we need to update the state-var name-generator code to + * generate GLSL-style names, like "gl_LightSource[0].position". + * Furthermore, we'll need to fix the state-var's size/datatype info. + */ + + if ((p->Type == PROGRAM_UNIFORM || p->Type == PROGRAM_SAMPLER) + && p->Used) { + /* add this uniform, indexing into the target's Parameters list */ + struct gl_uniform *uniform = + _mesa_append_uniform(shProg->Uniforms, p->Name, prog->Target, i); + if (uniform) + uniform->Initialized = p->Initialized; + } + + /* The samplerMap[] table we build here is used to remap/re-index + * sampler references by TEX instructions. + */ + if (p->Type == PROGRAM_SAMPLER && p->Used) { + /* Allocate a new sampler index */ + GLuint oldSampNum = (GLuint) prog->Parameters->ParameterValues[i][0]; + GLuint newSampNum = *numSamplers; + if (newSampNum >= ctx->Const.MaxTextureImageUnits) { + char s[100]; + _mesa_sprintf(s, "Too many texture samplers (%u, max is %u)", + newSampNum, ctx->Const.MaxTextureImageUnits); + link_error(shProg, s); + return GL_FALSE; + } + /* save old->new mapping in the table */ + if (oldSampNum < Elements(samplerMap)) + samplerMap[oldSampNum] = newSampNum; + /* update parameter's sampler index */ + prog->Parameters->ParameterValues[i][0] = (GLfloat) newSampNum; + (*numSamplers)++; + } + } + + /* OK, now scan the program/shader instructions looking for texture + * instructions using sampler vars. Replace old sampler indexes with + * new ones. + */ + prog->SamplersUsed = 0x0; + for (i = 0; i < prog->NumInstructions; i++) { + struct prog_instruction *inst = prog->Instructions + i; + if (_mesa_is_tex_instruction(inst->Opcode)) { + /* here, inst->TexSrcUnit is really the sampler unit */ + const GLint oldSampNum = inst->TexSrcUnit; + +#if 0 + printf("====== remap sampler from %d to %d\n", + inst->TexSrcUnit, samplerMap[ inst->TexSrcUnit ]); +#endif + + if (oldSampNum < Elements(samplerMap)) { + const GLuint newSampNum = samplerMap[oldSampNum]; + inst->TexSrcUnit = newSampNum; + prog->SamplerTargets[newSampNum] = inst->TexSrcTarget; + prog->SamplersUsed |= (1 << newSampNum); + if (inst->TexShadow) { + prog->ShadowSamplers |= (1 << newSampNum); + } + } + } + } + + return GL_TRUE; +} + + +/** + * Resolve binding of generic vertex attributes. + * For example, if the vertex shader declared "attribute vec4 foobar" we'll + * allocate a generic vertex attribute for "foobar" and plug that value into + * the vertex program instructions. + * But if the user called glBindAttributeLocation(), those bindings will + * have priority. + */ +static GLboolean +_slang_resolve_attributes(struct gl_shader_program *shProg, + const struct gl_program *origProg, + struct gl_program *linkedProg) +{ + GLint attribMap[MAX_VERTEX_GENERIC_ATTRIBS]; + GLuint i, j; + GLbitfield usedAttributes; /* generics only, not legacy attributes */ + GLbitfield inputsRead = 0x0; + + assert(origProg != linkedProg); + assert(origProg->Target == GL_VERTEX_PROGRAM_ARB); + assert(linkedProg->Target == GL_VERTEX_PROGRAM_ARB); + + if (!shProg->Attributes) + shProg->Attributes = _mesa_new_parameter_list(); + + if (linkedProg->Attributes) { + _mesa_free_parameter_list(linkedProg->Attributes); + } + linkedProg->Attributes = _mesa_new_parameter_list(); + + + /* Build a bitmask indicating which attribute indexes have been + * explicitly bound by the user with glBindAttributeLocation(). + */ + usedAttributes = 0x0; + for (i = 0; i < shProg->Attributes->NumParameters; i++) { + GLint attr = shProg->Attributes->Parameters[i].StateIndexes[0]; + usedAttributes |= (1 << attr); + } + + /* If gl_Vertex is used, that actually counts against the limit + * on generic vertex attributes. This avoids the ambiguity of + * whether glVertexAttrib4fv(0, v) sets legacy attribute 0 (vert pos) + * or generic attribute[0]. If gl_Vertex is used, we want the former. + */ + if (origProg->InputsRead & VERT_BIT_POS) { + usedAttributes |= 0x1; + } + + /* initialize the generic attribute map entries to -1 */ + for (i = 0; i < MAX_VERTEX_GENERIC_ATTRIBS; i++) { + attribMap[i] = -1; + } + + /* + * Scan program for generic attribute references + */ + for (i = 0; i < linkedProg->NumInstructions; i++) { + struct prog_instruction *inst = linkedProg->Instructions + i; + for (j = 0; j < 3; j++) { + if (inst->SrcReg[j].File == PROGRAM_INPUT) { + inputsRead |= (1 << inst->SrcReg[j].Index); + } + + if (inst->SrcReg[j].File == PROGRAM_INPUT && + inst->SrcReg[j].Index >= VERT_ATTRIB_GENERIC0) { + /* + * OK, we've found a generic vertex attribute reference. + */ + const GLint k = inst->SrcReg[j].Index - VERT_ATTRIB_GENERIC0; + + GLint attr = attribMap[k]; + + if (attr < 0) { + /* Need to figure out attribute mapping now. + */ + const char *name = origProg->Attributes->Parameters[k].Name; + const GLint size = origProg->Attributes->Parameters[k].Size; + const GLenum type =origProg->Attributes->Parameters[k].DataType; + GLint index; + + /* See if there's a user-defined attribute binding for + * this name. + */ + index = _mesa_lookup_parameter_index(shProg->Attributes, + -1, name); + if (index >= 0) { + /* Found a user-defined binding */ + attr = shProg->Attributes->Parameters[index].StateIndexes[0]; + } + else { + /* No user-defined binding, choose our own attribute number. + * Start at 1 since generic attribute 0 always aliases + * glVertex/position. + */ + for (attr = 0; attr < MAX_VERTEX_GENERIC_ATTRIBS; attr++) { + if (((1 << attr) & usedAttributes) == 0) + break; + } + if (attr == MAX_VERTEX_GENERIC_ATTRIBS) { + link_error(shProg, "Too many vertex attributes"); + return GL_FALSE; + } + + /* mark this attribute as used */ + usedAttributes |= (1 << attr); + } + + attribMap[k] = attr; + + /* Save the final name->attrib binding so it can be queried + * with glGetAttributeLocation(). + */ + _mesa_add_attribute(linkedProg->Attributes, name, + size, type, attr); + } + + assert(attr >= 0); + + /* update the instruction's src reg */ + inst->SrcReg[j].Index = VERT_ATTRIB_GENERIC0 + attr; + } + } + } + + /* Handle pre-defined attributes here (gl_Vertex, gl_Normal, etc). + * When the user queries the active attributes we need to include both + * the user-defined attributes and the built-in ones. + */ + for (i = VERT_ATTRIB_POS; i < VERT_ATTRIB_GENERIC0; i++) { + if (inputsRead & (1 << i)) { + _mesa_add_attribute(linkedProg->Attributes, + _slang_vert_attrib_name(i), + 4, /* size in floats */ + _slang_vert_attrib_type(i), + -1 /* attrib/input */); + } + } + + return GL_TRUE; +} + + +/** + * Scan program instructions to update the program's NumTemporaries field. + * Note: this implemenation relies on the code generator allocating + * temps in increasing order (0, 1, 2, ... ). + */ +static void +_slang_count_temporaries(struct gl_program *prog) +{ + GLuint i, j; + GLint maxIndex = -1; + + 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); + for (j = 0; j < numSrc; j++) { + if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { + if (maxIndex < inst->SrcReg[j].Index) + maxIndex = inst->SrcReg[j].Index; + } + if (inst->DstReg.File == PROGRAM_TEMPORARY) { + if (maxIndex < (GLint) inst->DstReg.Index) + maxIndex = inst->DstReg.Index; + } + } + } + + prog->NumTemporaries = (GLuint) (maxIndex + 1); +} + + +/** + * Scan program instructions to update the program's InputsRead and + * OutputsWritten fields. + */ +static void +_slang_update_inputs_outputs(struct gl_program *prog) +{ + GLuint i, j; + GLuint maxAddrReg = 0; + + prog->InputsRead = 0x0; + prog->OutputsWritten = 0x0; + + 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); + for (j = 0; j < numSrc; j++) { + if (inst->SrcReg[j].File == PROGRAM_INPUT) { + prog->InputsRead |= 1 << inst->SrcReg[j].Index; + } + else if (inst->SrcReg[j].File == PROGRAM_ADDRESS) { + maxAddrReg = MAX2(maxAddrReg, (GLuint) (inst->SrcReg[j].Index + 1)); + } + } + + if (inst->DstReg.File == PROGRAM_OUTPUT) { + prog->OutputsWritten |= 1 << inst->DstReg.Index; + if (inst->DstReg.RelAddr) { + /* If the output attribute is indexed with relative addressing + * we know that it must be a varying or texcoord such as + * gl_TexCoord[i] = v; In this case, mark all the texcoords + * or varying outputs as being written. It's not an error if + * a vertex shader writes varying vars that aren't used by the + * fragment shader. But it is an error for a fragment shader + * to use varyings that are not written by the vertex shader. + */ + if (prog->Target == GL_VERTEX_PROGRAM_ARB) { + if (inst->DstReg.Index == VERT_RESULT_TEX0) { + /* mark all texcoord outputs as written */ + const GLbitfield mask = + ((1 << MAX_TEXTURE_COORD_UNITS) - 1) << VERT_RESULT_TEX0; + prog->OutputsWritten |= mask; + } + else if (inst->DstReg.Index == VERT_RESULT_VAR0) { + /* mark all generic varying outputs as written */ + const GLbitfield mask = + ((1 << MAX_VARYING) - 1) << VERT_RESULT_VAR0; + prog->OutputsWritten |= mask; + } + } + } + } + else if (inst->DstReg.File == PROGRAM_ADDRESS) { + maxAddrReg = MAX2(maxAddrReg, inst->DstReg.Index + 1); + } + } + prog->NumAddressRegs = maxAddrReg; +} + + + +/** + * Remove extra #version directives from the concatenated source string. + * Disable the extra ones by converting first two chars to //, a comment. + * This is a bit of hack to work around a preprocessor bug that only + * allows one #version directive per source. + */ +static void +remove_extra_version_directives(GLchar *source) +{ + GLuint verCount = 0; + while (1) { + char *ver = _mesa_strstr(source, "#version"); + if (ver) { + verCount++; + if (verCount > 1) { + ver[0] = '/'; + ver[1] = '/'; + } + source += 8; + } + else { + break; + } + } +} + + + +/** + * Return a new shader whose source code is the concatenation of + * all the shader sources of the given type. + */ +static struct gl_shader * +concat_shaders(struct gl_shader_program *shProg, GLenum shaderType) +{ + struct gl_shader *newShader; + const struct gl_shader *firstShader = NULL; + GLuint shaderLengths[100]; + GLchar *source; + GLuint totalLen = 0, len = 0; + GLuint i; + + /* compute total size of new shader source code */ + for (i = 0; i < shProg->NumShaders; i++) { + const struct gl_shader *shader = shProg->Shaders[i]; + if (shader->Type == shaderType) { + shaderLengths[i] = _mesa_strlen(shader->Source); + totalLen += shaderLengths[i]; + if (!firstShader) + firstShader = shader; + } + } + + if (totalLen == 0) + return NULL; + + source = (GLchar *) _mesa_malloc(totalLen + 1); + if (!source) + return NULL; + + /* concatenate shaders */ + for (i = 0; i < shProg->NumShaders; i++) { + const struct gl_shader *shader = shProg->Shaders[i]; + if (shader->Type == shaderType) { + _mesa_memcpy(source + len, shader->Source, shaderLengths[i]); + len += shaderLengths[i]; + } + } + source[len] = '\0'; + /* + _mesa_printf("---NEW CONCATENATED SHADER---:\n%s\n------------\n", source); + */ + + remove_extra_version_directives(source); + + newShader = CALLOC_STRUCT(gl_shader); + newShader->Type = shaderType; + newShader->Source = source; + newShader->Pragmas = firstShader->Pragmas; + + return newShader; +} + + +/** + * Search the shader program's list of shaders to find the one that + * defines main(). + * This will involve shader concatenation and recompilation if needed. + */ +static struct gl_shader * +get_main_shader(GLcontext *ctx, + struct gl_shader_program *shProg, GLenum type) +{ + struct gl_shader *shader = NULL; + GLuint i; + + /* + * Look for a shader that defines main() and has no unresolved references. + */ + for (i = 0; i < shProg->NumShaders; i++) { + shader = shProg->Shaders[i]; + if (shader->Type == type && + shader->Main && + !shader->UnresolvedRefs) { + /* All set! */ + return shader; + } + } + + /* + * There must have been unresolved references during the original + * compilation. Try concatenating all the shaders of the given type + * and recompile that. + */ + shader = concat_shaders(shProg, type); + + if (shader) { + _slang_compile(ctx, shader); + + /* Finally, check if recompiling failed */ + if (!shader->CompileStatus || + !shader->Main || + shader->UnresolvedRefs) { + link_error(shProg, "Unresolved symbols"); + return NULL; + } + } + + return shader; +} + + +/** + * Shader linker. Currently: + * + * 1. The last attached vertex shader and fragment shader are linked. + * 2. Varying vars in the two shaders are combined so their locations + * agree between the vertex and fragment stages. They're treated as + * vertex program output attribs and as fragment program input attribs. + * 3. The vertex and fragment programs are cloned and modified to update + * src/dst register references so they use the new, linked varying + * storage locations. + */ +void +_slang_link(GLcontext *ctx, + GLhandleARB programObj, + struct gl_shader_program *shProg) +{ + const struct gl_vertex_program *vertProg = NULL; + const struct gl_fragment_program *fragProg = NULL; + GLuint numSamplers = 0; + GLuint i; + + _mesa_clear_shader_program_data(ctx, shProg); + + /* Initialize LinkStatus to "success". Will be cleared if error. */ + shProg->LinkStatus = GL_TRUE; + + /* check that all programs compiled successfully */ + for (i = 0; i < shProg->NumShaders; i++) { + if (!shProg->Shaders[i]->CompileStatus) { + link_error(shProg, "linking with uncompiled shader\n"); + return; + } + } + + shProg->Uniforms = _mesa_new_uniform_list(); + shProg->Varying = _mesa_new_parameter_list(); + + /* + * Find the vertex and fragment shaders which define main() + */ + { + struct gl_shader *vertShader, *fragShader; + vertShader = get_main_shader(ctx, shProg, GL_VERTEX_SHADER); + fragShader = get_main_shader(ctx, shProg, GL_FRAGMENT_SHADER); + if (vertShader) + vertProg = vertex_program(vertShader->Program); + if (fragShader) + fragProg = fragment_program(fragShader->Program); + if (!shProg->LinkStatus) + return; + } + +#if FEATURE_es2_glsl + /* must have both a vertex and fragment program for ES2 */ + if (!vertProg) { + link_error(shProg, "missing vertex shader\n"); + return; + } + if (!fragProg) { + link_error(shProg, "missing fragment shader\n"); + return; + } +#endif + + /* + * Make copies of the vertex/fragment programs now since we'll be + * changing src/dst registers after merging the uniforms and varying vars. + */ + _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL); + if (vertProg) { + struct gl_vertex_program *linked_vprog = + vertex_program(_mesa_clone_program(ctx, &vertProg->Base)); + shProg->VertexProgram = linked_vprog; /* refcount OK */ + /* vertex program ID not significant; just set Id for debugging purposes */ + shProg->VertexProgram->Base.Id = shProg->Name; + ASSERT(shProg->VertexProgram->Base.RefCount == 1); + } + + _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL); + if (fragProg) { + struct gl_fragment_program *linked_fprog = + fragment_program(_mesa_clone_program(ctx, &fragProg->Base)); + shProg->FragmentProgram = linked_fprog; /* refcount OK */ + /* vertex program ID not significant; just set Id for debugging purposes */ + shProg->FragmentProgram->Base.Id = shProg->Name; + ASSERT(shProg->FragmentProgram->Base.RefCount == 1); + } + + /* link varying vars */ + if (shProg->VertexProgram) { + if (!link_varying_vars(ctx, shProg, &shProg->VertexProgram->Base)) + return; + } + if (shProg->FragmentProgram) { + if (!link_varying_vars(ctx, shProg, &shProg->FragmentProgram->Base)) + return; + } + + /* link uniform vars */ + if (shProg->VertexProgram) { + if (!link_uniform_vars(ctx, shProg, &shProg->VertexProgram->Base, + &numSamplers)) { + return; + } + } + if (shProg->FragmentProgram) { + if (!link_uniform_vars(ctx, shProg, &shProg->FragmentProgram->Base, + &numSamplers)) { + return; + } + } + + /*_mesa_print_uniforms(shProg->Uniforms);*/ + + if (shProg->VertexProgram) { + if (!_slang_resolve_attributes(shProg, &vertProg->Base, + &shProg->VertexProgram->Base)) { + return; + } + } + + if (shProg->VertexProgram) { + _slang_update_inputs_outputs(&shProg->VertexProgram->Base); + _slang_count_temporaries(&shProg->VertexProgram->Base); + if (!(shProg->VertexProgram->Base.OutputsWritten & (1 << VERT_RESULT_HPOS))) { + /* the vertex program did not compute a vertex position */ + link_error(shProg, + "gl_Position was not written by vertex shader\n"); + return; + } + } + if (shProg->FragmentProgram) { + _slang_count_temporaries(&shProg->FragmentProgram->Base); + _slang_update_inputs_outputs(&shProg->FragmentProgram->Base); + } + + /* Check that all the varying vars needed by the fragment shader are + * actually produced by the vertex shader. + */ + if (shProg->FragmentProgram) { + const GLbitfield varyingRead + = shProg->FragmentProgram->Base.InputsRead >> FRAG_ATTRIB_VAR0; + const GLbitfield varyingWritten = shProg->VertexProgram ? + shProg->VertexProgram->Base.OutputsWritten >> VERT_RESULT_VAR0 : 0x0; + if ((varyingRead & varyingWritten) != varyingRead) { + link_error(shProg, + "Fragment program using varying vars not written by vertex shader\n"); + return; + } + } + + /* check that gl_FragColor and gl_FragData are not both written to */ + if (shProg->FragmentProgram) { + GLbitfield outputsWritten = shProg->FragmentProgram->Base.OutputsWritten; + if ((outputsWritten & ((1 << FRAG_RESULT_COLOR))) && + (outputsWritten >= (1 << FRAG_RESULT_DATA0))) { + link_error(shProg, "Fragment program cannot write both gl_FragColor" + " and gl_FragData[].\n"); + return; + } + } + + + if (fragProg && shProg->FragmentProgram) { + /* Compute initial program's TexturesUsed info */ + _mesa_update_shader_textures_used(&shProg->FragmentProgram->Base); + + /* notify driver that a new fragment program has been compiled/linked */ + ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB, + &shProg->FragmentProgram->Base); + if (ctx->Shader.Flags & GLSL_DUMP) { + _mesa_printf("Mesa pre-link fragment program:\n"); + _mesa_print_program(&fragProg->Base); + _mesa_print_program_parameters(ctx, &fragProg->Base); + + _mesa_printf("Mesa post-link fragment program:\n"); + _mesa_print_program(&shProg->FragmentProgram->Base); + _mesa_print_program_parameters(ctx, &shProg->FragmentProgram->Base); + } + } + + if (vertProg && shProg->VertexProgram) { + /* Compute initial program's TexturesUsed info */ + _mesa_update_shader_textures_used(&shProg->VertexProgram->Base); + + /* notify driver that a new vertex program has been compiled/linked */ + ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB, + &shProg->VertexProgram->Base); + if (ctx->Shader.Flags & GLSL_DUMP) { + _mesa_printf("Mesa pre-link vertex program:\n"); + _mesa_print_program(&vertProg->Base); + _mesa_print_program_parameters(ctx, &vertProg->Base); + + _mesa_printf("Mesa post-link vertex program:\n"); + _mesa_print_program(&shProg->VertexProgram->Base); + _mesa_print_program_parameters(ctx, &shProg->VertexProgram->Base); + } + } + + /* Debug: */ + if (0) { + if (shProg->VertexProgram) + _mesa_postprocess_program(ctx, &shProg->VertexProgram->Base); + if (shProg->FragmentProgram) + _mesa_postprocess_program(ctx, &shProg->FragmentProgram->Base); + } + + if (ctx->Shader.Flags & GLSL_DUMP) { + _mesa_printf("Varying vars:\n"); + _mesa_print_parameter_list(shProg->Varying); + if (shProg->InfoLog) { + _mesa_printf("Info Log: %s\n", shProg->InfoLog); + } + } + + shProg->LinkStatus = (shProg->VertexProgram || shProg->FragmentProgram); +} + diff --git a/mesalib/src/mesa/shader/slang/slang_link.h b/mesalib/src/mesa/shader/slang/slang_link.h new file mode 100644 index 000000000..2b44d2078 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_link.h @@ -0,0 +1,37 @@ +/* + * Mesa 3-D graphics library + * Version: 7.2 + * + * Copyright (C) 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. + */ + +#ifndef SLANG_LINK_H +#define SLANG_LINK_H 1 + +#include "slang_compile.h" + + +extern void +_slang_link(GLcontext *ctx, GLhandleARB h, + struct gl_shader_program *shProg); + + +#endif + diff --git a/mesalib/src/mesa/shader/slang/slang_log.c b/mesalib/src/mesa/shader/slang/slang_log.c new file mode 100644 index 000000000..d7d2b4fbf --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_log.c @@ -0,0 +1,134 @@ +/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 2005-2007 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. + */ + +#include "main/imports.h" +#include "main/context.h" +#include "slang_log.h" +#include "slang_utility.h" + + + +static char *out_of_memory = "Error: Out of memory.\n"; + +void +slang_info_log_construct(slang_info_log * log) +{ + log->text = NULL; + log->dont_free_text = GL_FALSE; + log->error_flag = GL_FALSE; +} + +void +slang_info_log_destruct(slang_info_log * log) +{ + if (!log->dont_free_text) + _mesa_free(log->text); +} + +static int +slang_info_log_message(slang_info_log * log, const char *prefix, + const char *msg) +{ + GLuint size; + + if (log->dont_free_text) + return 0; + size = slang_string_length(msg) + 2; + if (prefix != NULL) + size += slang_string_length(prefix) + 2; + if (log->text != NULL) { + GLuint old_len = slang_string_length(log->text); + log->text = (char *) + _mesa_realloc(log->text, old_len + 1, old_len + size); + } + else { + log->text = (char *) (_mesa_malloc(size)); + if (log->text != NULL) + log->text[0] = '\0'; + } + if (log->text == NULL) + return 0; + if (prefix != NULL) { + slang_string_concat(log->text, prefix); + slang_string_concat(log->text, ": "); + } + slang_string_concat(log->text, msg); + slang_string_concat(log->text, "\n"); + + return 1; +} + +int +slang_info_log_print(slang_info_log * log, const char *msg, ...) +{ + va_list va; + char buf[1024]; + + va_start(va, msg); + _mesa_vsprintf(buf, msg, va); + va_end(va); + return slang_info_log_message(log, NULL, buf); +} + +int +slang_info_log_error(slang_info_log * log, const char *msg, ...) +{ + va_list va; + char buf[1024]; + + va_start(va, msg); + _mesa_vsprintf(buf, msg, va); + va_end(va); + log->error_flag = GL_TRUE; + if (slang_info_log_message(log, "Error", buf)) + return 1; + slang_info_log_memory(log); + return 0; +} + +int +slang_info_log_warning(slang_info_log * log, const char *msg, ...) +{ + va_list va; + char buf[1024]; + + va_start(va, msg); + _mesa_vsprintf(buf, msg, va); + va_end(va); + if (slang_info_log_message(log, "Warning", buf)) + return 1; + slang_info_log_memory(log); + return 0; +} + +void +slang_info_log_memory(slang_info_log * log) +{ + if (!slang_info_log_message(log, "Error", "Out of memory.")) { + log->dont_free_text = GL_TRUE; + log->error_flag = GL_TRUE; + log->text = out_of_memory; + } +} diff --git a/mesalib/src/mesa/shader/slang/slang_log.h b/mesalib/src/mesa/shader/slang/slang_log.h new file mode 100644 index 000000000..dcaba0285 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_log.h @@ -0,0 +1,57 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-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 SLANG_LOG_H +#define SLANG_LOG_H + + +typedef struct slang_info_log_ +{ + char *text; + GLboolean dont_free_text; + GLboolean error_flag; +} slang_info_log; + + +extern void +slang_info_log_construct(slang_info_log *); + +extern void +slang_info_log_destruct(slang_info_log *); + +extern int +slang_info_log_print(slang_info_log *, const char *, ...); + +extern int +slang_info_log_error(slang_info_log *, const char *, ...); + +extern int +slang_info_log_warning(slang_info_log *, const char *, ...); + +extern void +slang_info_log_memory(slang_info_log *); + + +#endif /* SLANG_LOG_H */ diff --git a/mesalib/src/mesa/shader/slang/slang_mem.c b/mesalib/src/mesa/shader/slang/slang_mem.c new file mode 100644 index 000000000..9224578ed --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_mem.c @@ -0,0 +1,243 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-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 slang_mem.c + * + * Memory manager for GLSL compiler. The general idea is to do all + * allocations out of a large pool then just free the pool when done + * compiling to avoid intricate malloc/free tracking and memory leaks. + * + * \author Brian Paul + */ + +#include "main/context.h" +#include "main/macros.h" +#include "slang_mem.h" + + +#define GRANULARITY 8 +#define ROUND_UP(B) ( ((B) + (GRANULARITY - 1)) & ~(GRANULARITY - 1) ) + + +/** If 1, use conventional malloc/free. Helpful for debugging */ +#define USE_MALLOC_FREE 0 + + +struct slang_mempool_ +{ + GLuint Size, Used, Count, Largest; + char *Data; + struct slang_mempool_ *Next; +}; + + +slang_mempool * +_slang_new_mempool(GLuint initialSize) +{ + slang_mempool *pool = (slang_mempool *) _mesa_calloc(sizeof(slang_mempool)); + if (pool) { + pool->Data = (char *) _mesa_calloc(initialSize); + /*printf("ALLOC MEMPOOL %d at %p\n", initialSize, pool->Data);*/ + if (!pool->Data) { + _mesa_free(pool); + return NULL; + } + pool->Size = initialSize; + pool->Used = 0; + } + return pool; +} + + +void +_slang_delete_mempool(slang_mempool *pool) +{ + GLuint total = 0; + while (pool) { + slang_mempool *next = pool->Next; + /* + printf("DELETE MEMPOOL %u / %u count=%u largest=%u\n", + pool->Used, pool->Size, pool->Count, pool->Largest); + */ + total += pool->Used; + _mesa_free(pool->Data); + _mesa_free(pool); + pool = next; + } + /*printf("TOTAL ALLOCATED: %u\n", total);*/ +} + + +#ifdef DEBUG +static void +check_zero(const char *addr, GLuint n) +{ + GLuint i; + for (i = 0; i < n; i++) { + assert(addr[i]==0); + } +} +#endif + + +#ifdef DEBUG +static GLboolean +is_valid_address(const slang_mempool *pool, void *addr) +{ + while (pool) { + if ((char *) addr >= pool->Data && + (char *) addr < pool->Data + pool->Used) + return GL_TRUE; + + pool = pool->Next; + } + return GL_FALSE; +} +#endif + + +/** + * Alloc 'bytes' from shader mempool. + */ +void * +_slang_alloc(GLuint bytes) +{ +#if USE_MALLOC_FREE + return _mesa_calloc(bytes); +#else + slang_mempool *pool; + GET_CURRENT_CONTEXT(ctx); + pool = (slang_mempool *) ctx->Shader.MemPool; + + if (bytes == 0) + bytes = 1; + + while (pool) { + if (pool->Used + bytes <= pool->Size) { + /* found room */ + void *addr = (void *) (pool->Data + pool->Used); +#ifdef DEBUG + check_zero((char*) addr, bytes); +#endif + pool->Used += ROUND_UP(bytes); + pool->Largest = MAX2(pool->Largest, bytes); + pool->Count++; + /*printf("alloc %u Used %u\n", bytes, pool->Used);*/ + return addr; + } + else if (pool->Next) { + /* try next block */ + pool = pool->Next; + } + else { + /* alloc new pool */ + const GLuint sz = MAX2(bytes, pool->Size); + pool->Next = _slang_new_mempool(sz); + if (!pool->Next) { + /* we're _really_ out of memory */ + return NULL; + } + else { + pool = pool->Next; + pool->Largest = bytes; + pool->Count++; + pool->Used = ROUND_UP(bytes); +#ifdef DEBUG + check_zero((char*) pool->Data, bytes); +#endif + return (void *) pool->Data; + } + } + } + return NULL; +#endif +} + + +void * +_slang_realloc(void *oldBuffer, GLuint oldSize, GLuint newSize) +{ +#if USE_MALLOC_FREE + return _mesa_realloc(oldBuffer, oldSize, newSize); +#else + GET_CURRENT_CONTEXT(ctx); + slang_mempool *pool = (slang_mempool *) ctx->Shader.MemPool; + (void) pool; + + if (newSize < oldSize) { + return oldBuffer; + } + else { + const GLuint copySize = (oldSize < newSize) ? oldSize : newSize; + void *newBuffer = _slang_alloc(newSize); + + if (oldBuffer) + ASSERT(is_valid_address(pool, oldBuffer)); + + if (newBuffer && oldBuffer && copySize > 0) + _mesa_memcpy(newBuffer, oldBuffer, copySize); + + return newBuffer; + } +#endif +} + + +/** + * Clone string, storing in current mempool. + */ +char * +_slang_strdup(const char *s) +{ + if (s) { + size_t l = _mesa_strlen(s); + char *s2 = (char *) _slang_alloc(l + 1); + if (s2) + _mesa_strcpy(s2, s); + return s2; + } + else { + return NULL; + } +} + + +/** + * Don't actually free memory, but mark it (for debugging). + */ +void +_slang_free(void *addr) +{ +#if USE_MALLOC_FREE + _mesa_free(addr); +#else + if (addr) { + GET_CURRENT_CONTEXT(ctx); + slang_mempool *pool = (slang_mempool *) ctx->Shader.MemPool; + (void) pool; + ASSERT(is_valid_address(pool, addr)); + } +#endif +} diff --git a/mesalib/src/mesa/shader/slang/slang_mem.h b/mesalib/src/mesa/shader/slang/slang_mem.h new file mode 100644 index 000000000..b5bfae247 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_mem.h @@ -0,0 +1,55 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-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 SLANG_MEM_H +#define SLANG_MEM_H + + +#include "main/imports.h" + + +typedef struct slang_mempool_ slang_mempool; + + +extern slang_mempool * +_slang_new_mempool(GLuint initialSize); + +extern void +_slang_delete_mempool(slang_mempool *pool); + +extern void * +_slang_alloc(GLuint bytes); + +extern void * +_slang_realloc(void *oldBuffer, GLuint oldSize, GLuint newSize); + +extern char * +_slang_strdup(const char *s); + +extern void +_slang_free(void *addr); + + +#endif diff --git a/mesalib/src/mesa/shader/slang/slang_preprocess.c b/mesalib/src/mesa/shader/slang/slang_preprocess.c new file mode 100644 index 000000000..e9a24cc00 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_preprocess.c @@ -0,0 +1,1406 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2005-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 slang_preprocess.c + * slang preprocessor + * \author Michal Krol + */ + +#include "main/imports.h" +#include "shader/grammar/grammar_mesa.h" +#include "slang_preprocess.h" + +LONGSTRING static const char *slang_pp_directives_syn = +#include "library/slang_pp_directives_syn.h" +; + +LONGSTRING static const char *slang_pp_expression_syn = +#include "library/slang_pp_expression_syn.h" +; + +LONGSTRING static const char *slang_pp_version_syn = +#include "library/slang_pp_version_syn.h" +; + +static GLvoid +grammar_error_to_log (slang_info_log *log) +{ + char buf[1024]; + GLint pos; + + grammar_get_last_error ((byte *) (buf), sizeof (buf), &pos); + if (buf[0] == 0) { + _mesa_snprintf(buf, sizeof(buf), "Preprocessor error"); + } + slang_info_log_error (log, buf); +} + +GLboolean +_slang_preprocess_version (const char *text, GLuint *version, GLuint *eaten, slang_info_log *log) +{ + grammar id; + byte *prod, *I; + unsigned int size; + + id = grammar_load_from_text ((const byte *) (slang_pp_version_syn)); + if (id == 0) { + grammar_error_to_log (log); + return GL_FALSE; + } + + if (!grammar_fast_check (id, (const byte *) (text), &prod, &size, 8)) { + grammar_error_to_log (log); + grammar_destroy (id); + return GL_FALSE; + } + + /* there can be multiple #version directives - grab the last one */ + I = &prod[size - 6]; + *version = (GLuint) (I[0]) + (GLuint) (I[1]) * 100; + *eaten = (GLuint) (I[2]) + ((GLuint) (I[3]) << 8) + ((GLuint) (I[4]) << 16) + ((GLuint) (I[5]) << 24); + + grammar_destroy (id); + grammar_alloc_free (prod); + return GL_TRUE; +} + +/* + * The preprocessor does the following work. + * 1. Remove comments. Each comment block is replaced with a single space and if the + * block contains new-lines, they are preserved. This ensures that line numbers + * stay the same and if a comment block delimits two tokens, the are delitmited + * by the space after comment removal. + * 2. Remove preprocessor directives from the source string, checking their syntax and + * executing them if appropriate. Again, new-lines are preserved. + * 3. Expand macros. + * 4. Tokenize the source string by ensuring there is at least one space between every + * two adjacent tokens. + */ + +#define PP_ANNOTATE 0 + +static GLvoid +pp_annotate (slang_string *output, const char *fmt, ...) +{ +#if PP_ANNOTATE + va_list va; + char buffer[1024]; + + va_start (va, fmt); + _mesa_vsprintf (buffer, fmt, va); + va_end (va); + slang_string_pushs (output, buffer, _mesa_strlen (buffer)); +#else + (GLvoid) (output); + (GLvoid) (fmt); +#endif +} + + /* + * The expression is executed on a fixed-sized stack. The PUSH macro makes a runtime + * check if the stack is not overflown by too complex expressions. In that situation the + * GLSL preprocessor should report internal compiler error. + * The BINARYDIV makes a runtime check if the divider is not 0. If it is, it reports + * compilation error. + */ + +#define EXECUTION_STACK_SIZE 1024 + +#define PUSH(x)\ + do {\ + if (sp == 0) {\ + slang_info_log_error (elog, "internal compiler error: preprocessor execution stack overflow.");\ + return GL_FALSE;\ + }\ + stack[--sp] = x;\ + } while (GL_FALSE) + +#define POP(x)\ + do {\ + assert (sp < EXECUTION_STACK_SIZE);\ + x = stack[sp++];\ + } while (GL_FALSE) + +#define BINARY(op)\ + do {\ + GLint a, b;\ + POP(b);\ + POP(a);\ + PUSH(a op b);\ + } while (GL_FALSE) + +#define BINARYDIV(op)\ + do {\ + GLint a, b;\ + POP(b);\ + POP(a);\ + if (b == 0) {\ + slang_info_log_error (elog, "division by zero in preprocessor expression.");\ + return GL_FALSE;\ + }\ + PUSH(a op b);\ + } while (GL_FALSE) + +#define UNARY(op)\ + do {\ + GLint a;\ + POP(a);\ + PUSH(op a);\ + } while (GL_FALSE) + +#define OP_END 0 +#define OP_PUSHINT 1 +#define OP_LOGICALOR 2 +#define OP_LOGICALAND 3 +#define OP_OR 4 +#define OP_XOR 5 +#define OP_AND 6 +#define OP_EQUAL 7 +#define OP_NOTEQUAL 8 +#define OP_LESSEQUAL 9 +#define OP_GREATEREQUAL 10 +#define OP_LESS 11 +#define OP_GREATER 12 +#define OP_LEFTSHIFT 13 +#define OP_RIGHTSHIFT 14 +#define OP_ADD 15 +#define OP_SUBTRACT 16 +#define OP_MULTIPLY 17 +#define OP_DIVIDE 18 +#define OP_MODULUS 19 +#define OP_PLUS 20 +#define OP_MINUS 21 +#define OP_NEGATE 22 +#define OP_COMPLEMENT 23 + +static GLboolean +execute_expression (slang_string *output, const byte *code, GLuint *pi, GLint *result, + slang_info_log *elog) +{ + GLuint i = *pi; + GLint stack[EXECUTION_STACK_SIZE]; + GLuint sp = EXECUTION_STACK_SIZE; + + while (code[i] != OP_END) { + switch (code[i++]) { + case OP_PUSHINT: + i++; + PUSH(_mesa_atoi ((const char *) (&code[i]))); + i += _mesa_strlen ((const char *) (&code[i])) + 1; + break; + case OP_LOGICALOR: + BINARY(||); + break; + case OP_LOGICALAND: + BINARY(&&); + break; + case OP_OR: + BINARY(|); + break; + case OP_XOR: + BINARY(^); + break; + case OP_AND: + BINARY(&); + break; + case OP_EQUAL: + BINARY(==); + break; + case OP_NOTEQUAL: + BINARY(!=); + break; + case OP_LESSEQUAL: + BINARY(<=); + break; + case OP_GREATEREQUAL: + BINARY(>=); + break; + case OP_LESS: + BINARY(<); + break; + case OP_GREATER: + BINARY(>); + break; + case OP_LEFTSHIFT: + BINARY(<<); + break; + case OP_RIGHTSHIFT: + BINARY(>>); + break; + case OP_ADD: + BINARY(+); + break; + case OP_SUBTRACT: + BINARY(-); + break; + case OP_MULTIPLY: + BINARY(*); + break; + case OP_DIVIDE: + BINARYDIV(/); + break; + case OP_MODULUS: + BINARYDIV(%); + break; + case OP_PLUS: + UNARY(+); + break; + case OP_MINUS: + UNARY(-); + break; + case OP_NEGATE: + UNARY(!); + break; + case OP_COMPLEMENT: + UNARY(~); + break; + default: + assert (0); + } + } + + /* Write-back the index skipping the OP_END. */ + *pi = i + 1; + + /* There should be exactly one value left on the stack. This is our result. */ + POP(*result); + pp_annotate (output, "%d ", *result); + assert (sp == EXECUTION_STACK_SIZE); + return GL_TRUE; +} + +/* + * Function execute_expressions() executes up to 2 expressions. The second expression is there + * for the #line directive which takes 1 or 2 expressions that indicate line and file numbers. + * If it fails, it returns 0. If it succeeds, it returns the number of executed expressions. + */ + +#define EXP_END 0 +#define EXP_EXPRESSION 1 + +static GLuint +execute_expressions (slang_string *output, grammar eid, const byte *expr, GLint results[2], + slang_info_log *elog) +{ + GLint success; + byte *code; + GLuint size, count = 0; + + success = grammar_fast_check (eid, expr, &code, &size, 64); + if (success) { + GLuint i = 0; + + while (code[i++] == EXP_EXPRESSION) { + assert (count < 2); + + if (!execute_expression (output, code, &i, &results[count], elog)) { + count = 0; + break; + } + count++; + } + grammar_alloc_free (code); + } + else { + slang_info_log_error (elog, "syntax error in preprocessor expression.");\ + } + return count; +} + +/* + * The pp_symbol structure is used to hold macro definitions and macro formal parameters. The + * pp_symbols strcture is a collection of pp_symbol. It is used both for storing macro formal + * parameters and all global macro definitions. Making this unification wastes some memory, + * becuse macro formal parameters don't need further lists of symbols. We lose 8 bytes per + * formal parameter here, but making this we can use the same code to substitute macro parameters + * as well as macros in the source string. + */ + +typedef struct +{ + struct pp_symbol_ *symbols; + GLuint count; +} pp_symbols; + +static GLvoid +pp_symbols_init (pp_symbols *self) +{ + self->symbols = NULL; + self->count = 0; +} + +static GLvoid +pp_symbols_free (pp_symbols *); + +typedef struct pp_symbol_ +{ + slang_string name; + slang_string replacement; + pp_symbols parameters; +} pp_symbol; + +static GLvoid +pp_symbol_init (pp_symbol *self) +{ + slang_string_init (&self->name); + slang_string_init (&self->replacement); + pp_symbols_init (&self->parameters); +} + +static GLvoid +pp_symbol_free (pp_symbol *self) +{ + slang_string_free (&self->name); + slang_string_free (&self->replacement); + pp_symbols_free (&self->parameters); +} + +static GLvoid +pp_symbol_reset (pp_symbol *self) +{ + /* Leave symbol name intact. */ + slang_string_reset (&self->replacement); + pp_symbols_free (&self->parameters); + pp_symbols_init (&self->parameters); +} + +static GLvoid +pp_symbols_free (pp_symbols *self) +{ + GLuint i; + + for (i = 0; i < self->count; i++) + pp_symbol_free (&self->symbols[i]); + _mesa_free (self->symbols); +} + +static pp_symbol * +pp_symbols_push (pp_symbols *self) +{ + self->symbols = (pp_symbol *) (_mesa_realloc (self->symbols, self->count * sizeof (pp_symbol), + (self->count + 1) * sizeof (pp_symbol))); + if (self->symbols == NULL) + return NULL; + pp_symbol_init (&self->symbols[self->count]); + return &self->symbols[self->count++]; +} + +static GLboolean +pp_symbols_erase (pp_symbols *self, pp_symbol *symbol) +{ + assert (symbol >= self->symbols && symbol < self->symbols + self->count); + + self->count--; + pp_symbol_free (symbol); + if (symbol < self->symbols + self->count) + _mesa_memcpy (symbol, symbol + 1, sizeof (pp_symbol) * (self->symbols + self->count - symbol)); + self->symbols = (pp_symbol *) (_mesa_realloc (self->symbols, (self->count + 1) * sizeof (pp_symbol), + self->count * sizeof (pp_symbol))); + return self->symbols != NULL; +} + +static pp_symbol * +pp_symbols_find (pp_symbols *self, const char *name) +{ + GLuint i; + + for (i = 0; i < self->count; i++) + if (_mesa_strcmp (name, slang_string_cstr (&self->symbols[i].name)) == 0) + return &self->symbols[i]; + return NULL; +} + +/* + * The condition context of a single #if/#else/#endif level. Those can be nested, so there + * is a stack of condition contexts. + * There is a special global context on the bottom of the stack. It is there to simplify + * context handling. + */ + +typedef struct +{ + GLboolean current; /* The condition value of this level. */ + GLboolean effective; /* The effective product of current condition, outer level conditions + * and position within #if-#else-#endif sections. */ + GLboolean else_allowed; /* TRUE if in #if-#else section, FALSE if in #else-#endif section + * and for global context. */ + GLboolean endif_required; /* FALSE for global context only. */ +} pp_cond_ctx; + +/* Should be enuff. */ +#define CONDITION_STACK_SIZE 64 + +typedef struct +{ + pp_cond_ctx stack[CONDITION_STACK_SIZE]; + pp_cond_ctx *top; +} pp_cond_stack; + +static GLboolean +pp_cond_stack_push (pp_cond_stack *self, slang_info_log *elog) +{ + if (self->top == self->stack) { + slang_info_log_error (elog, "internal compiler error: preprocessor condition stack overflow."); + return GL_FALSE; + } + self->top--; + return GL_TRUE; +} + +static GLvoid +pp_cond_stack_reevaluate (pp_cond_stack *self) +{ + /* There must be at least 2 conditions on the stack - one global and one being evaluated. */ + assert (self->top <= &self->stack[CONDITION_STACK_SIZE - 2]); + + self->top->effective = self->top->current && self->top[1].effective; +} + + +/** + * Extension enables through #extension directive. + * NOTE: Currently, only enable/disable state is stored. + */ +typedef struct +{ + GLboolean ARB_draw_buffers; + GLboolean ARB_texture_rectangle; +} pp_ext; + + +/** + * Disable all extensions. Called at startup and on #extension all: disable. + */ +static GLvoid +pp_ext_disable_all(pp_ext *self) +{ + _mesa_memset(self, 0, sizeof(self)); +} + + +/** + * Called during preprocessor initialization to set the initial enable/disable + * state of extensions. + */ +static GLvoid +pp_ext_init(pp_ext *self, const struct gl_extensions *extensions) +{ + pp_ext_disable_all (self); + self->ARB_draw_buffers = GL_TRUE; + if (extensions->NV_texture_rectangle) + self->ARB_texture_rectangle = GL_TRUE; +} + +/** + * Called in response to #extension directives to enable/disable + * the named extension. + */ +static GLboolean +pp_ext_set(pp_ext *self, const char *name, GLboolean enable) +{ + if (_mesa_strcmp (name, "GL_ARB_draw_buffers") == 0) + self->ARB_draw_buffers = enable; + else if (_mesa_strcmp (name, "GL_ARB_texture_rectangle") == 0) + self->ARB_texture_rectangle = enable; + else + return GL_FALSE; + return GL_TRUE; +} + + +/** + * Called in response to #pragma. For example, "#pragma debug(on)" would + * call this function as pp_pragma("debug", "on"). + * \return GL_TRUE if pragma is valid, GL_FALSE if invalid + */ +static GLboolean +pp_pragma(struct gl_sl_pragmas *pragmas, const char *pragma, const char *param) +{ +#if 0 + printf("#pragma %s %s\n", pragma, param); +#endif + if (_mesa_strcmp(pragma, "optimize") == 0) { + if (!param) + return GL_FALSE; /* missing required param */ + if (_mesa_strcmp(param, "on") == 0) { + if (!pragmas->IgnoreOptimize) + pragmas->Optimize = GL_TRUE; + } + else if (_mesa_strcmp(param, "off") == 0) { + if (!pragmas->IgnoreOptimize) + pragmas->Optimize = GL_FALSE; + } + else { + return GL_FALSE; /* invalid param */ + } + } + else if (_mesa_strcmp(pragma, "debug") == 0) { + if (!param) + return GL_FALSE; /* missing required param */ + if (_mesa_strcmp(param, "on") == 0) { + if (!pragmas->IgnoreDebug) + pragmas->Debug = GL_TRUE; + } + else if (_mesa_strcmp(param, "off") == 0) { + if (!pragmas->IgnoreDebug) + pragmas->Debug = GL_FALSE; + } + else { + return GL_FALSE; /* invalid param */ + } + } + /* all other pragmas are silently ignored */ + return GL_TRUE; +} + + +/** + * The state of preprocessor: current line, file and version number, list + * of all defined macros and the #if/#endif context. + */ +typedef struct +{ + GLint line; + GLint file; + GLint version; + pp_symbols symbols; + pp_ext ext; + slang_info_log *elog; + pp_cond_stack cond; +} pp_state; + +static GLvoid +pp_state_init (pp_state *self, slang_info_log *elog, + const struct gl_extensions *extensions) +{ + self->line = 0; + self->file = 1; +#if FEATURE_es2_glsl + self->version = 100; +#else + self->version = 110; +#endif + pp_symbols_init (&self->symbols); + pp_ext_init (&self->ext, extensions); + self->elog = elog; + + /* Initialize condition stack and create the global context. */ + self->cond.top = &self->cond.stack[CONDITION_STACK_SIZE - 1]; + self->cond.top->current = GL_TRUE; + self->cond.top->effective = GL_TRUE; + self->cond.top->else_allowed = GL_FALSE; + self->cond.top->endif_required = GL_FALSE; +} + +static GLvoid +pp_state_free (pp_state *self) +{ + pp_symbols_free (&self->symbols); +} + +#define IS_FIRST_ID_CHAR(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z') || (x) == '_') +#define IS_NEXT_ID_CHAR(x) (IS_FIRST_ID_CHAR(x) || ((x) >= '0' && (x) <= '9')) +#define IS_WHITE(x) ((x) == ' ' || (x) == '\n') +#define IS_NULL(x) ((x) == '\0') + +#define SKIP_WHITE(x) do { while (IS_WHITE(*(x))) (x)++; } while (GL_FALSE) + +typedef struct +{ + slang_string *output; + const char *input; + pp_state *state; +} expand_state; + +static GLboolean +expand_defined (expand_state *e, slang_string *buffer) +{ + GLboolean in_paren = GL_FALSE; + const char *id; + + /* Parse the optional opening parenthesis. */ + SKIP_WHITE(e->input); + if (*e->input == '(') { + e->input++; + in_paren = GL_TRUE; + SKIP_WHITE(e->input); + } + + /* Parse operand. */ + if (!IS_FIRST_ID_CHAR(*e->input)) { + slang_info_log_error (e->state->elog, + "preprocess error: identifier expected after operator 'defined'."); + return GL_FALSE; + } + slang_string_reset (buffer); + slang_string_pushc (buffer, *e->input++); + while (IS_NEXT_ID_CHAR(*e->input)) + slang_string_pushc (buffer, *e->input++); + id = slang_string_cstr (buffer); + + /* Check if the operand is defined. Output 1 if it is defined, output 0 if not. */ + if (pp_symbols_find (&e->state->symbols, id) == NULL) + slang_string_pushs (e->output, " 0 ", 3); + else + slang_string_pushs (e->output, " 1 ", 3); + + /* Parse the closing parentehesis if the opening one was there. */ + if (in_paren) { + SKIP_WHITE(e->input); + if (*e->input != ')') { + slang_info_log_error (e->state->elog, "preprocess error: ')' expected."); + return GL_FALSE; + } + e->input++; + SKIP_WHITE(e->input); + } + return GL_TRUE; +} + +static GLboolean +expand (expand_state *, pp_symbols *); + +static GLboolean +expand_symbol (expand_state *e, pp_symbol *symbol) +{ + expand_state es; + + /* If the macro has some parameters, we need to parse them. */ + if (symbol->parameters.count != 0) { + GLuint i; + + /* Parse the opening parenthesis. */ + SKIP_WHITE(e->input); + if (*e->input != '(') { + slang_info_log_error (e->state->elog, "preprocess error: '(' expected."); + return GL_FALSE; + } + e->input++; + SKIP_WHITE(e->input); + + /* Parse macro actual parameters. This can be anything, separated by a colon. + */ + for (i = 0; i < symbol->parameters.count; i++) { + GLuint nested_paren_count = 0; /* track number of nested parentheses */ + + if (*e->input == ')') { + slang_info_log_error (e->state->elog, "preprocess error: unexpected ')'."); + return GL_FALSE; + } + + /* Eat all characters up to the comma or closing parentheses. */ + pp_symbol_reset (&symbol->parameters.symbols[i]); + while (!IS_NULL(*e->input)) { + /* Exit loop only when all nested parens have been eaten. */ + if (nested_paren_count == 0 && (*e->input == ',' || *e->input == ')')) + break; + + /* Actually count nested parens here. */ + if (*e->input == '(') + nested_paren_count++; + else if (*e->input == ')') + nested_paren_count--; + + slang_string_pushc (&symbol->parameters.symbols[i].replacement, *e->input++); + } + + /* If it was not the last paremeter, skip the comma. Otherwise, skip the + * closing parentheses. */ + if (i + 1 == symbol->parameters.count) { + /* This is the last paremeter - skip the closing parentheses. */ + if (*e->input != ')') { + slang_info_log_error (e->state->elog, "preprocess error: ')' expected."); + return GL_FALSE; + } + e->input++; + SKIP_WHITE(e->input); + } + else { + /* Skip the separating comma. */ + if (*e->input != ',') { + slang_info_log_error (e->state->elog, "preprocess error: ',' expected."); + return GL_FALSE; + } + e->input++; + SKIP_WHITE(e->input); + } + } + } + + /* Expand the macro. Use its parameters as a priority symbol list to expand + * macro parameters correctly. */ + es.output = e->output; + es.input = slang_string_cstr (&symbol->replacement); + es.state = e->state; + slang_string_pushc (e->output, ' '); + if (!expand (&es, &symbol->parameters)) + return GL_FALSE; + slang_string_pushc (e->output, ' '); + return GL_TRUE; +} + +/* + * Function expand() expands source text from <input> to <output>. The expansion is made using + * the list passed in <symbols> parameter. It allows us to expand macro formal parameters with + * actual parameters. The global list of symbols from pp state is used when doing a recursive + * call of expand(). + */ + +static GLboolean +expand (expand_state *e, pp_symbols *symbols) +{ + while (!IS_NULL(*e->input)) { + if (IS_FIRST_ID_CHAR(*e->input)) { + slang_string buffer; + const char *id; + + /* Parse the identifier. */ + slang_string_init (&buffer); + slang_string_pushc (&buffer, *e->input++); + while (IS_NEXT_ID_CHAR(*e->input)) + slang_string_pushc (&buffer, *e->input++); + id = slang_string_cstr (&buffer); + + /* Now check if the identifier is special in some way. The "defined" identifier is + * actually an operator that we must handle here and expand it either to " 0 " or " 1 ". + * The other identifiers start with "__" and we expand it to appropriate values + * taken from the preprocessor state. */ + if (_mesa_strcmp (id, "defined") == 0) { + if (!expand_defined (e, &buffer)) + return GL_FALSE; + } + else if (_mesa_strcmp (id, "__LINE__") == 0) { + slang_string_pushc (e->output, ' '); + slang_string_pushi (e->output, e->state->line); + slang_string_pushc (e->output, ' '); + } + else if (_mesa_strcmp (id, "__FILE__") == 0) { + slang_string_pushc (e->output, ' '); + slang_string_pushi (e->output, e->state->file); + slang_string_pushc (e->output, ' '); + } + else if (_mesa_strcmp (id, "__VERSION__") == 0) { + slang_string_pushc (e->output, ' '); + slang_string_pushi (e->output, e->state->version); + slang_string_pushc (e->output, ' '); + } +#if FEATURE_es2_glsl + else if (_mesa_strcmp (id, "GL_ES") == 0 || + _mesa_strcmp (id, "GL_FRAGMENT_PRECISION_HIGH") == 0) { + slang_string_pushc (e->output, ' '); + slang_string_pushi (e->output, '1'); + slang_string_pushc (e->output, ' '); + } +#endif + else { + pp_symbol *symbol; + + /* The list of symbols from <symbols> take precedence over the list from <state>. + * Note that in some cases this is the same list so avoid double look-up. */ + symbol = pp_symbols_find (symbols, id); + if (symbol == NULL && symbols != &e->state->symbols) + symbol = pp_symbols_find (&e->state->symbols, id); + + /* If the symbol was found, recursively expand its definition. */ + if (symbol != NULL) { + if (!expand_symbol (e, symbol)) { + slang_string_free (&buffer); + return GL_FALSE; + } + } + else { + slang_string_push (e->output, &buffer); + } + } + slang_string_free (&buffer); + } + else if (IS_WHITE(*e->input)) { + slang_string_pushc (e->output, *e->input++); + } + else { + while (!IS_WHITE(*e->input) && !IS_NULL(*e->input) && !IS_FIRST_ID_CHAR(*e->input)) + slang_string_pushc (e->output, *e->input++); + } + } + return GL_TRUE; +} + +static GLboolean +parse_if (slang_string *output, const byte *prod, GLuint *pi, GLint *result, pp_state *state, + grammar eid) +{ + const char *text; + GLuint len; + + text = (const char *) (&prod[*pi]); + len = _mesa_strlen (text); + + if (state->cond.top->effective) { + slang_string expr; + GLuint count; + GLint results[2]; + expand_state es; + + /* Expand the expression. */ + slang_string_init (&expr); + es.output = &expr; + es.input = text; + es.state = state; + if (!expand (&es, &state->symbols)) + return GL_FALSE; + + /* Execute the expression. */ + count = execute_expressions (output, eid, (const byte *) (slang_string_cstr (&expr)), + results, state->elog); + slang_string_free (&expr); + if (count != 1) + return GL_FALSE; + *result = results[0]; + } + else { + /* The directive is dead. */ + *result = 0; + } + + *pi += len + 1; + return GL_TRUE; +} + +#define ESCAPE_TOKEN 0 + +#define TOKEN_END 0 +#define TOKEN_DEFINE 1 +#define TOKEN_UNDEF 2 +#define TOKEN_IF 3 +#define TOKEN_ELSE 4 +#define TOKEN_ELIF 5 +#define TOKEN_ENDIF 6 +#define TOKEN_ERROR 7 +#define TOKEN_PRAGMA 8 +#define TOKEN_EXTENSION 9 +#define TOKEN_LINE 10 + +#define PARAM_END 0 +#define PARAM_PARAMETER 1 + +#define BEHAVIOR_REQUIRE 1 +#define BEHAVIOR_ENABLE 2 +#define BEHAVIOR_WARN 3 +#define BEHAVIOR_DISABLE 4 + +#define PRAGMA_NO_PARAM 0 +#define PRAGMA_PARAM 1 + + +static GLboolean +preprocess_source (slang_string *output, const char *source, + grammar pid, grammar eid, + slang_info_log *elog, + const struct gl_extensions *extensions, + struct gl_sl_pragmas *pragmas) +{ + static const char *predefined[] = { + "__FILE__", + "__LINE__", + "__VERSION__", +#if FEATURE_es2_glsl + "GL_ES", + "GL_FRAGMENT_PRECISION_HIGH", +#endif + NULL + }; + byte *prod; + GLuint size, i; + pp_state state; + + if (!grammar_fast_check (pid, (const byte *) (source), &prod, &size, 65536)) { + grammar_error_to_log (elog); + return GL_FALSE; + } + + pp_state_init (&state, elog, extensions); + + /* add the predefined symbols to the symbol table */ + for (i = 0; predefined[i]; i++) { + pp_symbol *symbol = NULL; + symbol = pp_symbols_push(&state.symbols); + assert(symbol); + slang_string_pushs(&symbol->name, + predefined[i], _mesa_strlen(predefined[i])); + } + + i = 0; + while (i < size) { + if (prod[i] != ESCAPE_TOKEN) { + if (state.cond.top->effective) { + slang_string input; + expand_state es; + + /* Eat only one line of source code to expand it. + * FIXME: This approach has one drawback. If a macro with parameters spans across + * multiple lines, the preprocessor will raise an error. */ + slang_string_init (&input); + while (prod[i] != '\0' && prod[i] != '\n') + slang_string_pushc (&input, prod[i++]); + if (prod[i] != '\0') + slang_string_pushc (&input, prod[i++]); + + /* Increment line number. */ + state.line++; + + es.output = output; + es.input = slang_string_cstr (&input); + es.state = &state; + if (!expand (&es, &state.symbols)) + goto error; + + slang_string_free (&input); + } + else { + /* Condition stack is disabled - keep track on line numbers and output only newlines. */ + if (prod[i] == '\n') { + state.line++; + /*pp_annotate (output, "%c", prod[i]);*/ + } + else { + /*pp_annotate (output, "%c", prod[i]);*/ + } + i++; + } + } + else { + const char *id; + GLuint idlen; + GLubyte token; + + i++; + token = prod[i++]; + switch (token) { + + case TOKEN_END: + /* End of source string. + * Check if all #ifs have been terminated by matching #endifs. + * On condition stack there should be only the global condition context. */ + if (state.cond.top->endif_required) { + slang_info_log_error (elog, "end of source without matching #endif."); + return GL_FALSE; + } + break; + + case TOKEN_DEFINE: + { + pp_symbol *symbol = NULL; + + /* Parse macro name. */ + id = (const char *) (&prod[i]); + idlen = _mesa_strlen (id); + if (state.cond.top->effective) { + pp_annotate (output, "// #define %s(", id); + + /* If the symbol is already defined, override it. */ + symbol = pp_symbols_find (&state.symbols, id); + if (symbol == NULL) { + symbol = pp_symbols_push (&state.symbols); + if (symbol == NULL) + goto error; + slang_string_pushs (&symbol->name, id, idlen); + } + else { + pp_symbol_reset (symbol); + } + } + i += idlen + 1; + + /* Parse optional macro parameters. */ + while (prod[i++] != PARAM_END) { + pp_symbol *param; + + id = (const char *) (&prod[i]); + idlen = _mesa_strlen (id); + if (state.cond.top->effective) { + pp_annotate (output, "%s, ", id); + param = pp_symbols_push (&symbol->parameters); + if (param == NULL) + goto error; + slang_string_pushs (¶m->name, id, idlen); + } + i += idlen + 1; + } + + /* Parse macro replacement. */ + id = (const char *) (&prod[i]); + idlen = _mesa_strlen (id); + if (state.cond.top->effective) { + slang_string replacement; + expand_state es; + + pp_annotate (output, ") %s", id); + + slang_string_init(&replacement); + slang_string_pushs(&replacement, id, idlen); + + /* Expand macro replacement. */ + es.output = &symbol->replacement; + es.input = slang_string_cstr(&replacement); + es.state = &state; + if (!expand(&es, &state.symbols)) { + slang_string_free(&replacement); + goto error; + } + slang_string_free(&replacement); + } + i += idlen + 1; + } + break; + + case TOKEN_UNDEF: + id = (const char *) (&prod[i]); + i += _mesa_strlen (id) + 1; + if (state.cond.top->effective) { + pp_symbol *symbol; + + pp_annotate (output, "// #undef %s", id); + /* Try to find symbol with given name and remove it. */ + symbol = pp_symbols_find (&state.symbols, id); + if (symbol != NULL) + if (!pp_symbols_erase (&state.symbols, symbol)) + goto error; + } + break; + + case TOKEN_IF: + { + GLint result; + + /* Parse #if expression end execute it. */ + pp_annotate (output, "// #if "); + if (!parse_if (output, prod, &i, &result, &state, eid)) + goto error; + + /* Push new condition on the stack. */ + if (!pp_cond_stack_push (&state.cond, state.elog)) + goto error; + state.cond.top->current = result ? GL_TRUE : GL_FALSE; + state.cond.top->else_allowed = GL_TRUE; + state.cond.top->endif_required = GL_TRUE; + pp_cond_stack_reevaluate (&state.cond); + } + break; + + case TOKEN_ELSE: + /* Check if #else is alloved here. */ + if (!state.cond.top->else_allowed) { + slang_info_log_error (elog, "#else without matching #if."); + goto error; + } + + /* Negate current condition and reevaluate it. */ + state.cond.top->current = !state.cond.top->current; + state.cond.top->else_allowed = GL_FALSE; + pp_cond_stack_reevaluate (&state.cond); + if (state.cond.top->effective) + pp_annotate (output, "// #else"); + break; + + case TOKEN_ELIF: + /* Check if #elif is alloved here. */ + if (!state.cond.top->else_allowed) { + slang_info_log_error (elog, "#elif without matching #if."); + goto error; + } + + /* Negate current condition and reevaluate it. */ + state.cond.top->current = !state.cond.top->current; + pp_cond_stack_reevaluate (&state.cond); + + if (state.cond.top->effective) + pp_annotate (output, "// #elif "); + + { + GLint result; + + /* Parse #elif expression end execute it. */ + if (!parse_if (output, prod, &i, &result, &state, eid)) + goto error; + + /* Update current condition and reevaluate it. */ + state.cond.top->current = result ? GL_TRUE : GL_FALSE; + pp_cond_stack_reevaluate (&state.cond); + } + break; + + case TOKEN_ENDIF: + /* Check if #endif is alloved here. */ + if (!state.cond.top->endif_required) { + slang_info_log_error (elog, "#endif without matching #if."); + goto error; + } + + /* Pop the condition off the stack. */ + state.cond.top++; + if (state.cond.top->effective) + pp_annotate (output, "// #endif"); + break; + + case TOKEN_EXTENSION: + /* Parse the extension name. */ + id = (const char *) (&prod[i]); + i += _mesa_strlen (id) + 1; + if (state.cond.top->effective) + pp_annotate (output, "// #extension %s: ", id); + + /* Parse and apply extension behavior. */ + if (state.cond.top->effective) { + switch (prod[i++]) { + + case BEHAVIOR_REQUIRE: + pp_annotate (output, "require"); + if (!pp_ext_set (&state.ext, id, GL_TRUE)) { + if (_mesa_strcmp (id, "all") == 0) { + slang_info_log_error (elog, "require: bad behavior for #extension all."); + goto error; + } + else { + slang_info_log_error (elog, "%s: required extension is not supported.", id); + goto error; + } + } + break; + + case BEHAVIOR_ENABLE: + pp_annotate (output, "enable"); + if (!pp_ext_set (&state.ext, id, GL_TRUE)) { + if (_mesa_strcmp (id, "all") == 0) { + slang_info_log_error (elog, "enable: bad behavior for #extension all."); + goto error; + } + else { + slang_info_log_warning (elog, "%s: enabled extension is not supported.", id); + } + } + break; + + case BEHAVIOR_WARN: + pp_annotate (output, "warn"); + if (!pp_ext_set (&state.ext, id, GL_TRUE)) { + if (_mesa_strcmp (id, "all") != 0) { + slang_info_log_warning (elog, "%s: enabled extension is not supported.", id); + } + } + break; + + case BEHAVIOR_DISABLE: + pp_annotate (output, "disable"); + if (!pp_ext_set (&state.ext, id, GL_FALSE)) { + if (_mesa_strcmp (id, "all") == 0) { + pp_ext_disable_all (&state.ext); + } + else { + slang_info_log_warning (elog, "%s: disabled extension is not supported.", id); + } + } + break; + + default: + assert (0); + } + } + break; + + case TOKEN_PRAGMA: + { + GLint have_param; + const char *pragma, *param; + + pragma = (const char *) (&prod[i]); + i += _mesa_strlen(pragma) + 1; + have_param = (prod[i++] == PRAGMA_PARAM); + if (have_param) { + param = (const char *) (&prod[i]); + i += _mesa_strlen(param) + 1; + } + else { + param = NULL; + } + pp_pragma(pragmas, pragma, param); + } + break; + + case TOKEN_LINE: + id = (const char *) (&prod[i]); + i += _mesa_strlen (id) + 1; + + if (state.cond.top->effective) { + slang_string buffer; + GLuint count; + GLint results[2]; + expand_state es; + + slang_string_init (&buffer); + state.line++; + es.output = &buffer; + es.input = id; + es.state = &state; + if (!expand (&es, &state.symbols)) + goto error; + + pp_annotate (output, "// #line "); + count = execute_expressions (output, eid, + (const byte *) (slang_string_cstr (&buffer)), + results, state.elog); + slang_string_free (&buffer); + if (count == 0) + goto error; + + state.line = results[0] - 1; + if (count == 2) + state.file = results[1]; + } + break; + } + } + } + + /* Check for missing #endifs. */ + if (state.cond.top->endif_required) { + slang_info_log_error (elog, "#endif expected but end of source found."); + goto error; + } + + grammar_alloc_free(prod); + pp_state_free (&state); + return GL_TRUE; + +error: + grammar_alloc_free(prod); + pp_state_free (&state); + return GL_FALSE; +} + + +/** + * Remove the continuation characters from the input string. + * This is the very first step in preprocessing and is effective + * even inside comment blocks. + * If there is a whitespace between a backslash and a newline, + * this is not considered as a line continuation. + * \return GL_TRUE for success, GL_FALSE otherwise. + */ +static GLboolean +_slang_preprocess_backslashes(slang_string *output, + const char *input) +{ + while (*input) { + if (input[0] == '\\') { + /* If a newline follows, eat the backslash and the newline. */ + if (input[1] == '\r') { + if (input[2] == '\n') { + input += 3; + } else { + input += 2; + } + } else if (input[1] == '\n') { + if (input[2] == '\r') { + input += 3; + } else { + input += 2; + } + } else { + /* Leave the backslash alone. */ + slang_string_pushc(output, *input++); + } + } else { + slang_string_pushc(output, *input++); + } + } + return GL_TRUE; +} + + +/** + * Run preprocessor on source code. + * \param extensions indicates which GL extensions are enabled + * \param output the post-process results + * \param input the input text + * \param elog log to record warnings, errors + * \param extensions out extension settings + * \param pragmas in/out #pragma settings + * \return GL_TRUE for success, GL_FALSE for error + */ +GLboolean +_slang_preprocess_directives(slang_string *output, + const char *input, + slang_info_log *elog, + const struct gl_extensions *extensions, + struct gl_sl_pragmas *pragmas) +{ + grammar pid, eid; + GLboolean success; + slang_string without_backslashes; + + pid = grammar_load_from_text ((const byte *) (slang_pp_directives_syn)); + if (pid == 0) { + grammar_error_to_log (elog); + return GL_FALSE; + } + eid = grammar_load_from_text ((const byte *) (slang_pp_expression_syn)); + if (eid == 0) { + grammar_error_to_log (elog); + grammar_destroy (pid); + return GL_FALSE; + } + + slang_string_init(&without_backslashes); + success = _slang_preprocess_backslashes(&without_backslashes, input); + + if (0) { + _mesa_printf("Pre-processed shader:\n"); + _mesa_printf("%s", slang_string_cstr(&without_backslashes)); + _mesa_printf("----------------------\n"); + } + + if (success) { + success = preprocess_source(output, + slang_string_cstr(&without_backslashes), + pid, + eid, + elog, + extensions, + pragmas); + } + + slang_string_free(&without_backslashes); + grammar_destroy (eid); + grammar_destroy (pid); + + if (0) { + _mesa_printf("Post-processed shader:\n"); + _mesa_printf("%s", slang_string_cstr(output)); + _mesa_printf("----------------------\n"); + } + + return success; +} + diff --git a/mesalib/src/mesa/shader/slang/slang_preprocess.h b/mesalib/src/mesa/shader/slang/slang_preprocess.h new file mode 100644 index 000000000..f344820da --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_preprocess.h @@ -0,0 +1,41 @@ +/* + * Mesa 3-D graphics library + * + * Copyright (C) 2005-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. + */ + +#ifndef SLANG_PREPROCESS_H +#define SLANG_PREPROCESS_H + +#include "slang_compile.h" +#include "slang_log.h" + + +extern GLboolean +_slang_preprocess_version (const char *, GLuint *, GLuint *, slang_info_log *); + +extern GLboolean +_slang_preprocess_directives(slang_string *output, const char *input, + slang_info_log *, + const struct gl_extensions *extensions, + struct gl_sl_pragmas *pragmas); + +#endif /* SLANG_PREPROCESS_H */ diff --git a/mesalib/src/mesa/shader/slang/slang_print.c b/mesalib/src/mesa/shader/slang/slang_print.c new file mode 100644 index 000000000..98c787753 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_print.c @@ -0,0 +1,883 @@ + +/** + * Dump/print a slang_operation tree + */ + + +#include "main/imports.h" +#include "slang_compile.h" +#include "slang_print.h" + + +static void +spaces(int n) +{ + while (n--) + printf(" "); +} + + +static void +print_type(const slang_fully_specified_type *t) +{ + switch (t->qualifier) { + case SLANG_QUAL_NONE: + /*printf("");*/ + break; + case SLANG_QUAL_CONST: + printf("const "); + break; + case SLANG_QUAL_ATTRIBUTE: + printf("attrib "); + break; + case SLANG_QUAL_VARYING: + printf("varying "); + break; + case SLANG_QUAL_UNIFORM: + printf("uniform "); + break; + case SLANG_QUAL_OUT: + printf("output "); + break; + case SLANG_QUAL_INOUT: + printf("inout "); + break; + case SLANG_QUAL_FIXEDOUTPUT: + printf("fixedoutput"); + break; + case SLANG_QUAL_FIXEDINPUT: + printf("fixedinput"); + break; + default: + printf("unknown qualifer!"); + } + + switch (t->specifier.type) { + case SLANG_SPEC_VOID: + printf("void"); + break; + case SLANG_SPEC_BOOL: + printf("bool"); + break; + case SLANG_SPEC_BVEC2: + printf("bvec2"); + break; + case SLANG_SPEC_BVEC3: + printf("bvec3"); + break; + case SLANG_SPEC_BVEC4: + printf("bvec4"); + break; + case SLANG_SPEC_INT: + printf("int"); + break; + case SLANG_SPEC_IVEC2: + printf("ivec2"); + break; + case SLANG_SPEC_IVEC3: + printf("ivec3"); + break; + case SLANG_SPEC_IVEC4: + printf("ivec4"); + break; + case SLANG_SPEC_FLOAT: + printf("float"); + break; + case SLANG_SPEC_VEC2: + printf("vec2"); + break; + case SLANG_SPEC_VEC3: + printf("vec3"); + break; + case SLANG_SPEC_VEC4: + printf("vec4"); + break; + case SLANG_SPEC_MAT2: + printf("mat2"); + break; + case SLANG_SPEC_MAT3: + printf("mat3"); + break; + case SLANG_SPEC_MAT4: + printf("mat4"); + break; + case SLANG_SPEC_MAT23: + printf("mat2x3"); + break; + case SLANG_SPEC_MAT32: + printf("mat3x2"); + break; + case SLANG_SPEC_MAT24: + printf("mat2x4"); + break; + case SLANG_SPEC_MAT42: + printf("mat4x2"); + break; + case SLANG_SPEC_MAT34: + printf("mat3x4"); + break; + case SLANG_SPEC_MAT43: + printf("mat4x3"); + break; + case SLANG_SPEC_SAMPLER1D: + printf("sampler1D"); + break; + case SLANG_SPEC_SAMPLER2D: + printf("sampler2D"); + break; + case SLANG_SPEC_SAMPLER3D: + printf("sampler3D"); + break; + case SLANG_SPEC_SAMPLERCUBE: + printf("samplerCube"); + break; + case SLANG_SPEC_SAMPLER1DSHADOW: + printf("sampler1DShadow"); + break; + case SLANG_SPEC_SAMPLER2DSHADOW: + printf("sampler2DShadow"); + break; + case SLANG_SPEC_STRUCT: + printf("struct"); + break; + case SLANG_SPEC_ARRAY: + printf("array"); + break; + default: + printf("unknown type"); + } + /*printf("\n");*/ +} + + +static void +print_variable(const slang_variable *v, int indent) +{ + spaces(indent); + printf("VAR "); + print_type(&v->type); + printf(" %s (at %p)", (char *) v->a_name, (void *) v); + if (v->initializer) { + printf(" :=\n"); + slang_print_tree(v->initializer, indent + 3); + } + else { + printf(";\n"); + } +} + + +static void +print_binary(const slang_operation *op, const char *oper, int indent) +{ + assert(op->num_children == 2); +#if 0 + printf("binary at %p locals=%p outer=%p\n", + (void *) op, + (void *) op->locals, + (void *) op->locals->outer_scope); +#endif + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("%s at %p locals=%p outer=%p\n", + oper, (void *) op, (void *) op->locals, + (void *) op->locals->outer_scope); + slang_print_tree(&op->children[1], indent + 3); +} + + +static void +print_generic2(const slang_operation *op, const char *oper, + const char *s, int indent) +{ + GLuint i; + if (oper) { + spaces(indent); + printf("%s %s at %p locals=%p outer=%p\n", + oper, s, (void *) op, (void *) op->locals, + (void *) op->locals->outer_scope); + } + for (i = 0; i < op->num_children; i++) { + spaces(indent); + printf("//child %u of %u:\n", i, op->num_children); + slang_print_tree(&op->children[i], indent); + } +} + +static void +print_generic(const slang_operation *op, const char *oper, int indent) +{ + print_generic2(op, oper, "", indent); +} + + +static const slang_variable_scope * +find_scope(const slang_variable_scope *s, slang_atom name) +{ + GLuint i; + for (i = 0; i < s->num_variables; i++) { + if (s->variables[i]->a_name == name) + return s; + } + if (s->outer_scope) + return find_scope(s->outer_scope, name); + else + return NULL; +} + +static const slang_variable * +find_var(const slang_variable_scope *s, slang_atom name) +{ + GLuint i; + for (i = 0; i < s->num_variables; i++) { + if (s->variables[i]->a_name == name) + return s->variables[i]; + } + if (s->outer_scope) + return find_var(s->outer_scope, name); + else + return NULL; +} + + +void +slang_print_tree(const slang_operation *op, int indent) +{ + GLuint i; + + switch (op->type) { + + case SLANG_OPER_NONE: + spaces(indent); + printf("SLANG_OPER_NONE\n"); + break; + + case SLANG_OPER_BLOCK_NO_NEW_SCOPE: + spaces(indent); + printf("{ locals=%p outer=%p\n", (void*)op->locals, (void*)op->locals->outer_scope); + print_generic(op, NULL, indent+3); + spaces(indent); + printf("}\n"); + break; + + case SLANG_OPER_BLOCK_NEW_SCOPE: + case SLANG_OPER_NON_INLINED_CALL: + spaces(indent); + printf("{{ // new scope locals=%p outer=%p: ", + (void *) op->locals, + (void *) op->locals->outer_scope); + for (i = 0; i < op->locals->num_variables; i++) { + printf("%s ", (char *) op->locals->variables[i]->a_name); + } + printf("\n"); + print_generic(op, NULL, indent+3); + spaces(indent); + printf("}}\n"); + break; + + case SLANG_OPER_VARIABLE_DECL: + assert(op->num_children == 0 || op->num_children == 1); + { + slang_variable *v; + v = _slang_variable_locate(op->locals, op->a_id, GL_TRUE); + if (v) { + const slang_variable_scope *scope; + spaces(indent); + printf("DECL (locals=%p outer=%p) ", (void*)op->locals, (void*) op->locals->outer_scope); + print_type(&v->type); + printf(" %s (%p)", (char *) op->a_id, + (void *) find_var(op->locals, op->a_id)); + + scope = find_scope(op->locals, op->a_id); + printf(" (in scope %p) ", (void *) scope); + assert(scope); + if (op->num_children == 1) { + printf(" :=\n"); + slang_print_tree(&op->children[0], indent + 3); + } + else if (v->initializer) { + printf(" := INITIALIZER\n"); + slang_print_tree(v->initializer, indent + 3); + } + else { + printf(";\n"); + } + /* + spaces(indent); + printf("TYPE: "); + print_type(&v->type); + spaces(indent); + printf("ADDR: %d size: %d\n", v->address, v->size); + */ + } + else { + spaces(indent); + printf("DECL %s (anonymous variable!!!!)\n", (char *) op->a_id); + } + } + break; + + case SLANG_OPER_ASM: + spaces(indent); + printf("ASM: %s at %p locals=%p outer=%p\n", + (char *) op->a_id, + (void *) op, + (void *) op->locals, + (void *) op->locals->outer_scope); + print_generic(op, "ASM", indent+3); + break; + + case SLANG_OPER_BREAK: + spaces(indent); + printf("BREAK\n"); + break; + + case SLANG_OPER_CONTINUE: + spaces(indent); + printf("CONTINUE\n"); + break; + + case SLANG_OPER_DISCARD: + spaces(indent); + printf("DISCARD\n"); + break; + + case SLANG_OPER_RETURN: + spaces(indent); + printf("RETURN\n"); + if (op->num_children > 0) + slang_print_tree(&op->children[0], indent + 3); + break; + + case SLANG_OPER_RETURN_INLINED: + spaces(indent); + printf("RETURN_INLINED\n"); + if (op->num_children > 0) + slang_print_tree(&op->children[0], indent + 3); + break; + + case SLANG_OPER_LABEL: + spaces(indent); + printf("LABEL %s\n", (char *) op->a_id); + break; + + case SLANG_OPER_EXPRESSION: + spaces(indent); + printf("EXPR: locals=%p outer=%p\n", + (void *) op->locals, + (void *) op->locals->outer_scope); + /*print_generic(op, "SLANG_OPER_EXPRESSION", indent);*/ + slang_print_tree(&op->children[0], indent + 3); + break; + + case SLANG_OPER_IF: + spaces(indent); + printf("IF\n"); + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("THEN\n"); + slang_print_tree(&op->children[1], indent + 3); + spaces(indent); + printf("ELSE\n"); + slang_print_tree(&op->children[2], indent + 3); + spaces(indent); + printf("ENDIF\n"); + break; + + case SLANG_OPER_WHILE: + assert(op->num_children == 2); + spaces(indent); + printf("WHILE LOOP: locals = %p\n", (void *) op->locals); + indent += 3; + spaces(indent); + printf("WHILE cond:\n"); + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("WHILE body:\n"); + slang_print_tree(&op->children[1], indent + 3); + indent -= 3; + spaces(indent); + printf("END WHILE LOOP\n"); + break; + + case SLANG_OPER_DO: + spaces(indent); + printf("DO LOOP: locals = %p\n", (void *) op->locals); + indent += 3; + spaces(indent); + printf("DO body:\n"); + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("DO cond:\n"); + slang_print_tree(&op->children[1], indent + 3); + indent -= 3; + spaces(indent); + printf("END DO LOOP\n"); + break; + + case SLANG_OPER_FOR: + spaces(indent); + printf("FOR LOOP: locals = %p\n", (void *) op->locals); + indent += 3; + spaces(indent); + printf("FOR init:\n"); + slang_print_tree(&op->children[0], indent + 3); + spaces(indent); + printf("FOR condition:\n"); + slang_print_tree(&op->children[1], indent + 3); + spaces(indent); + printf("FOR step:\n"); + slang_print_tree(&op->children[2], indent + 3); + spaces(indent); + printf("FOR body:\n"); + slang_print_tree(&op->children[3], indent + 3); + indent -= 3; + spaces(indent); + printf("ENDFOR\n"); + /* + print_generic(op, "FOR", indent + 3); + */ + break; + + case SLANG_OPER_VOID: + spaces(indent); + printf("(oper-void)\n"); + break; + + case SLANG_OPER_LITERAL_BOOL: + spaces(indent); + printf("LITERAL ("); + for (i = 0; i < op->literal_size; i++) + printf("%s ", op->literal[0] ? "TRUE" : "FALSE"); + printf(")\n"); + + break; + + case SLANG_OPER_LITERAL_INT: + spaces(indent); + printf("LITERAL ("); + for (i = 0; i < op->literal_size; i++) + printf("%d ", (int) op->literal[i]); + printf(")\n"); + break; + + case SLANG_OPER_LITERAL_FLOAT: + spaces(indent); + printf("LITERAL ("); + for (i = 0; i < op->literal_size; i++) + printf("%f ", op->literal[i]); + printf(")\n"); + break; + + case SLANG_OPER_IDENTIFIER: + { + const slang_variable_scope *scope; + spaces(indent); + if (op->var && op->var->a_name) { + scope = find_scope(op->locals, op->var->a_name); + printf("VAR %s (in scope %p)\n", (char *) op->var->a_name, + (void *) scope); + assert(scope); + } + else { + scope = find_scope(op->locals, op->a_id); + printf("VAR' %s (in scope %p) locals=%p outer=%p\n", + (char *) op->a_id, + (void *) scope, + (void *) op->locals, + (void *) op->locals->outer_scope); + /*assert(scope);*/ + } + } + break; + + case SLANG_OPER_SEQUENCE: + print_generic(op, "COMMA-SEQ", indent+3); + break; + + case SLANG_OPER_ASSIGN: + spaces(indent); + printf("ASSIGNMENT locals=%p outer=%p\n", + (void *) op->locals, + (void *) op->locals->outer_scope); + print_binary(op, ":=", indent); + break; + + case SLANG_OPER_ADDASSIGN: + spaces(indent); + printf("ASSIGN\n"); + print_binary(op, "+=", indent); + break; + + case SLANG_OPER_SUBASSIGN: + spaces(indent); + printf("ASSIGN\n"); + print_binary(op, "-=", indent); + break; + + case SLANG_OPER_MULASSIGN: + spaces(indent); + printf("ASSIGN\n"); + print_binary(op, "*=", indent); + break; + + case SLANG_OPER_DIVASSIGN: + spaces(indent); + printf("ASSIGN\n"); + print_binary(op, "/=", indent); + break; + + /*SLANG_OPER_MODASSIGN,*/ + /*SLANG_OPER_LSHASSIGN,*/ + /*SLANG_OPER_RSHASSIGN,*/ + /*SLANG_OPER_ORASSIGN,*/ + /*SLANG_OPER_XORASSIGN,*/ + /*SLANG_OPER_ANDASSIGN,*/ + case SLANG_OPER_SELECT: + spaces(indent); + printf("SLANG_OPER_SELECT n=%d\n", op->num_children); + assert(op->num_children == 3); + slang_print_tree(&op->children[0], indent+3); + spaces(indent); + printf("?\n"); + slang_print_tree(&op->children[1], indent+3); + spaces(indent); + printf(":\n"); + slang_print_tree(&op->children[2], indent+3); + break; + + case SLANG_OPER_LOGICALOR: + print_binary(op, "||", indent); + break; + + case SLANG_OPER_LOGICALXOR: + print_binary(op, "^^", indent); + break; + + case SLANG_OPER_LOGICALAND: + print_binary(op, "&&", indent); + break; + + /*SLANG_OPER_BITOR*/ + /*SLANG_OPER_BITXOR*/ + /*SLANG_OPER_BITAND*/ + case SLANG_OPER_EQUAL: + print_binary(op, "==", indent); + break; + + case SLANG_OPER_NOTEQUAL: + print_binary(op, "!=", indent); + break; + + case SLANG_OPER_LESS: + print_binary(op, "<", indent); + break; + + case SLANG_OPER_GREATER: + print_binary(op, ">", indent); + break; + + case SLANG_OPER_LESSEQUAL: + print_binary(op, "<=", indent); + break; + + case SLANG_OPER_GREATEREQUAL: + print_binary(op, ">=", indent); + break; + + /*SLANG_OPER_LSHIFT*/ + /*SLANG_OPER_RSHIFT*/ + case SLANG_OPER_ADD: + print_binary(op, "+", indent); + break; + + case SLANG_OPER_SUBTRACT: + print_binary(op, "-", indent); + break; + + case SLANG_OPER_MULTIPLY: + print_binary(op, "*", indent); + break; + + case SLANG_OPER_DIVIDE: + print_binary(op, "/", indent); + break; + + /*SLANG_OPER_MODULUS*/ + case SLANG_OPER_PREINCREMENT: + spaces(indent); + printf("PRE++\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + case SLANG_OPER_PREDECREMENT: + spaces(indent); + printf("PRE--\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + case SLANG_OPER_PLUS: + spaces(indent); + printf("SLANG_OPER_PLUS\n"); + break; + + case SLANG_OPER_MINUS: + spaces(indent); + printf("SLANG_OPER_MINUS\n"); + break; + + /*SLANG_OPER_COMPLEMENT*/ + case SLANG_OPER_NOT: + spaces(indent); + printf("NOT\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + case SLANG_OPER_SUBSCRIPT: + spaces(indent); + printf("SLANG_OPER_SUBSCRIPT locals=%p outer=%p\n", + (void *) op->locals, + (void *) op->locals->outer_scope); + print_generic(op, NULL, indent+3); + break; + + case SLANG_OPER_CALL: +#if 0 + slang_function *fun + = _slang_function_locate(A->space.funcs, oper->a_id, + oper->children, + oper->num_children, &A->space, A->atoms); +#endif + spaces(indent); + printf("CALL %s(\n", (char *) op->a_id); + for (i = 0; i < op->num_children; i++) { + slang_print_tree(&op->children[i], indent+3); + if (i + 1 < op->num_children) { + spaces(indent + 3); + printf(",\n"); + } + } + spaces(indent); + printf(")\n"); + break; + + case SLANG_OPER_METHOD: + spaces(indent); + printf("METHOD CALL %s.%s\n", (char *) op->a_obj, (char *) op->a_id); + break; + + case SLANG_OPER_FIELD: + spaces(indent); + printf("FIELD %s of\n", (char*) op->a_id); + slang_print_tree(&op->children[0], indent+3); + break; + + case SLANG_OPER_POSTINCREMENT: + spaces(indent); + printf("POST++\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + case SLANG_OPER_POSTDECREMENT: + spaces(indent); + printf("POST--\n"); + slang_print_tree(&op->children[0], indent+3); + break; + + default: + printf("unknown op->type %d\n", (int) op->type); + } + +} + + + +void +slang_print_function(const slang_function *f, GLboolean body) +{ + GLuint i; + +#if 0 + if (_mesa_strcmp((char *) f->header.a_name, "main") != 0) + return; +#endif + + printf("FUNCTION %s ( scope=%p\n", + (char *) f->header.a_name, (void *) f->parameters); + + for (i = 0; i < f->param_count; i++) { + print_variable(f->parameters->variables[i], 3); + } + + printf(") param scope = %p\n", (void *) f->parameters); + + if (body && f->body) + slang_print_tree(f->body, 0); +} + + + + + +const char * +slang_type_qual_string(slang_type_qualifier q) +{ + switch (q) { + case SLANG_QUAL_NONE: + return "none"; + case SLANG_QUAL_CONST: + return "const"; + case SLANG_QUAL_ATTRIBUTE: + return "attribute"; + case SLANG_QUAL_VARYING: + return "varying"; + case SLANG_QUAL_UNIFORM: + return "uniform"; + case SLANG_QUAL_OUT: + return "out"; + case SLANG_QUAL_INOUT: + return "inout"; + case SLANG_QUAL_FIXEDOUTPUT: + return "fixedoutput"; + case SLANG_QUAL_FIXEDINPUT: + return "fixedinputk"; + default: + return "qual?"; + } +} + + +static const char * +slang_type_string(slang_type_specifier_type t) +{ + switch (t) { + case SLANG_SPEC_VOID: + return "void"; + case SLANG_SPEC_BOOL: + return "bool"; + case SLANG_SPEC_BVEC2: + return "bvec2"; + case SLANG_SPEC_BVEC3: + return "bvec3"; + case SLANG_SPEC_BVEC4: + return "bvec4"; + case SLANG_SPEC_INT: + return "int"; + case SLANG_SPEC_IVEC2: + return "ivec2"; + case SLANG_SPEC_IVEC3: + return "ivec3"; + case SLANG_SPEC_IVEC4: + return "ivec4"; + case SLANG_SPEC_FLOAT: + return "float"; + case SLANG_SPEC_VEC2: + return "vec2"; + case SLANG_SPEC_VEC3: + return "vec3"; + case SLANG_SPEC_VEC4: + return "vec4"; + case SLANG_SPEC_MAT2: + return "mat2"; + case SLANG_SPEC_MAT3: + return "mat3"; + case SLANG_SPEC_MAT4: + return "mat4"; + case SLANG_SPEC_SAMPLER1D: + return "sampler1D"; + case SLANG_SPEC_SAMPLER2D: + return "sampler2D"; + case SLANG_SPEC_SAMPLER3D: + return "sampler3D"; + case SLANG_SPEC_SAMPLERCUBE: + return "samplerCube"; + case SLANG_SPEC_SAMPLER1DSHADOW: + return "sampler1DShadow"; + case SLANG_SPEC_SAMPLER2DSHADOW: + return "sampler2DShadow"; + case SLANG_SPEC_SAMPLER2DRECT: + return "sampler2DRect"; + case SLANG_SPEC_SAMPLER2DRECTSHADOW: + return "sampler2DRectShadow"; + case SLANG_SPEC_STRUCT: + return "struct"; + case SLANG_SPEC_ARRAY: + return "array"; + default: + return "type?"; + } +} + + +static const char * +slang_fq_type_string(const slang_fully_specified_type *t) +{ + static char str[1000]; + sprintf(str, "%s %s", slang_type_qual_string(t->qualifier), + slang_type_string(t->specifier.type)); + return str; +} + + +void +slang_print_type(const slang_fully_specified_type *t) +{ + printf("%s %s", slang_type_qual_string(t->qualifier), + slang_type_string(t->specifier.type)); +} + + +#if 0 +static char * +slang_var_string(const slang_variable *v) +{ + static char str[1000]; + sprintf(str, "%s : %s", + (char *) v->a_name, + slang_fq_type_string(&v->type)); + return str; +} +#endif + + +void +slang_print_variable(const slang_variable *v) +{ + printf("Name: %s\n", (char *) v->a_name); + printf("Type: %s\n", slang_fq_type_string(&v->type)); +} + + +void +_slang_print_var_scope(const slang_variable_scope *vars, int indent) +{ + GLuint i; + + spaces(indent); + printf("Var scope %p %d vars:\n", (void *) vars, vars->num_variables); + for (i = 0; i < vars->num_variables; i++) { + spaces(indent + 3); + printf("%s (at %p)\n", (char *) vars->variables[i]->a_name, (void*) (vars->variables + i)); + } + spaces(indent + 3); + printf("outer_scope = %p\n", (void*) vars->outer_scope); + + if (vars->outer_scope) { + /*spaces(indent + 3);*/ + _slang_print_var_scope(vars->outer_scope, indent + 3); + } +} + + + +int +slang_checksum_tree(const slang_operation *op) +{ + int s = op->num_children; + GLuint i; + + for (i = 0; i < op->num_children; i++) { + s += slang_checksum_tree(&op->children[i]); + } + return s; +} diff --git a/mesalib/src/mesa/shader/slang/slang_print.h b/mesalib/src/mesa/shader/slang/slang_print.h new file mode 100644 index 000000000..46605c806 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_print.h @@ -0,0 +1,29 @@ + + +#ifndef SLANG_PRINT +#define SLANG_PRINT + +extern void +slang_print_function(const slang_function *f, GLboolean body); + +extern void +slang_print_tree(const slang_operation *op, int indent); + +extern const char * +slang_type_qual_string(slang_type_qualifier q); + +extern void +slang_print_type(const slang_fully_specified_type *t); + +extern void +slang_print_variable(const slang_variable *v); + +extern void +_slang_print_var_scope(const slang_variable_scope *s, int indent); + + +extern int +slang_checksum_tree(const slang_operation *op); + +#endif /* SLANG_PRINT */ + diff --git a/mesalib/src/mesa/shader/slang/slang_simplify.c b/mesalib/src/mesa/shader/slang/slang_simplify.c new file mode 100644 index 000000000..b8a21f642 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_simplify.c @@ -0,0 +1,526 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 2005-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. + */ + +/** + * Functions for constant folding, built-in constant lookup, and function + * call casting. + */ + + +#include "main/imports.h" +#include "main/macros.h" +#include "main/get.h" +#include "slang_compile.h" +#include "slang_codegen.h" +#include "slang_simplify.h" +#include "slang_print.h" + + +#ifndef GL_MAX_FRAGMENT_UNIFORM_VECTORS +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#endif +#ifndef GL_MAX_VERTEX_UNIFORM_VECTORS +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#endif +#ifndef GL_MAX_VARYING_VECTORS +#define GL_MAX_VARYING_VECTORS 0x8DFC +#endif + + +/** + * Lookup the value of named constant, such as gl_MaxLights. + * \return value of constant, or -1 if unknown + */ +GLint +_slang_lookup_constant(const char *name) +{ + struct constant_info { + const char *Name; + const GLenum Token; + }; + static const struct constant_info info[] = { + { "gl_MaxClipPlanes", GL_MAX_CLIP_PLANES }, + { "gl_MaxCombinedTextureImageUnits", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS }, + { "gl_MaxDrawBuffers", GL_MAX_DRAW_BUFFERS }, + { "gl_MaxFragmentUniformComponents", GL_MAX_FRAGMENT_UNIFORM_COMPONENTS }, + { "gl_MaxLights", GL_MAX_LIGHTS }, + { "gl_MaxTextureUnits", GL_MAX_TEXTURE_UNITS }, + { "gl_MaxTextureCoords", GL_MAX_TEXTURE_COORDS }, + { "gl_MaxVertexAttribs", GL_MAX_VERTEX_ATTRIBS }, + { "gl_MaxVertexUniformComponents", GL_MAX_VERTEX_UNIFORM_COMPONENTS }, + { "gl_MaxVaryingFloats", GL_MAX_VARYING_FLOATS }, + { "gl_MaxVertexTextureImageUnits", GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS }, + { "gl_MaxTextureImageUnits", GL_MAX_TEXTURE_IMAGE_UNITS }, +#if FEATURE_es2_glsl + { "gl_MaxVertexUniformVectors", GL_MAX_VERTEX_UNIFORM_VECTORS }, + { "gl_MaxVaryingVectors", GL_MAX_VARYING_VECTORS }, + { "gl_MaxFragmentUniformVectors", GL_MAX_FRAGMENT_UNIFORM_VECTORS }, +#endif + { NULL, 0 } + }; + GLuint i; + + for (i = 0; info[i].Name; i++) { + if (strcmp(info[i].Name, name) == 0) { + /* found */ + GLint value = -1; + _mesa_GetIntegerv(info[i].Token, &value); + ASSERT(value >= 0); /* sanity check that glGetFloatv worked */ + return value; + } + } + return -1; +} + + +static slang_operation_type +literal_type(slang_operation_type t1, slang_operation_type t2) +{ + if (t1 == SLANG_OPER_LITERAL_FLOAT || t2 == SLANG_OPER_LITERAL_FLOAT) + return SLANG_OPER_LITERAL_FLOAT; + else + return SLANG_OPER_LITERAL_INT; +} + + +/** + * Recursively traverse an AST tree, applying simplifications wherever + * possible. + * At the least, we do constant folding. We need to do that much so that + * compile-time expressions can be evaluated for things like array + * declarations. I.e.: float foo[3 + 5]; + */ +void +_slang_simplify(slang_operation *oper, + const slang_name_space * space, + slang_atom_pool * atoms) +{ + GLboolean isFloat[4]; + GLboolean isBool[4]; + GLuint i, n; + + if (oper->type == SLANG_OPER_IDENTIFIER) { + /* see if it's a named constant */ + GLint value = _slang_lookup_constant((char *) oper->a_id); + /*printf("value[%s] = %d\n", (char*) oper->a_id, value);*/ + if (value >= 0) { + oper->literal[0] = + oper->literal[1] = + oper->literal[2] = + oper->literal[3] = (GLfloat) value; + oper->type = SLANG_OPER_LITERAL_INT; + return; + } + /* look for user-defined constant */ + { + slang_variable *var; + var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); + if (var) { + if (var->type.qualifier == SLANG_QUAL_CONST && + var->initializer && + (var->initializer->type == SLANG_OPER_LITERAL_INT || + var->initializer->type == SLANG_OPER_LITERAL_FLOAT)) { + oper->literal[0] = var->initializer->literal[0]; + oper->literal[1] = var->initializer->literal[1]; + oper->literal[2] = var->initializer->literal[2]; + oper->literal[3] = var->initializer->literal[3]; + oper->literal_size = var->initializer->literal_size; + oper->type = var->initializer->type; + /* + printf("value[%s] = %f\n", + (char*) oper->a_id, oper->literal[0]); + */ + return; + } + } + } + } + + /* first, simplify children */ + for (i = 0; i < oper->num_children; i++) { + _slang_simplify(&oper->children[i], space, atoms); + } + + /* examine children */ + n = MIN2(oper->num_children, 4); + for (i = 0; i < n; i++) { + isFloat[i] = (oper->children[i].type == SLANG_OPER_LITERAL_FLOAT || + oper->children[i].type == SLANG_OPER_LITERAL_INT); + isBool[i] = (oper->children[i].type == SLANG_OPER_LITERAL_BOOL); + } + + if (oper->num_children == 2 && isFloat[0] && isFloat[1]) { + /* probably simple arithmetic */ + switch (oper->type) { + case SLANG_OPER_ADD: + for (i = 0; i < 4; i++) { + oper->literal[i] + = oper->children[0].literal[i] + oper->children[1].literal[i]; + } + oper->literal_size = oper->children[0].literal_size; + oper->type = literal_type(oper->children[0].type, + oper->children[1].type); + slang_operation_destruct(oper); /* frees unused children */ + return; + case SLANG_OPER_SUBTRACT: + for (i = 0; i < 4; i++) { + oper->literal[i] + = oper->children[0].literal[i] - oper->children[1].literal[i]; + } + oper->literal_size = oper->children[0].literal_size; + oper->type = literal_type(oper->children[0].type, + oper->children[1].type); + slang_operation_destruct(oper); + return; + case SLANG_OPER_MULTIPLY: + for (i = 0; i < 4; i++) { + oper->literal[i] + = oper->children[0].literal[i] * oper->children[1].literal[i]; + } + oper->literal_size = oper->children[0].literal_size; + oper->type = literal_type(oper->children[0].type, + oper->children[1].type); + slang_operation_destruct(oper); + return; + case SLANG_OPER_DIVIDE: + for (i = 0; i < 4; i++) { + oper->literal[i] + = oper->children[0].literal[i] / oper->children[1].literal[i]; + } + oper->literal_size = oper->children[0].literal_size; + oper->type = literal_type(oper->children[0].type, + oper->children[1].type); + slang_operation_destruct(oper); + return; + default: + ; /* nothing */ + } + } + + if (oper->num_children == 1 && isFloat[0]) { + switch (oper->type) { + case SLANG_OPER_MINUS: + for (i = 0; i < 4; i++) { + oper->literal[i] = -oper->children[0].literal[i]; + } + oper->literal_size = oper->children[0].literal_size; + slang_operation_destruct(oper); + oper->type = SLANG_OPER_LITERAL_FLOAT; + return; + case SLANG_OPER_PLUS: + COPY_4V(oper->literal, oper->children[0].literal); + oper->literal_size = oper->children[0].literal_size; + slang_operation_destruct(oper); + oper->type = SLANG_OPER_LITERAL_FLOAT; + return; + default: + ; /* nothing */ + } + } + + if (oper->num_children == 2 && isBool[0] && isBool[1]) { + /* simple boolean expression */ + switch (oper->type) { + case SLANG_OPER_LOGICALAND: + for (i = 0; i < 4; i++) { + const GLint a = oper->children[0].literal[i] ? 1 : 0; + const GLint b = oper->children[1].literal[i] ? 1 : 0; + oper->literal[i] = (GLfloat) (a && b); + } + oper->literal_size = oper->children[0].literal_size; + slang_operation_destruct(oper); + oper->type = SLANG_OPER_LITERAL_BOOL; + return; + case SLANG_OPER_LOGICALOR: + for (i = 0; i < 4; i++) { + const GLint a = oper->children[0].literal[i] ? 1 : 0; + const GLint b = oper->children[1].literal[i] ? 1 : 0; + oper->literal[i] = (GLfloat) (a || b); + } + oper->literal_size = oper->children[0].literal_size; + slang_operation_destruct(oper); + oper->type = SLANG_OPER_LITERAL_BOOL; + return; + case SLANG_OPER_LOGICALXOR: + for (i = 0; i < 4; i++) { + const GLint a = oper->children[0].literal[i] ? 1 : 0; + const GLint b = oper->children[1].literal[i] ? 1 : 0; + oper->literal[i] = (GLfloat) (a ^ b); + } + oper->literal_size = oper->children[0].literal_size; + slang_operation_destruct(oper); + oper->type = SLANG_OPER_LITERAL_BOOL; + return; + default: + ; /* nothing */ + } + } + + if (oper->num_children == 4 + && isFloat[0] && isFloat[1] && isFloat[2] && isFloat[3]) { + /* vec4(flt, flt, flt, flt) constructor */ + if (oper->type == SLANG_OPER_CALL) { + if (strcmp((char *) oper->a_id, "vec4") == 0) { + oper->literal[0] = oper->children[0].literal[0]; + oper->literal[1] = oper->children[1].literal[0]; + oper->literal[2] = oper->children[2].literal[0]; + oper->literal[3] = oper->children[3].literal[0]; + oper->literal_size = 4; + slang_operation_destruct(oper); + oper->type = SLANG_OPER_LITERAL_FLOAT; + return; + } + } + } + + if (oper->num_children == 3 && isFloat[0] && isFloat[1] && isFloat[2]) { + /* vec3(flt, flt, flt) constructor */ + if (oper->type == SLANG_OPER_CALL) { + if (strcmp((char *) oper->a_id, "vec3") == 0) { + oper->literal[0] = oper->children[0].literal[0]; + oper->literal[1] = oper->children[1].literal[0]; + oper->literal[2] = oper->children[2].literal[0]; + oper->literal[3] = oper->literal[2]; + oper->literal_size = 3; + slang_operation_destruct(oper); + oper->type = SLANG_OPER_LITERAL_FLOAT; + return; + } + } + } + + if (oper->num_children == 2 && isFloat[0] && isFloat[1]) { + /* vec2(flt, flt) constructor */ + if (oper->type == SLANG_OPER_CALL) { + if (strcmp((char *) oper->a_id, "vec2") == 0) { + oper->literal[0] = oper->children[0].literal[0]; + oper->literal[1] = oper->children[1].literal[0]; + oper->literal[2] = oper->literal[1]; + oper->literal[3] = oper->literal[1]; + oper->literal_size = 2; + slang_operation_destruct(oper); /* XXX oper->locals goes NULL! */ + oper->type = SLANG_OPER_LITERAL_FLOAT; + assert(oper->num_children == 0); + return; + } + } + } + + if (oper->num_children == 1 && isFloat[0]) { + /* vec2/3/4(flt, flt) constructor */ + if (oper->type == SLANG_OPER_CALL) { + const char *func = (const char *) oper->a_id; + if (strncmp(func, "vec", 3) == 0 && func[3] >= '2' && func[3] <= '4') { + oper->literal[0] = + oper->literal[1] = + oper->literal[2] = + oper->literal[3] = oper->children[0].literal[0]; + oper->literal_size = func[3] - '0'; + assert(oper->literal_size >= 2); + assert(oper->literal_size <= 4); + slang_operation_destruct(oper); /* XXX oper->locals goes NULL! */ + oper->type = SLANG_OPER_LITERAL_FLOAT; + assert(oper->num_children == 0); + return; + } + } + } +} + + + +/** + * Insert casts to try to adapt actual parameters to formal parameters for a + * function call when an exact match for the parameter types is not found. + * Example: + * void foo(int i, bool b) {} + * x = foo(3.15, 9); + * Gets translated into: + * x = foo(int(3.15), bool(9)) + */ +GLboolean +_slang_cast_func_params(slang_operation *callOper, const slang_function *fun, + const slang_name_space * space, + slang_atom_pool * atoms, slang_info_log *log) +{ + const GLboolean haveRetValue = _slang_function_has_return_value(fun); + const int numParams = fun->param_count - haveRetValue; + int i; + int dbg = 0; + + if (dbg) + printf("Adapt call of %d args to func %s (%d params)\n", + callOper->num_children, (char*) fun->header.a_name, numParams); + + for (i = 0; i < numParams; i++) { + slang_typeinfo argType; + slang_variable *paramVar = fun->parameters->variables[i]; + + /* Get type of arg[i] */ + if (!slang_typeinfo_construct(&argType)) + return GL_FALSE; + if (!_slang_typeof_operation(&callOper->children[i], space, + &argType, atoms, log)) { + slang_typeinfo_destruct(&argType); + return GL_FALSE; + } + + /* see if arg type matches parameter type */ + if (!slang_type_specifier_equal(&argType.spec, + ¶mVar->type.specifier)) { + /* need to adapt arg type to match param type */ + const char *constructorName = + slang_type_specifier_type_to_string(paramVar->type.specifier.type); + slang_operation *child = slang_operation_new(1); + + if (dbg) + printf("Need to adapt types of arg %d\n", i); + + slang_operation_copy(child, &callOper->children[i]); + child->locals->outer_scope = callOper->children[i].locals; + +#if 0 + if (_slang_sizeof_type_specifier(&argType.spec) > + _slang_sizeof_type_specifier(¶mVar->type.specifier)) { + } +#endif + + callOper->children[i].type = SLANG_OPER_CALL; + callOper->children[i].a_id = slang_atom_pool_atom(atoms, constructorName); + callOper->children[i].num_children = 1; + callOper->children[i].children = child; + } + + slang_typeinfo_destruct(&argType); + } + + if (dbg) { + printf("===== New call to %s with cast arguments ===============\n", + (char*) fun->header.a_name); + slang_print_tree(callOper, 5); + } + + return GL_TRUE; +} + + +/** + * Adapt the arguments for a function call to match the parameters of + * the given function. + * This is for: + * 1. converting/casting argument types to match parameters + * 2. breaking up vector/matrix types into individual components to + * satisfy constructors. + */ +GLboolean +_slang_adapt_call(slang_operation *callOper, const slang_function *fun, + const slang_name_space * space, + slang_atom_pool * atoms, slang_info_log *log) +{ + const GLboolean haveRetValue = _slang_function_has_return_value(fun); + const int numParams = fun->param_count - haveRetValue; + int i; + int dbg = 0; + + if (dbg) + printf("Adapt %d args to %d parameters for %s\n", + callOper->num_children, numParams, (char *) fun->header.a_name); + + /* Only try adapting for constructors */ + if (fun->kind != SLANG_FUNC_CONSTRUCTOR) + return GL_FALSE; + + if (callOper->num_children != numParams) { + /* number of arguments doesn't match number of parameters */ + + /* For constructor calls, we can try to unroll vector/matrix args + * into individual floats/ints and try to match the function params. + */ + for (i = 0; i < numParams; i++) { + slang_typeinfo argType; + GLint argSz, j; + + /* Get type of arg[i] */ + if (!slang_typeinfo_construct(&argType)) + return GL_FALSE; + if (!_slang_typeof_operation(&callOper->children[i], space, + &argType, atoms, log)) { + slang_typeinfo_destruct(&argType); + return GL_FALSE; + } + + /* + paramSz = _slang_sizeof_type_specifier(¶mVar->type.specifier); + assert(paramSz == 1); + */ + argSz = _slang_sizeof_type_specifier(&argType.spec); + if (argSz > 1) { + slang_operation origArg; + /* break up arg[i] into components */ + if (dbg) + printf("Break up arg %d from 1 to %d elements\n", i, argSz); + + slang_operation_construct(&origArg); + slang_operation_copy(&origArg, &callOper->children[i]); + + /* insert argSz-1 new children/args */ + for (j = 0; j < argSz - 1; j++) { + (void) slang_operation_insert(&callOper->num_children, + &callOper->children, i); + } + + /* replace arg[i+j] with subscript/index oper */ + for (j = 0; j < argSz; j++) { + callOper->children[i + j].type = SLANG_OPER_SUBSCRIPT; + callOper->children[i + j].locals = _slang_variable_scope_new(callOper->locals); + callOper->children[i + j].num_children = 2; + callOper->children[i + j].children = slang_operation_new(2); + slang_operation_copy(&callOper->children[i + j].children[0], + &origArg); + callOper->children[i + j].children[1].type + = SLANG_OPER_LITERAL_INT; + callOper->children[i + j].children[1].literal[0] = (GLfloat) j; + } + } + } + } + + if (callOper->num_children < (GLuint) numParams) { + /* still not enough args for all params */ + return GL_FALSE; + } + else if (callOper->num_children > (GLuint) numParams) { + /* now too many arguments */ + /* just truncate */ + callOper->num_children = (GLuint) numParams; + } + + if (dbg) { + printf("===== New call to %s with adapted arguments ===============\n", + (char*) fun->header.a_name); + slang_print_tree(callOper, 5); + } + + return GL_TRUE; +} diff --git a/mesalib/src/mesa/shader/slang/slang_simplify.h b/mesalib/src/mesa/shader/slang/slang_simplify.h new file mode 100644 index 000000000..8689c23b1 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_simplify.h @@ -0,0 +1,50 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 2005-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. + */ + +#ifndef SLANG_SIMPLIFY_H +#define SLANG_SIMPLIFY_H + + +extern GLint +_slang_lookup_constant(const char *name); + + +extern void +_slang_simplify(slang_operation *oper, + const slang_name_space * space, + slang_atom_pool * atoms); + + +extern GLboolean +_slang_cast_func_params(slang_operation *callOper, const slang_function *fun, + const slang_name_space * space, + slang_atom_pool * atoms, slang_info_log *log); + +extern GLboolean +_slang_adapt_call(slang_operation *callOper, const slang_function *fun, + const slang_name_space * space, + slang_atom_pool * atoms, slang_info_log *log); + + +#endif /* SLANG_SIMPLIFY_H */ diff --git a/mesalib/src/mesa/shader/slang/slang_storage.c b/mesalib/src/mesa/shader/slang/slang_storage.c new file mode 100644 index 000000000..e8b0fb774 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_storage.c @@ -0,0 +1,316 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_storage.c + * slang variable storage + * \author Michal Krol + */ + +#include "main/imports.h" +#include "slang_storage.h" +#include "slang_mem.h" + +/* slang_storage_array */ + +GLboolean +slang_storage_array_construct(slang_storage_array * arr) +{ + arr->type = SLANG_STORE_AGGREGATE; + arr->aggregate = NULL; + arr->length = 0; + return GL_TRUE; +} + +GLvoid +slang_storage_array_destruct(slang_storage_array * arr) +{ + if (arr->aggregate != NULL) { + slang_storage_aggregate_destruct(arr->aggregate); + _slang_free(arr->aggregate); + } +} + +/* slang_storage_aggregate */ + +GLboolean +slang_storage_aggregate_construct(slang_storage_aggregate * agg) +{ + agg->arrays = NULL; + agg->count = 0; + return GL_TRUE; +} + +GLvoid +slang_storage_aggregate_destruct(slang_storage_aggregate * agg) +{ + GLuint i; + + for (i = 0; i < agg->count; i++) + slang_storage_array_destruct(agg->arrays + i); + _slang_free(agg->arrays); +} + +static slang_storage_array * +slang_storage_aggregate_push_new(slang_storage_aggregate * agg) +{ + slang_storage_array *arr = NULL; + + agg->arrays = (slang_storage_array *) + _slang_realloc(agg->arrays, + agg->count * sizeof(slang_storage_array), + (agg->count + 1) * sizeof(slang_storage_array)); + if (agg->arrays != NULL) { + arr = agg->arrays + agg->count; + if (!slang_storage_array_construct(arr)) + return NULL; + agg->count++; + } + return arr; +} + +/* _slang_aggregate_variable() */ + +static GLboolean +aggregate_vector(slang_storage_aggregate * agg, slang_storage_type basic_type, + GLuint row_count) +{ + slang_storage_array *arr = slang_storage_aggregate_push_new(agg); + if (arr == NULL) + return GL_FALSE; + arr->type = basic_type; + arr->length = row_count; + return GL_TRUE; +} + +static GLboolean +aggregate_matrix(slang_storage_aggregate * agg, slang_storage_type basic_type, + GLuint columns, GLuint rows) +{ + slang_storage_array *arr = slang_storage_aggregate_push_new(agg); + if (arr == NULL) + return GL_FALSE; + arr->type = SLANG_STORE_AGGREGATE; + arr->length = columns; + arr->aggregate = (slang_storage_aggregate *) + _slang_alloc(sizeof(slang_storage_aggregate)); + if (arr->aggregate == NULL) + return GL_FALSE; + if (!slang_storage_aggregate_construct(arr->aggregate)) { + _slang_free(arr->aggregate); + arr->aggregate = NULL; + return GL_FALSE; + } + if (!aggregate_vector(arr->aggregate, basic_type, rows)) + return GL_FALSE; + return GL_TRUE; +} + + +static GLboolean +aggregate_variables(slang_storage_aggregate * agg, + slang_variable_scope * vars, slang_function_scope * funcs, + slang_struct_scope * structs, + slang_variable_scope * globals, + slang_atom_pool * atoms) +{ + GLuint i; + + for (i = 0; i < vars->num_variables; i++) + if (!_slang_aggregate_variable(agg, &vars->variables[i]->type.specifier, + vars->variables[i]->array_len, funcs, + structs, globals, atoms)) + return GL_FALSE; + return GL_TRUE; +} + + +GLboolean +_slang_aggregate_variable(slang_storage_aggregate * agg, + slang_type_specifier * spec, GLuint array_len, + slang_function_scope * funcs, + slang_struct_scope * structs, + slang_variable_scope * vars, + slang_atom_pool * atoms) +{ + switch (spec->type) { + case SLANG_SPEC_BOOL: + return aggregate_vector(agg, SLANG_STORE_BOOL, 1); + case SLANG_SPEC_BVEC2: + return aggregate_vector(agg, SLANG_STORE_BOOL, 2); + case SLANG_SPEC_BVEC3: + return aggregate_vector(agg, SLANG_STORE_BOOL, 3); + case SLANG_SPEC_BVEC4: + return aggregate_vector(agg, SLANG_STORE_BOOL, 4); + case SLANG_SPEC_INT: + return aggregate_vector(agg, SLANG_STORE_INT, 1); + case SLANG_SPEC_IVEC2: + return aggregate_vector(agg, SLANG_STORE_INT, 2); + case SLANG_SPEC_IVEC3: + return aggregate_vector(agg, SLANG_STORE_INT, 3); + case SLANG_SPEC_IVEC4: + return aggregate_vector(agg, SLANG_STORE_INT, 4); + case SLANG_SPEC_FLOAT: + return aggregate_vector(agg, SLANG_STORE_FLOAT, 1); + case SLANG_SPEC_VEC2: + return aggregate_vector(agg, SLANG_STORE_FLOAT, 2); + case SLANG_SPEC_VEC3: + return aggregate_vector(agg, SLANG_STORE_FLOAT, 3); + case SLANG_SPEC_VEC4: + return aggregate_vector(agg, SLANG_STORE_FLOAT, 4); + case SLANG_SPEC_MAT2: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 2, 2); + case SLANG_SPEC_MAT3: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 3, 3); + case SLANG_SPEC_MAT4: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 4, 4); + + case SLANG_SPEC_MAT23: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 2, 3); + case SLANG_SPEC_MAT32: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 3, 2); + case SLANG_SPEC_MAT24: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 2, 4); + case SLANG_SPEC_MAT42: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 4, 2); + case SLANG_SPEC_MAT34: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 3, 4); + case SLANG_SPEC_MAT43: + return aggregate_matrix(agg, SLANG_STORE_FLOAT, 4, 3); + + case SLANG_SPEC_SAMPLER1D: + case SLANG_SPEC_SAMPLER2D: + case SLANG_SPEC_SAMPLER3D: + case SLANG_SPEC_SAMPLERCUBE: + case SLANG_SPEC_SAMPLER1DSHADOW: + case SLANG_SPEC_SAMPLER2DSHADOW: + case SLANG_SPEC_SAMPLER2DRECT: + case SLANG_SPEC_SAMPLER2DRECTSHADOW: + return aggregate_vector(agg, SLANG_STORE_INT, 1); + case SLANG_SPEC_STRUCT: + return aggregate_variables(agg, spec->_struct->fields, funcs, structs, + vars, atoms); + case SLANG_SPEC_ARRAY: + { + slang_storage_array *arr; + + arr = slang_storage_aggregate_push_new(agg); + if (arr == NULL) + return GL_FALSE; + arr->type = SLANG_STORE_AGGREGATE; + arr->aggregate = (slang_storage_aggregate *) + _slang_alloc(sizeof(slang_storage_aggregate)); + if (arr->aggregate == NULL) + return GL_FALSE; + if (!slang_storage_aggregate_construct(arr->aggregate)) { + _slang_free(arr->aggregate); + arr->aggregate = NULL; + return GL_FALSE; + } + if (!_slang_aggregate_variable(arr->aggregate, spec->_array, 0, + funcs, structs, vars, atoms)) + return GL_FALSE; + arr->length = array_len; + /* TODO: check if 0 < arr->length <= 65535 */ + } + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +GLuint +_slang_sizeof_type(slang_storage_type type) +{ + if (type == SLANG_STORE_AGGREGATE) + return 0; + if (type == SLANG_STORE_VEC4) + return 4 * sizeof(GLfloat); + return sizeof(GLfloat); +} + + +GLuint +_slang_sizeof_aggregate(const slang_storage_aggregate * agg) +{ + GLuint i, size = 0; + + for (i = 0; i < agg->count; i++) { + slang_storage_array *arr = &agg->arrays[i]; + GLuint element_size; + + if (arr->type == SLANG_STORE_AGGREGATE) + element_size = _slang_sizeof_aggregate(arr->aggregate); + else + element_size = _slang_sizeof_type(arr->type); + size += element_size * arr->length; + } + return size; +} + + +#if 0 +GLboolean +_slang_flatten_aggregate(slang_storage_aggregate * flat, + const slang_storage_aggregate * agg) +{ + GLuint i; + + for (i = 0; i < agg->count; i++) { + GLuint j; + + for (j = 0; j < agg->arrays[i].length; j++) { + if (agg->arrays[i].type == SLANG_STORE_AGGREGATE) { + if (!_slang_flatten_aggregate(flat, agg->arrays[i].aggregate)) + return GL_FALSE; + } + else { + GLuint k, count; + slang_storage_type type; + + if (agg->arrays[i].type == SLANG_STORE_VEC4) { + count = 4; + type = SLANG_STORE_FLOAT; + } + else { + count = 1; + type = agg->arrays[i].type; + } + + for (k = 0; k < count; k++) { + slang_storage_array *arr; + + arr = slang_storage_aggregate_push_new(flat); + if (arr == NULL) + return GL_FALSE; + arr->type = type; + arr->length = 1; + } + } + } + } + return GL_TRUE; +} +#endif diff --git a/mesalib/src/mesa/shader/slang/slang_storage.h b/mesalib/src/mesa/shader/slang/slang_storage.h new file mode 100644 index 000000000..1876a36dd --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_storage.h @@ -0,0 +1,139 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLANG_STORAGE_H +#define SLANG_STORAGE_H + +#include "slang_compile.h" + + +/* + * Program variable data storage is kept completely transparent to the + * front-end compiler. It is up to the back-end how the data is + * actually allocated. The slang_storage_type enum provides the basic + * information about how the memory is interpreted. This abstract + * piece of memory is called a data slot. A data slot of a particular + * type has a fixed size. + * + * For now, only the three basic types are supported, that is bool, + * int and float. Other built-in types like vector or matrix can + * easily be decomposed into a series of basic types. + * + * If the vec4 module is enabled, 4-component vectors of floats are + * used when possible. 4x4 matrices are constructed of 4 vec4 slots. + */ +typedef enum slang_storage_type_ +{ + /* core */ + SLANG_STORE_AGGREGATE, + SLANG_STORE_BOOL, + SLANG_STORE_INT, + SLANG_STORE_FLOAT, + /* vec4 */ + SLANG_STORE_VEC4 +} slang_storage_type; + + +/** + * The slang_storage_array structure groups data slots of the same + * type into an array. This array has a fixed length. Arrays are + * required to have a size equal to the sum of sizes of its + * elements. They are also required to support indirect + * addressing. That is, if B references first data slot in the array, + * S is the size of the data slot and I is the integral index that is + * not known at compile time, B+I*S references I-th data slot. + * + * This structure is also used to break down built-in data types that + * are not supported directly. Vectors, like vec3, are constructed + * from arrays of their basic types. Matrices are formed of an array + * of column vectors, which are in turn processed as other vectors. + */ +typedef struct slang_storage_array_ +{ + slang_storage_type type; + struct slang_storage_aggregate_ *aggregate; + GLuint length; +} slang_storage_array; + +GLboolean slang_storage_array_construct (slang_storage_array *); +GLvoid slang_storage_array_destruct (slang_storage_array *); + + +/** + * The slang_storage_aggregate structure relaxes the indirect + * addressing requirement for slang_storage_array + * structure. Aggregates are always accessed statically - its member + * addresses are well-known at compile time. For example, user-defined + * types are implemented as aggregates. Aggregates can collect data of + * a different type. + */ +typedef struct slang_storage_aggregate_ +{ + slang_storage_array *arrays; + GLuint count; +} slang_storage_aggregate; + +GLboolean slang_storage_aggregate_construct (slang_storage_aggregate *); +GLvoid slang_storage_aggregate_destruct (slang_storage_aggregate *); + + +extern GLboolean +_slang_aggregate_variable(slang_storage_aggregate *agg, + slang_type_specifier *spec, + GLuint array_len, + slang_function_scope *funcs, + slang_struct_scope *structs, + slang_variable_scope *vars, + slang_atom_pool *atoms); + +/* + * Returns the size (in machine units) of the given storage type. + * It is an error to pass-in SLANG_STORE_AGGREGATE. + * Returns 0 on error. + */ +extern GLuint +_slang_sizeof_type (slang_storage_type); + + +/** + * Returns total size (in machine units) of the given aggregate. + * Returns 0 on error. + */ +extern GLuint +_slang_sizeof_aggregate (const slang_storage_aggregate *); + + +#if 0 +/** + * Converts structured aggregate to a flat one, with arrays of generic + * type being one-element long. Returns GL_TRUE on success. Returns + * GL_FALSE otherwise. + */ +extern GLboolean +_slang_flatten_aggregate (slang_storage_aggregate *, + const slang_storage_aggregate *); + +#endif + +#endif /* SLANG_STORAGE_H */ diff --git a/mesalib/src/mesa/shader/slang/slang_typeinfo.c b/mesalib/src/mesa/shader/slang/slang_typeinfo.c new file mode 100644 index 000000000..4a48bc8b8 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_typeinfo.c @@ -0,0 +1,1138 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file slang_typeinfo.c + * slang type info + * \author Michal Krol + */ + +#include "main/imports.h" +#include "shader/prog_instruction.h" +#include "slang_typeinfo.h" +#include "slang_compile.h" +#include "slang_log.h" +#include "slang_mem.h" + + +/** + * Checks if a field selector is a general swizzle (an r-value swizzle + * with replicated components or an l-value swizzle mask) for a + * vector. Returns GL_TRUE if this is the case, <swz> is filled with + * swizzle information. Returns GL_FALSE otherwise. + */ +GLboolean +_slang_is_swizzle(const char *field, GLuint rows, slang_swizzle * swz) +{ + GLuint i; + GLboolean xyzw = GL_FALSE, rgba = GL_FALSE, stpq = GL_FALSE; + + /* init to undefined. + * We rely on undefined/nil values to distinguish between + * regular swizzles and writemasks. + * For example, the swizzle ".xNNN" is the writemask ".x". + * That's different than the swizzle ".xxxx". + */ + for (i = 0; i < 4; i++) + swz->swizzle[i] = SWIZZLE_NIL; + + /* the swizzle can be at most 4-component long */ + swz->num_components = slang_string_length(field); + if (swz->num_components > 4) + return GL_FALSE; + + for (i = 0; i < swz->num_components; i++) { + /* mark which swizzle group is used */ + switch (field[i]) { + case 'x': + case 'y': + case 'z': + case 'w': + xyzw = GL_TRUE; + break; + case 'r': + case 'g': + case 'b': + case 'a': + rgba = GL_TRUE; + break; + case 's': + case 't': + case 'p': + case 'q': + stpq = GL_TRUE; + break; + default: + return GL_FALSE; + } + + /* collect swizzle component */ + switch (field[i]) { + case 'x': + case 'r': + case 's': + swz->swizzle[i] = 0; + break; + case 'y': + case 'g': + case 't': + swz->swizzle[i] = 1; + break; + case 'z': + case 'b': + case 'p': + swz->swizzle[i] = 2; + break; + case 'w': + case 'a': + case 'q': + swz->swizzle[i] = 3; + break; + } + + /* check if the component is valid for given vector's row count */ + if (rows <= swz->swizzle[i]) + return GL_FALSE; + } + + /* only one swizzle group can be used */ + if ((xyzw && rgba) || (xyzw && stpq) || (rgba && stpq)) + return GL_FALSE; + + return GL_TRUE; +} + + + +/** + * Checks if a general swizzle is an l-value swizzle - these swizzles + * do not have duplicated fields. Returns GL_TRUE if this is a + * swizzle mask. Returns GL_FALSE otherwise + */ +static GLboolean +_slang_is_swizzle_mask(const slang_swizzle * swz, GLuint rows) +{ + GLuint i, c = 0; + + /* the swizzle may not be longer than the vector dim */ + if (swz->num_components > rows) + return GL_FALSE; + + /* the swizzle components cannot be duplicated */ + for (i = 0; i < swz->num_components; i++) { + if ((c & (1 << swz->swizzle[i])) != 0) + return GL_FALSE; + c |= 1 << swz->swizzle[i]; + } + + return GL_TRUE; +} + + +/** + * Combines (multiplies) two swizzles to form single swizzle. + * Example: "vec.wzyx.yx" --> "vec.zw". + */ +static void +_slang_multiply_swizzles(slang_swizzle * dst, const slang_swizzle * left, + const slang_swizzle * right) +{ + GLuint i; + + dst->num_components = right->num_components; + for (i = 0; i < right->num_components; i++) + dst->swizzle[i] = left->swizzle[right->swizzle[i]]; +} + + +typedef struct +{ + const char *name; + slang_type_specifier_type type; +} type_specifier_type_name; + +static const type_specifier_type_name type_specifier_type_names[] = { + {"void", SLANG_SPEC_VOID}, + {"bool", SLANG_SPEC_BOOL}, + {"bvec2", SLANG_SPEC_BVEC2}, + {"bvec3", SLANG_SPEC_BVEC3}, + {"bvec4", SLANG_SPEC_BVEC4}, + {"int", SLANG_SPEC_INT}, + {"ivec2", SLANG_SPEC_IVEC2}, + {"ivec3", SLANG_SPEC_IVEC3}, + {"ivec4", SLANG_SPEC_IVEC4}, + {"float", SLANG_SPEC_FLOAT}, + {"vec2", SLANG_SPEC_VEC2}, + {"vec3", SLANG_SPEC_VEC3}, + {"vec4", SLANG_SPEC_VEC4}, + {"mat2", SLANG_SPEC_MAT2}, + {"mat3", SLANG_SPEC_MAT3}, + {"mat4", SLANG_SPEC_MAT4}, + {"mat2x3", SLANG_SPEC_MAT23}, + {"mat3x2", SLANG_SPEC_MAT32}, + {"mat2x4", SLANG_SPEC_MAT24}, + {"mat4x2", SLANG_SPEC_MAT42}, + {"mat3x4", SLANG_SPEC_MAT34}, + {"mat4x3", SLANG_SPEC_MAT43}, + {"sampler1D", SLANG_SPEC_SAMPLER1D}, + {"sampler2D", SLANG_SPEC_SAMPLER2D}, + {"sampler3D", SLANG_SPEC_SAMPLER3D}, + {"samplerCube", SLANG_SPEC_SAMPLERCUBE}, + {"sampler1DShadow", SLANG_SPEC_SAMPLER1DSHADOW}, + {"sampler2DShadow", SLANG_SPEC_SAMPLER2DSHADOW}, + {"sampler2DRect", SLANG_SPEC_SAMPLER2DRECT}, + {"sampler2DRectShadow", SLANG_SPEC_SAMPLER2DRECTSHADOW}, + {NULL, SLANG_SPEC_VOID} +}; + +slang_type_specifier_type +slang_type_specifier_type_from_string(const char *name) +{ + const type_specifier_type_name *p = type_specifier_type_names; + while (p->name != NULL) { + if (slang_string_compare(p->name, name) == 0) + break; + p++; + } + return p->type; +} + +const char * +slang_type_specifier_type_to_string(slang_type_specifier_type type) +{ + const type_specifier_type_name *p = type_specifier_type_names; + while (p->name != NULL) { + if (p->type == type) + break; + p++; + } + return p->name; +} + +/* slang_fully_specified_type */ + +int +slang_fully_specified_type_construct(slang_fully_specified_type * type) +{ + type->qualifier = SLANG_QUAL_NONE; + slang_type_specifier_ctr(&type->specifier); + return 1; +} + +void +slang_fully_specified_type_destruct(slang_fully_specified_type * type) +{ + slang_type_specifier_dtr(&type->specifier); +} + +int +slang_fully_specified_type_copy(slang_fully_specified_type * x, + const slang_fully_specified_type * y) +{ + slang_fully_specified_type z; + + if (!slang_fully_specified_type_construct(&z)) + return 0; + z.qualifier = y->qualifier; + z.precision = y->precision; + z.variant = y->variant; + z.centroid = y->centroid; + z.array_len = y->array_len; + if (!slang_type_specifier_copy(&z.specifier, &y->specifier)) { + slang_fully_specified_type_destruct(&z); + return 0; + } + slang_fully_specified_type_destruct(x); + *x = z; + return 1; +} + + + +GLvoid +slang_type_specifier_ctr(slang_type_specifier * self) +{ + self->type = SLANG_SPEC_VOID; + self->_struct = NULL; + self->_array = NULL; +} + +GLvoid +slang_type_specifier_dtr(slang_type_specifier * self) +{ + if (self->_struct != NULL) { + slang_struct_destruct(self->_struct); + _slang_free(self->_struct); + } + if (self->_array != NULL) { + slang_type_specifier_dtr(self->_array); + _slang_free(self->_array); + } +} + +slang_type_specifier * +slang_type_specifier_new(slang_type_specifier_type type, + struct slang_struct_ *_struct, + struct slang_type_specifier_ *_array) +{ + slang_type_specifier *spec = + (slang_type_specifier *) _slang_alloc(sizeof(slang_type_specifier)); + if (spec) { + spec->type = type; + spec->_struct = _struct; + spec->_array = _array; + } + return spec; +} + +GLboolean +slang_type_specifier_copy(slang_type_specifier * x, + const slang_type_specifier * y) +{ + slang_type_specifier z; + + slang_type_specifier_ctr(&z); + z.type = y->type; + if (z.type == SLANG_SPEC_STRUCT) { + z._struct = (slang_struct *) _slang_alloc(sizeof(slang_struct)); + if (z._struct == NULL) { + slang_type_specifier_dtr(&z); + return GL_FALSE; + } + if (!slang_struct_construct(z._struct)) { + _slang_free(z._struct); + slang_type_specifier_dtr(&z); + return GL_FALSE; + } + if (!slang_struct_copy(z._struct, y->_struct)) { + slang_type_specifier_dtr(&z); + return GL_FALSE; + } + } + else if (z.type == SLANG_SPEC_ARRAY) { + z._array = (slang_type_specifier *) + _slang_alloc(sizeof(slang_type_specifier)); + if (z._array == NULL) { + slang_type_specifier_dtr(&z); + return GL_FALSE; + } + slang_type_specifier_ctr(z._array); + if (!slang_type_specifier_copy(z._array, y->_array)) { + slang_type_specifier_dtr(&z); + return GL_FALSE; + } + } + slang_type_specifier_dtr(x); + *x = z; + return GL_TRUE; +} + + +/** + * Test if two types are equal. + */ +GLboolean +slang_type_specifier_equal(const slang_type_specifier * x, + const slang_type_specifier * y) +{ + if (x->type != y->type) + return GL_FALSE; + if (x->type == SLANG_SPEC_STRUCT) + return slang_struct_equal(x->_struct, y->_struct); + if (x->type == SLANG_SPEC_ARRAY) + return slang_type_specifier_equal(x->_array, y->_array); + return GL_TRUE; +} + + +/** + * As above, but allow float/int casting. + */ +GLboolean +slang_type_specifier_compatible(const slang_type_specifier * x, + const slang_type_specifier * y) +{ + /* special case: float == int */ + if (x->type == SLANG_SPEC_INT && y->type == SLANG_SPEC_FLOAT) { + return GL_TRUE; + } + /* XXX may need to add bool/int compatibility, etc */ + + if (x->type != y->type) + return GL_FALSE; + if (x->type == SLANG_SPEC_STRUCT) + return slang_struct_equal(x->_struct, y->_struct); + if (x->type == SLANG_SPEC_ARRAY) + return slang_type_specifier_compatible(x->_array, y->_array); + return GL_TRUE; +} + + +GLboolean +slang_typeinfo_construct(slang_typeinfo * ti) +{ + _mesa_bzero(ti, sizeof(*ti)); + slang_type_specifier_ctr(&ti->spec); + ti->array_len = 0; + return GL_TRUE; +} + +GLvoid +slang_typeinfo_destruct(slang_typeinfo * ti) +{ + slang_type_specifier_dtr(&ti->spec); +} + + + +/** + * Determine the return type of a function. + * \param a_name the function name + * \param param function parameters (overloading) + * \param num_params number of parameters to function + * \param space namespace to search + * \param spec returns the type + * \param funFound returns pointer to the function, or NULL if not found. + * \return GL_TRUE for success, GL_FALSE if failure (bad function name) + */ +static GLboolean +_slang_typeof_function(slang_atom a_name, + slang_operation * params, GLuint num_params, + const slang_name_space * space, + slang_type_specifier * spec, + slang_function **funFound, + slang_atom_pool *atoms, slang_info_log *log) +{ + GLboolean error; + + *funFound = _slang_function_locate(space->funcs, a_name, params, + num_params, space, atoms, log, &error); + if (error) + return GL_FALSE; + + if (!*funFound) + return GL_TRUE; /* yes, not false */ + + return slang_type_specifier_copy(spec, &(*funFound)->header.type.specifier); +} + + +/** + * Determine the type of a math function. + * \param name name of the operator, one of +,-,*,/ or unary - + * \param params array of function parameters + * \param num_params number of parameters + * \param space namespace to use + * \param spec returns the function's type + * \param atoms atom pool + * \return GL_TRUE for success, GL_FALSE if failure + */ +static GLboolean +typeof_math_call(const char *name, slang_operation *call, + const slang_name_space * space, + slang_type_specifier * spec, + slang_atom_pool * atoms, + slang_info_log *log) +{ + if (call->fun) { + /* we've previously resolved this function call */ + slang_type_specifier_copy(spec, &call->fun->header.type.specifier); + return GL_TRUE; + } + else { + slang_atom atom; + slang_function *fun; + + /* number of params: */ + assert(call->num_children == 1 || call->num_children == 2); + + atom = slang_atom_pool_atom(atoms, name); + if (!_slang_typeof_function(atom, call->children, call->num_children, + space, spec, &fun, atoms, log)) + return GL_FALSE; + + if (fun) { + /* Save pointer to save time in future */ + call->fun = fun; + return GL_TRUE; + } + return GL_FALSE; + } +} + + +/** + * Determine the return type of an operation. + * \param op the operation node + * \param space the namespace to use + * \param ti the returned type + * \param atoms atom pool + * \return GL_TRUE for success, GL_FALSE if failure + */ +GLboolean +_slang_typeof_operation(slang_operation * op, + const slang_name_space * space, + slang_typeinfo * ti, + slang_atom_pool * atoms, + slang_info_log *log) +{ + ti->can_be_referenced = GL_FALSE; + ti->is_swizzled = GL_FALSE; + + switch (op->type) { + case SLANG_OPER_BLOCK_NO_NEW_SCOPE: + case SLANG_OPER_BLOCK_NEW_SCOPE: + case SLANG_OPER_ASM: + case SLANG_OPER_BREAK: + case SLANG_OPER_CONTINUE: + case SLANG_OPER_DISCARD: + case SLANG_OPER_RETURN: + case SLANG_OPER_IF: + case SLANG_OPER_WHILE: + case SLANG_OPER_DO: + case SLANG_OPER_FOR: + case SLANG_OPER_VOID: + ti->spec.type = SLANG_SPEC_VOID; + break; + case SLANG_OPER_EXPRESSION: + case SLANG_OPER_ASSIGN: + case SLANG_OPER_ADDASSIGN: + case SLANG_OPER_SUBASSIGN: + case SLANG_OPER_MULASSIGN: + case SLANG_OPER_DIVASSIGN: + case SLANG_OPER_PREINCREMENT: + case SLANG_OPER_PREDECREMENT: + if (!_slang_typeof_operation(op->children, space, ti, atoms, log)) + return GL_FALSE; + break; + case SLANG_OPER_LITERAL_BOOL: + if (op->literal_size == 1) + ti->spec.type = SLANG_SPEC_BOOL; + else if (op->literal_size == 2) + ti->spec.type = SLANG_SPEC_BVEC2; + else if (op->literal_size == 3) + ti->spec.type = SLANG_SPEC_BVEC3; + else if (op->literal_size == 4) + ti->spec.type = SLANG_SPEC_BVEC4; + else { + _mesa_problem(NULL, + "Unexpected bool literal_size %d in _slang_typeof_operation()", + op->literal_size); + ti->spec.type = SLANG_SPEC_BOOL; + } + break; + case SLANG_OPER_LOGICALOR: + case SLANG_OPER_LOGICALXOR: + case SLANG_OPER_LOGICALAND: + case SLANG_OPER_EQUAL: + case SLANG_OPER_NOTEQUAL: + case SLANG_OPER_LESS: + case SLANG_OPER_GREATER: + case SLANG_OPER_LESSEQUAL: + case SLANG_OPER_GREATEREQUAL: + case SLANG_OPER_NOT: + ti->spec.type = SLANG_SPEC_BOOL; + break; + case SLANG_OPER_LITERAL_INT: + if (op->literal_size == 1) + ti->spec.type = SLANG_SPEC_INT; + else if (op->literal_size == 2) + ti->spec.type = SLANG_SPEC_IVEC2; + else if (op->literal_size == 3) + ti->spec.type = SLANG_SPEC_IVEC3; + else if (op->literal_size == 4) + ti->spec.type = SLANG_SPEC_IVEC4; + else { + _mesa_problem(NULL, + "Unexpected int literal_size %d in _slang_typeof_operation()", + op->literal_size); + ti->spec.type = SLANG_SPEC_INT; + } + break; + case SLANG_OPER_LITERAL_FLOAT: + if (op->literal_size == 1) + ti->spec.type = SLANG_SPEC_FLOAT; + else if (op->literal_size == 2) + ti->spec.type = SLANG_SPEC_VEC2; + else if (op->literal_size == 3) + ti->spec.type = SLANG_SPEC_VEC3; + else if (op->literal_size == 4) + ti->spec.type = SLANG_SPEC_VEC4; + else { + _mesa_problem(NULL, + "Unexpected float literal_size %d in _slang_typeof_operation()", + op->literal_size); + ti->spec.type = SLANG_SPEC_FLOAT; + } + break; + case SLANG_OPER_IDENTIFIER: + case SLANG_OPER_VARIABLE_DECL: + { + slang_variable *var; + var = _slang_variable_locate(op->locals, op->a_id, GL_TRUE); + if (!var) { + slang_info_log_error(log, "undefined variable '%s'", + (char *) op->a_id); + return GL_FALSE; + } + if (!slang_type_specifier_copy(&ti->spec, &var->type.specifier)) { + slang_info_log_memory(log); + return GL_FALSE; + } + ti->can_be_referenced = GL_TRUE; + if (var->type.specifier.type == SLANG_SPEC_ARRAY && + var->type.array_len >= 1) { + /* the datatype is an array, ex: float[3] x; */ + ti->array_len = var->type.array_len; + } + else { + /* the variable is an array, ex: float x[3]; */ + ti->array_len = var->array_len; + } + } + break; + case SLANG_OPER_SEQUENCE: + /* TODO: check [0] and [1] if they match */ + if (!_slang_typeof_operation(&op->children[1], space, ti, atoms, log)) { + return GL_FALSE; + } + ti->can_be_referenced = GL_FALSE; + ti->is_swizzled = GL_FALSE; + break; + /*case SLANG_OPER_MODASSIGN: */ + /*case SLANG_OPER_LSHASSIGN: */ + /*case SLANG_OPER_RSHASSIGN: */ + /*case SLANG_OPER_ORASSIGN: */ + /*case SLANG_OPER_XORASSIGN: */ + /*case SLANG_OPER_ANDASSIGN: */ + case SLANG_OPER_SELECT: + /* TODO: check [1] and [2] if they match */ + if (!_slang_typeof_operation(&op->children[1], space, ti, atoms, log)) { + return GL_FALSE; + } + ti->can_be_referenced = GL_FALSE; + ti->is_swizzled = GL_FALSE; + break; + /*case SLANG_OPER_BITOR: */ + /*case SLANG_OPER_BITXOR: */ + /*case SLANG_OPER_BITAND: */ + /*case SLANG_OPER_LSHIFT: */ + /*case SLANG_OPER_RSHIFT: */ + case SLANG_OPER_ADD: + assert(op->num_children == 2); + if (!typeof_math_call("+", op, space, &ti->spec, atoms, log)) + return GL_FALSE; + break; + case SLANG_OPER_SUBTRACT: + assert(op->num_children == 2); + if (!typeof_math_call("-", op, space, &ti->spec, atoms, log)) + return GL_FALSE; + break; + case SLANG_OPER_MULTIPLY: + assert(op->num_children == 2); + if (!typeof_math_call("*", op, space, &ti->spec, atoms, log)) + return GL_FALSE; + break; + case SLANG_OPER_DIVIDE: + assert(op->num_children == 2); + if (!typeof_math_call("/", op, space, &ti->spec, atoms, log)) + return GL_FALSE; + break; + /*case SLANG_OPER_MODULUS: */ + case SLANG_OPER_PLUS: + if (!_slang_typeof_operation(op->children, space, ti, atoms, log)) + return GL_FALSE; + ti->can_be_referenced = GL_FALSE; + ti->is_swizzled = GL_FALSE; + break; + case SLANG_OPER_MINUS: + assert(op->num_children == 1); + if (!typeof_math_call("-", op, space, &ti->spec, atoms, log)) + return GL_FALSE; + break; + /*case SLANG_OPER_COMPLEMENT: */ + case SLANG_OPER_SUBSCRIPT: + { + slang_typeinfo _ti; + + if (!slang_typeinfo_construct(&_ti)) + return GL_FALSE; + if (!_slang_typeof_operation(op->children, space, &_ti, atoms, log)) { + slang_typeinfo_destruct(&_ti); + return GL_FALSE; + } + ti->can_be_referenced = _ti.can_be_referenced; + if (_ti.spec.type == SLANG_SPEC_ARRAY) { + if (!slang_type_specifier_copy(&ti->spec, _ti.spec._array)) { + slang_typeinfo_destruct(&_ti); + return GL_FALSE; + } + } + else { + if (!_slang_type_is_vector(_ti.spec.type) + && !_slang_type_is_matrix(_ti.spec.type)) { + slang_typeinfo_destruct(&_ti); + slang_info_log_error(log, "cannot index a non-array type"); + return GL_FALSE; + } + ti->spec.type = _slang_type_base(_ti.spec.type); + } + slang_typeinfo_destruct(&_ti); + } + break; + case SLANG_OPER_CALL: + if (op->array_constructor) { + /* build array typeinfo */ + ti->spec.type = SLANG_SPEC_ARRAY; + ti->spec._array = (slang_type_specifier *) + _slang_alloc(sizeof(slang_type_specifier)); + slang_type_specifier_ctr(ti->spec._array); + + ti->spec._array->type = + slang_type_specifier_type_from_string((char *) op->a_id); + ti->array_len = op->num_children; + } + else if (op->fun) { + /* we've resolved this call before */ + slang_type_specifier_copy(&ti->spec, &op->fun->header.type.specifier); + } + else { + slang_function *fun; + if (!_slang_typeof_function(op->a_id, op->children, op->num_children, + space, &ti->spec, &fun, atoms, log)) + return GL_FALSE; + if (fun) { + /* save result for future use */ + op->fun = fun; + } + else { + slang_struct *s = + slang_struct_scope_find(space->structs, op->a_id, GL_TRUE); + if (s) { + /* struct initializer */ + ti->spec.type = SLANG_SPEC_STRUCT; + ti->spec._struct = + (slang_struct *) _slang_alloc(sizeof(slang_struct)); + if (ti->spec._struct == NULL) + return GL_FALSE; + if (!slang_struct_construct(ti->spec._struct)) { + _slang_free(ti->spec._struct); + ti->spec._struct = NULL; + return GL_FALSE; + } + if (!slang_struct_copy(ti->spec._struct, s)) + return GL_FALSE; + } + else { + /* float, int, vec4, mat3, etc. constructor? */ + const char *name; + slang_type_specifier_type type; + + name = slang_atom_pool_id(atoms, op->a_id); + type = slang_type_specifier_type_from_string(name); + if (type == SLANG_SPEC_VOID) { + slang_info_log_error(log, "undefined function '%s'", name); + return GL_FALSE; + } + ti->spec.type = type; + } + } + } + break; + case SLANG_OPER_METHOD: + /* at this time, GLSL 1.20 only has one method: array.length() + * which returns an integer. + */ + ti->spec.type = SLANG_SPEC_INT; + break; + case SLANG_OPER_FIELD: + { + slang_typeinfo _ti; + + if (!slang_typeinfo_construct(&_ti)) + return GL_FALSE; + if (!_slang_typeof_operation(op->children, space, &_ti, atoms, log)) { + slang_typeinfo_destruct(&_ti); + return GL_FALSE; + } + if (_ti.spec.type == SLANG_SPEC_STRUCT) { + slang_variable *field; + + field = _slang_variable_locate(_ti.spec._struct->fields, op->a_id, + GL_FALSE); + if (field == NULL) { + slang_typeinfo_destruct(&_ti); + return GL_FALSE; + } + if (!slang_type_specifier_copy(&ti->spec, &field->type.specifier)) { + slang_typeinfo_destruct(&_ti); + return GL_FALSE; + } + ti->can_be_referenced = _ti.can_be_referenced; + ti->array_len = field->array_len; + } + else { + GLuint rows; + const char *swizzle; + slang_type_specifier_type base; + + /* determine the swizzle of the field expression */ + if (!_slang_type_is_vector(_ti.spec.type)) { + slang_typeinfo_destruct(&_ti); + slang_info_log_error(log, "Can't swizzle scalar expression"); + return GL_FALSE; + } + rows = _slang_type_dim(_ti.spec.type); + swizzle = slang_atom_pool_id(atoms, op->a_id); + if (!_slang_is_swizzle(swizzle, rows, &ti->swz)) { + slang_typeinfo_destruct(&_ti); + slang_info_log_error(log, "bad swizzle '%s'", swizzle); + return GL_FALSE; + } + ti->is_swizzled = GL_TRUE; + ti->can_be_referenced = _ti.can_be_referenced + && _slang_is_swizzle_mask(&ti->swz, rows); + if (_ti.is_swizzled) { + slang_swizzle swz; + + /* swizzle the swizzle */ + _slang_multiply_swizzles(&swz, &_ti.swz, &ti->swz); + ti->swz = swz; + } + base = _slang_type_base(_ti.spec.type); + switch (ti->swz.num_components) { + case 1: + ti->spec.type = base; + break; + case 2: + switch (base) { + case SLANG_SPEC_FLOAT: + ti->spec.type = SLANG_SPEC_VEC2; + break; + case SLANG_SPEC_INT: + ti->spec.type = SLANG_SPEC_IVEC2; + break; + case SLANG_SPEC_BOOL: + ti->spec.type = SLANG_SPEC_BVEC2; + break; + default: + break; + } + break; + case 3: + switch (base) { + case SLANG_SPEC_FLOAT: + ti->spec.type = SLANG_SPEC_VEC3; + break; + case SLANG_SPEC_INT: + ti->spec.type = SLANG_SPEC_IVEC3; + break; + case SLANG_SPEC_BOOL: + ti->spec.type = SLANG_SPEC_BVEC3; + break; + default: + break; + } + break; + case 4: + switch (base) { + case SLANG_SPEC_FLOAT: + ti->spec.type = SLANG_SPEC_VEC4; + break; + case SLANG_SPEC_INT: + ti->spec.type = SLANG_SPEC_IVEC4; + break; + case SLANG_SPEC_BOOL: + ti->spec.type = SLANG_SPEC_BVEC4; + break; + default: + break; + } + break; + default: + break; + } + } + slang_typeinfo_destruct(&_ti); + } + break; + case SLANG_OPER_POSTINCREMENT: + case SLANG_OPER_POSTDECREMENT: + if (!_slang_typeof_operation(op->children, space, ti, atoms, log)) + return GL_FALSE; + ti->can_be_referenced = GL_FALSE; + ti->is_swizzled = GL_FALSE; + break; + default: + return GL_FALSE; + } + + return GL_TRUE; +} + + +/** + * Determine if a type is a matrix. + * \return GL_TRUE if is a matrix, GL_FALSE otherwise. + */ +GLboolean +_slang_type_is_matrix(slang_type_specifier_type ty) +{ + switch (ty) { + case SLANG_SPEC_MAT2: + case SLANG_SPEC_MAT3: + case SLANG_SPEC_MAT4: + case SLANG_SPEC_MAT23: + case SLANG_SPEC_MAT32: + case SLANG_SPEC_MAT24: + case SLANG_SPEC_MAT42: + case SLANG_SPEC_MAT34: + case SLANG_SPEC_MAT43: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Determine if a type is a vector. + * \return GL_TRUE if is a vector, GL_FALSE otherwise. + */ +GLboolean +_slang_type_is_vector(slang_type_specifier_type ty) +{ + switch (ty) { + case SLANG_SPEC_VEC2: + case SLANG_SPEC_VEC3: + case SLANG_SPEC_VEC4: + case SLANG_SPEC_IVEC2: + case SLANG_SPEC_IVEC3: + case SLANG_SPEC_IVEC4: + case SLANG_SPEC_BVEC2: + case SLANG_SPEC_BVEC3: + case SLANG_SPEC_BVEC4: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Determine if a type is a float, float vector or float matrix. + * \return GL_TRUE if so, GL_FALSE otherwise + */ +GLboolean +_slang_type_is_float_vec_mat(slang_type_specifier_type ty) +{ + switch (ty) { + case SLANG_SPEC_FLOAT: + case SLANG_SPEC_VEC2: + case SLANG_SPEC_VEC3: + case SLANG_SPEC_VEC4: + case SLANG_SPEC_MAT2: + case SLANG_SPEC_MAT3: + case SLANG_SPEC_MAT4: + case SLANG_SPEC_MAT23: + case SLANG_SPEC_MAT32: + case SLANG_SPEC_MAT24: + case SLANG_SPEC_MAT42: + case SLANG_SPEC_MAT34: + case SLANG_SPEC_MAT43: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Given a vector type, return the type of the vector's elements. + * For a matrix, return the type of the columns. + */ +slang_type_specifier_type +_slang_type_base(slang_type_specifier_type ty) +{ + switch (ty) { + case SLANG_SPEC_FLOAT: + case SLANG_SPEC_VEC2: + case SLANG_SPEC_VEC3: + case SLANG_SPEC_VEC4: + return SLANG_SPEC_FLOAT; + case SLANG_SPEC_INT: + case SLANG_SPEC_IVEC2: + case SLANG_SPEC_IVEC3: + case SLANG_SPEC_IVEC4: + return SLANG_SPEC_INT; + case SLANG_SPEC_BOOL: + case SLANG_SPEC_BVEC2: + case SLANG_SPEC_BVEC3: + case SLANG_SPEC_BVEC4: + return SLANG_SPEC_BOOL; + case SLANG_SPEC_MAT2: + return SLANG_SPEC_VEC2; + case SLANG_SPEC_MAT3: + return SLANG_SPEC_VEC3; + case SLANG_SPEC_MAT4: + return SLANG_SPEC_VEC4; + case SLANG_SPEC_MAT23: + return SLANG_SPEC_VEC3; + case SLANG_SPEC_MAT32: + return SLANG_SPEC_VEC2; + case SLANG_SPEC_MAT24: + return SLANG_SPEC_VEC4; + case SLANG_SPEC_MAT42: + return SLANG_SPEC_VEC2; + case SLANG_SPEC_MAT34: + return SLANG_SPEC_VEC4; + case SLANG_SPEC_MAT43: + return SLANG_SPEC_VEC3; + default: + return SLANG_SPEC_VOID; + } +} + + +/** + * Return the dimensionality of a vector, or for a matrix, return number + * of columns. + */ +GLuint +_slang_type_dim(slang_type_specifier_type ty) +{ + switch (ty) { + case SLANG_SPEC_FLOAT: + case SLANG_SPEC_INT: + case SLANG_SPEC_BOOL: + return 1; + case SLANG_SPEC_VEC2: + case SLANG_SPEC_IVEC2: + case SLANG_SPEC_BVEC2: + case SLANG_SPEC_MAT2: + return 2; + case SLANG_SPEC_VEC3: + case SLANG_SPEC_IVEC3: + case SLANG_SPEC_BVEC3: + case SLANG_SPEC_MAT3: + return 3; + case SLANG_SPEC_VEC4: + case SLANG_SPEC_IVEC4: + case SLANG_SPEC_BVEC4: + case SLANG_SPEC_MAT4: + return 4; + + case SLANG_SPEC_MAT23: + return 2; + case SLANG_SPEC_MAT32: + return 3; + case SLANG_SPEC_MAT24: + return 2; + case SLANG_SPEC_MAT42: + return 4; + case SLANG_SPEC_MAT34: + return 3; + case SLANG_SPEC_MAT43: + return 4; + + default: + return 0; + } +} + + +/** + * Return the GL_* type that corresponds to a SLANG_SPEC_* type. + */ +GLenum +_slang_gltype_from_specifier(const slang_type_specifier *type) +{ + switch (type->type) { + case SLANG_SPEC_BOOL: + return GL_BOOL; + case SLANG_SPEC_BVEC2: + return GL_BOOL_VEC2; + case SLANG_SPEC_BVEC3: + return GL_BOOL_VEC3; + case SLANG_SPEC_BVEC4: + return GL_BOOL_VEC4; + case SLANG_SPEC_INT: + return GL_INT; + case SLANG_SPEC_IVEC2: + return GL_INT_VEC2; + case SLANG_SPEC_IVEC3: + return GL_INT_VEC3; + case SLANG_SPEC_IVEC4: + return GL_INT_VEC4; + case SLANG_SPEC_FLOAT: + return GL_FLOAT; + case SLANG_SPEC_VEC2: + return GL_FLOAT_VEC2; + case SLANG_SPEC_VEC3: + return GL_FLOAT_VEC3; + case SLANG_SPEC_VEC4: + return GL_FLOAT_VEC4; + case SLANG_SPEC_MAT2: + return GL_FLOAT_MAT2; + case SLANG_SPEC_MAT3: + return GL_FLOAT_MAT3; + case SLANG_SPEC_MAT4: + return GL_FLOAT_MAT4; + case SLANG_SPEC_MAT23: + return GL_FLOAT_MAT2x3; + case SLANG_SPEC_MAT32: + return GL_FLOAT_MAT3x2; + case SLANG_SPEC_MAT24: + return GL_FLOAT_MAT2x4; + case SLANG_SPEC_MAT42: + return GL_FLOAT_MAT4x2; + case SLANG_SPEC_MAT34: + return GL_FLOAT_MAT3x4; + case SLANG_SPEC_MAT43: + return GL_FLOAT_MAT4x3; + case SLANG_SPEC_SAMPLER1D: + return GL_SAMPLER_1D; + case SLANG_SPEC_SAMPLER2D: + return GL_SAMPLER_2D; + case SLANG_SPEC_SAMPLER3D: + return GL_SAMPLER_3D; + case SLANG_SPEC_SAMPLERCUBE: + return GL_SAMPLER_CUBE; + case SLANG_SPEC_SAMPLER1DSHADOW: + return GL_SAMPLER_1D_SHADOW; + case SLANG_SPEC_SAMPLER2DSHADOW: + return GL_SAMPLER_2D_SHADOW; + case SLANG_SPEC_SAMPLER2DRECT: + return GL_SAMPLER_2D_RECT_ARB; + case SLANG_SPEC_SAMPLER2DRECTSHADOW: + return GL_SAMPLER_2D_RECT_SHADOW_ARB; + case SLANG_SPEC_ARRAY: + return _slang_gltype_from_specifier(type->_array); + case SLANG_SPEC_STRUCT: + /* fall-through */ + default: + return GL_NONE; + } +} + diff --git a/mesalib/src/mesa/shader/slang/slang_typeinfo.h b/mesalib/src/mesa/shader/slang/slang_typeinfo.h new file mode 100644 index 000000000..e6fecd350 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_typeinfo.h @@ -0,0 +1,239 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SLANG_TYPEINFO_H +#define SLANG_TYPEINFO_H 1 + +#include "main/imports.h" +#include "main/mtypes.h" +#include "slang_log.h" +#include "slang_utility.h" +#include "slang_vartable.h" + + +struct slang_operation_; + +struct slang_name_space_; + + + +/** + * Holds complete information about vector swizzle - the <swizzle> + * array contains vector component source indices, where 0 is "x", 1 + * is "y", 2 is "z" and 3 is "w". + * Example: "xwz" --> { 3, { 0, 3, 2, not used } }. + */ +typedef struct slang_swizzle_ +{ + GLuint num_components; + GLuint swizzle[4]; +} slang_swizzle; + +extern GLboolean +_slang_is_swizzle(const char *field, GLuint rows, slang_swizzle *swz); + + +typedef enum slang_type_variant_ +{ + SLANG_VARIANT, /* the default */ + SLANG_INVARIANT /* indicates the "invariant" keyword */ +} slang_type_variant; + + +typedef enum slang_type_centroid_ +{ + SLANG_CENTER, /* the default */ + SLANG_CENTROID /* indicates the "centroid" keyword */ +} slang_type_centroid; + + +typedef enum slang_type_qualifier_ +{ + SLANG_QUAL_NONE, + SLANG_QUAL_CONST, + SLANG_QUAL_ATTRIBUTE, + SLANG_QUAL_VARYING, + SLANG_QUAL_UNIFORM, + SLANG_QUAL_OUT, + SLANG_QUAL_INOUT, + SLANG_QUAL_FIXEDOUTPUT, /* internal */ + SLANG_QUAL_FIXEDINPUT /* internal */ +} slang_type_qualifier; + + +typedef enum slang_type_precision_ +{ + SLANG_PREC_DEFAULT, + SLANG_PREC_LOW, + SLANG_PREC_MEDIUM, + SLANG_PREC_HIGH +} slang_type_precision; + + +/** + * The basic shading language types (float, vec4, mat3, etc) + */ +typedef enum slang_type_specifier_type_ +{ + SLANG_SPEC_VOID, + SLANG_SPEC_BOOL, + SLANG_SPEC_BVEC2, + SLANG_SPEC_BVEC3, + SLANG_SPEC_BVEC4, + SLANG_SPEC_INT, + SLANG_SPEC_IVEC2, + SLANG_SPEC_IVEC3, + SLANG_SPEC_IVEC4, + SLANG_SPEC_FLOAT, + SLANG_SPEC_VEC2, + SLANG_SPEC_VEC3, + SLANG_SPEC_VEC4, + SLANG_SPEC_MAT2, + SLANG_SPEC_MAT3, + SLANG_SPEC_MAT4, + SLANG_SPEC_MAT23, + SLANG_SPEC_MAT32, + SLANG_SPEC_MAT24, + SLANG_SPEC_MAT42, + SLANG_SPEC_MAT34, + SLANG_SPEC_MAT43, + SLANG_SPEC_SAMPLER1D, + SLANG_SPEC_SAMPLER2D, + SLANG_SPEC_SAMPLER3D, + SLANG_SPEC_SAMPLERCUBE, + SLANG_SPEC_SAMPLER2DRECT, + SLANG_SPEC_SAMPLER1DSHADOW, + SLANG_SPEC_SAMPLER2DSHADOW, + SLANG_SPEC_SAMPLER2DRECTSHADOW, + SLANG_SPEC_STRUCT, + SLANG_SPEC_ARRAY +} slang_type_specifier_type; + + +extern slang_type_specifier_type +slang_type_specifier_type_from_string(const char *); + +extern const char * +slang_type_specifier_type_to_string(slang_type_specifier_type); + + +/** + * Describes more sophisticated types, like structs and arrays. + */ +typedef struct slang_type_specifier_ +{ + slang_type_specifier_type type; + struct slang_struct_ *_struct; /**< if type == SLANG_SPEC_STRUCT */ + struct slang_type_specifier_ *_array; /**< if type == SLANG_SPEC_ARRAY */ +} slang_type_specifier; + + +extern GLvoid +slang_type_specifier_ctr(slang_type_specifier *); + +extern GLvoid +slang_type_specifier_dtr(slang_type_specifier *); + +extern slang_type_specifier * +slang_type_specifier_new(slang_type_specifier_type type, + struct slang_struct_ *_struct, + struct slang_type_specifier_ *_array); + + +extern GLboolean +slang_type_specifier_copy(slang_type_specifier *, const slang_type_specifier *); + +extern GLboolean +slang_type_specifier_equal(const slang_type_specifier *, + const slang_type_specifier *); + + +extern GLboolean +slang_type_specifier_compatible(const slang_type_specifier * x, + const slang_type_specifier * y); + + +typedef struct slang_fully_specified_type_ +{ + slang_type_qualifier qualifier; + slang_type_specifier specifier; + slang_type_precision precision; + slang_type_variant variant; + slang_type_centroid centroid; + GLint array_len; /**< -1 if not an array type */ +} slang_fully_specified_type; + +extern int +slang_fully_specified_type_construct(slang_fully_specified_type *); + +extern void +slang_fully_specified_type_destruct(slang_fully_specified_type *); + +extern int +slang_fully_specified_type_copy(slang_fully_specified_type *, + const slang_fully_specified_type *); + + + +typedef struct slang_typeinfo_ +{ + GLboolean can_be_referenced; + GLboolean is_swizzled; + slang_swizzle swz; + slang_type_specifier spec; + GLuint array_len; +} slang_typeinfo; + +extern GLboolean +slang_typeinfo_construct(slang_typeinfo *); + +extern GLvoid +slang_typeinfo_destruct(slang_typeinfo *); + + +extern GLboolean +_slang_typeof_operation(struct slang_operation_ *, + const struct slang_name_space_ *, + slang_typeinfo *, slang_atom_pool *, + slang_info_log *log); + +extern GLboolean +_slang_type_is_matrix(slang_type_specifier_type); + +extern GLboolean +_slang_type_is_vector(slang_type_specifier_type); + +extern GLboolean +_slang_type_is_float_vec_mat(slang_type_specifier_type); + +extern slang_type_specifier_type +_slang_type_base(slang_type_specifier_type); + +extern GLuint +_slang_type_dim(slang_type_specifier_type); + +extern GLenum +_slang_gltype_from_specifier(const slang_type_specifier *type); + +#endif diff --git a/mesalib/src/mesa/shader/slang/slang_utility.c b/mesalib/src/mesa/shader/slang/slang_utility.c new file mode 100644 index 000000000..3631e32b3 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_utility.c @@ -0,0 +1,228 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-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 slang_utility.c + * slang utilities + * \author Michal Krol + */ + +#include "main/imports.h" +#include "slang_utility.h" +#include "slang_mem.h" + +char * +slang_string_concat (char *dst, const char *src) +{ + return _mesa_strcpy (dst + _mesa_strlen (dst), src); +} + + +/* slang_string */ + +GLvoid +slang_string_init (slang_string *self) +{ + self->data = NULL; + self->capacity = 0; + self->length = 0; + self->fail = GL_FALSE; +} + +GLvoid +slang_string_free (slang_string *self) +{ + if (self->data != NULL) + _mesa_free (self->data); +} + +GLvoid +slang_string_reset (slang_string *self) +{ + self->length = 0; + self->fail = GL_FALSE; +} + +static GLboolean +grow (slang_string *self, GLuint size) +{ + if (self->fail) + return GL_FALSE; + if (size > self->capacity) { + /* do not overflow 32-bit range */ + assert (size < 0x80000000); + + self->data = (char *) (_mesa_realloc (self->data, self->capacity, size * 2)); + self->capacity = size * 2; + if (self->data == NULL) { + self->capacity = 0; + self->fail = GL_TRUE; + return GL_FALSE; + } + } + return GL_TRUE; +} + +GLvoid +slang_string_push (slang_string *self, const slang_string *str) +{ + if (str->fail) { + self->fail = GL_TRUE; + return; + } + if (grow (self, self->length + str->length)) { + _mesa_memcpy (&self->data[self->length], str->data, str->length); + self->length += str->length; + } +} + +GLvoid +slang_string_pushc (slang_string *self, const char c) +{ + if (grow (self, self->length + 1)) { + self->data[self->length] = c; + self->length++; + } +} + +GLvoid +slang_string_pushs (slang_string *self, const char *cstr, GLuint len) +{ + if (grow (self, self->length + len)) { + _mesa_memcpy (&self->data[self->length], cstr, len); + self->length += len; + } +} + +GLvoid +slang_string_pushi (slang_string *self, GLint i) +{ + char buffer[12]; + + _mesa_sprintf (buffer, "%d", i); + slang_string_pushs (self, buffer, strlen (buffer)); +} + +const char * +slang_string_cstr (slang_string *self) +{ + if (grow (self, self->length + 1)) + self->data[self->length] = '\0'; + return self->data; +} + +/* slang_atom_pool */ + +void +slang_atom_pool_construct(slang_atom_pool * pool) +{ + GLuint i; + + for (i = 0; i < SLANG_ATOM_POOL_SIZE; i++) + pool->entries[i] = NULL; +} + +void +slang_atom_pool_destruct (slang_atom_pool * pool) +{ + GLuint i; + + for (i = 0; i < SLANG_ATOM_POOL_SIZE; i++) { + slang_atom_entry * entry; + + entry = pool->entries[i]; + while (entry != NULL) { + slang_atom_entry *next = entry->next; + _slang_free(entry->id); + _slang_free(entry); + entry = next; + } + } +} + +/* + * Search the atom pool for an atom with a given name. + * If atom is not found, create and add it to the pool. + * Returns ATOM_NULL if the atom was not found and the function failed + * to create a new atom. + */ +slang_atom +slang_atom_pool_atom(slang_atom_pool * pool, const char * id) +{ + GLuint hash; + const char * p = id; + slang_atom_entry ** entry; + + /* Hash a given string to a number in the range [0, ATOM_POOL_SIZE). */ + hash = 0; + while (*p != '\0') { + GLuint g; + + hash = (hash << 4) + (GLuint) (*p++); + g = hash & 0xf0000000; + if (g != 0) + hash ^= g >> 24; + hash &= ~g; + } + hash %= SLANG_ATOM_POOL_SIZE; + + /* Now the hash points to a linked list of atoms with names that + * have the same hash value. Search the linked list for a given + * name. + */ + entry = &pool->entries[hash]; + while (*entry != NULL) { + /* If the same, return the associated atom. */ + if (slang_string_compare((**entry).id, id) == 0) + return (slang_atom) (**entry).id; + /* Grab the next atom in the linked list. */ + entry = &(**entry).next; + } + + /* Okay, we have not found an atom. Create a new entry for it. + * Note that the <entry> points to the last entry's <next> field. + */ + *entry = (slang_atom_entry *) _slang_alloc(sizeof(slang_atom_entry)); + if (*entry == NULL) + return SLANG_ATOM_NULL; + + /* Initialize a new entry. Because we'll need the actual name of + * the atom, we use the pointer to this string as an actual atom's + * value. + */ + (**entry).next = NULL; + (**entry).id = _slang_strdup(id); + if ((**entry).id == NULL) + return SLANG_ATOM_NULL; + return (slang_atom) (**entry).id; +} + +/** + * Return the name of a given atom. + */ +const char * +slang_atom_pool_id(slang_atom_pool * pool, slang_atom atom) +{ + return (const char *) (atom); +} diff --git a/mesalib/src/mesa/shader/slang/slang_utility.h b/mesalib/src/mesa/shader/slang/slang_utility.h new file mode 100644 index 000000000..032c56181 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_utility.h @@ -0,0 +1,100 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 2005-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 SLANG_UTILITY_H +#define SLANG_UTILITY_H + + +/* Compile-time assertions. If the expression is zero, try to declare an + * array of size [-1] to cause compilation error. + */ +#define static_assert(expr) do { int _array[(expr) ? 1 : -1]; (void) _array[0]; } while (0) + + +#define slang_string_compare(str1, str2) _mesa_strcmp (str1, str2) +#define slang_string_copy(dst, src) _mesa_strcpy (dst, src) +#define slang_string_length(str) _mesa_strlen (str) + +char *slang_string_concat (char *, const char *); + +/* slang_string */ + +typedef struct +{ + char *data; + GLuint length; + GLuint capacity; + GLboolean fail; +} slang_string; + +GLvoid +slang_string_init (slang_string *); + +GLvoid +slang_string_free (slang_string *); + +GLvoid +slang_string_reset (slang_string *); + +GLvoid +slang_string_push (slang_string *, const slang_string *); + +GLvoid +slang_string_pushc (slang_string *, const char); + +GLvoid +slang_string_pushs (slang_string *, const char *, GLuint); + +GLvoid +slang_string_pushi (slang_string *, GLint); + +const char * +slang_string_cstr (slang_string *); + +/* slang_atom */ + +typedef GLvoid *slang_atom; + +#define SLANG_ATOM_NULL ((slang_atom) 0) + +typedef struct slang_atom_entry_ +{ + char *id; + struct slang_atom_entry_ *next; +} slang_atom_entry; + +#define SLANG_ATOM_POOL_SIZE 1023 + +typedef struct slang_atom_pool_ +{ + slang_atom_entry *entries[SLANG_ATOM_POOL_SIZE]; +} slang_atom_pool; + +GLvoid slang_atom_pool_construct (slang_atom_pool *); +GLvoid slang_atom_pool_destruct (slang_atom_pool *); +slang_atom slang_atom_pool_atom (slang_atom_pool *, const char *); +const char *slang_atom_pool_id (slang_atom_pool *, slang_atom); + + +#endif diff --git a/mesalib/src/mesa/shader/slang/slang_vartable.c b/mesalib/src/mesa/shader/slang/slang_vartable.c new file mode 100644 index 000000000..a4ebacc09 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_vartable.c @@ -0,0 +1,362 @@ + +#include "main/imports.h" +#include "shader/program.h" +#include "shader/prog_print.h" +#include "slang_compile.h" +#include "slang_compile_variable.h" +#include "slang_emit.h" +#include "slang_mem.h" +#include "slang_vartable.h" +#include "slang_ir.h" + + +static int dbg = 0; + + +typedef enum { + FREE, + VAR, + TEMP +} TempState; + + +/** + * Variable/register info for one variable scope. + */ +struct table +{ + int Level; + int NumVars; + slang_variable **Vars; /* array [NumVars] */ + + TempState Temps[MAX_PROGRAM_TEMPS * 4]; /* per-component state */ + int ValSize[MAX_PROGRAM_TEMPS * 4]; /**< For debug only */ + + struct table *Parent; /** Parent scope table */ +}; + + +/** + * A variable table is a stack of tables, one per scope. + */ +struct slang_var_table_ +{ + GLint CurLevel; + GLuint MaxRegisters; + struct table *Top; /**< Table at top of stack */ +}; + + + +slang_var_table * +_slang_new_var_table(GLuint maxRegisters) +{ + slang_var_table *vt + = (slang_var_table *) _slang_alloc(sizeof(slang_var_table)); + if (vt) { + vt->MaxRegisters = maxRegisters; + } + return vt; +} + + +void +_slang_delete_var_table(slang_var_table *vt) +{ + if (vt->Top) { + _mesa_problem(NULL, "non-empty var table in _slang_delete_var_table()"); + return; + } + _slang_free(vt); +} + + + +/** + * Create new table on top of vartable stack. + * Used when we enter a {} block. + */ +void +_slang_push_var_table(slang_var_table *vt) +{ + struct table *t = (struct table *) _slang_alloc(sizeof(struct table)); + if (t) { + t->Level = vt->CurLevel++; + t->Parent = vt->Top; + if (t->Parent) { + /* copy the info indicating which temp regs are in use */ + memcpy(t->Temps, t->Parent->Temps, sizeof(t->Temps)); + memcpy(t->ValSize, t->Parent->ValSize, sizeof(t->ValSize)); + } + vt->Top = t; + if (dbg) printf("Pushing level %d\n", t->Level); + } +} + + +/** + * Pop top entry from variable table. + * Used when we leave a {} block. + */ +void +_slang_pop_var_table(slang_var_table *vt) +{ + struct table *t = vt->Top; + int i; + + if (dbg) printf("Popping level %d\n", t->Level); + + /* free the storage allocated for each variable */ + for (i = 0; i < t->NumVars; i++) { + slang_ir_storage *store = t->Vars[i]->store; + GLint j; + GLuint comp; + if (dbg) printf(" Free var %s, size %d at %d.%s\n", + (char*) t->Vars[i]->a_name, store->Size, + store->Index, + _mesa_swizzle_string(store->Swizzle, 0, 0)); + + if (store->File == PROGRAM_SAMPLER) { + /* samplers have no storage */ + continue; + } + + if (store->Size == 1) + comp = GET_SWZ(store->Swizzle, 0); + else + comp = 0; + + /* store->Index may be -1 if we run out of registers */ + if (store->Index >= 0) { + for (j = 0; j < store->Size; j++) { + assert(t->Temps[store->Index * 4 + j + comp] == VAR); + t->Temps[store->Index * 4 + j + comp] = FREE; + } + } + store->Index = -1; + } + if (t->Parent) { + /* just verify that any remaining allocations in this scope + * were for temps + */ + for (i = 0; i < (int) vt->MaxRegisters * 4; i++) { + if (t->Temps[i] != FREE && t->Parent->Temps[i] == FREE) { + if (dbg) printf(" Free reg %d\n", i/4); + assert(t->Temps[i] == TEMP); + } + } + } + + if (t->Vars) { + _slang_free(t->Vars); + t->Vars = NULL; + } + + vt->Top = t->Parent; + _slang_free(t); + vt->CurLevel--; +} + + +/** + * Add a new variable to the given var/symbol table. + */ +void +_slang_add_variable(slang_var_table *vt, slang_variable *v) +{ + struct table *t; + assert(vt); + t = vt->Top; + assert(t); + if (dbg) printf("Adding var %s, store %p\n", (char *) v->a_name, (void *) v->store); + t->Vars = (slang_variable **) + _slang_realloc(t->Vars, + t->NumVars * sizeof(slang_variable *), + (t->NumVars + 1) * sizeof(slang_variable *)); + t->Vars[t->NumVars] = v; + t->NumVars++; +} + + +/** + * Look for variable by name in given table. + * If not found, Parent table will be searched. + */ +slang_variable * +_slang_find_variable(const slang_var_table *vt, slang_atom name) +{ + struct table *t = vt->Top; + while (1) { + int i; + for (i = 0; i < t->NumVars; i++) { + if (t->Vars[i]->a_name == name) + return t->Vars[i]; + } + if (t->Parent) + t = t->Parent; + else + return NULL; + } +} + + +/** + * Allocation helper. + * \param size var size in floats + * \return position for var, measured in floats + */ +static GLint +alloc_reg(slang_var_table *vt, GLint size, GLboolean isTemp) +{ + struct table *t = vt->Top; + /* if size == 1, allocate anywhere, else, pos must be multiple of 4 */ + const GLuint step = (size == 1) ? 1 : 4; + GLuint i, j; + assert(size > 0); /* number of floats */ + + for (i = 0; i <= vt->MaxRegisters * 4 - size; i += step) { + GLuint found = 0; + for (j = 0; j < (GLuint) size; j++) { + assert(i + j < 4 * MAX_PROGRAM_TEMPS); + if (i + j < vt->MaxRegisters * 4 && t->Temps[i + j] == FREE) { + found++; + } + else { + break; + } + } + if (found == size) { + /* found block of size free regs */ + if (size > 1) + assert(i % 4 == 0); + for (j = 0; j < (GLuint) size; j++) { + assert(i + j < 4 * MAX_PROGRAM_TEMPS); + t->Temps[i + j] = isTemp ? TEMP : VAR; + } + assert(i < MAX_PROGRAM_TEMPS * 4); + t->ValSize[i] = size; + return i; + } + } + + /* if we get here, we ran out of registers */ + return -1; +} + + +/** + * Allocate temp register(s) for storing a variable. + * \param size size needed, in floats + * \param swizzle returns swizzle mask for accessing var in register + * \return register allocated, or -1 + */ +GLboolean +_slang_alloc_var(slang_var_table *vt, slang_ir_storage *store) +{ + struct table *t = vt->Top; + int i; + + if (store->File == PROGRAM_SAMPLER) { + /* don't really allocate storage */ + store->Index = 0; + return GL_TRUE; + } + + i = alloc_reg(vt, store->Size, GL_FALSE); + if (i < 0) + return GL_FALSE; + + store->Index = i / 4; + store->Swizzle = _slang_var_swizzle(store->Size, i % 4); + + if (dbg) + printf("Alloc var storage sz %d at %d.%s (level %d) store %p\n", + store->Size, store->Index, + _mesa_swizzle_string(store->Swizzle, 0, 0), + t->Level, + (void*) store); + + return GL_TRUE; +} + + + +/** + * Allocate temp register(s) for storing an unnamed intermediate value. + */ +GLboolean +_slang_alloc_temp(slang_var_table *vt, slang_ir_storage *store) +{ + struct table *t = vt->Top; + const int i = alloc_reg(vt, store->Size, GL_TRUE); + if (i < 0) + return GL_FALSE; + + assert(store->Index < 0); + + store->Index = i / 4; + store->Swizzle = _slang_var_swizzle(store->Size, i % 4); + + if (dbg) printf("Alloc temp sz %d at %d.%s (level %d) store %p\n", + store->Size, store->Index, + _mesa_swizzle_string(store->Swizzle, 0, 0), t->Level, + (void *) store); + + return GL_TRUE; +} + + +void +_slang_free_temp(slang_var_table *vt, slang_ir_storage *store) +{ + struct table *t = vt->Top; + GLuint i; + GLuint r = store->Index; + assert(store->Size > 0); + assert(r >= 0); + assert(r + store->Size <= vt->MaxRegisters * 4); + if (dbg) printf("Free temp sz %d at %d.%s (level %d) store %p\n", + store->Size, r, + _mesa_swizzle_string(store->Swizzle, 0, 0), + t->Level, (void *) store); + if (store->Size == 1) { + const GLuint comp = GET_SWZ(store->Swizzle, 0); + /* we can actually fail some of these assertions because of the + * troublesome IR_SWIZZLE handling. + */ +#if 0 + assert(store->Swizzle == MAKE_SWIZZLE4(comp, comp, comp, comp)); + assert(comp < 4); + assert(t->ValSize[r * 4 + comp] == 1); +#endif + assert(t->Temps[r * 4 + comp] == TEMP); + t->Temps[r * 4 + comp] = FREE; + } + else { + /*assert(store->Swizzle == SWIZZLE_NOOP);*/ + assert(t->ValSize[r*4] == store->Size); + for (i = 0; i < (GLuint) store->Size; i++) { + assert(t->Temps[r * 4 + i] == TEMP); + t->Temps[r * 4 + i] = FREE; + } + } +} + + +GLboolean +_slang_is_temp(const slang_var_table *vt, const slang_ir_storage *store) +{ + struct table *t = vt->Top; + GLuint comp; + assert(store->Index >= 0); + assert(store->Index < (int) vt->MaxRegisters); + if (store->Swizzle == SWIZZLE_NOOP) + comp = 0; + else + comp = GET_SWZ(store->Swizzle, 0); + + if (t->Temps[store->Index * 4 + comp] == TEMP) + return GL_TRUE; + else + return GL_FALSE; +} diff --git a/mesalib/src/mesa/shader/slang/slang_vartable.h b/mesalib/src/mesa/shader/slang/slang_vartable.h new file mode 100644 index 000000000..94bcd63f4 --- /dev/null +++ b/mesalib/src/mesa/shader/slang/slang_vartable.h @@ -0,0 +1,42 @@ + +#ifndef SLANG_VARTABLE_H +#define SLANG_VARTABLE_H + +struct slang_ir_storage_; + +typedef struct slang_var_table_ slang_var_table; + +struct slang_variable_; + +extern slang_var_table * +_slang_new_var_table(GLuint maxRegisters); + +extern void +_slang_delete_var_table(slang_var_table *vt); + +extern void +_slang_push_var_table(slang_var_table *parent); + +extern void +_slang_pop_var_table(slang_var_table *t); + +extern void +_slang_add_variable(slang_var_table *t, struct slang_variable_ *v); + +extern struct slang_variable_ * +_slang_find_variable(const slang_var_table *t, slang_atom name); + +extern GLboolean +_slang_alloc_var(slang_var_table *t, struct slang_ir_storage_ *store); + +extern GLboolean +_slang_alloc_temp(slang_var_table *t, struct slang_ir_storage_ *store); + +extern void +_slang_free_temp(slang_var_table *t, struct slang_ir_storage_ *store); + +extern GLboolean +_slang_is_temp(const slang_var_table *t, const struct slang_ir_storage_ *store); + + +#endif /* SLANG_VARTABLE_H */ diff --git a/mesalib/src/mesa/shader/symbol_table.c b/mesalib/src/mesa/shader/symbol_table.c new file mode 100644 index 000000000..7a9aa7b8f --- /dev/null +++ b/mesalib/src/mesa/shader/symbol_table.c @@ -0,0 +1,350 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <assert.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; + + + /** + * Arbitrary user supplied data. + */ + void *data; +}; + + +/** + */ +struct symbol_header { + /** Symbol name. */ + const 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; +}; + + +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; + + 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; +} + + +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; +} + + +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 = name; + + hash_table_insert(table->ht, hdr, name); + } + + check_symbol_table(table); + + 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; + + 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) +{ + while (table->current_scope != NULL) { + _mesa_symbol_table_pop_scope(table); + } + + hash_table_dtor(table->ht); + free(table); +} diff --git a/mesalib/src/mesa/shader/symbol_table.h b/mesalib/src/mesa/shader/symbol_table.h new file mode 100644 index 000000000..0c054ef13 --- /dev/null +++ b/mesalib/src/mesa/shader/symbol_table.h @@ -0,0 +1,55 @@ +/* + * 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 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 */ |