📄 nvfragparse.c
字号:
/* * Mesa 3-D graphics library * Version: 6.5 * * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *//** * \file nvfragparse.c * NVIDIA fragment program parser. * \author Brian Paul *//* * Regarding GL_NV_fragment_program: * * Portions of this software may use or implement intellectual * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims * any and all warranties with respect to such intellectual property, * including any use thereof or modifications thereto. */#include "glheader.h"#include "context.h"#include "imports.h"#include "macros.h"#include "prog_parameter.h"#include "prog_instruction.h"#include "nvfragparse.h"#include "program.h"#define INPUT_1V 1#define INPUT_2V 2#define INPUT_3V 3#define INPUT_1S 4#define INPUT_2S 5#define INPUT_CC 6#define INPUT_1V_T 7 /* one source vector, plus textureId */#define INPUT_3V_T 8 /* one source vector, plus textureId */#define INPUT_NONE 9#define INPUT_1V_S 10 /* a string and a vector register */#define OUTPUT_V 20#define OUTPUT_S 21#define OUTPUT_NONE 22/* IRIX defines some of these */#undef _R#undef _H#undef _X#undef _C#undef _S/* Optional suffixes */#define _R FLOAT32 /* float */#define _H FLOAT16 /* half-float */#define _X FIXED12 /* fixed */#define _C 0x08 /* set cond codes */#define _S 0x10 /* saturate, clamp result to [0,1] */struct instruction_pattern { const char *name; enum prog_opcode opcode; GLuint inputs; GLuint outputs; GLuint suffixes;};static const struct instruction_pattern Instructions[] = { { "ADD", OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, { "COS", OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, { "DDX", OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, { "DDY", OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, { "DP3", OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S }, { "DP4", OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S }, { "DST", OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H | _C | _S }, { "EX2", OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, { "FLR", OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, { "FRC", OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, { "KIL", OPCODE_KIL_NV, INPUT_CC, OUTPUT_NONE, 0 }, { "LG2", OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, { "LIT", OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, { "LRP", OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S }, { "MAD", OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S }, { "MAX", OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, { "MIN", OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, { "MOV", OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, { "MUL", OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, { "PK2H", OPCODE_PK2H, INPUT_1V, OUTPUT_S, 0 }, { "PK2US", OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0 }, { "PK4B", OPCODE_PK4B, INPUT_1V, OUTPUT_S, 0 }, { "PK4UB", OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0 }, { "POW", OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H | _C | _S }, { "RCP", OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, { "RFL", OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H | _C | _S }, { "RSQ", OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, { "SEQ", OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, { "SFL", OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, { "SGE", OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, { "SGT", OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, { "SIN", OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, { "SLE", OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, { "SLT", OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, { "SNE", OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, { "STR", OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, { "SUB", OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, { "TEX", OPCODE_TEX, INPUT_1V_T, OUTPUT_V, _C | _S }, { "TXD", OPCODE_TXD, INPUT_3V_T, OUTPUT_V, _C | _S }, { "TXP", OPCODE_TXP_NV, INPUT_1V_T, OUTPUT_V, _C | _S }, { "UP2H", OPCODE_UP2H, INPUT_1S, OUTPUT_V, _C | _S }, { "UP2US", OPCODE_UP2US, INPUT_1S, OUTPUT_V, _C | _S }, { "UP4B", OPCODE_UP4B, INPUT_1S, OUTPUT_V, _C | _S }, { "UP4UB", OPCODE_UP4UB, INPUT_1S, OUTPUT_V, _C | _S }, { "X2D", OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H | _C | _S }, { "PRINT", OPCODE_PRINT, INPUT_1V_S, OUTPUT_NONE, 0 }, { NULL, (enum prog_opcode) -1, 0, 0, 0 }};/* * Information needed or computed during parsing. * Remember, we can't modify the target program object until we've * _successfully_ parsed the program text. */struct parse_state { GLcontext *ctx; const GLubyte *start; /* start of program string */ const GLubyte *pos; /* current position */ const GLubyte *curLine; struct gl_fragment_program *program; /* current program */ struct gl_program_parameter_list *parameters; GLuint numInst; /* number of instructions parsed */ GLuint inputsRead; /* bitmask of input registers used */ GLuint outputsWritten; /* bitmask of 1 << FRAG_OUTPUT_* bits */ GLuint texturesUsed[MAX_TEXTURE_IMAGE_UNITS];};/* * Called whenever we find an error during parsing. */static voidrecord_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_patternMatchInstruction(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 GLintGetToken(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 GLbooleanParse_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 GLbooleanPeek_Token(struct parse_state *parseState, GLubyte *token){ GLint i, len; i = GetToken(parseState, token); if (i <= 0) { parseState->pos += (-i); return GL_FALSE; } len = (GLint)_mesa_strlen((const char *) token); parseState->pos += (i - len); return GL_TRUE;}/**********************************************************************/static const char *InputRegisters[MAX_NV_FRAGMENT_PROGRAM_INPUTS + 1] = { "WPOS", "COL0", "COL1", "FOGC", "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL};static const char *OutputRegisters[MAX_NV_FRAGMENT_PROGRAM_OUTPUTS + 1] = { "COLR", "COLH", /* These are only allows for register combiners */ /* "TEX0", "TEX1", "TEX2", "TEX3", */ "DEPR", NULL};/**********************************************************************//** * Try to match 'pattern' as the next token after any whitespace/comments. */static GLbooleanParse_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 GLbooleanParse_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 GLbooleanParse_ScalarConstant(struct parse_state *parseState, GLfloat *number){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -