-/* $Id: nvvertparse.c,v 1.2 2003/02/23 05:24:39 brianp Exp $ */
-
/*
* Mesa 3-D graphics library
* Version: 5.1
/**
* \file nvvertparse.c
- * \brief NVIDIA vertex program parser.
+ * NVIDIA vertex program parser.
* \author Brian Paul
*/
+/*
+ * Regarding GL_NV_vertex_program, GL_NV_vertex_program1_1:
+ *
+ * Portions of this software may use or implement intellectual
+ * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
+ * any and all warranties with respect to such intellectual property,
+ * including any use thereof or modifications thereto.
+ */
#include "glheader.h"
#include "context.h"
#include "nvprogram.h"
#include "nvvertparse.h"
#include "nvvertprog.h"
+#include "program.h"
+/**
+ * Current parsing state. This structure is passed among the parsing
+ * functions and keeps track of the current parser position and various
+ * program attributes.
+ */
struct parse_state {
+ GLcontext *ctx;
+ const GLubyte *start;
const GLubyte *pos;
+ const GLubyte *curLine;
GLboolean isStateProgram;
GLboolean isPositionInvariant;
GLboolean isVersion1_1;
GLuint inputsRead;
GLuint outputsWritten;
- GLuint progRegsWritten;
+ 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');
* \return <= 0 we found an error, else, return number of characters parsed.
*/
static GLint
-GetToken(const GLubyte *str, GLubyte *token)
+GetToken(struct parse_state *parseState, GLubyte *token)
{
+ const GLubyte *str = parseState->pos;
GLint i = 0, j = 0;
token[0] = 0;
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++;
}
}
return i;
}
- /* punctuation */
+ /* punctuation character */
if (str[i]) {
token[0] = str[i++];
token[1] = 0;
Parse_Token(struct parse_state *parseState, GLubyte *token)
{
GLint i;
- i = GetToken(parseState->pos, token);
+ i = GetToken(parseState, token);
if (i <= 0) {
parseState->pos += (-i);
return GL_FALSE;
Peek_Token(struct parse_state *parseState, GLubyte *token)
{
GLint i, len;
- i = GetToken(parseState->pos, token);
+ i = GetToken(parseState, token);
if (i <= 0) {
parseState->pos += (-i);
return GL_FALSE;
}
- len = _mesa_strlen((char *) token);
+ len = _mesa_strlen((const char *) token);
parseState->pos += (i - len);
return GL_TRUE;
}
-/**
- * String equality test
- */
-static GLboolean
-StrEq(const GLubyte *a, const GLubyte *b)
-{
- GLint i;
- for (i = 0; a[i] && b[i] && a[i] == b[i]; i++)
- ;
- if (a[i] == 0 && b[i] == 0)
- return GL_TRUE;
- else
- return GL_FALSE;
-}
-
-
-/**********************************************************************/
-
-static const char *InputRegisters[] = {
- "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
- "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
-};
-
-static const char *OutputRegisters[] = {
- "HPOS", "COL0", "COL1", "BFC0", "BFC1", "FOGC", "PSIZ",
- "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
-};
-
-static const char *Opcodes[] = {
- "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
- "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
- "ABS", "END", NULL
-};
-
-
-#ifdef DEBUG
-
-#define RETURN_ERROR \
-do { \
- _mesa_printf("vpparse.c error at %d: parse error\n", __LINE__); \
- return GL_FALSE; \
-} while(0)
-
-#define RETURN_ERROR1(msg) \
-do { \
- _mesa_printf("vpparse.c error at %d: %s\n", __LINE__, msg); \
- return GL_FALSE; \
-} while(0)
-
-#define RETURN_ERROR2(msg1, msg2) \
-do { \
- _mesa_printf("vpparse.c error at %d: %s %s\n", __LINE__, msg1, msg2); \
- return GL_FALSE; \
-} while(0)
-
-#else
-
-#define RETURN_ERROR return GL_FALSE
-#define RETURN_ERROR1(msg1) return GL_FALSE
-#define RETURN_ERROR2(msg1, msg2) return GL_FALSE
-
-#endif
-
-
-static GLuint
-IsProgRegister(GLuint r)
-{
- return (GLuint) (r >= VP_PROG_REG_START && r <= VP_PROG_REG_END);
-}
-
-static GLuint
-IsInputRegister(GLuint r)
-{
- return (GLuint) (r >= VP_INPUT_REG_START && r <= VP_INPUT_REG_END);
-}
-
-static GLuint
-IsOutputRegister(GLuint r)
-{
- return (GLuint) (r >= VP_OUTPUT_REG_START && r <= VP_OUTPUT_REG_END);
-}
-
-
-
/**
* 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 (*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 (*parseState->pos != pattern[i])
- RETURN_ERROR2("failed to match", pattern); /* failure */
- parseState->pos += 1;
+ 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", "BFC0", "BFC1", "FOGC", "PSIZ",
+ "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
+};
+
+/* NOTE: the order here must match opcodes in nvvertprog.h */
+static const char *Opcodes[] = {
+ "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
+ "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
+ "ABS", "END",
+ /* GL_ARB_vertex_program */
+ "FLR", "FRC", "EX2", "LG2", "POW", "XPD", "SWZ",
+ NULL
+};
+
+
+
/**
* Parse a temporary register: Rnn
*/
if (IsDigit(token[1])) {
GLint reg = _mesa_atoi((char *) (token + 1));
- if (reg >= VP_NUM_TEMP_REGS)
+ if (reg >= MAX_NV_VERTEX_PROGRAM_TEMPS)
RETURN_ERROR1("Bad temporary register name");
- *tempRegNum = VP_TEMP_REG_START + reg;
+ *tempRegNum = reg;
}
else {
RETURN_ERROR1("Bad temporary register name");
if (IsDigit(token[0])) {
/* a numbered program parameter register */
GLint reg = _mesa_atoi((char *) token);
- if (reg >= VP_NUM_PROG_REGS)
- RETURN_ERROR1("Bad constant program number");
- *regNum = VP_PROG_REG_START + reg;
+ if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
+ RETURN_ERROR1("Bad program parameter number");
+ *regNum = reg;
}
else {
RETURN_ERROR;
GLint reg;
(void) Parse_Token(parseState, token);
reg = _mesa_atoi((char *) token);
- if (reg >= VP_NUM_PROG_REGS)
- RETURN_ERROR1("Bad constant program number");
- srcReg->Register = VP_PROG_REG_START + reg;
+ if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
+ RETURN_ERROR1("Bad program parameter number");
+ srcReg->File = PROGRAM_ENV_PARAM;
+ srcReg->Index = reg;
}
- else if (StrEq(token, (GLubyte *) "A0")) {
+ else if (_mesa_strcmp((const char *) token, "A0") == 0) {
/* address register "A0.x" */
if (!Parse_AddrReg(parseState))
RETURN_ERROR;
srcReg->RelAddr = GL_TRUE;
- srcReg->Register = 0;
-
+ srcReg->File = PROGRAM_ENV_PARAM;
/* Look for +/-N offset */
if (!Peek_Token(parseState, token))
RETURN_ERROR;
if (sign == '-') {
if (k > 64)
RETURN_ERROR1("Bad address offset");
- srcReg->Register = -k;
+ srcReg->Index = -k;
}
else {
if (k > 63)
RETURN_ERROR1("Bad address offset");
- srcReg->Register = k;
+ srcReg->Index = k;
}
}
else {
if (IsDigit(token[0])) {
GLint reg = _mesa_atoi((char *) token);
- if (reg >= VP_NUM_INPUT_REGS)
+ if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS)
RETURN_ERROR1("Bad vertex attribute register name");
- *tempRegNum = VP_INPUT_REG_START + reg;
+ *tempRegNum = reg;
}
else {
for (j = 0; InputRegisters[j]; j++) {
- if (StrEq(token, (const GLubyte *) InputRegisters[j])) {
- *tempRegNum = VP_INPUT_REG_START + j;
+ if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
+ *tempRegNum = j;
break;
}
}
/* try to match an output register name */
for (j = start; OutputRegisters[j]; j++) {
- if (StrEq(token, (const GLubyte *) OutputRegisters[j])) {
- *outputRegNum = VP_OUTPUT_REG_START + j;
+ if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) {
+ *outputRegNum = j;
break;
}
}
if (token[0] == 'R') {
/* a temporary register */
- if (!Parse_TempReg(parseState, &dstReg->Register))
+ dstReg->File = PROGRAM_TEMPORARY;
+ if (!Parse_TempReg(parseState, &dstReg->Index))
RETURN_ERROR;
}
else if (!parseState->isStateProgram && token[0] == 'o') {
/* an output register */
- if (!Parse_OutputReg(parseState, &dstReg->Register))
+ dstReg->File = PROGRAM_OUTPUT;
+ if (!Parse_OutputReg(parseState, &dstReg->Index))
RETURN_ERROR;
}
else if (parseState->isStateProgram && token[0] == 'c') {
/* absolute program parameter register */
- if (!Parse_AbsParamReg(parseState, &dstReg->Register))
+ dstReg->File = PROGRAM_ENV_PARAM;
+ if (!Parse_AbsParamReg(parseState, &dstReg->Index))
RETURN_ERROR;
}
else {
/* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
if (token[0] == 'R') {
- if (!Parse_TempReg(parseState, &srcReg->Register))
+ srcReg->File = PROGRAM_TEMPORARY;
+ if (!Parse_TempReg(parseState, &srcReg->Index))
RETURN_ERROR;
}
else if (token[0] == 'c') {
RETURN_ERROR;
}
else if (token[0] == 'v') {
- if (!Parse_AttribReg(parseState, &srcReg->Register))
+ srcReg->File = PROGRAM_INPUT;
+ if (!Parse_AttribReg(parseState, &srcReg->Index))
RETURN_ERROR;
}
else {
/* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
if (token[0] == 'R') {
- if (!Parse_TempReg(parseState, &srcReg->Register))
+ srcReg->File = PROGRAM_TEMPORARY;
+ if (!Parse_TempReg(parseState, &srcReg->Index))
RETURN_ERROR;
}
else if (token[0] == 'c') {
RETURN_ERROR;
}
else if (token[0] == 'v') {
- if (!Parse_AttribReg(parseState, &srcReg->Register))
+ srcReg->File = PROGRAM_INPUT;
+ if (!Parse_AttribReg(parseState, &srcReg->Index))
RETURN_ERROR;
}
else {
static GLint
-Parse_UnaryOpInstruction(struct parse_state *parseState, struct vp_instruction *inst)
+Parse_UnaryOpInstruction(struct parse_state *parseState,
+ struct vp_instruction *inst, enum vp_opcode opcode)
{
- GLubyte token[100];
+ if (opcode == VP_OPCODE_ABS && !parseState->isVersion1_1)
+ RETURN_ERROR1("ABS illegal for vertex program 1.0");
- /* opcode */
- if (!Parse_Token(parseState, token))
- RETURN_ERROR;
-
- if (StrEq(token, (GLubyte *) "MOV")) {
- inst->Opcode = VP_OPCODE_MOV;
- }
- else if (StrEq(token, (GLubyte *) "LIT")) {
- inst->Opcode = VP_OPCODE_LIT;
- }
- else if (StrEq(token, (GLubyte *) "ABS") && parseState->isVersion1_1) {
- inst->Opcode = VP_OPCODE_ABS;
- }
- else {
- RETURN_ERROR;
- }
+ inst->Opcode = opcode;
+ inst->StringPos = parseState->curLine - parseState->start;
/* dest reg */
if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
static GLboolean
-Parse_BiOpInstruction(struct parse_state *parseState, struct vp_instruction *inst)
+Parse_BiOpInstruction(struct parse_state *parseState,
+ struct vp_instruction *inst, enum vp_opcode opcode)
{
- GLubyte token[100];
+ if (opcode == VP_OPCODE_DPH && !parseState->isVersion1_1)
+ RETURN_ERROR1("DPH illegal for vertex program 1.0");
+ if (opcode == VP_OPCODE_SUB && !parseState->isVersion1_1)
+ RETURN_ERROR1("SUB illegal for vertex program 1.0");
- /* opcode */
- if (!Parse_Token(parseState, token))
- RETURN_ERROR;
-
- if (StrEq(token, (GLubyte *) "MUL")) {
- inst->Opcode = VP_OPCODE_MUL;
- }
- else if (StrEq(token, (GLubyte *) "ADD")) {
- inst->Opcode = VP_OPCODE_ADD;
- }
- else if (StrEq(token, (GLubyte *) "DP3")) {
- inst->Opcode = VP_OPCODE_DP3;
- }
- else if (StrEq(token, (GLubyte *) "DP4")) {
- inst->Opcode = VP_OPCODE_DP4;
- }
- else if (StrEq(token, (GLubyte *) "DST")) {
- inst->Opcode = VP_OPCODE_DST;
- }
- else if (StrEq(token, (GLubyte *) "MIN")) {
- inst->Opcode = VP_OPCODE_ADD;
- }
- else if (StrEq(token, (GLubyte *) "MAX")) {
- inst->Opcode = VP_OPCODE_ADD;
- }
- else if (StrEq(token, (GLubyte *) "SLT")) {
- inst->Opcode = VP_OPCODE_SLT;
- }
- else if (StrEq(token, (GLubyte *) "SGE")) {
- inst->Opcode = VP_OPCODE_SGE;
- }
- else if (StrEq(token, (GLubyte *) "DPH") && parseState->isVersion1_1) {
- inst->Opcode = VP_OPCODE_DPH;
- }
- else if (StrEq(token, (GLubyte *) "SUB") && parseState->isVersion1_1) {
- inst->Opcode = VP_OPCODE_SUB;
- }
- else {
- RETURN_ERROR;
- }
+ inst->Opcode = opcode;
+ inst->StringPos = parseState->curLine - parseState->start;
/* dest reg */
if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
RETURN_ERROR;
/* make sure we don't reference more than one program parameter register */
- if (IsProgRegister(inst->SrcReg[0].Register) &&
- IsProgRegister(inst->SrcReg[1].Register) &&
- inst->SrcReg[0].Register != inst->SrcReg[1].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 (IsInputRegister(inst->SrcReg[0].Register) &&
- IsInputRegister(inst->SrcReg[1].Register) &&
- inst->SrcReg[0].Register != inst->SrcReg[1].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 vp_instruction *inst)
+Parse_TriOpInstruction(struct parse_state *parseState,
+ struct vp_instruction *inst, enum vp_opcode opcode)
{
- GLubyte token[100];
-
- /* opcode */
- if (!Parse_Token(parseState, token))
- RETURN_ERROR;
-
- if (StrEq(token, (GLubyte *) "MAD")) {
- inst->Opcode = VP_OPCODE_MAD;
- }
- else {
- RETURN_ERROR;
- }
+ inst->Opcode = opcode;
+ inst->StringPos = parseState->curLine - parseState->start;
/* dest reg */
if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
RETURN_ERROR;
/* make sure we don't reference more than one program parameter register */
- if ((IsProgRegister(inst->SrcReg[0].Register) &&
- IsProgRegister(inst->SrcReg[1].Register) &&
- inst->SrcReg[0].Register != inst->SrcReg[1].Register) ||
- (IsProgRegister(inst->SrcReg[0].Register) &&
- IsProgRegister(inst->SrcReg[2].Register) &&
- inst->SrcReg[0].Register != inst->SrcReg[2].Register) ||
- (IsProgRegister(inst->SrcReg[1].Register) &&
- IsProgRegister(inst->SrcReg[2].Register) &&
- inst->SrcReg[1].Register != inst->SrcReg[2].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 ((IsInputRegister(inst->SrcReg[0].Register) &&
- IsInputRegister(inst->SrcReg[1].Register) &&
- inst->SrcReg[0].Register != inst->SrcReg[1].Register) ||
- (IsInputRegister(inst->SrcReg[0].Register) &&
- IsInputRegister(inst->SrcReg[2].Register) &&
- inst->SrcReg[0].Register != inst->SrcReg[2].Register) ||
- (IsInputRegister(inst->SrcReg[1].Register) &&
- IsInputRegister(inst->SrcReg[2].Register) &&
- inst->SrcReg[1].Register != inst->SrcReg[2].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 vp_instruction *inst)
+Parse_ScalarInstruction(struct parse_state *parseState,
+ struct vp_instruction *inst, enum vp_opcode opcode)
{
- GLubyte token[100];
-
- /* opcode */
- if (!Parse_Token(parseState, token))
- RETURN_ERROR;
+ if (opcode == VP_OPCODE_RCC && !parseState->isVersion1_1)
+ RETURN_ERROR1("RCC illegal for vertex program 1.0");
- if (StrEq(token, (GLubyte *) "RCP")) {
- inst->Opcode = VP_OPCODE_RCP;
- }
- else if (StrEq(token, (GLubyte *) "RSQ")) {
- inst->Opcode = VP_OPCODE_RSQ;
- }
- else if (StrEq(token, (GLubyte *) "EXP")) {
- inst->Opcode = VP_OPCODE_EXP;
- }
- else if (StrEq(token, (GLubyte *) "LOG")) {
- inst->Opcode = VP_OPCODE_LOG;
- }
- else if (StrEq(token, (GLubyte *) "RCC") && parseState->isVersion1_1) {
- inst->Opcode = VP_OPCODE_RCC;
- }
- else {
- RETURN_ERROR;
- }
+ inst->Opcode = opcode;
+ inst->StringPos = parseState->curLine - parseState->start;
/* dest reg */
if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
Parse_AddressInstruction(struct parse_state *parseState, struct vp_instruction *inst)
{
inst->Opcode = VP_OPCODE_ARL;
-
- /* opcode */
- if (!Parse_String(parseState, "ARL"))
- RETURN_ERROR;
+ inst->StringPos = parseState->curLine - parseState->start;
/* dest A0 reg */
if (!Parse_AddrReg(parseState))
{
GLubyte token[100];
- /* opcode */
- if (!Parse_String(parseState, "END"))
- RETURN_ERROR;
-
inst->Opcode = VP_OPCODE_END;
+ inst->StringPos = parseState->curLine - parseState->start;
/* this should fail! */
if (Parse_Token(parseState, token))
struct vp_instruction program[])
{
while (1) {
- GLubyte token[100];
- if (!Peek_Token(parseState, token)) {
- RETURN_ERROR1("Unexpected end of input");
- return GL_FALSE; /* end of input */
+ 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 (!StrEq(token, (GLubyte *) "OPTION"))
- return GL_TRUE; /* probably an instruction */
-
- Parse_Token(parseState, token);
-
- if (!Parse_String(parseState, "NV_position_invariant"))
- return GL_FALSE;
if (!Parse_String(parseState, ";"))
return GL_FALSE;
- parseState->isPositionInvariant = GL_TRUE;
}
}
Parse_InstructionSequence(struct parse_state *parseState,
struct vp_instruction program[])
{
- GLubyte token[100];
-
while (1) {
struct vp_instruction *inst = program + parseState->numInst;
/* Initialize the instruction */
- inst->SrcReg[0].Register = -1;
- inst->SrcReg[1].Register = -1;
- inst->SrcReg[2].Register = -1;
- inst->DstReg.Register = -1;
+ inst->SrcReg[0].File = (enum register_file) -1;
+ inst->SrcReg[1].File = (enum register_file) -1;
+ inst->SrcReg[2].File = (enum register_file) -1;
+ inst->DstReg.File = (enum register_file) -1;
- if (!Peek_Token(parseState, token))
- RETURN_ERROR;
-
- if (StrEq(token, (GLubyte *) "MOV") ||
- StrEq(token, (GLubyte *) "LIT") ||
- StrEq(token, (GLubyte *) "ABS")) {
- if (!Parse_UnaryOpInstruction(parseState, inst))
+ if (Parse_String(parseState, "MOV")) {
+ if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_MOV))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "LIT")) {
+ if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_LIT))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "ABS")) {
+ if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_ABS))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "MUL")) {
+ if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MUL))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "ADD")) {
+ if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_ADD))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "DP3")) {
+ if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP3))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "DP4")) {
+ if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP4))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "DST")) {
+ if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DST))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "MIN")) {
+ if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MIN))
RETURN_ERROR;
}
- else if (StrEq(token, (GLubyte *) "MUL") ||
- StrEq(token, (GLubyte *) "ADD") ||
- StrEq(token, (GLubyte *) "DP3") ||
- StrEq(token, (GLubyte *) "DP4") ||
- StrEq(token, (GLubyte *) "DST") ||
- StrEq(token, (GLubyte *) "MIN") ||
- StrEq(token, (GLubyte *) "MAX") ||
- StrEq(token, (GLubyte *) "SLT") ||
- StrEq(token, (GLubyte *) "SGE") ||
- StrEq(token, (GLubyte *) "DPH") ||
- StrEq(token, (GLubyte *) "SUB")) {
- if (!Parse_BiOpInstruction(parseState, inst))
+ else if (Parse_String(parseState, "MAX")) {
+ if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MAX))
RETURN_ERROR;
}
- else if (StrEq(token, (GLubyte *) "MAD")) {
- if (!Parse_TriOpInstruction(parseState, inst))
+ else if (Parse_String(parseState, "SLT")) {
+ if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SLT))
RETURN_ERROR;
}
- else if (StrEq(token, (GLubyte *) "RCP") ||
- StrEq(token, (GLubyte *) "RSQ") ||
- StrEq(token, (GLubyte *) "EXP") ||
- StrEq(token, (GLubyte *) "LOG") ||
- StrEq(token, (GLubyte *) "RCC")) {
- if (!Parse_ScalarInstruction(parseState, inst))
+ else if (Parse_String(parseState, "SGE")) {
+ if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SGE))
RETURN_ERROR;
}
- else if (StrEq(token, (GLubyte *) "ARL")) {
+ else if (Parse_String(parseState, "DPH")) {
+ if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DPH))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "SUB")) {
+ if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SUB))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "MAD")) {
+ if (!Parse_TriOpInstruction(parseState, inst, VP_OPCODE_MAD))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "RCP")) {
+ if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCP))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "RSQ")) {
+ if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RSQ))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "EXP")) {
+ if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_EXP))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "LOG")) {
+ if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_LOG))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "RCC")) {
+ if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCC))
+ RETURN_ERROR;
+ }
+ else if (Parse_String(parseState, "ARL")) {
if (!Parse_AddressInstruction(parseState, inst))
RETURN_ERROR;
}
- else if (StrEq(token, (GLubyte *) "END")) {
+ else if (Parse_String(parseState, "END")) {
if (!Parse_EndInstruction(parseState, inst))
RETURN_ERROR;
else {
}
else {
/* bad instruction name */
- RETURN_ERROR2("Unexpected token: ", token);
+ RETURN_ERROR1("Unexpected token");
}
/* examine input/output registers */
- {
- const GLint srcReg0 = inst->SrcReg[0].Register;
- const GLint srcReg1 = inst->SrcReg[1].Register;
- const GLint srcReg2 = inst->SrcReg[2].Register;
- const GLint dstReg = inst->DstReg.Register;
-
- if (IsOutputRegister(dstReg))
- parseState->outputsWritten |= (1 << (dstReg - VP_OUTPUT_REG_START));
- else if (IsProgRegister(dstReg))
- parseState->progRegsWritten |= (1 << (dstReg - VP_PROG_REG_START));
-
- if (IsInputRegister(srcReg0) && !inst->SrcReg[0].RelAddr)
- parseState->inputsRead |= (1 << (srcReg0 - VP_INPUT_REG_START));
-
- if (IsInputRegister(srcReg1) && !inst->SrcReg[1].RelAddr)
- parseState->inputsRead |= (1 << (srcReg1 - VP_INPUT_REG_START));
-
- if (IsInputRegister(srcReg2) && !inst->SrcReg[2].RelAddr)
- parseState->inputsRead |= (1 << (srcReg2 - VP_INPUT_REG_START));
- }
+ 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++;
MEMCPY(programString, str, len);
programString[len] = 0;
- /* get ready to parse */
+ /* 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.progRegsWritten = 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) {
/* successful parse! */
if (parseState.isStateProgram) {
- if (parseState.progRegsWritten == 0) {
+ if (!parseState.anyProgRegsWritten) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glLoadProgramNV(c[#] not written)");
return;
}
}
- /* save bitmasks of registers read/written */
- program->InputsRead = parseState.inputsRead;
- program->OutputsWritten = parseState.outputsWritten;
- program->IsPositionInvariant = parseState.isPositionInvariant;
-
/* copy the compiled instructions */
assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
newInst = (struct vp_instruction *)
FREE(program->Base.String);
}
program->Base.String = programString;
+ program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
if (program->Instructions) {
FREE(program->Instructions);
}
program->Instructions = newInst;
+ program->InputsRead = parseState.inputsRead;
+ program->OutputsWritten = parseState.outputsWritten;
+ program->IsPositionInvariant = parseState.isPositionInvariant;
-#ifdef DEBUG_foo
+#ifdef DEBUG
_mesa_printf("--- glLoadProgramNV result ---\n");
_mesa_print_nv_vertex_program(program);
_mesa_printf("------------------------------\n");
}
else {
/* Error! */
- ctx->Program.ErrorPos = parseState.pos - str;
_mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
-#ifdef DEBUG
- {
- GLint line, column;
- const char *lineStr;
- lineStr = _mesa_find_line_column((const char *) programString,
- (const char *) parseState.pos, &line, &column);
- _mesa_debug(ctx, "Parse error on line %d, column %d:%s\n",
- line, column, lineStr);
- _mesa_free((void *) lineStr);
- }
-#endif
+ /* 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);
}
}
if (src->Negate)
_mesa_printf("-");
if (src->RelAddr) {
- if (src->Register > 0)
- _mesa_printf("c[A0.x + %d]", src->Register);
- else if (src->Register < 0)
- _mesa_printf("c[A0.x - %d]", -src->Register);
+ if (src->Index > 0)
+ _mesa_printf("c[A0.x + %d]", src->Index);
+ else if (src->Index < 0)
+ _mesa_printf("c[A0.x - %d]", -src->Index);
else
_mesa_printf("c[A0.x]");
}
- else if (src->Register >= VP_OUTPUT_REG_START
- && src->Register <= VP_OUTPUT_REG_END) {
- _mesa_printf("o[%s]", OutputRegisters[src->Register - VP_OUTPUT_REG_START]);
+ else if (src->File == PROGRAM_OUTPUT) {
+ _mesa_printf("o[%s]", OutputRegisters[src->Index]);
}
- else if (src->Register >= VP_INPUT_REG_START
- && src->Register <= VP_INPUT_REG_END) {
- _mesa_printf("v[%s]", InputRegisters[src->Register - VP_INPUT_REG_START]);
+ else if (src->File == PROGRAM_INPUT) {
+ _mesa_printf("v[%s]", InputRegisters[src->Index]);
}
- else if (src->Register >= VP_PROG_REG_START
- && src->Register <= VP_PROG_REG_END) {
- _mesa_printf("c[%d]", src->Register - VP_PROG_REG_START);
+ else if (src->File == PROGRAM_ENV_PARAM) {
+ _mesa_printf("c[%d]", src->Index);
}
else {
- _mesa_printf("R%d", src->Register - VP_TEMP_REG_START);
+ ASSERT(src->File == PROGRAM_TEMPORARY);
+ _mesa_printf("R%d", src->Index);
}
if (src->Swizzle[0] == src->Swizzle[1] &&
GLint w = dst->WriteMask[0] + dst->WriteMask[1]
+ dst->WriteMask[2] + dst->WriteMask[3];
- if (dst->Register >= VP_OUTPUT_REG_START
- && dst->Register <= VP_OUTPUT_REG_END) {
- _mesa_printf("o[%s]", OutputRegisters[dst->Register - VP_OUTPUT_REG_START]);
+ if (dst->File == PROGRAM_OUTPUT) {
+ _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
}
- else if (dst->Register >= VP_INPUT_REG_START
- && dst->Register <= VP_INPUT_REG_END) {
- _mesa_printf("v[%s]", InputRegisters[dst->Register - VP_INPUT_REG_START]);
+ else if (dst->File == PROGRAM_INPUT) {
+ _mesa_printf("v[%s]", InputRegisters[dst->Index]);
}
- else if (dst->Register >= VP_PROG_REG_START
- && dst->Register <= VP_PROG_REG_END) {
- _mesa_printf("c[%d]", dst->Register - VP_PROG_REG_START);
+ else if (dst->File == PROGRAM_ENV_PARAM) {
+ _mesa_printf("c[%d]", dst->Index);
}
else {
- _mesa_printf("R%d", dst->Register - VP_TEMP_REG_START);
+ ASSERT(dst->File == PROGRAM_TEMPORARY);
+ _mesa_printf("R%d", dst->Index);
}
if (w != 0 && w != 4) {
/**
- * Print (unparse) the given vertex program. Just for debugging.
+ * Print a single NVIDIA vertex program instruction.
*/
void
-_mesa_print_nv_vertex_program(const struct vertex_program *program)
+_mesa_print_nv_vertex_instruction(const struct vp_instruction *inst)
{
- const struct vp_instruction *inst;
-
- for (inst = program->Instructions; ; inst++) {
- switch (inst->Opcode) {
+ switch (inst->Opcode) {
case VP_OPCODE_MOV:
case VP_OPCODE_LIT:
case VP_OPCODE_RCP:
break;
case VP_OPCODE_END:
_mesa_printf("END\n");
- return;
+ break;
default:
_mesa_printf("BAD INSTRUCTION\n");
- }
}
}
+
+/**
+ * Print (unparse) the given vertex program. Just for debugging.
+ */
+void
+_mesa_print_nv_vertex_program(const struct vertex_program *program)
+{
+ const struct vp_instruction *inst;
+
+ for (inst = program->Instructions; ; inst++) {
+ _mesa_print_nv_vertex_instruction(inst);
+ if (inst->Opcode == VP_OPCODE_END)
+ return;
+ }
+}
+
+
+const char *
+_mesa_nv_vertex_input_register_name(GLuint i)
+{
+ ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
+ return InputRegisters[i];
+}
+
+
+const char *
+_mesa_nv_vertex_output_register_name(GLuint i)
+{
+ ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
+ return OutputRegisters[i];
+}