diff options
Diffstat (limited to 'mesalib/src/mesa/program')
-rw-r--r-- | mesalib/src/mesa/program/ir_to_mesa.cpp | 8 | ||||
-rw-r--r-- | mesalib/src/mesa/program/nvfragparse.c | 3183 | ||||
-rw-r--r-- | mesalib/src/mesa/program/prog_execute.c | 3790 | ||||
-rw-r--r-- | mesalib/src/mesa/program/prog_parameter.c | 1336 | ||||
-rw-r--r-- | mesalib/src/mesa/program/prog_parameter.h | 30 | ||||
-rw-r--r-- | mesalib/src/mesa/program/prog_parameter_layout.c | 2 | ||||
-rw-r--r-- | mesalib/src/mesa/program/prog_print.c | 2 | ||||
-rw-r--r-- | mesalib/src/mesa/program/prog_statevars.c | 2 | ||||
-rw-r--r-- | mesalib/src/mesa/program/program.c | 8 | ||||
-rw-r--r-- | mesalib/src/mesa/program/program_parse.y | 56 | ||||
-rw-r--r-- | mesalib/src/mesa/program/program_parser.h | 3 | ||||
-rw-r--r-- | mesalib/src/mesa/program/sampler.cpp | 2 |
12 files changed, 4235 insertions, 4187 deletions
diff --git a/mesalib/src/mesa/program/ir_to_mesa.cpp b/mesalib/src/mesa/program/ir_to_mesa.cpp index a08aa0af8..326d1fb63 100644 --- a/mesalib/src/mesa/program/ir_to_mesa.cpp +++ b/mesalib/src/mesa/program/ir_to_mesa.cpp @@ -585,7 +585,7 @@ ir_to_mesa_visitor::src_reg_for_float(float val) src_reg src(PROGRAM_CONSTANT, -1, NULL);
src.index = _mesa_add_unnamed_constant(this->prog->Parameters,
- &val, 1, &src.swizzle);
+ (const gl_constant_value *)&val, 1, &src.swizzle);
return src;
}
@@ -1795,7 +1795,7 @@ ir_to_mesa_visitor::visit(ir_constant *ir) src = src_reg(PROGRAM_CONSTANT, -1, NULL);
src.index = _mesa_add_unnamed_constant(this->prog->Parameters,
- values,
+ (gl_constant_value *) values,
ir->type->vector_elements,
&src.swizzle);
emit(ir, OPCODE_MOV, mat_column, src);
@@ -1833,7 +1833,7 @@ ir_to_mesa_visitor::visit(ir_constant *ir) this->result = src_reg(PROGRAM_CONSTANT, -1, ir->type);
this->result.index = _mesa_add_unnamed_constant(this->prog->Parameters,
- values,
+ (gl_constant_value *) values,
ir->type->vector_elements,
&this->result.swizzle);
}
@@ -2533,7 +2533,7 @@ add_uniforms_to_parameters_list(struct gl_shader_program *shader_program, */
if (file == PROGRAM_SAMPLER) {
for (unsigned int j = 0; j < size / 4; j++)
- prog->Parameters->ParameterValues[index + j][0] = next_sampler++;
+ prog->Parameters->ParameterValues[index + j][0].f = next_sampler++;
}
/* The location chosen in the Parameters list here (returned
diff --git a/mesalib/src/mesa/program/nvfragparse.c b/mesalib/src/mesa/program/nvfragparse.c index 04538e071..ce72c610d 100644 --- a/mesalib/src/mesa/program/nvfragparse.c +++ b/mesalib/src/mesa/program/nvfragparse.c @@ -1,1588 +1,1595 @@ -/*
- * Mesa 3-D graphics library
- * Version: 6.5
- *
- * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file nvfragparse.c
- * NVIDIA fragment program parser.
- * \author Brian Paul
- */
-
-/*
- * Regarding GL_NV_fragment_program:
- *
- * Portions of this software may use or implement intellectual
- * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
- * any and all warranties with respect to such intellectual property,
- * including any use thereof or modifications thereto.
- */
-
-#include "main/glheader.h"
-#include "main/context.h"
-#include "main/imports.h"
-#include "main/macros.h"
-#include "program.h"
-#include "prog_parameter.h"
-#include "prog_print.h"
-#include "prog_instruction.h"
-#include "nvfragparse.h"
-
-
-#define INPUT_1V 1
-#define INPUT_2V 2
-#define INPUT_3V 3
-#define INPUT_1S 4
-#define INPUT_2S 5
-#define INPUT_CC 6
-#define INPUT_1V_T 7 /* one source vector, plus textureId */
-#define INPUT_3V_T 8 /* one source vector, plus textureId */
-#define INPUT_NONE 9
-#define INPUT_1V_S 10 /* a string and a vector register */
-#define OUTPUT_V 20
-#define OUTPUT_S 21
-#define OUTPUT_NONE 22
-
-/* IRIX defines some of these */
-#undef _R
-#undef _H
-#undef _X
-#undef _C
-#undef _S
-
-/* Optional suffixes */
-#define _R FLOAT32 /* float */
-#define _H FLOAT16 /* half-float */
-#define _X FIXED12 /* fixed */
-#define _C 0x08 /* set cond codes */
-#define _S 0x10 /* saturate, clamp result to [0,1] */
-
-struct instruction_pattern {
- const char *name;
- enum prog_opcode opcode;
- GLuint inputs;
- GLuint outputs;
- GLuint suffixes;
-};
-
-static const struct instruction_pattern Instructions[] = {
- { "ADD", OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "COS", OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
- { "DDX", OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
- { "DDY", OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
- { "DP3", OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
- { "DP4", OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
- { "DST", OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H | _C | _S },
- { "EX2", OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
- { "FLR", OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "FRC", OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "KIL", OPCODE_KIL_NV, INPUT_CC, OUTPUT_NONE, 0 },
- { "LG2", OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
- { "LIT", OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
- { "LRP", OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "MAD", OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "MAX", OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "MIN", OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "MOV", OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "MUL", OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "PK2H", OPCODE_PK2H, INPUT_1V, OUTPUT_S, 0 },
- { "PK2US", OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0 },
- { "PK4B", OPCODE_PK4B, INPUT_1V, OUTPUT_S, 0 },
- { "PK4UB", OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0 },
- { "POW", OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H | _C | _S },
- { "RCP", OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
- { "RFL", OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H | _C | _S },
- { "RSQ", OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
- { "SEQ", OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "SFL", OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "SGE", OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "SGT", OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "SIN", OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
- { "SLE", OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "SLT", OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "SNE", OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "STR", OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "SUB", OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
- { "TEX", OPCODE_TEX, INPUT_1V_T, OUTPUT_V, _C | _S },
- { "TXD", OPCODE_TXD, INPUT_3V_T, OUTPUT_V, _C | _S },
- { "TXP", OPCODE_TXP_NV, INPUT_1V_T, OUTPUT_V, _C | _S },
- { "UP2H", OPCODE_UP2H, INPUT_1S, OUTPUT_V, _C | _S },
- { "UP2US", OPCODE_UP2US, INPUT_1S, OUTPUT_V, _C | _S },
- { "UP4B", OPCODE_UP4B, INPUT_1S, OUTPUT_V, _C | _S },
- { "UP4UB", OPCODE_UP4UB, INPUT_1S, OUTPUT_V, _C | _S },
- { "X2D", OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H | _C | _S },
- { "PRINT", OPCODE_PRINT, INPUT_1V_S, OUTPUT_NONE, 0 },
- { NULL, (enum prog_opcode) -1, 0, 0, 0 }
-};
-
-
-/*
- * Information needed or computed during parsing.
- * Remember, we can't modify the target program object until we've
- * _successfully_ parsed the program text.
- */
-struct parse_state {
- struct gl_context *ctx;
- const GLubyte *start; /* start of program string */
- const GLubyte *pos; /* current position */
- const GLubyte *curLine;
- struct gl_fragment_program *program; /* current program */
-
- struct gl_program_parameter_list *parameters;
-
- GLuint numInst; /* number of instructions parsed */
- GLuint inputsRead; /* bitmask of input registers used */
- GLuint outputsWritten; /* bitmask of 1 << FRAG_OUTPUT_* bits */
- GLuint texturesUsed[MAX_TEXTURE_IMAGE_UNITS];
-};
-
-
-
-/*
- * Called whenever we find an error during parsing.
- */
-static void
-record_error(struct parse_state *parseState, const char *msg, int lineNo)
-{
-#ifdef DEBUG
- GLint line, column;
- const GLubyte *lineStr;
- lineStr = _mesa_find_line_column(parseState->start,
- parseState->pos, &line, &column);
- _mesa_debug(parseState->ctx,
- "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
- lineNo, line, column, (char *) lineStr, msg);
- free((void *) lineStr);
-#else
- (void) lineNo;
-#endif
-
- /* Check that no error was already recorded. Only record the first one. */
- if (parseState->ctx->Program.ErrorString[0] == 0) {
- _mesa_set_program_error(parseState->ctx,
- parseState->pos - parseState->start,
- msg);
- }
-}
-
-
-#define RETURN_ERROR \
-do { \
- record_error(parseState, "Unexpected end of input.", __LINE__); \
- return GL_FALSE; \
-} while(0)
-
-#define RETURN_ERROR1(msg) \
-do { \
- record_error(parseState, msg, __LINE__); \
- return GL_FALSE; \
-} while(0)
-
-#define RETURN_ERROR2(msg1, msg2) \
-do { \
- char err[1000]; \
- sprintf(err, "%s %s", msg1, msg2); \
- record_error(parseState, err, __LINE__); \
- return GL_FALSE; \
-} while(0)
-
-
-
-
-/*
- * Search a list of instruction structures for a match.
- */
-static struct instruction_pattern
-MatchInstruction(const GLubyte *token)
-{
- const struct instruction_pattern *inst;
- struct instruction_pattern result;
-
- result.name = NULL;
- result.opcode = MAX_OPCODE; /* i.e. invalid instruction */
- result.inputs = 0;
- result.outputs = 0;
- result.suffixes = 0;
-
- for (inst = Instructions; inst->name; inst++) {
- if (strncmp((const char *) token, inst->name, 3) == 0) {
- /* matched! */
- int i = 3;
- result = *inst;
- result.suffixes = 0;
- /* look at suffix */
- if (token[i] == 'R') {
- result.suffixes |= _R;
- i++;
- }
- else if (token[i] == 'H') {
- result.suffixes |= _H;
- i++;
- }
- else if (token[i] == 'X') {
- result.suffixes |= _X;
- i++;
- }
- if (token[i] == 'C') {
- result.suffixes |= _C;
- i++;
- }
- if (token[i] == '_' && token[i+1] == 'S' &&
- token[i+2] == 'A' && token[i+3] == 'T') {
- result.suffixes |= _S;
- }
- return result;
- }
- }
-
- return result;
-}
-
-
-
-
-/**********************************************************************/
-
-
-static GLboolean IsLetter(GLubyte b)
-{
- return (b >= 'a' && b <= 'z') ||
- (b >= 'A' && b <= 'Z') ||
- (b == '_') ||
- (b == '$');
-}
-
-
-static GLboolean IsDigit(GLubyte b)
-{
- return b >= '0' && b <= '9';
-}
-
-
-static GLboolean IsWhitespace(GLubyte b)
-{
- return b == ' ' || b == '\t' || b == '\n' || b == '\r';
-}
-
-
-/**
- * Starting at 'str' find the next token. A token can be an integer,
- * an identifier or punctuation symbol.
- * \return <= 0 we found an error, else, return number of characters parsed.
- */
-static GLint
-GetToken(struct parse_state *parseState, GLubyte *token)
-{
- const GLubyte *str = parseState->pos;
- GLint i = 0, j = 0;
-
- token[0] = 0;
-
- /* skip whitespace and comments */
- while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
- if (str[i] == '#') {
- /* skip comment */
- while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
- i++;
- }
- if (str[i] == '\n' || str[i] == '\r')
- parseState->curLine = str + i + 1;
- }
- else {
- /* skip whitespace */
- if (str[i] == '\n' || str[i] == '\r')
- parseState->curLine = str + i + 1;
- i++;
- }
- }
-
- if (str[i] == 0)
- return -i;
-
- /* try matching an integer */
- while (str[i] && IsDigit(str[i])) {
- token[j++] = str[i++];
- }
- if (j > 0 || !str[i]) {
- token[j] = 0;
- return i;
- }
-
- /* try matching an identifier */
- if (IsLetter(str[i])) {
- while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
- token[j++] = str[i++];
- }
- token[j] = 0;
- return i;
- }
-
- /* punctuation character */
- if (str[i]) {
- token[0] = str[i++];
- token[1] = 0;
- return i;
- }
-
- /* end of input */
- token[0] = 0;
- return i;
-}
-
-
-/**
- * Get next token from input stream and increment stream pointer past token.
- */
-static GLboolean
-Parse_Token(struct parse_state *parseState, GLubyte *token)
-{
- GLint i;
- i = GetToken(parseState, token);
- if (i <= 0) {
- parseState->pos += (-i);
- return GL_FALSE;
- }
- parseState->pos += i;
- return GL_TRUE;
-}
-
-
-/**
- * Get next token from input stream but don't increment stream pointer.
- */
-static GLboolean
-Peek_Token(struct parse_state *parseState, GLubyte *token)
-{
- GLint i, len;
- i = GetToken(parseState, token);
- if (i <= 0) {
- parseState->pos += (-i);
- return GL_FALSE;
- }
- len = (GLint) strlen((const char *) token);
- parseState->pos += (i - len);
- return GL_TRUE;
-}
-
-
-/**********************************************************************/
-
-static const char *InputRegisters[MAX_NV_FRAGMENT_PROGRAM_INPUTS + 1] = {
- "WPOS", "COL0", "COL1", "FOGC",
- "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
-};
-
-
-
-/**********************************************************************/
-
-/**
- * Try to match 'pattern' as the next token after any whitespace/comments.
- */
-static GLboolean
-Parse_String(struct parse_state *parseState, const char *pattern)
-{
- const GLubyte *m;
- GLint i;
-
- /* skip whitespace and comments */
- while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
- if (*parseState->pos == '#') {
- while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
- parseState->pos += 1;
- }
- if (*parseState->pos == '\n' || *parseState->pos == '\r')
- parseState->curLine = parseState->pos + 1;
- }
- else {
- /* skip whitespace */
- if (*parseState->pos == '\n' || *parseState->pos == '\r')
- parseState->curLine = parseState->pos + 1;
- parseState->pos += 1;
- }
- }
-
- /* Try to match the pattern */
- m = parseState->pos;
- for (i = 0; pattern[i]; i++) {
- if (*m != (GLubyte) pattern[i])
- return GL_FALSE;
- m += 1;
- }
- parseState->pos = m;
-
- return GL_TRUE; /* success */
-}
-
-
-static GLboolean
-Parse_Identifier(struct parse_state *parseState, GLubyte *ident)
-{
- if (!Parse_Token(parseState, ident))
- RETURN_ERROR;
- if (IsLetter(ident[0]))
- return GL_TRUE;
- else
- RETURN_ERROR1("Expected an identfier");
-}
-
-
-/**
- * Parse a floating point constant, or a defined symbol name.
- * [+/-]N[.N[eN]]
- * Output: number[0 .. 3] will get the value.
- */
-static GLboolean
-Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number)
-{
- char *end = NULL;
-
- *number = (GLfloat) _mesa_strtof((const char *) parseState->pos, &end);
-
- if (end && end > (char *) parseState->pos) {
- /* got a number */
- parseState->pos = (GLubyte *) end;
- number[1] = *number;
- number[2] = *number;
- number[3] = *number;
- return GL_TRUE;
- }
- else {
- /* should be an identifier */
- GLubyte ident[100];
- const GLfloat *constant;
- if (!Parse_Identifier(parseState, ident))
- RETURN_ERROR1("Expected an identifier");
- constant = _mesa_lookup_parameter_value(parseState->parameters,
- -1, (const char *) ident);
- /* XXX Check that it's a constant and not a parameter */
- if (!constant) {
- RETURN_ERROR1("Undefined symbol");
- }
- else {
- COPY_4V(number, constant);
- return GL_TRUE;
- }
- }
-}
-
-
-
-/**
- * Parse a vector constant, one of:
- * { float }
- * { float, float }
- * { float, float, float }
- * { float, float, float, float }
- */
-static GLboolean
-Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
-{
- /* "{" was already consumed */
-
- ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0);
-
- if (!Parse_ScalarConstant(parseState, vec+0)) /* X */
- return GL_FALSE;
-
- if (Parse_String(parseState, "}")) {
- return GL_TRUE;
- }
-
- if (!Parse_String(parseState, ","))
- RETURN_ERROR1("Expected comma in vector constant");
-
- if (!Parse_ScalarConstant(parseState, vec+1)) /* Y */
- return GL_FALSE;
-
- if (Parse_String(parseState, "}")) {
- return GL_TRUE;
- }
-
- if (!Parse_String(parseState, ","))
- RETURN_ERROR1("Expected comma in vector constant");
-
- if (!Parse_ScalarConstant(parseState, vec+2)) /* Z */
- return GL_FALSE;
-
- if (Parse_String(parseState, "}")) {
- return GL_TRUE;
- }
-
- if (!Parse_String(parseState, ","))
- RETURN_ERROR1("Expected comma in vector constant");
-
- if (!Parse_ScalarConstant(parseState, vec+3)) /* W */
- return GL_FALSE;
-
- if (!Parse_String(parseState, "}"))
- RETURN_ERROR1("Expected closing brace in vector constant");
-
- return GL_TRUE;
-}
-
-
-/**
- * Parse <number>, <varname> or {a, b, c, d}.
- * Return number of values in the vector or scalar, or zero if parse error.
- */
-static GLuint
-Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec)
-{
- if (Parse_String(parseState, "{")) {
- return Parse_VectorConstant(parseState, vec);
- }
- else {
- GLboolean b = Parse_ScalarConstant(parseState, vec);
- if (b) {
- vec[1] = vec[2] = vec[3] = vec[0];
- }
- return b;
- }
-}
-
-
-/**
- * Parse a texture image source:
- * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
- */
-static GLboolean
-Parse_TextureImageId(struct parse_state *parseState,
- GLubyte *texUnit, GLubyte *texTargetBit)
-{
- GLubyte imageSrc[100];
- GLint unit;
-
- if (!Parse_Token(parseState, imageSrc))
- RETURN_ERROR;
-
- if (imageSrc[0] != 'T' ||
- imageSrc[1] != 'E' ||
- imageSrc[2] != 'X') {
- RETURN_ERROR1("Expected TEX# source");
- }
- unit = atoi((const char *) imageSrc + 3);
- if ((unit < 0 || unit > MAX_TEXTURE_IMAGE_UNITS) ||
- (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) {
- RETURN_ERROR1("Invalied TEX# source index");
- }
- *texUnit = unit;
-
- if (!Parse_String(parseState, ","))
- RETURN_ERROR1("Expected ,");
-
- if (Parse_String(parseState, "1D")) {
- *texTargetBit = TEXTURE_1D_BIT;
- }
- else if (Parse_String(parseState, "2D")) {
- *texTargetBit = TEXTURE_2D_BIT;
- }
- else if (Parse_String(parseState, "3D")) {
- *texTargetBit = TEXTURE_3D_BIT;
- }
- else if (Parse_String(parseState, "CUBE")) {
- *texTargetBit = TEXTURE_CUBE_BIT;
- }
- else if (Parse_String(parseState, "RECT")) {
- *texTargetBit = TEXTURE_RECT_BIT;
- }
- else {
- RETURN_ERROR1("Invalid texture target token");
- }
-
- /* update record of referenced texture units */
- parseState->texturesUsed[*texUnit] |= *texTargetBit;
- if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) {
- RETURN_ERROR1("Only one texture target can be used per texture unit.");
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
- * like .wxyz, .xxyy, etc and return the swizzle indexes.
- */
-static GLboolean
-Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4])
-{
- if (token[1] == 0) {
- /* single letter swizzle (scalar) */
- if (token[0] == 'x')
- ASSIGN_4V(swizzle, 0, 0, 0, 0);
- else if (token[0] == 'y')
- ASSIGN_4V(swizzle, 1, 1, 1, 1);
- else if (token[0] == 'z')
- ASSIGN_4V(swizzle, 2, 2, 2, 2);
- else if (token[0] == 'w')
- ASSIGN_4V(swizzle, 3, 3, 3, 3);
- else
- return GL_FALSE;
- }
- else {
- /* 4-component swizzle (vector) */
- GLint k;
- for (k = 0; k < 4 && token[k]; k++) {
- if (token[k] == 'x')
- swizzle[k] = 0;
- else if (token[k] == 'y')
- swizzle[k] = 1;
- else if (token[k] == 'z')
- swizzle[k] = 2;
- else if (token[k] == 'w')
- swizzle[k] = 3;
- else
- return GL_FALSE;
- }
- if (k != 4)
- return GL_FALSE;
- }
- return GL_TRUE;
-}
-
-
-static GLboolean
-Parse_CondCodeMask(struct parse_state *parseState,
- struct prog_dst_register *dstReg)
-{
- if (Parse_String(parseState, "EQ"))
- dstReg->CondMask = COND_EQ;
- else if (Parse_String(parseState, "GE"))
- dstReg->CondMask = COND_GE;
- else if (Parse_String(parseState, "GT"))
- dstReg->CondMask = COND_GT;
- else if (Parse_String(parseState, "LE"))
- dstReg->CondMask = COND_LE;
- else if (Parse_String(parseState, "LT"))
- dstReg->CondMask = COND_LT;
- else if (Parse_String(parseState, "NE"))
- dstReg->CondMask = COND_NE;
- else if (Parse_String(parseState, "TR"))
- dstReg->CondMask = COND_TR;
- else if (Parse_String(parseState, "FL"))
- dstReg->CondMask = COND_FL;
- else
- RETURN_ERROR1("Invalid condition code mask");
-
- /* look for optional .xyzw swizzle */
- if (Parse_String(parseState, ".")) {
- GLubyte token[100];
- GLuint swz[4];
-
- if (!Parse_Token(parseState, token)) /* get xyzw suffix */
- RETURN_ERROR;
-
- if (!Parse_SwizzleSuffix(token, swz))
- RETURN_ERROR1("Invalid swizzle suffix");
-
- dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Parse a temporary register: Rnn or Hnn
- */
-static GLboolean
-Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
-{
- GLubyte token[100];
-
- /* Should be 'R##' or 'H##' */
- if (!Parse_Token(parseState, token))
- RETURN_ERROR;
- if (token[0] != 'R' && token[0] != 'H')
- RETURN_ERROR1("Expected R## or H##");
-
- if (IsDigit(token[1])) {
- GLint reg = atoi((const char *) (token + 1));
- if (token[0] == 'H')
- reg += 32;
- if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS)
- RETURN_ERROR1("Invalid temporary register name");
- *tempRegNum = reg;
- }
- else {
- RETURN_ERROR1("Invalid temporary register name");
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Parse a write-only dummy register: RC or HC.
- */
-static GLboolean
-Parse_DummyReg(struct parse_state *parseState, GLint *regNum)
-{
- if (Parse_String(parseState, "RC")) {
- *regNum = 0;
- }
- else if (Parse_String(parseState, "HC")) {
- *regNum = 1;
- }
- else {
- RETURN_ERROR1("Invalid write-only register name");
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Parse a program local parameter register "p[##]"
- */
-static GLboolean
-Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum)
-{
- GLubyte token[100];
-
- if (!Parse_String(parseState, "p["))
- RETURN_ERROR1("Expected p[");
-
- if (!Parse_Token(parseState, token))
- RETURN_ERROR;
-
- if (IsDigit(token[0])) {
- /* a numbered program parameter register */
- GLint reg = atoi((const char *) token);
- if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS)
- RETURN_ERROR1("Invalid constant program number");
- *regNum = reg;
- }
- else {
- RETURN_ERROR;
- }
-
- if (!Parse_String(parseState, "]"))
- RETURN_ERROR1("Expected ]");
-
- return GL_TRUE;
-}
-
-
-/**
- * Parse f[name] - fragment input register
- */
-static GLboolean
-Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum)
-{
- GLubyte token[100];
- GLint j;
-
- /* Match 'f[' */
- if (!Parse_String(parseState, "f["))
- RETURN_ERROR1("Expected f[");
-
- /* get <name> and look for match */
- if (!Parse_Token(parseState, token)) {
- RETURN_ERROR;
- }
- for (j = 0; InputRegisters[j]; j++) {
- if (strcmp((const char *) token, InputRegisters[j]) == 0) {
- *tempRegNum = j;
- parseState->inputsRead |= (1 << j);
- break;
- }
- }
- if (!InputRegisters[j]) {
- /* unknown input register label */
- RETURN_ERROR2("Invalid register name", token);
- }
-
- /* Match '[' */
- if (!Parse_String(parseState, "]"))
- RETURN_ERROR1("Expected ]");
-
- return GL_TRUE;
-}
-
-
-static GLboolean
-Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
-{
- GLubyte token[100];
-
- /* Match "o[" */
- if (!Parse_String(parseState, "o["))
- RETURN_ERROR1("Expected o[");
-
- /* Get output reg name */
- if (!Parse_Token(parseState, token))
- RETURN_ERROR;
-
- /* try to match an output register name */
- if (strcmp((char *) token, "COLR") == 0 ||
- strcmp((char *) token, "COLH") == 0) {
- /* note that we don't distinguish between COLR and COLH */
- *outputRegNum = FRAG_RESULT_COLOR;
- parseState->outputsWritten |= (1 << FRAG_RESULT_COLOR);
- }
- else if (strcmp((char *) token, "DEPR") == 0) {
- *outputRegNum = FRAG_RESULT_DEPTH;
- parseState->outputsWritten |= (1 << FRAG_RESULT_DEPTH);
- }
- else {
- RETURN_ERROR1("Invalid output register name");
- }
-
- /* Match ']' */
- if (!Parse_String(parseState, "]"))
- RETURN_ERROR1("Expected ]");
-
- return GL_TRUE;
-}
-
-
-static GLboolean
-Parse_MaskedDstReg(struct parse_state *parseState,
- struct prog_dst_register *dstReg)
-{
- GLubyte token[100];
- GLint idx;
-
- /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
- if (!Peek_Token(parseState, token))
- RETURN_ERROR;
-
- if (strcmp((const char *) token, "RC") == 0 ||
- strcmp((const char *) token, "HC") == 0) {
- /* a write-only register */
- dstReg->File = PROGRAM_WRITE_ONLY;
- if (!Parse_DummyReg(parseState, &idx))
- RETURN_ERROR;
- dstReg->Index = idx;
- }
- else if (token[0] == 'R' || token[0] == 'H') {
- /* a temporary register */
- dstReg->File = PROGRAM_TEMPORARY;
- if (!Parse_TempReg(parseState, &idx))
- RETURN_ERROR;
- dstReg->Index = idx;
- }
- else if (token[0] == 'o') {
- /* an output register */
- dstReg->File = PROGRAM_OUTPUT;
- if (!Parse_OutputReg(parseState, &idx))
- RETURN_ERROR;
- dstReg->Index = idx;
- }
- else {
- RETURN_ERROR1("Invalid destination register name");
- }
-
- /* Parse optional write mask */
- if (Parse_String(parseState, ".")) {
- /* got a mask */
- GLint k = 0;
-
- if (!Parse_Token(parseState, token)) /* get xyzw writemask */
- RETURN_ERROR;
-
- dstReg->WriteMask = 0;
-
- if (token[k] == 'x') {
- dstReg->WriteMask |= WRITEMASK_X;
- k++;
- }
- if (token[k] == 'y') {
- dstReg->WriteMask |= WRITEMASK_Y;
- k++;
- }
- if (token[k] == 'z') {
- dstReg->WriteMask |= WRITEMASK_Z;
- k++;
- }
- if (token[k] == 'w') {
- dstReg->WriteMask |= WRITEMASK_W;
- k++;
- }
- if (k == 0) {
- RETURN_ERROR1("Invalid writemask character");
- }
-
- }
- else {
- dstReg->WriteMask = WRITEMASK_XYZW;
- }
-
- /* optional condition code mask */
- if (Parse_String(parseState, "(")) {
- /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
- /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
- if (!Parse_CondCodeMask(parseState, dstReg))
- RETURN_ERROR;
-
- if (!Parse_String(parseState, ")")) /* consume ")" */
- RETURN_ERROR1("Expected )");
-
- return GL_TRUE;
- }
- else {
- /* no cond code mask */
- dstReg->CondMask = COND_TR;
- dstReg->CondSwizzle = SWIZZLE_NOOP;
- return GL_TRUE;
- }
-}
-
-
-/**
- * Parse a vector source (register, constant, etc):
- * <vectorSrc> ::= <absVectorSrc>
- * | <baseVectorSrc>
- * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
- */
-static GLboolean
-Parse_VectorSrc(struct parse_state *parseState,
- struct prog_src_register *srcReg)
-{
- GLfloat sign = 1.0F;
- GLubyte token[100];
- GLint idx;
- GLuint negateBase, negateAbs;
-
- /*
- * First, take care of +/- and absolute value stuff.
- */
- if (Parse_String(parseState, "-"))
- sign = -1.0F;
- else if (Parse_String(parseState, "+"))
- sign = +1.0F;
-
- if (Parse_String(parseState, "|")) {
- srcReg->Abs = GL_TRUE;
- negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
-
- if (Parse_String(parseState, "-"))
- negateBase = NEGATE_XYZW;
- else if (Parse_String(parseState, "+"))
- negateBase = NEGATE_NONE;
- else
- negateBase = NEGATE_NONE;
- }
- else {
- srcReg->Abs = GL_FALSE;
- negateAbs = NEGATE_NONE;
- negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
- }
-
- srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
-
- /* This should be the real src vector/register name */
- if (!Peek_Token(parseState, token))
- RETURN_ERROR;
-
- /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
- * literal or vector literal.
- */
- if (token[0] == 'R' || token[0] == 'H') {
- srcReg->File = PROGRAM_TEMPORARY;
- if (!Parse_TempReg(parseState, &idx))
- RETURN_ERROR;
- srcReg->Index = idx;
- }
- else if (token[0] == 'f') {
- /* XXX this might be an identifier! */
- srcReg->File = PROGRAM_INPUT;
- if (!Parse_FragReg(parseState, &idx))
- RETURN_ERROR;
- srcReg->Index = idx;
- }
- else if (token[0] == 'p') {
- /* XXX this might be an identifier! */
- srcReg->File = PROGRAM_LOCAL_PARAM;
- if (!Parse_ProgramParamReg(parseState, &idx))
- RETURN_ERROR;
- srcReg->Index = idx;
- }
- else if (IsLetter(token[0])){
- GLubyte ident[100];
- GLint paramIndex;
- if (!Parse_Identifier(parseState, ident))
- RETURN_ERROR;
- paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
- -1, (const char *) ident);
- if (paramIndex < 0) {
- RETURN_ERROR2("Undefined constant or parameter: ", ident);
- }
- srcReg->File = PROGRAM_NAMED_PARAM;
- srcReg->Index = paramIndex;
- }
- else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){
- /* literal scalar constant */
- GLfloat values[4];
- GLuint paramIndex;
- if (!Parse_ScalarConstant(parseState, values))
- RETURN_ERROR;
- paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
- values, 4, NULL);
- srcReg->File = PROGRAM_NAMED_PARAM;
- srcReg->Index = paramIndex;
- }
- else if (token[0] == '{'){
- /* literal vector constant */
- GLfloat values[4];
- GLuint paramIndex;
- (void) Parse_String(parseState, "{");
- if (!Parse_VectorConstant(parseState, values))
- RETURN_ERROR;
- paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
- values, 4, NULL);
- srcReg->File = PROGRAM_NAMED_PARAM;
- srcReg->Index = paramIndex;
- }
- else {
- RETURN_ERROR2("Invalid source register name", token);
- }
-
- /* init swizzle fields */
- srcReg->Swizzle = SWIZZLE_NOOP;
-
- /* Look for optional swizzle suffix */
- if (Parse_String(parseState, ".")) {
- GLuint swz[4];
-
- if (!Parse_Token(parseState, token))
- RETURN_ERROR;
-
- if (!Parse_SwizzleSuffix(token, swz))
- RETURN_ERROR1("Invalid swizzle suffix");
-
- srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
- }
-
- /* Finish absolute value */
- if (srcReg->Abs && !Parse_String(parseState, "|")) {
- RETURN_ERROR1("Expected |");
- }
-
- return GL_TRUE;
-}
-
-
-static GLboolean
-Parse_ScalarSrcReg(struct parse_state *parseState,
- struct prog_src_register *srcReg)
-{
- GLubyte token[100];
- GLfloat sign = 1.0F;
- GLboolean needSuffix = GL_TRUE;
- GLint idx;
- GLuint negateBase, negateAbs;
-
- /*
- * First, take care of +/- and absolute value stuff.
- */
- if (Parse_String(parseState, "-"))
- sign = -1.0F;
- else if (Parse_String(parseState, "+"))
- sign = +1.0F;
-
- if (Parse_String(parseState, "|")) {
- srcReg->Abs = GL_TRUE;
- negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
-
- if (Parse_String(parseState, "-"))
- negateBase = NEGATE_XYZW;
- else if (Parse_String(parseState, "+"))
- negateBase = NEGATE_NONE;
- else
- negateBase = NEGATE_NONE;
- }
- else {
- srcReg->Abs = GL_FALSE;
- negateAbs = NEGATE_NONE;
- negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
- }
-
- srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
-
- if (!Peek_Token(parseState, token))
- RETURN_ERROR;
-
- /* Src reg can be R<n>, H<n> or a named fragment attrib */
- if (token[0] == 'R' || token[0] == 'H') {
- srcReg->File = PROGRAM_TEMPORARY;
- if (!Parse_TempReg(parseState, &idx))
- RETURN_ERROR;
- srcReg->Index = idx;
- }
- else if (token[0] == 'f') {
- srcReg->File = PROGRAM_INPUT;
- if (!Parse_FragReg(parseState, &idx))
- RETURN_ERROR;
- srcReg->Index = idx;
- }
- else if (token[0] == '{') {
- /* vector literal */
- GLfloat values[4];
- GLuint paramIndex;
- (void) Parse_String(parseState, "{");
- if (!Parse_VectorConstant(parseState, values))
- RETURN_ERROR;
- paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
- values, 4, NULL);
- srcReg->File = PROGRAM_NAMED_PARAM;
- srcReg->Index = paramIndex;
- }
- else if (IsLetter(token[0])){
- /* named param/constant */
- GLubyte ident[100];
- GLint paramIndex;
- if (!Parse_Identifier(parseState, ident))
- RETURN_ERROR;
- paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
- -1, (const char *) ident);
- if (paramIndex < 0) {
- RETURN_ERROR2("Undefined constant or parameter: ", ident);
- }
- srcReg->File = PROGRAM_NAMED_PARAM;
- srcReg->Index = paramIndex;
- }
- else if (IsDigit(token[0])) {
- /* scalar literal */
- GLfloat values[4];
- GLuint paramIndex;
- if (!Parse_ScalarConstant(parseState, values))
- RETURN_ERROR;
- paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
- values, 4, NULL);
- srcReg->Index = paramIndex;
- srcReg->File = PROGRAM_NAMED_PARAM;
- needSuffix = GL_FALSE;
- }
- else {
- RETURN_ERROR2("Invalid scalar source argument", token);
- }
-
- srcReg->Swizzle = 0;
- if (needSuffix) {
- /* parse .[xyzw] suffix */
- if (!Parse_String(parseState, "."))
- RETURN_ERROR1("Expected .");
-
- if (!Parse_Token(parseState, token))
- RETURN_ERROR;
-
- if (token[0] == 'x' && token[1] == 0) {
- srcReg->Swizzle = 0;
- }
- else if (token[0] == 'y' && token[1] == 0) {
- srcReg->Swizzle = 1;
- }
- else if (token[0] == 'z' && token[1] == 0) {
- srcReg->Swizzle = 2;
- }
- else if (token[0] == 'w' && token[1] == 0) {
- srcReg->Swizzle = 3;
- }
- else {
- RETURN_ERROR1("Invalid scalar source suffix");
- }
- }
-
- /* Finish absolute value */
- if (srcReg->Abs && !Parse_String(parseState, "|")) {
- RETURN_ERROR1("Expected |");
- }
-
- return GL_TRUE;
-}
-
-
-static GLboolean
-Parse_PrintInstruction(struct parse_state *parseState,
- struct prog_instruction *inst)
-{
- const GLubyte *str;
- GLubyte *msg;
- GLuint len;
- GLint idx;
-
- /* The first argument is a literal string 'just like this' */
- if (!Parse_String(parseState, "'"))
- RETURN_ERROR1("Expected '");
-
- str = parseState->pos;
- for (len = 0; str[len] != '\''; len++) /* find closing quote */
- ;
- parseState->pos += len + 1;
- msg = (GLubyte*) malloc(len + 1);
-
- memcpy(msg, str, len);
- msg[len] = 0;
- inst->Data = msg;
-
- if (Parse_String(parseState, ",")) {
- /* got an optional register to print */
- GLubyte token[100];
- GetToken(parseState, token);
- if (token[0] == 'o') {
- /* dst reg */
- if (!Parse_OutputReg(parseState, &idx))
- RETURN_ERROR;
- inst->SrcReg[0].Index = idx;
- inst->SrcReg[0].File = PROGRAM_OUTPUT;
- }
- else {
- /* src reg */
- if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
- RETURN_ERROR;
- }
- }
- else {
- inst->SrcReg[0].File = PROGRAM_UNDEFINED;
- }
-
- inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
- inst->SrcReg[0].Abs = GL_FALSE;
- inst->SrcReg[0].Negate = NEGATE_NONE;
-
- return GL_TRUE;
-}
-
-
-static GLboolean
-Parse_InstructionSequence(struct parse_state *parseState,
- struct prog_instruction program[])
-{
- while (1) {
- struct prog_instruction *inst = program + parseState->numInst;
- struct instruction_pattern instMatch;
- GLubyte token[100];
-
- /* Initialize the instruction */
- _mesa_init_instructions(inst, 1);
-
- /* special instructions */
- if (Parse_String(parseState, "DEFINE")) {
- GLubyte id[100];
- GLfloat value[7]; /* yes, 7 to be safe */
- if (!Parse_Identifier(parseState, id))
- RETURN_ERROR;
- /* XXX make sure id is not a reserved identifer, like R9 */
- if (!Parse_String(parseState, "="))
- RETURN_ERROR1("Expected =");
- if (!Parse_VectorOrScalarConstant(parseState, value))
- RETURN_ERROR;
- if (!Parse_String(parseState, ";"))
- RETURN_ERROR1("Expected ;");
- if (_mesa_lookup_parameter_index(parseState->parameters,
- -1, (const char *) id) >= 0) {
- RETURN_ERROR2(id, "already defined");
- }
- _mesa_add_named_parameter(parseState->parameters,
- (const char *) id, value);
- }
- else if (Parse_String(parseState, "DECLARE")) {
- GLubyte id[100];
- GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */
- if (!Parse_Identifier(parseState, id))
- RETURN_ERROR;
- /* XXX make sure id is not a reserved identifer, like R9 */
- if (Parse_String(parseState, "=")) {
- if (!Parse_VectorOrScalarConstant(parseState, value))
- RETURN_ERROR;
- }
- if (!Parse_String(parseState, ";"))
- RETURN_ERROR1("Expected ;");
- if (_mesa_lookup_parameter_index(parseState->parameters,
- -1, (const char *) id) >= 0) {
- RETURN_ERROR2(id, "already declared");
- }
- _mesa_add_named_parameter(parseState->parameters,
- (const char *) id, value);
- }
- else if (Parse_String(parseState, "END")) {
- inst->Opcode = OPCODE_END;
- parseState->numInst++;
- if (Parse_Token(parseState, token)) {
- RETURN_ERROR1("Code after END opcode.");
- }
- break;
- }
- else {
- /* general/arithmetic instruction */
-
- /* get token */
- if (!Parse_Token(parseState, token)) {
- RETURN_ERROR1("Missing END instruction.");
- }
-
- /* try to find matching instuction */
- instMatch = MatchInstruction(token);
- if (instMatch.opcode >= MAX_OPCODE) {
- /* bad instruction name */
- RETURN_ERROR2("Unexpected token: ", token);
- }
-
- inst->Opcode = instMatch.opcode;
- inst->Precision = instMatch.suffixes & (_R | _H | _X);
- inst->SaturateMode = (instMatch.suffixes & (_S))
- ? SATURATE_ZERO_ONE : SATURATE_OFF;
- inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
-
- /*
- * parse the input and output operands
- */
- if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
- if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
- RETURN_ERROR;
- if (!Parse_String(parseState, ","))
- RETURN_ERROR1("Expected ,");
- }
- else if (instMatch.outputs == OUTPUT_NONE) {
- if (instMatch.opcode == OPCODE_KIL_NV) {
- /* This is a little weird, the cond code info is in
- * the dest register.
- */
- if (!Parse_CondCodeMask(parseState, &inst->DstReg))
- RETURN_ERROR;
- }
- else {
- ASSERT(instMatch.opcode == OPCODE_PRINT);
- }
- }
-
- if (instMatch.inputs == INPUT_1V) {
- if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
- RETURN_ERROR;
- }
- else if (instMatch.inputs == INPUT_2V) {
- if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
- RETURN_ERROR;
- if (!Parse_String(parseState, ","))
- RETURN_ERROR1("Expected ,");
- if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
- RETURN_ERROR;
- }
- else if (instMatch.inputs == INPUT_3V) {
- if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
- RETURN_ERROR;
- if (!Parse_String(parseState, ","))
- RETURN_ERROR1("Expected ,");
- if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
- RETURN_ERROR;
- if (!Parse_String(parseState, ","))
- RETURN_ERROR1("Expected ,");
- if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
- RETURN_ERROR;
- }
- else if (instMatch.inputs == INPUT_1S) {
- if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
- RETURN_ERROR;
- }
- else if (instMatch.inputs == INPUT_2S) {
- if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
- RETURN_ERROR;
- if (!Parse_String(parseState, ","))
- RETURN_ERROR1("Expected ,");
- if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
- RETURN_ERROR;
- }
- else if (instMatch.inputs == INPUT_CC) {
- /* XXX to-do */
- }
- else if (instMatch.inputs == INPUT_1V_T) {
- GLubyte unit, idx;
- if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
- RETURN_ERROR;
- if (!Parse_String(parseState, ","))
- RETURN_ERROR1("Expected ,");
- if (!Parse_TextureImageId(parseState, &unit, &idx))
- RETURN_ERROR;
- inst->TexSrcUnit = unit;
- inst->TexSrcTarget = idx;
- }
- else if (instMatch.inputs == INPUT_3V_T) {
- GLubyte unit, idx;
- if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
- RETURN_ERROR;
- if (!Parse_String(parseState, ","))
- RETURN_ERROR1("Expected ,");
- if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
- RETURN_ERROR;
- if (!Parse_String(parseState, ","))
- RETURN_ERROR1("Expected ,");
- if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
- RETURN_ERROR;
- if (!Parse_String(parseState, ","))
- RETURN_ERROR1("Expected ,");
- if (!Parse_TextureImageId(parseState, &unit, &idx))
- RETURN_ERROR;
- inst->TexSrcUnit = unit;
- inst->TexSrcTarget = idx;
- }
- else if (instMatch.inputs == INPUT_1V_S) {
- if (!Parse_PrintInstruction(parseState, inst))
- RETURN_ERROR;
- }
-
- /* end of statement semicolon */
- if (!Parse_String(parseState, ";"))
- RETURN_ERROR1("Expected ;");
-
- parseState->numInst++;
-
- if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
- RETURN_ERROR1("Program too long");
- }
- }
- return GL_TRUE;
-}
-
-
-
-/**
- * Parse/compile the 'str' returning the compiled 'program'.
- * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
- * indicates the position of the error in 'str'.
- */
-void
-_mesa_parse_nv_fragment_program(struct gl_context *ctx, GLenum dstTarget,
- const GLubyte *str, GLsizei len,
- struct gl_fragment_program *program)
-{
- struct parse_state parseState;
- struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
- struct prog_instruction *newInst;
- GLenum target;
- GLubyte *programString;
-
- /* Make a null-terminated copy of the program string */
- programString = (GLubyte *) MALLOC(len + 1);
- if (!programString) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
- return;
- }
- memcpy(programString, str, len);
- programString[len] = 0;
-
- /* Get ready to parse */
- memset(&parseState, 0, sizeof(struct parse_state));
- parseState.ctx = ctx;
- parseState.start = programString;
- parseState.program = program;
- parseState.numInst = 0;
- parseState.curLine = programString;
- parseState.parameters = _mesa_new_parameter_list();
-
- /* Reset error state */
- _mesa_set_program_error(ctx, -1, NULL);
-
- /* check the program header */
- if (strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
- target = GL_FRAGMENT_PROGRAM_NV;
- parseState.pos = programString + 7;
- }
- else if (strncmp((const char *) programString, "!!FCP1.0", 8) == 0) {
- /* fragment / register combiner program - not supported */
- _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
- _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
- return;
- }
- else {
- /* invalid header */
- _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
- _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
- return;
- }
-
- /* make sure target and header match */
- if (target != dstTarget) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
- target, dstTarget);
- return;
- }
-
- if (Parse_InstructionSequence(&parseState, instBuffer)) {
- GLuint u;
- /* successful parse! */
-
- if (parseState.outputsWritten == 0) {
- /* must write at least one output! */
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "Invalid fragment program - no outputs written.");
- return;
- }
-
- /* copy the compiled instructions */
- assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
- newInst = _mesa_alloc_instructions(parseState.numInst);
- if (!newInst) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
- return; /* out of memory */
- }
- _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
-
- /* install the program */
- program->Base.Target = target;
- if (program->Base.String) {
- FREE(program->Base.String);
- }
- program->Base.String = programString;
- program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
- if (program->Base.Instructions) {
- free(program->Base.Instructions);
- }
- program->Base.Instructions = newInst;
- program->Base.NumInstructions = parseState.numInst;
- program->Base.InputsRead = parseState.inputsRead;
- program->Base.OutputsWritten = parseState.outputsWritten;
- for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
- program->Base.TexturesUsed[u] = parseState.texturesUsed[u];
-
- /* save program parameters */
- program->Base.Parameters = parseState.parameters;
-
- /* allocate registers for declared program parameters */
-#if 00
- _mesa_assign_program_registers(&(program->SymbolTable));
-#endif
-
-#ifdef DEBUG_foo
- printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
- _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
- printf("----------------------------------\n");
-#endif
- }
- else {
- /* Error! */
- _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
- /* NOTE: _mesa_set_program_error would have been called already */
- }
-}
-
-
-const char *
-_mesa_nv_fragment_input_register_name(GLuint i)
-{
- ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
- return InputRegisters[i];
-}
-
+/* + * Mesa 3-D graphics library + * Version: 6.5 + * + * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file nvfragparse.c + * NVIDIA fragment program parser. + * \author Brian Paul + */ + +/* + * Regarding GL_NV_fragment_program: + * + * Portions of this software may use or implement intellectual + * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims + * any and all warranties with respect to such intellectual property, + * including any use thereof or modifications thereto. + */ + +#include "main/glheader.h" +#include "main/context.h" +#include "main/imports.h" +#include "main/macros.h" +#include "program.h" +#include "prog_parameter.h" +#include "prog_print.h" +#include "prog_instruction.h" +#include "nvfragparse.h" + + +#define INPUT_1V 1 +#define INPUT_2V 2 +#define INPUT_3V 3 +#define INPUT_1S 4 +#define INPUT_2S 5 +#define INPUT_CC 6 +#define INPUT_1V_T 7 /* one source vector, plus textureId */ +#define INPUT_3V_T 8 /* one source vector, plus textureId */ +#define INPUT_NONE 9 +#define INPUT_1V_S 10 /* a string and a vector register */ +#define OUTPUT_V 20 +#define OUTPUT_S 21 +#define OUTPUT_NONE 22 + +/* IRIX defines some of these */ +#undef _R +#undef _H +#undef _X +#undef _C +#undef _S + +/* Optional suffixes */ +#define _R FLOAT32 /* float */ +#define _H FLOAT16 /* half-float */ +#define _X FIXED12 /* fixed */ +#define _C 0x08 /* set cond codes */ +#define _S 0x10 /* saturate, clamp result to [0,1] */ + +struct instruction_pattern { + const char *name; + enum prog_opcode opcode; + GLuint inputs; + GLuint outputs; + GLuint suffixes; +}; + +static const struct instruction_pattern Instructions[] = { + { "ADD", OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "COS", OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, + { "DDX", OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, + { "DDY", OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, + { "DP3", OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S }, + { "DP4", OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S }, + { "DST", OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H | _C | _S }, + { "EX2", OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, + { "FLR", OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "FRC", OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "KIL", OPCODE_KIL_NV, INPUT_CC, OUTPUT_NONE, 0 }, + { "LG2", OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, + { "LIT", OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, + { "LRP", OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "MAD", OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "MAX", OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "MIN", OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "MOV", OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "MUL", OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "PK2H", OPCODE_PK2H, INPUT_1V, OUTPUT_S, 0 }, + { "PK2US", OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0 }, + { "PK4B", OPCODE_PK4B, INPUT_1V, OUTPUT_S, 0 }, + { "PK4UB", OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0 }, + { "POW", OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H | _C | _S }, + { "RCP", OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, + { "RFL", OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H | _C | _S }, + { "RSQ", OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, + { "SEQ", OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "SFL", OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "SGE", OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "SGT", OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "SIN", OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, + { "SLE", OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "SLT", OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "SNE", OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "STR", OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "SUB", OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, + { "TEX", OPCODE_TEX, INPUT_1V_T, OUTPUT_V, _C | _S }, + { "TXD", OPCODE_TXD, INPUT_3V_T, OUTPUT_V, _C | _S }, + { "TXP", OPCODE_TXP_NV, INPUT_1V_T, OUTPUT_V, _C | _S }, + { "UP2H", OPCODE_UP2H, INPUT_1S, OUTPUT_V, _C | _S }, + { "UP2US", OPCODE_UP2US, INPUT_1S, OUTPUT_V, _C | _S }, + { "UP4B", OPCODE_UP4B, INPUT_1S, OUTPUT_V, _C | _S }, + { "UP4UB", OPCODE_UP4UB, INPUT_1S, OUTPUT_V, _C | _S }, + { "X2D", OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H | _C | _S }, + { "PRINT", OPCODE_PRINT, INPUT_1V_S, OUTPUT_NONE, 0 }, + { NULL, (enum prog_opcode) -1, 0, 0, 0 } +}; + + +/* + * Information needed or computed during parsing. + * Remember, we can't modify the target program object until we've + * _successfully_ parsed the program text. + */ +struct parse_state { + struct gl_context *ctx; + const GLubyte *start; /* start of program string */ + const GLubyte *pos; /* current position */ + const GLubyte *curLine; + struct gl_fragment_program *program; /* current program */ + + struct gl_program_parameter_list *parameters; + + GLuint numInst; /* number of instructions parsed */ + GLuint inputsRead; /* bitmask of input registers used */ + GLuint outputsWritten; /* bitmask of 1 << FRAG_OUTPUT_* bits */ + GLuint texturesUsed[MAX_TEXTURE_IMAGE_UNITS]; +}; + + + +/* + * Called whenever we find an error during parsing. + */ +static void +record_error(struct parse_state *parseState, const char *msg, int lineNo) +{ +#ifdef DEBUG + GLint line, column; + const GLubyte *lineStr; + lineStr = _mesa_find_line_column(parseState->start, + parseState->pos, &line, &column); + _mesa_debug(parseState->ctx, + "nvfragparse.c(%d): line %d, column %d:%s (%s)\n", + lineNo, line, column, (char *) lineStr, msg); + free((void *) lineStr); +#else + (void) lineNo; +#endif + + /* Check that no error was already recorded. Only record the first one. */ + if (parseState->ctx->Program.ErrorString[0] == 0) { + _mesa_set_program_error(parseState->ctx, + parseState->pos - parseState->start, + msg); + } +} + + +#define RETURN_ERROR \ +do { \ + record_error(parseState, "Unexpected end of input.", __LINE__); \ + return GL_FALSE; \ +} while(0) + +#define RETURN_ERROR1(msg) \ +do { \ + record_error(parseState, msg, __LINE__); \ + return GL_FALSE; \ +} while(0) + +#define RETURN_ERROR2(msg1, msg2) \ +do { \ + char err[1000]; \ + sprintf(err, "%s %s", msg1, msg2); \ + record_error(parseState, err, __LINE__); \ + return GL_FALSE; \ +} while(0) + + + + +/* + * Search a list of instruction structures for a match. + */ +static struct instruction_pattern +MatchInstruction(const GLubyte *token) +{ + const struct instruction_pattern *inst; + struct instruction_pattern result; + + result.name = NULL; + result.opcode = MAX_OPCODE; /* i.e. invalid instruction */ + result.inputs = 0; + result.outputs = 0; + result.suffixes = 0; + + for (inst = Instructions; inst->name; inst++) { + if (strncmp((const char *) token, inst->name, 3) == 0) { + /* matched! */ + int i = 3; + result = *inst; + result.suffixes = 0; + /* look at suffix */ + if (token[i] == 'R') { + result.suffixes |= _R; + i++; + } + else if (token[i] == 'H') { + result.suffixes |= _H; + i++; + } + else if (token[i] == 'X') { + result.suffixes |= _X; + i++; + } + if (token[i] == 'C') { + result.suffixes |= _C; + i++; + } + if (token[i] == '_' && token[i+1] == 'S' && + token[i+2] == 'A' && token[i+3] == 'T') { + result.suffixes |= _S; + } + return result; + } + } + + return result; +} + + + + +/**********************************************************************/ + + +static GLboolean IsLetter(GLubyte b) +{ + return (b >= 'a' && b <= 'z') || + (b >= 'A' && b <= 'Z') || + (b == '_') || + (b == '$'); +} + + +static GLboolean IsDigit(GLubyte b) +{ + return b >= '0' && b <= '9'; +} + + +static GLboolean IsWhitespace(GLubyte b) +{ + return b == ' ' || b == '\t' || b == '\n' || b == '\r'; +} + + +/** + * Starting at 'str' find the next token. A token can be an integer, + * an identifier or punctuation symbol. + * \return <= 0 we found an error, else, return number of characters parsed. + */ +static GLint +GetToken(struct parse_state *parseState, GLubyte *token) +{ + const GLubyte *str = parseState->pos; + GLint i = 0, j = 0; + + token[0] = 0; + + /* skip whitespace and comments */ + while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) { + if (str[i] == '#') { + /* skip comment */ + while (str[i] && (str[i] != '\n' && str[i] != '\r')) { + i++; + } + if (str[i] == '\n' || str[i] == '\r') + parseState->curLine = str + i + 1; + } + else { + /* skip whitespace */ + if (str[i] == '\n' || str[i] == '\r') + parseState->curLine = str + i + 1; + i++; + } + } + + if (str[i] == 0) + return -i; + + /* try matching an integer */ + while (str[i] && IsDigit(str[i])) { + token[j++] = str[i++]; + } + if (j > 0 || !str[i]) { + token[j] = 0; + return i; + } + + /* try matching an identifier */ + if (IsLetter(str[i])) { + while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) { + token[j++] = str[i++]; + } + token[j] = 0; + return i; + } + + /* punctuation character */ + if (str[i]) { + token[0] = str[i++]; + token[1] = 0; + return i; + } + + /* end of input */ + token[0] = 0; + return i; +} + + +/** + * Get next token from input stream and increment stream pointer past token. + */ +static GLboolean +Parse_Token(struct parse_state *parseState, GLubyte *token) +{ + GLint i; + i = GetToken(parseState, token); + if (i <= 0) { + parseState->pos += (-i); + return GL_FALSE; + } + parseState->pos += i; + return GL_TRUE; +} + + +/** + * Get next token from input stream but don't increment stream pointer. + */ +static GLboolean +Peek_Token(struct parse_state *parseState, GLubyte *token) +{ + GLint i, len; + i = GetToken(parseState, token); + if (i <= 0) { + parseState->pos += (-i); + return GL_FALSE; + } + len = (GLint) strlen((const char *) token); + parseState->pos += (i - len); + return GL_TRUE; +} + + +/**********************************************************************/ + +static const char *InputRegisters[MAX_NV_FRAGMENT_PROGRAM_INPUTS + 1] = { + "WPOS", "COL0", "COL1", "FOGC", + "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL +}; + + + +/**********************************************************************/ + +/** + * Try to match 'pattern' as the next token after any whitespace/comments. + */ +static GLboolean +Parse_String(struct parse_state *parseState, const char *pattern) +{ + const GLubyte *m; + GLint i; + + /* skip whitespace and comments */ + while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') { + if (*parseState->pos == '#') { + while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) { + parseState->pos += 1; + } + if (*parseState->pos == '\n' || *parseState->pos == '\r') + parseState->curLine = parseState->pos + 1; + } + else { + /* skip whitespace */ + if (*parseState->pos == '\n' || *parseState->pos == '\r') + parseState->curLine = parseState->pos + 1; + parseState->pos += 1; + } + } + + /* Try to match the pattern */ + m = parseState->pos; + for (i = 0; pattern[i]; i++) { + if (*m != (GLubyte) pattern[i]) + return GL_FALSE; + m += 1; + } + parseState->pos = m; + + return GL_TRUE; /* success */ +} + + +static GLboolean +Parse_Identifier(struct parse_state *parseState, GLubyte *ident) +{ + if (!Parse_Token(parseState, ident)) + RETURN_ERROR; + if (IsLetter(ident[0])) + return GL_TRUE; + else + RETURN_ERROR1("Expected an identfier"); +} + + +/** + * Parse a floating point constant, or a defined symbol name. + * [+/-]N[.N[eN]] + * Output: number[0 .. 3] will get the value. + */ +static GLboolean +Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number) +{ + char *end = NULL; + + *number = (GLfloat) _mesa_strtof((const char *) parseState->pos, &end); + + if (end && end > (char *) parseState->pos) { + /* got a number */ + parseState->pos = (GLubyte *) end; + number[1] = *number; + number[2] = *number; + number[3] = *number; + return GL_TRUE; + } + else { + /* should be an identifier */ + GLubyte ident[100]; + const GLfloat *constant; + if (!Parse_Identifier(parseState, ident)) + RETURN_ERROR1("Expected an identifier"); + constant = (GLfloat *)_mesa_lookup_parameter_value(parseState->parameters, + -1, + (const char *) ident); + /* XXX Check that it's a constant and not a parameter */ + if (!constant) { + RETURN_ERROR1("Undefined symbol"); + } + else { + COPY_4V(number, constant); + return GL_TRUE; + } + } +} + + + +/** + * Parse a vector constant, one of: + * { float } + * { float, float } + * { float, float, float } + * { float, float, float, float } + */ +static GLboolean +Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec) +{ + /* "{" was already consumed */ + + ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0); + + if (!Parse_ScalarConstant(parseState, vec+0)) /* X */ + return GL_FALSE; + + if (Parse_String(parseState, "}")) { + return GL_TRUE; + } + + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected comma in vector constant"); + + if (!Parse_ScalarConstant(parseState, vec+1)) /* Y */ + return GL_FALSE; + + if (Parse_String(parseState, "}")) { + return GL_TRUE; + } + + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected comma in vector constant"); + + if (!Parse_ScalarConstant(parseState, vec+2)) /* Z */ + return GL_FALSE; + + if (Parse_String(parseState, "}")) { + return GL_TRUE; + } + + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected comma in vector constant"); + + if (!Parse_ScalarConstant(parseState, vec+3)) /* W */ + return GL_FALSE; + + if (!Parse_String(parseState, "}")) + RETURN_ERROR1("Expected closing brace in vector constant"); + + return GL_TRUE; +} + + +/** + * Parse <number>, <varname> or {a, b, c, d}. + * Return number of values in the vector or scalar, or zero if parse error. + */ +static GLuint +Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec) +{ + if (Parse_String(parseState, "{")) { + return Parse_VectorConstant(parseState, vec); + } + else { + GLboolean b = Parse_ScalarConstant(parseState, vec); + if (b) { + vec[1] = vec[2] = vec[3] = vec[0]; + } + return b; + } +} + + +/** + * Parse a texture image source: + * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT] + */ +static GLboolean +Parse_TextureImageId(struct parse_state *parseState, + GLubyte *texUnit, GLubyte *texTargetBit) +{ + GLubyte imageSrc[100]; + GLint unit; + + if (!Parse_Token(parseState, imageSrc)) + RETURN_ERROR; + + if (imageSrc[0] != 'T' || + imageSrc[1] != 'E' || + imageSrc[2] != 'X') { + RETURN_ERROR1("Expected TEX# source"); + } + unit = atoi((const char *) imageSrc + 3); + if ((unit < 0 || unit > MAX_TEXTURE_IMAGE_UNITS) || + (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) { + RETURN_ERROR1("Invalied TEX# source index"); + } + *texUnit = unit; + + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + + if (Parse_String(parseState, "1D")) { + *texTargetBit = TEXTURE_1D_BIT; + } + else if (Parse_String(parseState, "2D")) { + *texTargetBit = TEXTURE_2D_BIT; + } + else if (Parse_String(parseState, "3D")) { + *texTargetBit = TEXTURE_3D_BIT; + } + else if (Parse_String(parseState, "CUBE")) { + *texTargetBit = TEXTURE_CUBE_BIT; + } + else if (Parse_String(parseState, "RECT")) { + *texTargetBit = TEXTURE_RECT_BIT; + } + else { + RETURN_ERROR1("Invalid texture target token"); + } + + /* update record of referenced texture units */ + parseState->texturesUsed[*texUnit] |= *texTargetBit; + if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) { + RETURN_ERROR1("Only one texture target can be used per texture unit."); + } + + return GL_TRUE; +} + + +/** + * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix + * like .wxyz, .xxyy, etc and return the swizzle indexes. + */ +static GLboolean +Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4]) +{ + if (token[1] == 0) { + /* single letter swizzle (scalar) */ + if (token[0] == 'x') + ASSIGN_4V(swizzle, 0, 0, 0, 0); + else if (token[0] == 'y') + ASSIGN_4V(swizzle, 1, 1, 1, 1); + else if (token[0] == 'z') + ASSIGN_4V(swizzle, 2, 2, 2, 2); + else if (token[0] == 'w') + ASSIGN_4V(swizzle, 3, 3, 3, 3); + else + return GL_FALSE; + } + else { + /* 4-component swizzle (vector) */ + GLint k; + for (k = 0; k < 4 && token[k]; k++) { + if (token[k] == 'x') + swizzle[k] = 0; + else if (token[k] == 'y') + swizzle[k] = 1; + else if (token[k] == 'z') + swizzle[k] = 2; + else if (token[k] == 'w') + swizzle[k] = 3; + else + return GL_FALSE; + } + if (k != 4) + return GL_FALSE; + } + return GL_TRUE; +} + + +static GLboolean +Parse_CondCodeMask(struct parse_state *parseState, + struct prog_dst_register *dstReg) +{ + if (Parse_String(parseState, "EQ")) + dstReg->CondMask = COND_EQ; + else if (Parse_String(parseState, "GE")) + dstReg->CondMask = COND_GE; + else if (Parse_String(parseState, "GT")) + dstReg->CondMask = COND_GT; + else if (Parse_String(parseState, "LE")) + dstReg->CondMask = COND_LE; + else if (Parse_String(parseState, "LT")) + dstReg->CondMask = COND_LT; + else if (Parse_String(parseState, "NE")) + dstReg->CondMask = COND_NE; + else if (Parse_String(parseState, "TR")) + dstReg->CondMask = COND_TR; + else if (Parse_String(parseState, "FL")) + dstReg->CondMask = COND_FL; + else + RETURN_ERROR1("Invalid condition code mask"); + + /* look for optional .xyzw swizzle */ + if (Parse_String(parseState, ".")) { + GLubyte token[100]; + GLuint swz[4]; + + if (!Parse_Token(parseState, token)) /* get xyzw suffix */ + RETURN_ERROR; + + if (!Parse_SwizzleSuffix(token, swz)) + RETURN_ERROR1("Invalid swizzle suffix"); + + dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]); + } + + return GL_TRUE; +} + + +/** + * Parse a temporary register: Rnn or Hnn + */ +static GLboolean +Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum) +{ + GLubyte token[100]; + + /* Should be 'R##' or 'H##' */ + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + if (token[0] != 'R' && token[0] != 'H') + RETURN_ERROR1("Expected R## or H##"); + + if (IsDigit(token[1])) { + GLint reg = atoi((const char *) (token + 1)); + if (token[0] == 'H') + reg += 32; + if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS) + RETURN_ERROR1("Invalid temporary register name"); + *tempRegNum = reg; + } + else { + RETURN_ERROR1("Invalid temporary register name"); + } + + return GL_TRUE; +} + + +/** + * Parse a write-only dummy register: RC or HC. + */ +static GLboolean +Parse_DummyReg(struct parse_state *parseState, GLint *regNum) +{ + if (Parse_String(parseState, "RC")) { + *regNum = 0; + } + else if (Parse_String(parseState, "HC")) { + *regNum = 1; + } + else { + RETURN_ERROR1("Invalid write-only register name"); + } + + return GL_TRUE; +} + + +/** + * Parse a program local parameter register "p[##]" + */ +static GLboolean +Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum) +{ + GLubyte token[100]; + + if (!Parse_String(parseState, "p[")) + RETURN_ERROR1("Expected p["); + + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (IsDigit(token[0])) { + /* a numbered program parameter register */ + GLint reg = atoi((const char *) token); + if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS) + RETURN_ERROR1("Invalid constant program number"); + *regNum = reg; + } + else { + RETURN_ERROR; + } + + if (!Parse_String(parseState, "]")) + RETURN_ERROR1("Expected ]"); + + return GL_TRUE; +} + + +/** + * Parse f[name] - fragment input register + */ +static GLboolean +Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum) +{ + GLubyte token[100]; + GLint j; + + /* Match 'f[' */ + if (!Parse_String(parseState, "f[")) + RETURN_ERROR1("Expected f["); + + /* get <name> and look for match */ + if (!Parse_Token(parseState, token)) { + RETURN_ERROR; + } + for (j = 0; InputRegisters[j]; j++) { + if (strcmp((const char *) token, InputRegisters[j]) == 0) { + *tempRegNum = j; + parseState->inputsRead |= (1 << j); + break; + } + } + if (!InputRegisters[j]) { + /* unknown input register label */ + RETURN_ERROR2("Invalid register name", token); + } + + /* Match '[' */ + if (!Parse_String(parseState, "]")) + RETURN_ERROR1("Expected ]"); + + return GL_TRUE; +} + + +static GLboolean +Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum) +{ + GLubyte token[100]; + + /* Match "o[" */ + if (!Parse_String(parseState, "o[")) + RETURN_ERROR1("Expected o["); + + /* Get output reg name */ + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + /* try to match an output register name */ + if (strcmp((char *) token, "COLR") == 0 || + strcmp((char *) token, "COLH") == 0) { + /* note that we don't distinguish between COLR and COLH */ + *outputRegNum = FRAG_RESULT_COLOR; + parseState->outputsWritten |= (1 << FRAG_RESULT_COLOR); + } + else if (strcmp((char *) token, "DEPR") == 0) { + *outputRegNum = FRAG_RESULT_DEPTH; + parseState->outputsWritten |= (1 << FRAG_RESULT_DEPTH); + } + else { + RETURN_ERROR1("Invalid output register name"); + } + + /* Match ']' */ + if (!Parse_String(parseState, "]")) + RETURN_ERROR1("Expected ]"); + + return GL_TRUE; +} + + +static GLboolean +Parse_MaskedDstReg(struct parse_state *parseState, + struct prog_dst_register *dstReg) +{ + GLubyte token[100]; + GLint idx; + + /* Dst reg can be R<n>, H<n>, o[n], RC or HC */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + if (strcmp((const char *) token, "RC") == 0 || + strcmp((const char *) token, "HC") == 0) { + /* a write-only register */ + dstReg->File = PROGRAM_WRITE_ONLY; + if (!Parse_DummyReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else if (token[0] == 'R' || token[0] == 'H') { + /* a temporary register */ + dstReg->File = PROGRAM_TEMPORARY; + if (!Parse_TempReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else if (token[0] == 'o') { + /* an output register */ + dstReg->File = PROGRAM_OUTPUT; + if (!Parse_OutputReg(parseState, &idx)) + RETURN_ERROR; + dstReg->Index = idx; + } + else { + RETURN_ERROR1("Invalid destination register name"); + } + + /* Parse optional write mask */ + if (Parse_String(parseState, ".")) { + /* got a mask */ + GLint k = 0; + + if (!Parse_Token(parseState, token)) /* get xyzw writemask */ + RETURN_ERROR; + + dstReg->WriteMask = 0; + + if (token[k] == 'x') { + dstReg->WriteMask |= WRITEMASK_X; + k++; + } + if (token[k] == 'y') { + dstReg->WriteMask |= WRITEMASK_Y; + k++; + } + if (token[k] == 'z') { + dstReg->WriteMask |= WRITEMASK_Z; + k++; + } + if (token[k] == 'w') { + dstReg->WriteMask |= WRITEMASK_W; + k++; + } + if (k == 0) { + RETURN_ERROR1("Invalid writemask character"); + } + + } + else { + dstReg->WriteMask = WRITEMASK_XYZW; + } + + /* optional condition code mask */ + if (Parse_String(parseState, "(")) { + /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */ + /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */ + if (!Parse_CondCodeMask(parseState, dstReg)) + RETURN_ERROR; + + if (!Parse_String(parseState, ")")) /* consume ")" */ + RETURN_ERROR1("Expected )"); + + return GL_TRUE; + } + else { + /* no cond code mask */ + dstReg->CondMask = COND_TR; + dstReg->CondSwizzle = SWIZZLE_NOOP; + return GL_TRUE; + } +} + + +/** + * Parse a vector source (register, constant, etc): + * <vectorSrc> ::= <absVectorSrc> + * | <baseVectorSrc> + * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|" + */ +static GLboolean +Parse_VectorSrc(struct parse_state *parseState, + struct prog_src_register *srcReg) +{ + GLfloat sign = 1.0F; + GLubyte token[100]; + GLint idx; + GLuint negateBase, negateAbs; + + /* + * First, take care of +/- and absolute value stuff. + */ + if (Parse_String(parseState, "-")) + sign = -1.0F; + else if (Parse_String(parseState, "+")) + sign = +1.0F; + + if (Parse_String(parseState, "|")) { + srcReg->Abs = GL_TRUE; + negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE; + + if (Parse_String(parseState, "-")) + negateBase = NEGATE_XYZW; + else if (Parse_String(parseState, "+")) + negateBase = NEGATE_NONE; + else + negateBase = NEGATE_NONE; + } + else { + srcReg->Abs = GL_FALSE; + negateAbs = NEGATE_NONE; + negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE; + } + + srcReg->Negate = srcReg->Abs ? negateAbs : negateBase; + + /* This should be the real src vector/register name */ + if (!Peek_Token(parseState, token)) + RETURN_ERROR; + + /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar + * literal or vector literal. + */ + if (token[0] == 'R' || token[0] == 'H') { + srcReg->File = PROGRAM_TEMPORARY; + if (!Parse_TempReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else if (token[0] == 'f') { + /* XXX this might be an identifier! */ + srcReg->File = PROGRAM_INPUT; + if (!Parse_FragReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else if (token[0] == 'p') { + /* XXX this might be an identifier! */ + srcReg->File = PROGRAM_LOCAL_PARAM; + if (!Parse_ProgramParamReg(parseState, &idx)) + RETURN_ERROR; + srcReg->Index = idx; + } + else if (IsLetter(token[0])){ + GLubyte ident[100]; + GLint paramIndex; + if (!Parse_Identifier(parseState, ident)) + RETURN_ERROR; + paramIndex = _mesa_lookup_parameter_index(parseState->parameters, + -1, (const char *) ident); + if (paramIndex < 0) { + RETURN_ERROR2("Undefined constant or parameter: ", ident); + } + srcReg->File = PROGRAM_NAMED_PARAM; + srcReg->Index = paramIndex; + } + else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){ + /* literal scalar constant */ + GLfloat values[4]; + GLuint paramIndex; + if (!Parse_ScalarConstant(parseState, values)) + RETURN_ERROR; + paramIndex = _mesa_add_unnamed_constant(parseState->parameters, + (gl_constant_value *) 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, + (gl_constant_value *) 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, + (gl_constant_value *) 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, + (gl_constant_value *) values, + 4, NULL); + srcReg->Index = paramIndex; + srcReg->File = PROGRAM_NAMED_PARAM; + needSuffix = GL_FALSE; + } + else { + RETURN_ERROR2("Invalid scalar source argument", token); + } + + srcReg->Swizzle = 0; + if (needSuffix) { + /* parse .[xyzw] suffix */ + if (!Parse_String(parseState, ".")) + RETURN_ERROR1("Expected ."); + + if (!Parse_Token(parseState, token)) + RETURN_ERROR; + + if (token[0] == 'x' && token[1] == 0) { + srcReg->Swizzle = 0; + } + else if (token[0] == 'y' && token[1] == 0) { + srcReg->Swizzle = 1; + } + else if (token[0] == 'z' && token[1] == 0) { + srcReg->Swizzle = 2; + } + else if (token[0] == 'w' && token[1] == 0) { + srcReg->Swizzle = 3; + } + else { + RETURN_ERROR1("Invalid scalar source suffix"); + } + } + + /* Finish absolute value */ + if (srcReg->Abs && !Parse_String(parseState, "|")) { + RETURN_ERROR1("Expected |"); + } + + return GL_TRUE; +} + + +static GLboolean +Parse_PrintInstruction(struct parse_state *parseState, + struct prog_instruction *inst) +{ + const GLubyte *str; + GLubyte *msg; + GLuint len; + GLint idx; + + /* The first argument is a literal string 'just like this' */ + if (!Parse_String(parseState, "'")) + RETURN_ERROR1("Expected '"); + + str = parseState->pos; + for (len = 0; str[len] != '\''; len++) /* find closing quote */ + ; + parseState->pos += len + 1; + msg = (GLubyte*) malloc(len + 1); + + memcpy(msg, str, len); + msg[len] = 0; + inst->Data = msg; + + if (Parse_String(parseState, ",")) { + /* got an optional register to print */ + GLubyte token[100]; + GetToken(parseState, token); + if (token[0] == 'o') { + /* dst reg */ + if (!Parse_OutputReg(parseState, &idx)) + RETURN_ERROR; + inst->SrcReg[0].Index = idx; + inst->SrcReg[0].File = PROGRAM_OUTPUT; + } + else { + /* src reg */ + if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + } + } + else { + inst->SrcReg[0].File = PROGRAM_UNDEFINED; + } + + inst->SrcReg[0].Swizzle = SWIZZLE_NOOP; + inst->SrcReg[0].Abs = GL_FALSE; + inst->SrcReg[0].Negate = NEGATE_NONE; + + return GL_TRUE; +} + + +static GLboolean +Parse_InstructionSequence(struct parse_state *parseState, + struct prog_instruction program[]) +{ + while (1) { + struct prog_instruction *inst = program + parseState->numInst; + struct instruction_pattern instMatch; + GLubyte token[100]; + + /* Initialize the instruction */ + _mesa_init_instructions(inst, 1); + + /* special instructions */ + if (Parse_String(parseState, "DEFINE")) { + GLubyte id[100]; + GLfloat value[7]; /* yes, 7 to be safe */ + if (!Parse_Identifier(parseState, id)) + RETURN_ERROR; + /* XXX make sure id is not a reserved identifer, like R9 */ + if (!Parse_String(parseState, "=")) + RETURN_ERROR1("Expected ="); + if (!Parse_VectorOrScalarConstant(parseState, value)) + RETURN_ERROR; + if (!Parse_String(parseState, ";")) + RETURN_ERROR1("Expected ;"); + if (_mesa_lookup_parameter_index(parseState->parameters, + -1, (const char *) id) >= 0) { + RETURN_ERROR2(id, "already defined"); + } + _mesa_add_named_parameter(parseState->parameters, + (const char *) id, + (gl_constant_value *) 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, + (gl_constant_value *) value); + } + else if (Parse_String(parseState, "END")) { + inst->Opcode = OPCODE_END; + parseState->numInst++; + if (Parse_Token(parseState, token)) { + RETURN_ERROR1("Code after END opcode."); + } + break; + } + else { + /* general/arithmetic instruction */ + + /* get token */ + if (!Parse_Token(parseState, token)) { + RETURN_ERROR1("Missing END instruction."); + } + + /* try to find matching instuction */ + instMatch = MatchInstruction(token); + if (instMatch.opcode >= MAX_OPCODE) { + /* bad instruction name */ + RETURN_ERROR2("Unexpected token: ", token); + } + + inst->Opcode = instMatch.opcode; + inst->Precision = instMatch.suffixes & (_R | _H | _X); + inst->SaturateMode = (instMatch.suffixes & (_S)) + ? SATURATE_ZERO_ONE : SATURATE_OFF; + inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE; + + /* + * parse the input and output operands + */ + if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) { + if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + } + else if (instMatch.outputs == OUTPUT_NONE) { + if (instMatch.opcode == OPCODE_KIL_NV) { + /* This is a little weird, the cond code info is in + * the dest register. + */ + if (!Parse_CondCodeMask(parseState, &inst->DstReg)) + RETURN_ERROR; + } + else { + ASSERT(instMatch.opcode == OPCODE_PRINT); + } + } + + if (instMatch.inputs == INPUT_1V) { + if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + } + else if (instMatch.inputs == INPUT_2V) { + if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) + RETURN_ERROR; + } + else if (instMatch.inputs == INPUT_3V) { + if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_VectorSrc(parseState, &inst->SrcReg[2])) + RETURN_ERROR; + } + else if (instMatch.inputs == INPUT_1S) { + if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + } + else if (instMatch.inputs == INPUT_2S) { + if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1])) + RETURN_ERROR; + } + else if (instMatch.inputs == INPUT_CC) { + /* XXX to-do */ + } + else if (instMatch.inputs == INPUT_1V_T) { + GLubyte unit, idx; + if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_TextureImageId(parseState, &unit, &idx)) + RETURN_ERROR; + inst->TexSrcUnit = unit; + inst->TexSrcTarget = idx; + } + else if (instMatch.inputs == INPUT_3V_T) { + GLubyte unit, idx; + if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_VectorSrc(parseState, &inst->SrcReg[2])) + RETURN_ERROR; + if (!Parse_String(parseState, ",")) + RETURN_ERROR1("Expected ,"); + if (!Parse_TextureImageId(parseState, &unit, &idx)) + RETURN_ERROR; + inst->TexSrcUnit = unit; + inst->TexSrcTarget = idx; + } + else if (instMatch.inputs == INPUT_1V_S) { + if (!Parse_PrintInstruction(parseState, inst)) + RETURN_ERROR; + } + + /* end of statement semicolon */ + if (!Parse_String(parseState, ";")) + RETURN_ERROR1("Expected ;"); + + parseState->numInst++; + + if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS) + RETURN_ERROR1("Program too long"); + } + } + return GL_TRUE; +} + + + +/** + * Parse/compile the 'str' returning the compiled 'program'. + * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos + * indicates the position of the error in 'str'. + */ +void +_mesa_parse_nv_fragment_program(struct gl_context *ctx, GLenum dstTarget, + const GLubyte *str, GLsizei len, + struct gl_fragment_program *program) +{ + struct parse_state parseState; + struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS]; + struct prog_instruction *newInst; + GLenum target; + GLubyte *programString; + + /* Make a null-terminated copy of the program string */ + programString = (GLubyte *) MALLOC(len + 1); + if (!programString) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + return; + } + memcpy(programString, str, len); + programString[len] = 0; + + /* Get ready to parse */ + memset(&parseState, 0, sizeof(struct parse_state)); + parseState.ctx = ctx; + parseState.start = programString; + parseState.program = program; + parseState.numInst = 0; + parseState.curLine = programString; + parseState.parameters = _mesa_new_parameter_list(); + + /* Reset error state */ + _mesa_set_program_error(ctx, -1, NULL); + + /* check the program header */ + if (strncmp((const char *) programString, "!!FP1.0", 7) == 0) { + target = GL_FRAGMENT_PROGRAM_NV; + parseState.pos = programString + 7; + } + else if (strncmp((const char *) programString, "!!FCP1.0", 8) == 0) { + /* fragment / register combiner program - not supported */ + _mesa_set_program_error(ctx, 0, "Invalid fragment program header"); + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); + return; + } + else { + /* invalid header */ + _mesa_set_program_error(ctx, 0, "Invalid fragment program header"); + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); + return; + } + + /* make sure target and header match */ + if (target != dstTarget) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glLoadProgramNV(target mismatch 0x%x != 0x%x)", + target, dstTarget); + return; + } + + if (Parse_InstructionSequence(&parseState, instBuffer)) { + GLuint u; + /* successful parse! */ + + if (parseState.outputsWritten == 0) { + /* must write at least one output! */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "Invalid fragment program - no outputs written."); + return; + } + + /* copy the compiled instructions */ + assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS); + newInst = _mesa_alloc_instructions(parseState.numInst); + if (!newInst) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); + return; /* out of memory */ + } + _mesa_copy_instructions(newInst, instBuffer, parseState.numInst); + + /* install the program */ + program->Base.Target = target; + if (program->Base.String) { + FREE(program->Base.String); + } + program->Base.String = programString; + program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB; + if (program->Base.Instructions) { + free(program->Base.Instructions); + } + program->Base.Instructions = newInst; + program->Base.NumInstructions = parseState.numInst; + program->Base.InputsRead = parseState.inputsRead; + program->Base.OutputsWritten = parseState.outputsWritten; + for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++) + program->Base.TexturesUsed[u] = parseState.texturesUsed[u]; + + /* save program parameters */ + program->Base.Parameters = parseState.parameters; + + /* allocate registers for declared program parameters */ +#if 00 + _mesa_assign_program_registers(&(program->SymbolTable)); +#endif + +#ifdef DEBUG_foo + printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id); + _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0); + printf("----------------------------------\n"); +#endif + } + else { + /* Error! */ + _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV"); + /* NOTE: _mesa_set_program_error would have been called already */ + } +} + + +const char * +_mesa_nv_fragment_input_register_name(GLuint i) +{ + ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS); + return InputRegisters[i]; +} + diff --git a/mesalib/src/mesa/program/prog_execute.c b/mesalib/src/mesa/program/prog_execute.c index 28a3e1e20..dbfd1b918 100644 --- a/mesalib/src/mesa/program/prog_execute.c +++ b/mesalib/src/mesa/program/prog_execute.c @@ -1,1895 +1,1895 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.3
- *
- * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file prog_execute.c
- * Software interpreter for vertex/fragment programs.
- * \author Brian Paul
- */
-
-/*
- * NOTE: we do everything in single-precision floating point; we don't
- * currently observe the single/half/fixed-precision qualifiers.
- *
- */
-
-
-#include "main/glheader.h"
-#include "main/colormac.h"
-#include "main/macros.h"
-#include "prog_execute.h"
-#include "prog_instruction.h"
-#include "prog_parameter.h"
-#include "prog_print.h"
-#include "prog_noise.h"
-
-
-/* debug predicate */
-#define DEBUG_PROG 0
-
-
-/**
- * Set x to positive or negative infinity.
- */
-#if defined(USE_IEEE) || defined(_WIN32)
-#define SET_POS_INFINITY(x) \
- do { \
- fi_type fi; \
- fi.i = 0x7F800000; \
- x = fi.f; \
- } while (0)
-#define SET_NEG_INFINITY(x) \
- do { \
- fi_type fi; \
- fi.i = 0xFF800000; \
- x = fi.f; \
- } while (0)
-#elif defined(VMS)
-#define SET_POS_INFINITY(x) x = __MAXFLOAT
-#define SET_NEG_INFINITY(x) x = -__MAXFLOAT
-#else
-#define SET_POS_INFINITY(x) x = (GLfloat) HUGE_VAL
-#define SET_NEG_INFINITY(x) x = (GLfloat) -HUGE_VAL
-#endif
-
-#define SET_FLOAT_BITS(x, bits) ((fi_type *) (void *) &(x))->i = bits
-
-
-static const GLfloat ZeroVec[4] = { 0.0F, 0.0F, 0.0F, 0.0F };
-
-
-
-/**
- * Return TRUE for +0 and other positive values, FALSE otherwise.
- * Used for RCC opcode.
- */
-static INLINE GLboolean
-positive(float x)
-{
- fi_type fi;
- fi.f = x;
- if (fi.i & 0x80000000)
- return GL_FALSE;
- return GL_TRUE;
-}
-
-
-
-/**
- * Return a pointer to the 4-element float vector specified by the given
- * source register.
- */
-static INLINE const GLfloat *
-get_src_register_pointer(const struct prog_src_register *source,
- const struct gl_program_machine *machine)
-{
- const struct gl_program *prog = machine->CurProgram;
- GLint reg = source->Index;
-
- if (source->RelAddr) {
- /* add address register value to src index/offset */
- reg += machine->AddressReg[0][0];
- if (reg < 0) {
- return ZeroVec;
- }
- }
-
- switch (source->File) {
- case PROGRAM_TEMPORARY:
- if (reg >= MAX_PROGRAM_TEMPS)
- return ZeroVec;
- return machine->Temporaries[reg];
-
- case PROGRAM_INPUT:
- if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
- if (reg >= VERT_ATTRIB_MAX)
- return ZeroVec;
- return machine->VertAttribs[reg];
- }
- else {
- if (reg >= FRAG_ATTRIB_MAX)
- return ZeroVec;
- return machine->Attribs[reg][machine->CurElement];
- }
-
- case PROGRAM_OUTPUT:
- if (reg >= MAX_PROGRAM_OUTPUTS)
- return ZeroVec;
- return machine->Outputs[reg];
-
- case PROGRAM_LOCAL_PARAM:
- if (reg >= MAX_PROGRAM_LOCAL_PARAMS)
- return ZeroVec;
- return machine->CurProgram->LocalParams[reg];
-
- case PROGRAM_ENV_PARAM:
- if (reg >= MAX_PROGRAM_ENV_PARAMS)
- return ZeroVec;
- return machine->EnvParams[reg];
-
- case PROGRAM_STATE_VAR:
- /* Fallthrough */
- case PROGRAM_CONSTANT:
- /* Fallthrough */
- case PROGRAM_UNIFORM:
- /* Fallthrough */
- case PROGRAM_NAMED_PARAM:
- if (reg >= (GLint) prog->Parameters->NumParameters)
- return ZeroVec;
- return prog->Parameters->ParameterValues[reg];
-
- case PROGRAM_SYSTEM_VALUE:
- assert(reg < Elements(machine->SystemValues));
- return machine->SystemValues[reg];
-
- default:
- _mesa_problem(NULL,
- "Invalid src register file %d in get_src_register_pointer()",
- source->File);
- return NULL;
- }
-}
-
-
-/**
- * Return a pointer to the 4-element float vector specified by the given
- * destination register.
- */
-static INLINE GLfloat *
-get_dst_register_pointer(const struct prog_dst_register *dest,
- struct gl_program_machine *machine)
-{
- static GLfloat dummyReg[4];
- GLint reg = dest->Index;
-
- if (dest->RelAddr) {
- /* add address register value to src index/offset */
- reg += machine->AddressReg[0][0];
- if (reg < 0) {
- return dummyReg;
- }
- }
-
- switch (dest->File) {
- case PROGRAM_TEMPORARY:
- if (reg >= MAX_PROGRAM_TEMPS)
- return dummyReg;
- return machine->Temporaries[reg];
-
- case PROGRAM_OUTPUT:
- if (reg >= MAX_PROGRAM_OUTPUTS)
- return dummyReg;
- return machine->Outputs[reg];
-
- case PROGRAM_WRITE_ONLY:
- return dummyReg;
-
- default:
- _mesa_problem(NULL,
- "Invalid dest register file %d in get_dst_register_pointer()",
- dest->File);
- return NULL;
- }
-}
-
-
-
-/**
- * Fetch a 4-element float vector from the given source register.
- * Apply swizzling and negating as needed.
- */
-static void
-fetch_vector4(const struct prog_src_register *source,
- const struct gl_program_machine *machine, GLfloat result[4])
-{
- const GLfloat *src = get_src_register_pointer(source, machine);
- ASSERT(src);
-
- if (source->Swizzle == SWIZZLE_NOOP) {
- /* no swizzling */
- COPY_4V(result, src);
- }
- else {
- ASSERT(GET_SWZ(source->Swizzle, 0) <= 3);
- ASSERT(GET_SWZ(source->Swizzle, 1) <= 3);
- ASSERT(GET_SWZ(source->Swizzle, 2) <= 3);
- ASSERT(GET_SWZ(source->Swizzle, 3) <= 3);
- result[0] = src[GET_SWZ(source->Swizzle, 0)];
- result[1] = src[GET_SWZ(source->Swizzle, 1)];
- result[2] = src[GET_SWZ(source->Swizzle, 2)];
- result[3] = src[GET_SWZ(source->Swizzle, 3)];
- }
-
- if (source->Abs) {
- result[0] = FABSF(result[0]);
- result[1] = FABSF(result[1]);
- result[2] = FABSF(result[2]);
- result[3] = FABSF(result[3]);
- }
- if (source->Negate) {
- ASSERT(source->Negate == NEGATE_XYZW);
- result[0] = -result[0];
- result[1] = -result[1];
- result[2] = -result[2];
- result[3] = -result[3];
- }
-
-#ifdef NAN_CHECK
- assert(!IS_INF_OR_NAN(result[0]));
- assert(!IS_INF_OR_NAN(result[0]));
- assert(!IS_INF_OR_NAN(result[0]));
- assert(!IS_INF_OR_NAN(result[0]));
-#endif
-}
-
-
-/**
- * Fetch a 4-element uint vector from the given source register.
- * Apply swizzling but not negation/abs.
- */
-static void
-fetch_vector4ui(const struct prog_src_register *source,
- const struct gl_program_machine *machine, GLuint result[4])
-{
- const GLuint *src = (GLuint *) get_src_register_pointer(source, machine);
- ASSERT(src);
-
- if (source->Swizzle == SWIZZLE_NOOP) {
- /* no swizzling */
- COPY_4V(result, src);
- }
- else {
- ASSERT(GET_SWZ(source->Swizzle, 0) <= 3);
- ASSERT(GET_SWZ(source->Swizzle, 1) <= 3);
- ASSERT(GET_SWZ(source->Swizzle, 2) <= 3);
- ASSERT(GET_SWZ(source->Swizzle, 3) <= 3);
- result[0] = src[GET_SWZ(source->Swizzle, 0)];
- result[1] = src[GET_SWZ(source->Swizzle, 1)];
- result[2] = src[GET_SWZ(source->Swizzle, 2)];
- result[3] = src[GET_SWZ(source->Swizzle, 3)];
- }
-
- /* Note: no Negate or Abs here */
-}
-
-
-
-/**
- * Fetch the derivative with respect to X or Y for the given register.
- * XXX this currently only works for fragment program input attribs.
- */
-static void
-fetch_vector4_deriv(struct gl_context * ctx,
- const struct prog_src_register *source,
- const struct gl_program_machine *machine,
- char xOrY, GLfloat result[4])
-{
- if (source->File == PROGRAM_INPUT &&
- source->Index < (GLint) machine->NumDeriv) {
- const GLint col = machine->CurElement;
- const GLfloat w = machine->Attribs[FRAG_ATTRIB_WPOS][col][3];
- const GLfloat invQ = 1.0f / w;
- GLfloat deriv[4];
-
- if (xOrY == 'X') {
- deriv[0] = machine->DerivX[source->Index][0] * invQ;
- deriv[1] = machine->DerivX[source->Index][1] * invQ;
- deriv[2] = machine->DerivX[source->Index][2] * invQ;
- deriv[3] = machine->DerivX[source->Index][3] * invQ;
- }
- else {
- deriv[0] = machine->DerivY[source->Index][0] * invQ;
- deriv[1] = machine->DerivY[source->Index][1] * invQ;
- deriv[2] = machine->DerivY[source->Index][2] * invQ;
- deriv[3] = machine->DerivY[source->Index][3] * invQ;
- }
-
- result[0] = deriv[GET_SWZ(source->Swizzle, 0)];
- result[1] = deriv[GET_SWZ(source->Swizzle, 1)];
- result[2] = deriv[GET_SWZ(source->Swizzle, 2)];
- result[3] = deriv[GET_SWZ(source->Swizzle, 3)];
-
- if (source->Abs) {
- result[0] = FABSF(result[0]);
- result[1] = FABSF(result[1]);
- result[2] = FABSF(result[2]);
- result[3] = FABSF(result[3]);
- }
- if (source->Negate) {
- ASSERT(source->Negate == NEGATE_XYZW);
- result[0] = -result[0];
- result[1] = -result[1];
- result[2] = -result[2];
- result[3] = -result[3];
- }
- }
- else {
- ASSIGN_4V(result, 0.0, 0.0, 0.0, 0.0);
- }
-}
-
-
-/**
- * As above, but only return result[0] element.
- */
-static void
-fetch_vector1(const struct prog_src_register *source,
- const struct gl_program_machine *machine, GLfloat result[4])
-{
- const GLfloat *src = get_src_register_pointer(source, machine);
- ASSERT(src);
-
- result[0] = src[GET_SWZ(source->Swizzle, 0)];
-
- if (source->Abs) {
- result[0] = FABSF(result[0]);
- }
- if (source->Negate) {
- result[0] = -result[0];
- }
-}
-
-
-static GLuint
-fetch_vector1ui(const struct prog_src_register *source,
- const struct gl_program_machine *machine)
-{
- const GLuint *src = (GLuint *) get_src_register_pointer(source, machine);
- return src[GET_SWZ(source->Swizzle, 0)];
-}
-
-
-/**
- * Fetch texel from texture. Use partial derivatives when possible.
- */
-static INLINE void
-fetch_texel(struct gl_context *ctx,
- const struct gl_program_machine *machine,
- const struct prog_instruction *inst,
- const GLfloat texcoord[4], GLfloat lodBias,
- GLfloat color[4])
-{
- const GLuint unit = machine->Samplers[inst->TexSrcUnit];
-
- /* Note: we only have the right derivatives for fragment input attribs.
- */
- if (machine->NumDeriv > 0 &&
- inst->SrcReg[0].File == PROGRAM_INPUT &&
- inst->SrcReg[0].Index == FRAG_ATTRIB_TEX0 + inst->TexSrcUnit) {
- /* simple texture fetch for which we should have derivatives */
- GLuint attr = inst->SrcReg[0].Index;
- machine->FetchTexelDeriv(ctx, texcoord,
- machine->DerivX[attr],
- machine->DerivY[attr],
- lodBias, unit, color);
- }
- else {
- machine->FetchTexelLod(ctx, texcoord, lodBias, unit, color);
- }
-}
-
-
-/**
- * Test value against zero and return GT, LT, EQ or UN if NaN.
- */
-static INLINE GLuint
-generate_cc(float value)
-{
- if (value != value)
- return COND_UN; /* NaN */
- if (value > 0.0F)
- return COND_GT;
- if (value < 0.0F)
- return COND_LT;
- return COND_EQ;
-}
-
-
-/**
- * Test if the ccMaskRule is satisfied by the given condition code.
- * Used to mask destination writes according to the current condition code.
- */
-static INLINE GLboolean
-test_cc(GLuint condCode, GLuint ccMaskRule)
-{
- switch (ccMaskRule) {
- case COND_EQ: return (condCode == COND_EQ);
- case COND_NE: return (condCode != COND_EQ);
- case COND_LT: return (condCode == COND_LT);
- case COND_GE: return (condCode == COND_GT || condCode == COND_EQ);
- case COND_LE: return (condCode == COND_LT || condCode == COND_EQ);
- case COND_GT: return (condCode == COND_GT);
- case COND_TR: return GL_TRUE;
- case COND_FL: return GL_FALSE;
- default: return GL_TRUE;
- }
-}
-
-
-/**
- * Evaluate the 4 condition codes against a predicate and return GL_TRUE
- * or GL_FALSE to indicate result.
- */
-static INLINE GLboolean
-eval_condition(const struct gl_program_machine *machine,
- const struct prog_instruction *inst)
-{
- const GLuint swizzle = inst->DstReg.CondSwizzle;
- const GLuint condMask = inst->DstReg.CondMask;
- if (test_cc(machine->CondCodes[GET_SWZ(swizzle, 0)], condMask) ||
- test_cc(machine->CondCodes[GET_SWZ(swizzle, 1)], condMask) ||
- test_cc(machine->CondCodes[GET_SWZ(swizzle, 2)], condMask) ||
- test_cc(machine->CondCodes[GET_SWZ(swizzle, 3)], condMask)) {
- return GL_TRUE;
- }
- else {
- return GL_FALSE;
- }
-}
-
-
-
-/**
- * Store 4 floats into a register. Observe the instructions saturate and
- * set-condition-code flags.
- */
-static void
-store_vector4(const struct prog_instruction *inst,
- struct gl_program_machine *machine, const GLfloat value[4])
-{
- const struct prog_dst_register *dstReg = &(inst->DstReg);
- const GLboolean clamp = inst->SaturateMode == SATURATE_ZERO_ONE;
- GLuint writeMask = dstReg->WriteMask;
- GLfloat clampedValue[4];
- GLfloat *dst = get_dst_register_pointer(dstReg, machine);
-
-#if 0
- if (value[0] > 1.0e10 ||
- IS_INF_OR_NAN(value[0]) ||
- IS_INF_OR_NAN(value[1]) ||
- IS_INF_OR_NAN(value[2]) || IS_INF_OR_NAN(value[3]))
- printf("store %g %g %g %g\n", value[0], value[1], value[2], value[3]);
-#endif
-
- if (clamp) {
- clampedValue[0] = CLAMP(value[0], 0.0F, 1.0F);
- clampedValue[1] = CLAMP(value[1], 0.0F, 1.0F);
- clampedValue[2] = CLAMP(value[2], 0.0F, 1.0F);
- clampedValue[3] = CLAMP(value[3], 0.0F, 1.0F);
- value = clampedValue;
- }
-
- if (dstReg->CondMask != COND_TR) {
- /* condition codes may turn off some writes */
- if (writeMask & WRITEMASK_X) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 0)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_X;
- }
- if (writeMask & WRITEMASK_Y) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 1)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_Y;
- }
- if (writeMask & WRITEMASK_Z) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 2)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_Z;
- }
- if (writeMask & WRITEMASK_W) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 3)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_W;
- }
- }
-
-#ifdef NAN_CHECK
- assert(!IS_INF_OR_NAN(value[0]));
- assert(!IS_INF_OR_NAN(value[0]));
- assert(!IS_INF_OR_NAN(value[0]));
- assert(!IS_INF_OR_NAN(value[0]));
-#endif
-
- if (writeMask & WRITEMASK_X)
- dst[0] = value[0];
- if (writeMask & WRITEMASK_Y)
- dst[1] = value[1];
- if (writeMask & WRITEMASK_Z)
- dst[2] = value[2];
- if (writeMask & WRITEMASK_W)
- dst[3] = value[3];
-
- if (inst->CondUpdate) {
- if (writeMask & WRITEMASK_X)
- machine->CondCodes[0] = generate_cc(value[0]);
- if (writeMask & WRITEMASK_Y)
- machine->CondCodes[1] = generate_cc(value[1]);
- if (writeMask & WRITEMASK_Z)
- machine->CondCodes[2] = generate_cc(value[2]);
- if (writeMask & WRITEMASK_W)
- machine->CondCodes[3] = generate_cc(value[3]);
-#if DEBUG_PROG
- printf("CondCodes=(%s,%s,%s,%s) for:\n",
- _mesa_condcode_string(machine->CondCodes[0]),
- _mesa_condcode_string(machine->CondCodes[1]),
- _mesa_condcode_string(machine->CondCodes[2]),
- _mesa_condcode_string(machine->CondCodes[3]));
-#endif
- }
-}
-
-
-/**
- * Store 4 uints into a register. Observe the set-condition-code flags.
- */
-static void
-store_vector4ui(const struct prog_instruction *inst,
- struct gl_program_machine *machine, const GLuint value[4])
-{
- const struct prog_dst_register *dstReg = &(inst->DstReg);
- GLuint writeMask = dstReg->WriteMask;
- GLuint *dst = (GLuint *) get_dst_register_pointer(dstReg, machine);
-
- if (dstReg->CondMask != COND_TR) {
- /* condition codes may turn off some writes */
- if (writeMask & WRITEMASK_X) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 0)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_X;
- }
- if (writeMask & WRITEMASK_Y) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 1)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_Y;
- }
- if (writeMask & WRITEMASK_Z) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 2)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_Z;
- }
- if (writeMask & WRITEMASK_W) {
- if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 3)],
- dstReg->CondMask))
- writeMask &= ~WRITEMASK_W;
- }
- }
-
- if (writeMask & WRITEMASK_X)
- dst[0] = value[0];
- if (writeMask & WRITEMASK_Y)
- dst[1] = value[1];
- if (writeMask & WRITEMASK_Z)
- dst[2] = value[2];
- if (writeMask & WRITEMASK_W)
- dst[3] = value[3];
-
- if (inst->CondUpdate) {
- if (writeMask & WRITEMASK_X)
- machine->CondCodes[0] = generate_cc((float)value[0]);
- if (writeMask & WRITEMASK_Y)
- machine->CondCodes[1] = generate_cc((float)value[1]);
- if (writeMask & WRITEMASK_Z)
- machine->CondCodes[2] = generate_cc((float)value[2]);
- if (writeMask & WRITEMASK_W)
- machine->CondCodes[3] = generate_cc((float)value[3]);
-#if DEBUG_PROG
- printf("CondCodes=(%s,%s,%s,%s) for:\n",
- _mesa_condcode_string(machine->CondCodes[0]),
- _mesa_condcode_string(machine->CondCodes[1]),
- _mesa_condcode_string(machine->CondCodes[2]),
- _mesa_condcode_string(machine->CondCodes[3]));
-#endif
- }
-}
-
-
-
-/**
- * Execute the given vertex/fragment program.
- *
- * \param ctx rendering context
- * \param program the program to execute
- * \param machine machine state (must be initialized)
- * \return GL_TRUE if program completed or GL_FALSE if program executed KIL.
- */
-GLboolean
-_mesa_execute_program(struct gl_context * ctx,
- const struct gl_program *program,
- struct gl_program_machine *machine)
-{
- const GLuint numInst = program->NumInstructions;
- const GLuint maxExec = 10000;
- GLuint pc, numExec = 0;
-
- machine->CurProgram = program;
-
- if (DEBUG_PROG) {
- printf("execute program %u --------------------\n", program->Id);
- }
-
- if (program->Target == GL_VERTEX_PROGRAM_ARB) {
- machine->EnvParams = ctx->VertexProgram.Parameters;
- }
- else {
- machine->EnvParams = ctx->FragmentProgram.Parameters;
- }
-
- for (pc = 0; pc < numInst; pc++) {
- const struct prog_instruction *inst = program->Instructions + pc;
-
- if (DEBUG_PROG) {
- _mesa_print_instruction(inst);
- }
-
- switch (inst->Opcode) {
- case OPCODE_ABS:
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] = FABSF(a[0]);
- result[1] = FABSF(a[1]);
- result[2] = FABSF(a[2]);
- result[3] = FABSF(a[3]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_ADD:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = a[0] + b[0];
- result[1] = a[1] + b[1];
- result[2] = a[2] + b[2];
- result[3] = a[3] + b[3];
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("ADD (%g %g %g %g) = (%g %g %g %g) + (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_AND: /* bitwise AND */
- {
- GLuint a[4], b[4], result[4];
- fetch_vector4ui(&inst->SrcReg[0], machine, a);
- fetch_vector4ui(&inst->SrcReg[1], machine, b);
- result[0] = a[0] & b[0];
- result[1] = a[1] & b[1];
- result[2] = a[2] & b[2];
- result[3] = a[3] & b[3];
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_ARL:
- {
- GLfloat t[4];
- fetch_vector4(&inst->SrcReg[0], machine, t);
- machine->AddressReg[0][0] = IFLOOR(t[0]);
- if (DEBUG_PROG) {
- printf("ARL %d\n", machine->AddressReg[0][0]);
- }
- }
- break;
- case OPCODE_BGNLOOP:
- /* no-op */
- ASSERT(program->Instructions[inst->BranchTarget].Opcode
- == OPCODE_ENDLOOP);
- break;
- case OPCODE_ENDLOOP:
- /* subtract 1 here since pc is incremented by for(pc) loop */
- ASSERT(program->Instructions[inst->BranchTarget].Opcode
- == OPCODE_BGNLOOP);
- pc = inst->BranchTarget - 1; /* go to matching BNGLOOP */
- break;
- case OPCODE_BGNSUB: /* begin subroutine */
- break;
- case OPCODE_ENDSUB: /* end subroutine */
- break;
- case OPCODE_BRA: /* branch (conditional) */
- if (eval_condition(machine, inst)) {
- /* take branch */
- /* Subtract 1 here since we'll do pc++ below */
- pc = inst->BranchTarget - 1;
- }
- break;
- case OPCODE_BRK: /* break out of loop (conditional) */
- ASSERT(program->Instructions[inst->BranchTarget].Opcode
- == OPCODE_ENDLOOP);
- if (eval_condition(machine, inst)) {
- /* break out of loop */
- /* pc++ at end of for-loop will put us after the ENDLOOP inst */
- pc = inst->BranchTarget;
- }
- break;
- case OPCODE_CONT: /* continue loop (conditional) */
- ASSERT(program->Instructions[inst->BranchTarget].Opcode
- == OPCODE_ENDLOOP);
- if (eval_condition(machine, inst)) {
- /* continue at ENDLOOP */
- /* Subtract 1 here since we'll do pc++ at end of for-loop */
- pc = inst->BranchTarget - 1;
- }
- break;
- case OPCODE_CAL: /* Call subroutine (conditional) */
- if (eval_condition(machine, inst)) {
- /* call the subroutine */
- if (machine->StackDepth >= MAX_PROGRAM_CALL_DEPTH) {
- return GL_TRUE; /* Per GL_NV_vertex_program2 spec */
- }
- machine->CallStack[machine->StackDepth++] = pc + 1; /* next inst */
- /* Subtract 1 here since we'll do pc++ at end of for-loop */
- pc = inst->BranchTarget - 1;
- }
- break;
- case OPCODE_CMP:
- {
- GLfloat a[4], b[4], c[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- fetch_vector4(&inst->SrcReg[2], machine, c);
- result[0] = a[0] < 0.0F ? b[0] : c[0];
- result[1] = a[1] < 0.0F ? b[1] : c[1];
- result[2] = a[2] < 0.0F ? b[2] : c[2];
- result[3] = a[3] < 0.0F ? b[3] : c[3];
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("CMP (%g %g %g %g) = (%g %g %g %g) < 0 ? (%g %g %g %g) : (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3],
- c[0], c[1], c[2], c[3]);
- }
- }
- break;
- case OPCODE_COS:
- {
- GLfloat a[4], result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- result[0] = result[1] = result[2] = result[3]
- = (GLfloat) cos(a[0]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_DDX: /* Partial derivative with respect to X */
- {
- GLfloat result[4];
- fetch_vector4_deriv(ctx, &inst->SrcReg[0], machine,
- 'X', result);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_DDY: /* Partial derivative with respect to Y */
- {
- GLfloat result[4];
- fetch_vector4_deriv(ctx, &inst->SrcReg[0], machine,
- 'Y', result);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_DP2:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = result[1] = result[2] = result[3] = DOT2(a, b);
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("DP2 %g = (%g %g) . (%g %g)\n",
- result[0], a[0], a[1], b[0], b[1]);
- }
- }
- break;
- case OPCODE_DP2A:
- {
- GLfloat a[4], b[4], c, result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- fetch_vector1(&inst->SrcReg[1], machine, &c);
- result[0] = result[1] = result[2] = result[3] = DOT2(a, b) + c;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("DP2A %g = (%g %g) . (%g %g) + %g\n",
- result[0], a[0], a[1], b[0], b[1], c);
- }
- }
- break;
- case OPCODE_DP3:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = result[1] = result[2] = result[3] = DOT3(a, b);
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("DP3 %g = (%g %g %g) . (%g %g %g)\n",
- result[0], a[0], a[1], a[2], b[0], b[1], b[2]);
- }
- }
- break;
- case OPCODE_DP4:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = result[1] = result[2] = result[3] = DOT4(a, b);
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("DP4 %g = (%g, %g %g %g) . (%g, %g %g %g)\n",
- result[0], a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_DPH:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = result[1] = result[2] = result[3] = DOT3(a, b) + b[3];
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_DST: /* Distance vector */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = 1.0F;
- result[1] = a[1] * b[1];
- result[2] = a[2];
- result[3] = b[3];
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_EXP:
- {
- GLfloat t[4], q[4], floor_t0;
- fetch_vector1(&inst->SrcReg[0], machine, t);
- floor_t0 = FLOORF(t[0]);
- if (floor_t0 > FLT_MAX_EXP) {
- SET_POS_INFINITY(q[0]);
- SET_POS_INFINITY(q[2]);
- }
- else if (floor_t0 < FLT_MIN_EXP) {
- q[0] = 0.0F;
- q[2] = 0.0F;
- }
- else {
- q[0] = LDEXPF(1.0, (int) floor_t0);
- /* Note: GL_NV_vertex_program expects
- * result.z = result.x * APPX(result.y)
- * We do what the ARB extension says.
- */
- q[2] = (GLfloat) pow(2.0, t[0]);
- }
- q[1] = t[0] - floor_t0;
- q[3] = 1.0F;
- store_vector4( inst, machine, q );
- }
- break;
- case OPCODE_EX2: /* Exponential base 2 */
- {
- GLfloat a[4], result[4], val;
- fetch_vector1(&inst->SrcReg[0], machine, a);
- val = (GLfloat) pow(2.0, a[0]);
- /*
- if (IS_INF_OR_NAN(val))
- val = 1.0e10;
- */
- result[0] = result[1] = result[2] = result[3] = val;
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_FLR:
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] = FLOORF(a[0]);
- result[1] = FLOORF(a[1]);
- result[2] = FLOORF(a[2]);
- result[3] = FLOORF(a[3]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_FRC:
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] = a[0] - FLOORF(a[0]);
- result[1] = a[1] - FLOORF(a[1]);
- result[2] = a[2] - FLOORF(a[2]);
- result[3] = a[3] - FLOORF(a[3]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_IF:
- {
- GLboolean cond;
- ASSERT(program->Instructions[inst->BranchTarget].Opcode
- == OPCODE_ELSE ||
- program->Instructions[inst->BranchTarget].Opcode
- == OPCODE_ENDIF);
- /* eval condition */
- if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
- GLfloat a[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- cond = (a[0] != 0.0);
- }
- else {
- cond = eval_condition(machine, inst);
- }
- if (DEBUG_PROG) {
- printf("IF: %d\n", cond);
- }
- /* do if/else */
- if (cond) {
- /* do if-clause (just continue execution) */
- }
- else {
- /* go to the instruction after ELSE or ENDIF */
- assert(inst->BranchTarget >= 0);
- pc = inst->BranchTarget;
- }
- }
- break;
- case OPCODE_ELSE:
- /* goto ENDIF */
- ASSERT(program->Instructions[inst->BranchTarget].Opcode
- == OPCODE_ENDIF);
- assert(inst->BranchTarget >= 0);
- pc = inst->BranchTarget;
- break;
- case OPCODE_ENDIF:
- /* nothing */
- break;
- case OPCODE_KIL_NV: /* NV_f_p only (conditional) */
- if (eval_condition(machine, inst)) {
- return GL_FALSE;
- }
- break;
- case OPCODE_KIL: /* ARB_f_p only */
- {
- GLfloat a[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- if (DEBUG_PROG) {
- printf("KIL if (%g %g %g %g) <= 0.0\n",
- a[0], a[1], a[2], a[3]);
- }
-
- if (a[0] < 0.0F || a[1] < 0.0F || a[2] < 0.0F || a[3] < 0.0F) {
- return GL_FALSE;
- }
- }
- break;
- case OPCODE_LG2: /* log base 2 */
- {
- GLfloat a[4], result[4], val;
- fetch_vector1(&inst->SrcReg[0], machine, a);
- /* The fast LOG2 macro doesn't meet the precision requirements.
- */
- if (a[0] == 0.0F) {
- val = -FLT_MAX;
- }
- else {
- val = (float)(log(a[0]) * 1.442695F);
- }
- result[0] = result[1] = result[2] = result[3] = val;
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_LIT:
- {
- const GLfloat epsilon = 1.0F / 256.0F; /* from NV VP spec */
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- a[0] = MAX2(a[0], 0.0F);
- a[1] = MAX2(a[1], 0.0F);
- /* XXX ARB version clamps a[3], NV version doesn't */
- a[3] = CLAMP(a[3], -(128.0F - epsilon), (128.0F - epsilon));
- result[0] = 1.0F;
- result[1] = a[0];
- /* XXX we could probably just use pow() here */
- if (a[0] > 0.0F) {
- if (a[1] == 0.0 && a[3] == 0.0)
- result[2] = 1.0F;
- else
- result[2] = (GLfloat) pow(a[1], a[3]);
- }
- else {
- result[2] = 0.0F;
- }
- result[3] = 1.0F;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("LIT (%g %g %g %g) : (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3]);
- }
- }
- break;
- case OPCODE_LOG:
- {
- GLfloat t[4], q[4], abs_t0;
- fetch_vector1(&inst->SrcReg[0], machine, t);
- abs_t0 = FABSF(t[0]);
- if (abs_t0 != 0.0F) {
- /* Since we really can't handle infinite values on VMS
- * like other OSes we'll use __MAXFLOAT to represent
- * infinity. This may need some tweaking.
- */
-#ifdef VMS
- if (abs_t0 == __MAXFLOAT)
-#else
- if (IS_INF_OR_NAN(abs_t0))
-#endif
- {
- SET_POS_INFINITY(q[0]);
- q[1] = 1.0F;
- SET_POS_INFINITY(q[2]);
- }
- else {
- int exponent;
- GLfloat mantissa = FREXPF(t[0], &exponent);
- q[0] = (GLfloat) (exponent - 1);
- q[1] = (GLfloat) (2.0 * mantissa); /* map [.5, 1) -> [1, 2) */
-
- /* The fast LOG2 macro doesn't meet the precision
- * requirements.
- */
- q[2] = (float)(log(t[0]) * 1.442695F);
- }
- }
- else {
- SET_NEG_INFINITY(q[0]);
- q[1] = 1.0F;
- SET_NEG_INFINITY(q[2]);
- }
- q[3] = 1.0;
- store_vector4(inst, machine, q);
- }
- break;
- case OPCODE_LRP:
- {
- GLfloat a[4], b[4], c[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- fetch_vector4(&inst->SrcReg[2], machine, c);
- result[0] = a[0] * b[0] + (1.0F - a[0]) * c[0];
- result[1] = a[1] * b[1] + (1.0F - a[1]) * c[1];
- result[2] = a[2] * b[2] + (1.0F - a[2]) * c[2];
- result[3] = a[3] * b[3] + (1.0F - a[3]) * c[3];
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("LRP (%g %g %g %g) = (%g %g %g %g), "
- "(%g %g %g %g), (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3], c[0], c[1], c[2], c[3]);
- }
- }
- break;
- case OPCODE_MAD:
- {
- GLfloat a[4], b[4], c[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- fetch_vector4(&inst->SrcReg[2], machine, c);
- result[0] = a[0] * b[0] + c[0];
- result[1] = a[1] * b[1] + c[1];
- result[2] = a[2] * b[2] + c[2];
- result[3] = a[3] * b[3] + c[3];
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("MAD (%g %g %g %g) = (%g %g %g %g) * "
- "(%g %g %g %g) + (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3], c[0], c[1], c[2], c[3]);
- }
- }
- break;
- case OPCODE_MAX:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = MAX2(a[0], b[0]);
- result[1] = MAX2(a[1], b[1]);
- result[2] = MAX2(a[2], b[2]);
- result[3] = MAX2(a[3], b[3]);
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("MAX (%g %g %g %g) = (%g %g %g %g), (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_MIN:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = MIN2(a[0], b[0]);
- result[1] = MIN2(a[1], b[1]);
- result[2] = MIN2(a[2], b[2]);
- result[3] = MIN2(a[3], b[3]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_MOV:
- {
- GLfloat result[4];
- fetch_vector4(&inst->SrcReg[0], machine, result);
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("MOV (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3]);
- }
- }
- break;
- case OPCODE_MUL:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = a[0] * b[0];
- result[1] = a[1] * b[1];
- result[2] = a[2] * b[2];
- result[3] = a[3] * b[3];
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("MUL (%g %g %g %g) = (%g %g %g %g) * (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_NOISE1:
- {
- GLfloat a[4], result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- result[0] =
- result[1] =
- result[2] =
- result[3] = _mesa_noise1(a[0]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_NOISE2:
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] =
- result[1] =
- result[2] = result[3] = _mesa_noise2(a[0], a[1]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_NOISE3:
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] =
- result[1] =
- result[2] =
- result[3] = _mesa_noise3(a[0], a[1], a[2]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_NOISE4:
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] =
- result[1] =
- result[2] =
- result[3] = _mesa_noise4(a[0], a[1], a[2], a[3]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_NOP:
- break;
- case OPCODE_NOT: /* bitwise NOT */
- {
- GLuint a[4], result[4];
- fetch_vector4ui(&inst->SrcReg[0], machine, a);
- result[0] = ~a[0];
- result[1] = ~a[1];
- result[2] = ~a[2];
- result[3] = ~a[3];
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_NRM3: /* 3-component normalization */
- {
- GLfloat a[4], result[4];
- GLfloat tmp;
- fetch_vector4(&inst->SrcReg[0], machine, a);
- tmp = a[0] * a[0] + a[1] * a[1] + a[2] * a[2];
- if (tmp != 0.0F)
- tmp = INV_SQRTF(tmp);
- result[0] = tmp * a[0];
- result[1] = tmp * a[1];
- result[2] = tmp * a[2];
- result[3] = 0.0; /* undefined, but prevent valgrind warnings */
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_NRM4: /* 4-component normalization */
- {
- GLfloat a[4], result[4];
- GLfloat tmp;
- fetch_vector4(&inst->SrcReg[0], machine, a);
- tmp = a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3];
- if (tmp != 0.0F)
- tmp = INV_SQRTF(tmp);
- result[0] = tmp * a[0];
- result[1] = tmp * a[1];
- result[2] = tmp * a[2];
- result[3] = tmp * a[3];
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_OR: /* bitwise OR */
- {
- GLuint a[4], b[4], result[4];
- fetch_vector4ui(&inst->SrcReg[0], machine, a);
- fetch_vector4ui(&inst->SrcReg[1], machine, b);
- result[0] = a[0] | b[0];
- result[1] = a[1] | b[1];
- result[2] = a[2] | b[2];
- result[3] = a[3] | b[3];
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_PK2H: /* pack two 16-bit floats in one 32-bit float */
- {
- GLfloat a[4];
- GLuint result[4];
- GLhalfNV hx, hy;
- fetch_vector4(&inst->SrcReg[0], machine, a);
- hx = _mesa_float_to_half(a[0]);
- hy = _mesa_float_to_half(a[1]);
- result[0] =
- result[1] =
- result[2] =
- result[3] = hx | (hy << 16);
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_PK2US: /* pack two GLushorts into one 32-bit float */
- {
- GLfloat a[4];
- GLuint result[4], usx, usy;
- fetch_vector4(&inst->SrcReg[0], machine, a);
- a[0] = CLAMP(a[0], 0.0F, 1.0F);
- a[1] = CLAMP(a[1], 0.0F, 1.0F);
- usx = IROUND(a[0] * 65535.0F);
- usy = IROUND(a[1] * 65535.0F);
- result[0] =
- result[1] =
- result[2] =
- result[3] = usx | (usy << 16);
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_PK4B: /* pack four GLbytes into one 32-bit float */
- {
- GLfloat a[4];
- GLuint result[4], ubx, uby, ubz, ubw;
- fetch_vector4(&inst->SrcReg[0], machine, a);
- a[0] = CLAMP(a[0], -128.0F / 127.0F, 1.0F);
- a[1] = CLAMP(a[1], -128.0F / 127.0F, 1.0F);
- a[2] = CLAMP(a[2], -128.0F / 127.0F, 1.0F);
- a[3] = CLAMP(a[3], -128.0F / 127.0F, 1.0F);
- ubx = IROUND(127.0F * a[0] + 128.0F);
- uby = IROUND(127.0F * a[1] + 128.0F);
- ubz = IROUND(127.0F * a[2] + 128.0F);
- ubw = IROUND(127.0F * a[3] + 128.0F);
- result[0] =
- result[1] =
- result[2] =
- result[3] = ubx | (uby << 8) | (ubz << 16) | (ubw << 24);
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_PK4UB: /* pack four GLubytes into one 32-bit float */
- {
- GLfloat a[4];
- GLuint result[4], ubx, uby, ubz, ubw;
- fetch_vector4(&inst->SrcReg[0], machine, a);
- a[0] = CLAMP(a[0], 0.0F, 1.0F);
- a[1] = CLAMP(a[1], 0.0F, 1.0F);
- a[2] = CLAMP(a[2], 0.0F, 1.0F);
- a[3] = CLAMP(a[3], 0.0F, 1.0F);
- ubx = IROUND(255.0F * a[0]);
- uby = IROUND(255.0F * a[1]);
- ubz = IROUND(255.0F * a[2]);
- ubw = IROUND(255.0F * a[3]);
- result[0] =
- result[1] =
- result[2] =
- result[3] = ubx | (uby << 8) | (ubz << 16) | (ubw << 24);
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_POW:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- fetch_vector1(&inst->SrcReg[1], machine, b);
- result[0] = result[1] = result[2] = result[3]
- = (GLfloat) pow(a[0], b[0]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_RCC: /* clamped riciprocal */
- {
- const float largest = 1.884467e+19, smallest = 5.42101e-20;
- GLfloat a[4], r, result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- if (DEBUG_PROG) {
- if (a[0] == 0)
- printf("RCC(0)\n");
- else if (IS_INF_OR_NAN(a[0]))
- printf("RCC(inf)\n");
- }
- if (a[0] == 1.0F) {
- r = 1.0F;
- }
- else {
- r = 1.0F / a[0];
- }
- if (positive(r)) {
- if (r > largest) {
- r = largest;
- }
- else if (r < smallest) {
- r = smallest;
- }
- }
- else {
- if (r < -largest) {
- r = -largest;
- }
- else if (r > -smallest) {
- r = -smallest;
- }
- }
- result[0] = result[1] = result[2] = result[3] = r;
- store_vector4(inst, machine, result);
- }
- break;
-
- case OPCODE_RCP:
- {
- GLfloat a[4], result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- if (DEBUG_PROG) {
- if (a[0] == 0)
- printf("RCP(0)\n");
- else if (IS_INF_OR_NAN(a[0]))
- printf("RCP(inf)\n");
- }
- result[0] = result[1] = result[2] = result[3] = 1.0F / a[0];
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_RET: /* return from subroutine (conditional) */
- if (eval_condition(machine, inst)) {
- if (machine->StackDepth == 0) {
- return GL_TRUE; /* Per GL_NV_vertex_program2 spec */
- }
- /* subtract one because of pc++ in the for loop */
- pc = machine->CallStack[--machine->StackDepth] - 1;
- }
- break;
- case OPCODE_RFL: /* reflection vector */
- {
- GLfloat axis[4], dir[4], result[4], tmpX, tmpW;
- fetch_vector4(&inst->SrcReg[0], machine, axis);
- fetch_vector4(&inst->SrcReg[1], machine, dir);
- tmpW = DOT3(axis, axis);
- tmpX = (2.0F * DOT3(axis, dir)) / tmpW;
- result[0] = tmpX * axis[0] - dir[0];
- result[1] = tmpX * axis[1] - dir[1];
- result[2] = tmpX * axis[2] - dir[2];
- /* result[3] is never written! XXX enforce in parser! */
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_RSQ: /* 1 / sqrt() */
- {
- GLfloat a[4], result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- a[0] = FABSF(a[0]);
- result[0] = result[1] = result[2] = result[3] = INV_SQRTF(a[0]);
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("RSQ %g = 1/sqrt(|%g|)\n", result[0], a[0]);
- }
- }
- break;
- case OPCODE_SCS: /* sine and cos */
- {
- GLfloat a[4], result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- result[0] = (GLfloat) cos(a[0]);
- result[1] = (GLfloat) sin(a[0]);
- result[2] = 0.0; /* undefined! */
- result[3] = 0.0; /* undefined! */
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_SEQ: /* set on equal */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = (a[0] == b[0]) ? 1.0F : 0.0F;
- result[1] = (a[1] == b[1]) ? 1.0F : 0.0F;
- result[2] = (a[2] == b[2]) ? 1.0F : 0.0F;
- result[3] = (a[3] == b[3]) ? 1.0F : 0.0F;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("SEQ (%g %g %g %g) = (%g %g %g %g) == (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_SFL: /* set false, operands ignored */
- {
- static const GLfloat result[4] = { 0.0F, 0.0F, 0.0F, 0.0F };
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_SGE: /* set on greater or equal */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = (a[0] >= b[0]) ? 1.0F : 0.0F;
- result[1] = (a[1] >= b[1]) ? 1.0F : 0.0F;
- result[2] = (a[2] >= b[2]) ? 1.0F : 0.0F;
- result[3] = (a[3] >= b[3]) ? 1.0F : 0.0F;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("SGE (%g %g %g %g) = (%g %g %g %g) >= (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_SGT: /* set on greater */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = (a[0] > b[0]) ? 1.0F : 0.0F;
- result[1] = (a[1] > b[1]) ? 1.0F : 0.0F;
- result[2] = (a[2] > b[2]) ? 1.0F : 0.0F;
- result[3] = (a[3] > b[3]) ? 1.0F : 0.0F;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("SGT (%g %g %g %g) = (%g %g %g %g) > (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_SIN:
- {
- GLfloat a[4], result[4];
- fetch_vector1(&inst->SrcReg[0], machine, a);
- result[0] = result[1] = result[2] = result[3]
- = (GLfloat) sin(a[0]);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_SLE: /* set on less or equal */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = (a[0] <= b[0]) ? 1.0F : 0.0F;
- result[1] = (a[1] <= b[1]) ? 1.0F : 0.0F;
- result[2] = (a[2] <= b[2]) ? 1.0F : 0.0F;
- result[3] = (a[3] <= b[3]) ? 1.0F : 0.0F;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("SLE (%g %g %g %g) = (%g %g %g %g) <= (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_SLT: /* set on less */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = (a[0] < b[0]) ? 1.0F : 0.0F;
- result[1] = (a[1] < b[1]) ? 1.0F : 0.0F;
- result[2] = (a[2] < b[2]) ? 1.0F : 0.0F;
- result[3] = (a[3] < b[3]) ? 1.0F : 0.0F;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("SLT (%g %g %g %g) = (%g %g %g %g) < (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_SNE: /* set on not equal */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = (a[0] != b[0]) ? 1.0F : 0.0F;
- result[1] = (a[1] != b[1]) ? 1.0F : 0.0F;
- result[2] = (a[2] != b[2]) ? 1.0F : 0.0F;
- result[3] = (a[3] != b[3]) ? 1.0F : 0.0F;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("SNE (%g %g %g %g) = (%g %g %g %g) != (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3],
- b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_SSG: /* set sign (-1, 0 or +1) */
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] = (GLfloat) ((a[0] > 0.0F) - (a[0] < 0.0F));
- result[1] = (GLfloat) ((a[1] > 0.0F) - (a[1] < 0.0F));
- result[2] = (GLfloat) ((a[2] > 0.0F) - (a[2] < 0.0F));
- result[3] = (GLfloat) ((a[3] > 0.0F) - (a[3] < 0.0F));
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_STR: /* set true, operands ignored */
- {
- static const GLfloat result[4] = { 1.0F, 1.0F, 1.0F, 1.0F };
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_SUB:
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = a[0] - b[0];
- result[1] = a[1] - b[1];
- result[2] = a[2] - b[2];
- result[3] = a[3] - b[3];
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("SUB (%g %g %g %g) = (%g %g %g %g) - (%g %g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]);
- }
- }
- break;
- case OPCODE_SWZ: /* extended swizzle */
- {
- const struct prog_src_register *source = &inst->SrcReg[0];
- const GLfloat *src = get_src_register_pointer(source, machine);
- GLfloat result[4];
- GLuint i;
- for (i = 0; i < 4; i++) {
- const GLuint swz = GET_SWZ(source->Swizzle, i);
- if (swz == SWIZZLE_ZERO)
- result[i] = 0.0;
- else if (swz == SWIZZLE_ONE)
- result[i] = 1.0;
- else {
- ASSERT(swz >= 0);
- ASSERT(swz <= 3);
- result[i] = src[swz];
- }
- if (source->Negate & (1 << i))
- result[i] = -result[i];
- }
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_TEX: /* Both ARB and NV frag prog */
- /* Simple texel lookup */
- {
- GLfloat texcoord[4], color[4];
- fetch_vector4(&inst->SrcReg[0], machine, texcoord);
-
- fetch_texel(ctx, machine, inst, texcoord, 0.0, color);
-
- if (DEBUG_PROG) {
- printf("TEX (%g, %g, %g, %g) = texture[%d][%g, %g, %g, %g]\n",
- color[0], color[1], color[2], color[3],
- inst->TexSrcUnit,
- texcoord[0], texcoord[1], texcoord[2], texcoord[3]);
- }
- store_vector4(inst, machine, color);
- }
- break;
- case OPCODE_TXB: /* GL_ARB_fragment_program only */
- /* Texel lookup with LOD bias */
- {
- GLfloat texcoord[4], color[4], lodBias;
-
- fetch_vector4(&inst->SrcReg[0], machine, texcoord);
-
- /* texcoord[3] is the bias to add to lambda */
- lodBias = texcoord[3];
-
- fetch_texel(ctx, machine, inst, texcoord, lodBias, color);
-
- if (DEBUG_PROG) {
- printf("TXB (%g, %g, %g, %g) = texture[%d][%g %g %g %g]"
- " bias %g\n",
- color[0], color[1], color[2], color[3],
- inst->TexSrcUnit,
- texcoord[0],
- texcoord[1],
- texcoord[2],
- texcoord[3],
- lodBias);
- }
-
- store_vector4(inst, machine, color);
- }
- break;
- case OPCODE_TXD: /* GL_NV_fragment_program only */
- /* Texture lookup w/ partial derivatives for LOD */
- {
- GLfloat texcoord[4], dtdx[4], dtdy[4], color[4];
- fetch_vector4(&inst->SrcReg[0], machine, texcoord);
- fetch_vector4(&inst->SrcReg[1], machine, dtdx);
- fetch_vector4(&inst->SrcReg[2], machine, dtdy);
- machine->FetchTexelDeriv(ctx, texcoord, dtdx, dtdy,
- 0.0, /* lodBias */
- inst->TexSrcUnit, color);
- store_vector4(inst, machine, color);
- }
- break;
- case OPCODE_TXL:
- /* Texel lookup with explicit LOD */
- {
- GLfloat texcoord[4], color[4], lod;
-
- fetch_vector4(&inst->SrcReg[0], machine, texcoord);
-
- /* texcoord[3] is the LOD */
- lod = texcoord[3];
-
- machine->FetchTexelLod(ctx, texcoord, lod,
- machine->Samplers[inst->TexSrcUnit], color);
-
- store_vector4(inst, machine, color);
- }
- break;
- case OPCODE_TXP: /* GL_ARB_fragment_program only */
- /* Texture lookup w/ projective divide */
- {
- GLfloat texcoord[4], color[4];
-
- fetch_vector4(&inst->SrcReg[0], machine, texcoord);
- /* Not so sure about this test - if texcoord[3] is
- * zero, we'd probably be fine except for an ASSERT in
- * IROUND_POS() which gets triggered by the inf values created.
- */
- if (texcoord[3] != 0.0) {
- texcoord[0] /= texcoord[3];
- texcoord[1] /= texcoord[3];
- texcoord[2] /= texcoord[3];
- }
-
- fetch_texel(ctx, machine, inst, texcoord, 0.0, color);
-
- store_vector4(inst, machine, color);
- }
- break;
- case OPCODE_TXP_NV: /* GL_NV_fragment_program only */
- /* Texture lookup w/ projective divide, as above, but do not
- * do the divide by w if sampling from a cube map.
- */
- {
- GLfloat texcoord[4], color[4];
-
- fetch_vector4(&inst->SrcReg[0], machine, texcoord);
- if (inst->TexSrcTarget != TEXTURE_CUBE_INDEX &&
- texcoord[3] != 0.0) {
- texcoord[0] /= texcoord[3];
- texcoord[1] /= texcoord[3];
- texcoord[2] /= texcoord[3];
- }
-
- fetch_texel(ctx, machine, inst, texcoord, 0.0, color);
-
- store_vector4(inst, machine, color);
- }
- break;
- case OPCODE_TRUNC: /* truncate toward zero */
- {
- GLfloat a[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- result[0] = (GLfloat) (GLint) a[0];
- result[1] = (GLfloat) (GLint) a[1];
- result[2] = (GLfloat) (GLint) a[2];
- result[3] = (GLfloat) (GLint) a[3];
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_UP2H: /* unpack two 16-bit floats */
- {
- const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine);
- GLfloat result[4];
- GLushort hx, hy;
- hx = raw & 0xffff;
- hy = raw >> 16;
- result[0] = result[2] = _mesa_half_to_float(hx);
- result[1] = result[3] = _mesa_half_to_float(hy);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_UP2US: /* unpack two GLushorts */
- {
- const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine);
- GLfloat result[4];
- GLushort usx, usy;
- usx = raw & 0xffff;
- usy = raw >> 16;
- result[0] = result[2] = usx * (1.0f / 65535.0f);
- result[1] = result[3] = usy * (1.0f / 65535.0f);
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_UP4B: /* unpack four GLbytes */
- {
- const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine);
- GLfloat result[4];
- result[0] = (((raw >> 0) & 0xff) - 128) / 127.0F;
- result[1] = (((raw >> 8) & 0xff) - 128) / 127.0F;
- result[2] = (((raw >> 16) & 0xff) - 128) / 127.0F;
- result[3] = (((raw >> 24) & 0xff) - 128) / 127.0F;
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_UP4UB: /* unpack four GLubytes */
- {
- const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine);
- GLfloat result[4];
- result[0] = ((raw >> 0) & 0xff) / 255.0F;
- result[1] = ((raw >> 8) & 0xff) / 255.0F;
- result[2] = ((raw >> 16) & 0xff) / 255.0F;
- result[3] = ((raw >> 24) & 0xff) / 255.0F;
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_XOR: /* bitwise XOR */
- {
- GLuint a[4], b[4], result[4];
- fetch_vector4ui(&inst->SrcReg[0], machine, a);
- fetch_vector4ui(&inst->SrcReg[1], machine, b);
- result[0] = a[0] ^ b[0];
- result[1] = a[1] ^ b[1];
- result[2] = a[2] ^ b[2];
- result[3] = a[3] ^ b[3];
- store_vector4ui(inst, machine, result);
- }
- break;
- case OPCODE_XPD: /* cross product */
- {
- GLfloat a[4], b[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- result[0] = a[1] * b[2] - a[2] * b[1];
- result[1] = a[2] * b[0] - a[0] * b[2];
- result[2] = a[0] * b[1] - a[1] * b[0];
- result[3] = 1.0;
- store_vector4(inst, machine, result);
- if (DEBUG_PROG) {
- printf("XPD (%g %g %g %g) = (%g %g %g) X (%g %g %g)\n",
- result[0], result[1], result[2], result[3],
- a[0], a[1], a[2], b[0], b[1], b[2]);
- }
- }
- break;
- case OPCODE_X2D: /* 2-D matrix transform */
- {
- GLfloat a[4], b[4], c[4], result[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- fetch_vector4(&inst->SrcReg[1], machine, b);
- fetch_vector4(&inst->SrcReg[2], machine, c);
- result[0] = a[0] + b[0] * c[0] + b[1] * c[1];
- result[1] = a[1] + b[0] * c[2] + b[1] * c[3];
- result[2] = a[2] + b[0] * c[0] + b[1] * c[1];
- result[3] = a[3] + b[0] * c[2] + b[1] * c[3];
- store_vector4(inst, machine, result);
- }
- break;
- case OPCODE_PRINT:
- {
- if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
- GLfloat a[4];
- fetch_vector4(&inst->SrcReg[0], machine, a);
- printf("%s%g, %g, %g, %g\n", (const char *) inst->Data,
- a[0], a[1], a[2], a[3]);
- }
- else {
- printf("%s\n", (const char *) inst->Data);
- }
- }
- break;
- case OPCODE_END:
- return GL_TRUE;
- default:
- _mesa_problem(ctx, "Bad opcode %d in _mesa_execute_program",
- inst->Opcode);
- return GL_TRUE; /* return value doesn't matter */
- }
-
- numExec++;
- if (numExec > maxExec) {
- static GLboolean reported = GL_FALSE;
- if (!reported) {
- _mesa_problem(ctx, "Infinite loop detected in fragment program");
- reported = GL_TRUE;
- }
- return GL_TRUE;
- }
-
- } /* for pc */
-
- return GL_TRUE;
-}
+/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file prog_execute.c + * Software interpreter for vertex/fragment programs. + * \author Brian Paul + */ + +/* + * NOTE: we do everything in single-precision floating point; we don't + * currently observe the single/half/fixed-precision qualifiers. + * + */ + + +#include "main/glheader.h" +#include "main/colormac.h" +#include "main/macros.h" +#include "prog_execute.h" +#include "prog_instruction.h" +#include "prog_parameter.h" +#include "prog_print.h" +#include "prog_noise.h" + + +/* debug predicate */ +#define DEBUG_PROG 0 + + +/** + * Set x to positive or negative infinity. + */ +#if defined(USE_IEEE) || defined(_WIN32) +#define SET_POS_INFINITY(x) \ + do { \ + fi_type fi; \ + fi.i = 0x7F800000; \ + x = fi.f; \ + } while (0) +#define SET_NEG_INFINITY(x) \ + do { \ + fi_type fi; \ + fi.i = 0xFF800000; \ + x = fi.f; \ + } while (0) +#elif defined(VMS) +#define SET_POS_INFINITY(x) x = __MAXFLOAT +#define SET_NEG_INFINITY(x) x = -__MAXFLOAT +#else +#define SET_POS_INFINITY(x) x = (GLfloat) HUGE_VAL +#define SET_NEG_INFINITY(x) x = (GLfloat) -HUGE_VAL +#endif + +#define SET_FLOAT_BITS(x, bits) ((fi_type *) (void *) &(x))->i = bits + + +static const GLfloat ZeroVec[4] = { 0.0F, 0.0F, 0.0F, 0.0F }; + + + +/** + * Return TRUE for +0 and other positive values, FALSE otherwise. + * Used for RCC opcode. + */ +static INLINE GLboolean +positive(float x) +{ + fi_type fi; + fi.f = x; + if (fi.i & 0x80000000) + return GL_FALSE; + return GL_TRUE; +} + + + +/** + * Return a pointer to the 4-element float vector specified by the given + * source register. + */ +static INLINE const GLfloat * +get_src_register_pointer(const struct prog_src_register *source, + const struct gl_program_machine *machine) +{ + const struct gl_program *prog = machine->CurProgram; + GLint reg = source->Index; + + if (source->RelAddr) { + /* add address register value to src index/offset */ + reg += machine->AddressReg[0][0]; + if (reg < 0) { + return ZeroVec; + } + } + + switch (source->File) { + case PROGRAM_TEMPORARY: + if (reg >= MAX_PROGRAM_TEMPS) + return ZeroVec; + return machine->Temporaries[reg]; + + case PROGRAM_INPUT: + if (prog->Target == GL_VERTEX_PROGRAM_ARB) { + if (reg >= VERT_ATTRIB_MAX) + return ZeroVec; + return machine->VertAttribs[reg]; + } + else { + if (reg >= FRAG_ATTRIB_MAX) + return ZeroVec; + return machine->Attribs[reg][machine->CurElement]; + } + + case PROGRAM_OUTPUT: + if (reg >= MAX_PROGRAM_OUTPUTS) + return ZeroVec; + return machine->Outputs[reg]; + + case PROGRAM_LOCAL_PARAM: + if (reg >= MAX_PROGRAM_LOCAL_PARAMS) + return ZeroVec; + return machine->CurProgram->LocalParams[reg]; + + case PROGRAM_ENV_PARAM: + if (reg >= MAX_PROGRAM_ENV_PARAMS) + return ZeroVec; + return machine->EnvParams[reg]; + + case PROGRAM_STATE_VAR: + /* Fallthrough */ + case PROGRAM_CONSTANT: + /* Fallthrough */ + case PROGRAM_UNIFORM: + /* Fallthrough */ + case PROGRAM_NAMED_PARAM: + if (reg >= (GLint) prog->Parameters->NumParameters) + return ZeroVec; + return (GLfloat *) prog->Parameters->ParameterValues[reg]; + + case PROGRAM_SYSTEM_VALUE: + assert(reg < Elements(machine->SystemValues)); + return machine->SystemValues[reg]; + + default: + _mesa_problem(NULL, + "Invalid src register file %d in get_src_register_pointer()", + source->File); + return NULL; + } +} + + +/** + * Return a pointer to the 4-element float vector specified by the given + * destination register. + */ +static INLINE GLfloat * +get_dst_register_pointer(const struct prog_dst_register *dest, + struct gl_program_machine *machine) +{ + static GLfloat dummyReg[4]; + GLint reg = dest->Index; + + if (dest->RelAddr) { + /* add address register value to src index/offset */ + reg += machine->AddressReg[0][0]; + if (reg < 0) { + return dummyReg; + } + } + + switch (dest->File) { + case PROGRAM_TEMPORARY: + if (reg >= MAX_PROGRAM_TEMPS) + return dummyReg; + return machine->Temporaries[reg]; + + case PROGRAM_OUTPUT: + if (reg >= MAX_PROGRAM_OUTPUTS) + return dummyReg; + return machine->Outputs[reg]; + + case PROGRAM_WRITE_ONLY: + return dummyReg; + + default: + _mesa_problem(NULL, + "Invalid dest register file %d in get_dst_register_pointer()", + dest->File); + return NULL; + } +} + + + +/** + * Fetch a 4-element float vector from the given source register. + * Apply swizzling and negating as needed. + */ +static void +fetch_vector4(const struct prog_src_register *source, + const struct gl_program_machine *machine, GLfloat result[4]) +{ + const GLfloat *src = get_src_register_pointer(source, machine); + ASSERT(src); + + if (source->Swizzle == SWIZZLE_NOOP) { + /* no swizzling */ + COPY_4V(result, src); + } + else { + ASSERT(GET_SWZ(source->Swizzle, 0) <= 3); + ASSERT(GET_SWZ(source->Swizzle, 1) <= 3); + ASSERT(GET_SWZ(source->Swizzle, 2) <= 3); + ASSERT(GET_SWZ(source->Swizzle, 3) <= 3); + result[0] = src[GET_SWZ(source->Swizzle, 0)]; + result[1] = src[GET_SWZ(source->Swizzle, 1)]; + result[2] = src[GET_SWZ(source->Swizzle, 2)]; + result[3] = src[GET_SWZ(source->Swizzle, 3)]; + } + + if (source->Abs) { + result[0] = FABSF(result[0]); + result[1] = FABSF(result[1]); + result[2] = FABSF(result[2]); + result[3] = FABSF(result[3]); + } + if (source->Negate) { + ASSERT(source->Negate == NEGATE_XYZW); + result[0] = -result[0]; + result[1] = -result[1]; + result[2] = -result[2]; + result[3] = -result[3]; + } + +#ifdef NAN_CHECK + assert(!IS_INF_OR_NAN(result[0])); + assert(!IS_INF_OR_NAN(result[0])); + assert(!IS_INF_OR_NAN(result[0])); + assert(!IS_INF_OR_NAN(result[0])); +#endif +} + + +/** + * Fetch a 4-element uint vector from the given source register. + * Apply swizzling but not negation/abs. + */ +static void +fetch_vector4ui(const struct prog_src_register *source, + const struct gl_program_machine *machine, GLuint result[4]) +{ + const GLuint *src = (GLuint *) get_src_register_pointer(source, machine); + ASSERT(src); + + if (source->Swizzle == SWIZZLE_NOOP) { + /* no swizzling */ + COPY_4V(result, src); + } + else { + ASSERT(GET_SWZ(source->Swizzle, 0) <= 3); + ASSERT(GET_SWZ(source->Swizzle, 1) <= 3); + ASSERT(GET_SWZ(source->Swizzle, 2) <= 3); + ASSERT(GET_SWZ(source->Swizzle, 3) <= 3); + result[0] = src[GET_SWZ(source->Swizzle, 0)]; + result[1] = src[GET_SWZ(source->Swizzle, 1)]; + result[2] = src[GET_SWZ(source->Swizzle, 2)]; + result[3] = src[GET_SWZ(source->Swizzle, 3)]; + } + + /* Note: no Negate or Abs here */ +} + + + +/** + * Fetch the derivative with respect to X or Y for the given register. + * XXX this currently only works for fragment program input attribs. + */ +static void +fetch_vector4_deriv(struct gl_context * ctx, + const struct prog_src_register *source, + const struct gl_program_machine *machine, + char xOrY, GLfloat result[4]) +{ + if (source->File == PROGRAM_INPUT && + source->Index < (GLint) machine->NumDeriv) { + const GLint col = machine->CurElement; + const GLfloat w = machine->Attribs[FRAG_ATTRIB_WPOS][col][3]; + const GLfloat invQ = 1.0f / w; + GLfloat deriv[4]; + + if (xOrY == 'X') { + deriv[0] = machine->DerivX[source->Index][0] * invQ; + deriv[1] = machine->DerivX[source->Index][1] * invQ; + deriv[2] = machine->DerivX[source->Index][2] * invQ; + deriv[3] = machine->DerivX[source->Index][3] * invQ; + } + else { + deriv[0] = machine->DerivY[source->Index][0] * invQ; + deriv[1] = machine->DerivY[source->Index][1] * invQ; + deriv[2] = machine->DerivY[source->Index][2] * invQ; + deriv[3] = machine->DerivY[source->Index][3] * invQ; + } + + result[0] = deriv[GET_SWZ(source->Swizzle, 0)]; + result[1] = deriv[GET_SWZ(source->Swizzle, 1)]; + result[2] = deriv[GET_SWZ(source->Swizzle, 2)]; + result[3] = deriv[GET_SWZ(source->Swizzle, 3)]; + + if (source->Abs) { + result[0] = FABSF(result[0]); + result[1] = FABSF(result[1]); + result[2] = FABSF(result[2]); + result[3] = FABSF(result[3]); + } + if (source->Negate) { + ASSERT(source->Negate == NEGATE_XYZW); + result[0] = -result[0]; + result[1] = -result[1]; + result[2] = -result[2]; + result[3] = -result[3]; + } + } + else { + ASSIGN_4V(result, 0.0, 0.0, 0.0, 0.0); + } +} + + +/** + * As above, but only return result[0] element. + */ +static void +fetch_vector1(const struct prog_src_register *source, + const struct gl_program_machine *machine, GLfloat result[4]) +{ + const GLfloat *src = get_src_register_pointer(source, machine); + ASSERT(src); + + result[0] = src[GET_SWZ(source->Swizzle, 0)]; + + if (source->Abs) { + result[0] = FABSF(result[0]); + } + if (source->Negate) { + result[0] = -result[0]; + } +} + + +static GLuint +fetch_vector1ui(const struct prog_src_register *source, + const struct gl_program_machine *machine) +{ + const GLuint *src = (GLuint *) get_src_register_pointer(source, machine); + return src[GET_SWZ(source->Swizzle, 0)]; +} + + +/** + * Fetch texel from texture. Use partial derivatives when possible. + */ +static INLINE void +fetch_texel(struct gl_context *ctx, + const struct gl_program_machine *machine, + const struct prog_instruction *inst, + const GLfloat texcoord[4], GLfloat lodBias, + GLfloat color[4]) +{ + const GLuint unit = machine->Samplers[inst->TexSrcUnit]; + + /* Note: we only have the right derivatives for fragment input attribs. + */ + if (machine->NumDeriv > 0 && + inst->SrcReg[0].File == PROGRAM_INPUT && + inst->SrcReg[0].Index == FRAG_ATTRIB_TEX0 + inst->TexSrcUnit) { + /* simple texture fetch for which we should have derivatives */ + GLuint attr = inst->SrcReg[0].Index; + machine->FetchTexelDeriv(ctx, texcoord, + machine->DerivX[attr], + machine->DerivY[attr], + lodBias, unit, color); + } + else { + machine->FetchTexelLod(ctx, texcoord, lodBias, unit, color); + } +} + + +/** + * Test value against zero and return GT, LT, EQ or UN if NaN. + */ +static INLINE GLuint +generate_cc(float value) +{ + if (value != value) + return COND_UN; /* NaN */ + if (value > 0.0F) + return COND_GT; + if (value < 0.0F) + return COND_LT; + return COND_EQ; +} + + +/** + * Test if the ccMaskRule is satisfied by the given condition code. + * Used to mask destination writes according to the current condition code. + */ +static INLINE GLboolean +test_cc(GLuint condCode, GLuint ccMaskRule) +{ + switch (ccMaskRule) { + case COND_EQ: return (condCode == COND_EQ); + case COND_NE: return (condCode != COND_EQ); + case COND_LT: return (condCode == COND_LT); + case COND_GE: return (condCode == COND_GT || condCode == COND_EQ); + case COND_LE: return (condCode == COND_LT || condCode == COND_EQ); + case COND_GT: return (condCode == COND_GT); + case COND_TR: return GL_TRUE; + case COND_FL: return GL_FALSE; + default: return GL_TRUE; + } +} + + +/** + * Evaluate the 4 condition codes against a predicate and return GL_TRUE + * or GL_FALSE to indicate result. + */ +static INLINE GLboolean +eval_condition(const struct gl_program_machine *machine, + const struct prog_instruction *inst) +{ + const GLuint swizzle = inst->DstReg.CondSwizzle; + const GLuint condMask = inst->DstReg.CondMask; + if (test_cc(machine->CondCodes[GET_SWZ(swizzle, 0)], condMask) || + test_cc(machine->CondCodes[GET_SWZ(swizzle, 1)], condMask) || + test_cc(machine->CondCodes[GET_SWZ(swizzle, 2)], condMask) || + test_cc(machine->CondCodes[GET_SWZ(swizzle, 3)], condMask)) { + return GL_TRUE; + } + else { + return GL_FALSE; + } +} + + + +/** + * Store 4 floats into a register. Observe the instructions saturate and + * set-condition-code flags. + */ +static void +store_vector4(const struct prog_instruction *inst, + struct gl_program_machine *machine, const GLfloat value[4]) +{ + const struct prog_dst_register *dstReg = &(inst->DstReg); + const GLboolean clamp = inst->SaturateMode == SATURATE_ZERO_ONE; + GLuint writeMask = dstReg->WriteMask; + GLfloat clampedValue[4]; + GLfloat *dst = get_dst_register_pointer(dstReg, machine); + +#if 0 + if (value[0] > 1.0e10 || + IS_INF_OR_NAN(value[0]) || + IS_INF_OR_NAN(value[1]) || + IS_INF_OR_NAN(value[2]) || IS_INF_OR_NAN(value[3])) + printf("store %g %g %g %g\n", value[0], value[1], value[2], value[3]); +#endif + + if (clamp) { + clampedValue[0] = CLAMP(value[0], 0.0F, 1.0F); + clampedValue[1] = CLAMP(value[1], 0.0F, 1.0F); + clampedValue[2] = CLAMP(value[2], 0.0F, 1.0F); + clampedValue[3] = CLAMP(value[3], 0.0F, 1.0F); + value = clampedValue; + } + + if (dstReg->CondMask != COND_TR) { + /* condition codes may turn off some writes */ + if (writeMask & WRITEMASK_X) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 0)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_X; + } + if (writeMask & WRITEMASK_Y) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 1)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_Y; + } + if (writeMask & WRITEMASK_Z) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 2)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_Z; + } + if (writeMask & WRITEMASK_W) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 3)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_W; + } + } + +#ifdef NAN_CHECK + assert(!IS_INF_OR_NAN(value[0])); + assert(!IS_INF_OR_NAN(value[0])); + assert(!IS_INF_OR_NAN(value[0])); + assert(!IS_INF_OR_NAN(value[0])); +#endif + + if (writeMask & WRITEMASK_X) + dst[0] = value[0]; + if (writeMask & WRITEMASK_Y) + dst[1] = value[1]; + if (writeMask & WRITEMASK_Z) + dst[2] = value[2]; + if (writeMask & WRITEMASK_W) + dst[3] = value[3]; + + if (inst->CondUpdate) { + if (writeMask & WRITEMASK_X) + machine->CondCodes[0] = generate_cc(value[0]); + if (writeMask & WRITEMASK_Y) + machine->CondCodes[1] = generate_cc(value[1]); + if (writeMask & WRITEMASK_Z) + machine->CondCodes[2] = generate_cc(value[2]); + if (writeMask & WRITEMASK_W) + machine->CondCodes[3] = generate_cc(value[3]); +#if DEBUG_PROG + printf("CondCodes=(%s,%s,%s,%s) for:\n", + _mesa_condcode_string(machine->CondCodes[0]), + _mesa_condcode_string(machine->CondCodes[1]), + _mesa_condcode_string(machine->CondCodes[2]), + _mesa_condcode_string(machine->CondCodes[3])); +#endif + } +} + + +/** + * Store 4 uints into a register. Observe the set-condition-code flags. + */ +static void +store_vector4ui(const struct prog_instruction *inst, + struct gl_program_machine *machine, const GLuint value[4]) +{ + const struct prog_dst_register *dstReg = &(inst->DstReg); + GLuint writeMask = dstReg->WriteMask; + GLuint *dst = (GLuint *) get_dst_register_pointer(dstReg, machine); + + if (dstReg->CondMask != COND_TR) { + /* condition codes may turn off some writes */ + if (writeMask & WRITEMASK_X) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 0)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_X; + } + if (writeMask & WRITEMASK_Y) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 1)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_Y; + } + if (writeMask & WRITEMASK_Z) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 2)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_Z; + } + if (writeMask & WRITEMASK_W) { + if (!test_cc(machine->CondCodes[GET_SWZ(dstReg->CondSwizzle, 3)], + dstReg->CondMask)) + writeMask &= ~WRITEMASK_W; + } + } + + if (writeMask & WRITEMASK_X) + dst[0] = value[0]; + if (writeMask & WRITEMASK_Y) + dst[1] = value[1]; + if (writeMask & WRITEMASK_Z) + dst[2] = value[2]; + if (writeMask & WRITEMASK_W) + dst[3] = value[3]; + + if (inst->CondUpdate) { + if (writeMask & WRITEMASK_X) + machine->CondCodes[0] = generate_cc((float)value[0]); + if (writeMask & WRITEMASK_Y) + machine->CondCodes[1] = generate_cc((float)value[1]); + if (writeMask & WRITEMASK_Z) + machine->CondCodes[2] = generate_cc((float)value[2]); + if (writeMask & WRITEMASK_W) + machine->CondCodes[3] = generate_cc((float)value[3]); +#if DEBUG_PROG + printf("CondCodes=(%s,%s,%s,%s) for:\n", + _mesa_condcode_string(machine->CondCodes[0]), + _mesa_condcode_string(machine->CondCodes[1]), + _mesa_condcode_string(machine->CondCodes[2]), + _mesa_condcode_string(machine->CondCodes[3])); +#endif + } +} + + + +/** + * Execute the given vertex/fragment program. + * + * \param ctx rendering context + * \param program the program to execute + * \param machine machine state (must be initialized) + * \return GL_TRUE if program completed or GL_FALSE if program executed KIL. + */ +GLboolean +_mesa_execute_program(struct gl_context * ctx, + const struct gl_program *program, + struct gl_program_machine *machine) +{ + const GLuint numInst = program->NumInstructions; + const GLuint maxExec = 10000; + GLuint pc, numExec = 0; + + machine->CurProgram = program; + + if (DEBUG_PROG) { + printf("execute program %u --------------------\n", program->Id); + } + + if (program->Target == GL_VERTEX_PROGRAM_ARB) { + machine->EnvParams = ctx->VertexProgram.Parameters; + } + else { + machine->EnvParams = ctx->FragmentProgram.Parameters; + } + + for (pc = 0; pc < numInst; pc++) { + const struct prog_instruction *inst = program->Instructions + pc; + + if (DEBUG_PROG) { + _mesa_print_instruction(inst); + } + + switch (inst->Opcode) { + case OPCODE_ABS: + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = FABSF(a[0]); + result[1] = FABSF(a[1]); + result[2] = FABSF(a[2]); + result[3] = FABSF(a[3]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_ADD: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = a[0] + b[0]; + result[1] = a[1] + b[1]; + result[2] = a[2] + b[2]; + result[3] = a[3] + b[3]; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("ADD (%g %g %g %g) = (%g %g %g %g) + (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_AND: /* bitwise AND */ + { + GLuint a[4], b[4], result[4]; + fetch_vector4ui(&inst->SrcReg[0], machine, a); + fetch_vector4ui(&inst->SrcReg[1], machine, b); + result[0] = a[0] & b[0]; + result[1] = a[1] & b[1]; + result[2] = a[2] & b[2]; + result[3] = a[3] & b[3]; + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_ARL: + { + GLfloat t[4]; + fetch_vector4(&inst->SrcReg[0], machine, t); + machine->AddressReg[0][0] = IFLOOR(t[0]); + if (DEBUG_PROG) { + printf("ARL %d\n", machine->AddressReg[0][0]); + } + } + break; + case OPCODE_BGNLOOP: + /* no-op */ + ASSERT(program->Instructions[inst->BranchTarget].Opcode + == OPCODE_ENDLOOP); + break; + case OPCODE_ENDLOOP: + /* subtract 1 here since pc is incremented by for(pc) loop */ + ASSERT(program->Instructions[inst->BranchTarget].Opcode + == OPCODE_BGNLOOP); + pc = inst->BranchTarget - 1; /* go to matching BNGLOOP */ + break; + case OPCODE_BGNSUB: /* begin subroutine */ + break; + case OPCODE_ENDSUB: /* end subroutine */ + break; + case OPCODE_BRA: /* branch (conditional) */ + if (eval_condition(machine, inst)) { + /* take branch */ + /* Subtract 1 here since we'll do pc++ below */ + pc = inst->BranchTarget - 1; + } + break; + case OPCODE_BRK: /* break out of loop (conditional) */ + ASSERT(program->Instructions[inst->BranchTarget].Opcode + == OPCODE_ENDLOOP); + if (eval_condition(machine, inst)) { + /* break out of loop */ + /* pc++ at end of for-loop will put us after the ENDLOOP inst */ + pc = inst->BranchTarget; + } + break; + case OPCODE_CONT: /* continue loop (conditional) */ + ASSERT(program->Instructions[inst->BranchTarget].Opcode + == OPCODE_ENDLOOP); + if (eval_condition(machine, inst)) { + /* continue at ENDLOOP */ + /* Subtract 1 here since we'll do pc++ at end of for-loop */ + pc = inst->BranchTarget - 1; + } + break; + case OPCODE_CAL: /* Call subroutine (conditional) */ + if (eval_condition(machine, inst)) { + /* call the subroutine */ + if (machine->StackDepth >= MAX_PROGRAM_CALL_DEPTH) { + return GL_TRUE; /* Per GL_NV_vertex_program2 spec */ + } + machine->CallStack[machine->StackDepth++] = pc + 1; /* next inst */ + /* Subtract 1 here since we'll do pc++ at end of for-loop */ + pc = inst->BranchTarget - 1; + } + break; + case OPCODE_CMP: + { + GLfloat a[4], b[4], c[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + fetch_vector4(&inst->SrcReg[2], machine, c); + result[0] = a[0] < 0.0F ? b[0] : c[0]; + result[1] = a[1] < 0.0F ? b[1] : c[1]; + result[2] = a[2] < 0.0F ? b[2] : c[2]; + result[3] = a[3] < 0.0F ? b[3] : c[3]; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("CMP (%g %g %g %g) = (%g %g %g %g) < 0 ? (%g %g %g %g) : (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3], + c[0], c[1], c[2], c[3]); + } + } + break; + case OPCODE_COS: + { + GLfloat a[4], result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + result[0] = result[1] = result[2] = result[3] + = (GLfloat) cos(a[0]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_DDX: /* Partial derivative with respect to X */ + { + GLfloat result[4]; + fetch_vector4_deriv(ctx, &inst->SrcReg[0], machine, + 'X', result); + store_vector4(inst, machine, result); + } + break; + case OPCODE_DDY: /* Partial derivative with respect to Y */ + { + GLfloat result[4]; + fetch_vector4_deriv(ctx, &inst->SrcReg[0], machine, + 'Y', result); + store_vector4(inst, machine, result); + } + break; + case OPCODE_DP2: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = result[1] = result[2] = result[3] = DOT2(a, b); + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("DP2 %g = (%g %g) . (%g %g)\n", + result[0], a[0], a[1], b[0], b[1]); + } + } + break; + case OPCODE_DP2A: + { + GLfloat a[4], b[4], c, result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + fetch_vector1(&inst->SrcReg[1], machine, &c); + result[0] = result[1] = result[2] = result[3] = DOT2(a, b) + c; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("DP2A %g = (%g %g) . (%g %g) + %g\n", + result[0], a[0], a[1], b[0], b[1], c); + } + } + break; + case OPCODE_DP3: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = result[1] = result[2] = result[3] = DOT3(a, b); + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("DP3 %g = (%g %g %g) . (%g %g %g)\n", + result[0], a[0], a[1], a[2], b[0], b[1], b[2]); + } + } + break; + case OPCODE_DP4: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = result[1] = result[2] = result[3] = DOT4(a, b); + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("DP4 %g = (%g, %g %g %g) . (%g, %g %g %g)\n", + result[0], a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_DPH: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = result[1] = result[2] = result[3] = DOT3(a, b) + b[3]; + store_vector4(inst, machine, result); + } + break; + case OPCODE_DST: /* Distance vector */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = 1.0F; + result[1] = a[1] * b[1]; + result[2] = a[2]; + result[3] = b[3]; + store_vector4(inst, machine, result); + } + break; + case OPCODE_EXP: + { + GLfloat t[4], q[4], floor_t0; + fetch_vector1(&inst->SrcReg[0], machine, t); + floor_t0 = FLOORF(t[0]); + if (floor_t0 > FLT_MAX_EXP) { + SET_POS_INFINITY(q[0]); + SET_POS_INFINITY(q[2]); + } + else if (floor_t0 < FLT_MIN_EXP) { + q[0] = 0.0F; + q[2] = 0.0F; + } + else { + q[0] = LDEXPF(1.0, (int) floor_t0); + /* Note: GL_NV_vertex_program expects + * result.z = result.x * APPX(result.y) + * We do what the ARB extension says. + */ + q[2] = (GLfloat) pow(2.0, t[0]); + } + q[1] = t[0] - floor_t0; + q[3] = 1.0F; + store_vector4( inst, machine, q ); + } + break; + case OPCODE_EX2: /* Exponential base 2 */ + { + GLfloat a[4], result[4], val; + fetch_vector1(&inst->SrcReg[0], machine, a); + val = (GLfloat) pow(2.0, a[0]); + /* + if (IS_INF_OR_NAN(val)) + val = 1.0e10; + */ + result[0] = result[1] = result[2] = result[3] = val; + store_vector4(inst, machine, result); + } + break; + case OPCODE_FLR: + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = FLOORF(a[0]); + result[1] = FLOORF(a[1]); + result[2] = FLOORF(a[2]); + result[3] = FLOORF(a[3]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_FRC: + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = a[0] - FLOORF(a[0]); + result[1] = a[1] - FLOORF(a[1]); + result[2] = a[2] - FLOORF(a[2]); + result[3] = a[3] - FLOORF(a[3]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_IF: + { + GLboolean cond; + ASSERT(program->Instructions[inst->BranchTarget].Opcode + == OPCODE_ELSE || + program->Instructions[inst->BranchTarget].Opcode + == OPCODE_ENDIF); + /* eval condition */ + if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { + GLfloat a[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + cond = (a[0] != 0.0); + } + else { + cond = eval_condition(machine, inst); + } + if (DEBUG_PROG) { + printf("IF: %d\n", cond); + } + /* do if/else */ + if (cond) { + /* do if-clause (just continue execution) */ + } + else { + /* go to the instruction after ELSE or ENDIF */ + assert(inst->BranchTarget >= 0); + pc = inst->BranchTarget; + } + } + break; + case OPCODE_ELSE: + /* goto ENDIF */ + ASSERT(program->Instructions[inst->BranchTarget].Opcode + == OPCODE_ENDIF); + assert(inst->BranchTarget >= 0); + pc = inst->BranchTarget; + break; + case OPCODE_ENDIF: + /* nothing */ + break; + case OPCODE_KIL_NV: /* NV_f_p only (conditional) */ + if (eval_condition(machine, inst)) { + return GL_FALSE; + } + break; + case OPCODE_KIL: /* ARB_f_p only */ + { + GLfloat a[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + if (DEBUG_PROG) { + printf("KIL if (%g %g %g %g) <= 0.0\n", + a[0], a[1], a[2], a[3]); + } + + if (a[0] < 0.0F || a[1] < 0.0F || a[2] < 0.0F || a[3] < 0.0F) { + return GL_FALSE; + } + } + break; + case OPCODE_LG2: /* log base 2 */ + { + GLfloat a[4], result[4], val; + fetch_vector1(&inst->SrcReg[0], machine, a); + /* The fast LOG2 macro doesn't meet the precision requirements. + */ + if (a[0] == 0.0F) { + val = -FLT_MAX; + } + else { + val = (float)(log(a[0]) * 1.442695F); + } + result[0] = result[1] = result[2] = result[3] = val; + store_vector4(inst, machine, result); + } + break; + case OPCODE_LIT: + { + const GLfloat epsilon = 1.0F / 256.0F; /* from NV VP spec */ + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + a[0] = MAX2(a[0], 0.0F); + a[1] = MAX2(a[1], 0.0F); + /* XXX ARB version clamps a[3], NV version doesn't */ + a[3] = CLAMP(a[3], -(128.0F - epsilon), (128.0F - epsilon)); + result[0] = 1.0F; + result[1] = a[0]; + /* XXX we could probably just use pow() here */ + if (a[0] > 0.0F) { + if (a[1] == 0.0 && a[3] == 0.0) + result[2] = 1.0F; + else + result[2] = (GLfloat) pow(a[1], a[3]); + } + else { + result[2] = 0.0F; + } + result[3] = 1.0F; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("LIT (%g %g %g %g) : (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3]); + } + } + break; + case OPCODE_LOG: + { + GLfloat t[4], q[4], abs_t0; + fetch_vector1(&inst->SrcReg[0], machine, t); + abs_t0 = FABSF(t[0]); + if (abs_t0 != 0.0F) { + /* Since we really can't handle infinite values on VMS + * like other OSes we'll use __MAXFLOAT to represent + * infinity. This may need some tweaking. + */ +#ifdef VMS + if (abs_t0 == __MAXFLOAT) +#else + if (IS_INF_OR_NAN(abs_t0)) +#endif + { + SET_POS_INFINITY(q[0]); + q[1] = 1.0F; + SET_POS_INFINITY(q[2]); + } + else { + int exponent; + GLfloat mantissa = FREXPF(t[0], &exponent); + q[0] = (GLfloat) (exponent - 1); + q[1] = (GLfloat) (2.0 * mantissa); /* map [.5, 1) -> [1, 2) */ + + /* The fast LOG2 macro doesn't meet the precision + * requirements. + */ + q[2] = (float)(log(t[0]) * 1.442695F); + } + } + else { + SET_NEG_INFINITY(q[0]); + q[1] = 1.0F; + SET_NEG_INFINITY(q[2]); + } + q[3] = 1.0; + store_vector4(inst, machine, q); + } + break; + case OPCODE_LRP: + { + GLfloat a[4], b[4], c[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + fetch_vector4(&inst->SrcReg[2], machine, c); + result[0] = a[0] * b[0] + (1.0F - a[0]) * c[0]; + result[1] = a[1] * b[1] + (1.0F - a[1]) * c[1]; + result[2] = a[2] * b[2] + (1.0F - a[2]) * c[2]; + result[3] = a[3] * b[3] + (1.0F - a[3]) * c[3]; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("LRP (%g %g %g %g) = (%g %g %g %g), " + "(%g %g %g %g), (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3], c[0], c[1], c[2], c[3]); + } + } + break; + case OPCODE_MAD: + { + GLfloat a[4], b[4], c[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + fetch_vector4(&inst->SrcReg[2], machine, c); + result[0] = a[0] * b[0] + c[0]; + result[1] = a[1] * b[1] + c[1]; + result[2] = a[2] * b[2] + c[2]; + result[3] = a[3] * b[3] + c[3]; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("MAD (%g %g %g %g) = (%g %g %g %g) * " + "(%g %g %g %g) + (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3], c[0], c[1], c[2], c[3]); + } + } + break; + case OPCODE_MAX: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = MAX2(a[0], b[0]); + result[1] = MAX2(a[1], b[1]); + result[2] = MAX2(a[2], b[2]); + result[3] = MAX2(a[3], b[3]); + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("MAX (%g %g %g %g) = (%g %g %g %g), (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_MIN: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = MIN2(a[0], b[0]); + result[1] = MIN2(a[1], b[1]); + result[2] = MIN2(a[2], b[2]); + result[3] = MIN2(a[3], b[3]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_MOV: + { + GLfloat result[4]; + fetch_vector4(&inst->SrcReg[0], machine, result); + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("MOV (%g %g %g %g)\n", + result[0], result[1], result[2], result[3]); + } + } + break; + case OPCODE_MUL: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = a[0] * b[0]; + result[1] = a[1] * b[1]; + result[2] = a[2] * b[2]; + result[3] = a[3] * b[3]; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("MUL (%g %g %g %g) = (%g %g %g %g) * (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_NOISE1: + { + GLfloat a[4], result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + result[0] = + result[1] = + result[2] = + result[3] = _mesa_noise1(a[0]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_NOISE2: + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = + result[1] = + result[2] = result[3] = _mesa_noise2(a[0], a[1]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_NOISE3: + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = + result[1] = + result[2] = + result[3] = _mesa_noise3(a[0], a[1], a[2]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_NOISE4: + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = + result[1] = + result[2] = + result[3] = _mesa_noise4(a[0], a[1], a[2], a[3]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_NOP: + break; + case OPCODE_NOT: /* bitwise NOT */ + { + GLuint a[4], result[4]; + fetch_vector4ui(&inst->SrcReg[0], machine, a); + result[0] = ~a[0]; + result[1] = ~a[1]; + result[2] = ~a[2]; + result[3] = ~a[3]; + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_NRM3: /* 3-component normalization */ + { + GLfloat a[4], result[4]; + GLfloat tmp; + fetch_vector4(&inst->SrcReg[0], machine, a); + tmp = a[0] * a[0] + a[1] * a[1] + a[2] * a[2]; + if (tmp != 0.0F) + tmp = INV_SQRTF(tmp); + result[0] = tmp * a[0]; + result[1] = tmp * a[1]; + result[2] = tmp * a[2]; + result[3] = 0.0; /* undefined, but prevent valgrind warnings */ + store_vector4(inst, machine, result); + } + break; + case OPCODE_NRM4: /* 4-component normalization */ + { + GLfloat a[4], result[4]; + GLfloat tmp; + fetch_vector4(&inst->SrcReg[0], machine, a); + tmp = a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3]; + if (tmp != 0.0F) + tmp = INV_SQRTF(tmp); + result[0] = tmp * a[0]; + result[1] = tmp * a[1]; + result[2] = tmp * a[2]; + result[3] = tmp * a[3]; + store_vector4(inst, machine, result); + } + break; + case OPCODE_OR: /* bitwise OR */ + { + GLuint a[4], b[4], result[4]; + fetch_vector4ui(&inst->SrcReg[0], machine, a); + fetch_vector4ui(&inst->SrcReg[1], machine, b); + result[0] = a[0] | b[0]; + result[1] = a[1] | b[1]; + result[2] = a[2] | b[2]; + result[3] = a[3] | b[3]; + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_PK2H: /* pack two 16-bit floats in one 32-bit float */ + { + GLfloat a[4]; + GLuint result[4]; + GLhalfNV hx, hy; + fetch_vector4(&inst->SrcReg[0], machine, a); + hx = _mesa_float_to_half(a[0]); + hy = _mesa_float_to_half(a[1]); + result[0] = + result[1] = + result[2] = + result[3] = hx | (hy << 16); + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_PK2US: /* pack two GLushorts into one 32-bit float */ + { + GLfloat a[4]; + GLuint result[4], usx, usy; + fetch_vector4(&inst->SrcReg[0], machine, a); + a[0] = CLAMP(a[0], 0.0F, 1.0F); + a[1] = CLAMP(a[1], 0.0F, 1.0F); + usx = IROUND(a[0] * 65535.0F); + usy = IROUND(a[1] * 65535.0F); + result[0] = + result[1] = + result[2] = + result[3] = usx | (usy << 16); + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_PK4B: /* pack four GLbytes into one 32-bit float */ + { + GLfloat a[4]; + GLuint result[4], ubx, uby, ubz, ubw; + fetch_vector4(&inst->SrcReg[0], machine, a); + a[0] = CLAMP(a[0], -128.0F / 127.0F, 1.0F); + a[1] = CLAMP(a[1], -128.0F / 127.0F, 1.0F); + a[2] = CLAMP(a[2], -128.0F / 127.0F, 1.0F); + a[3] = CLAMP(a[3], -128.0F / 127.0F, 1.0F); + ubx = IROUND(127.0F * a[0] + 128.0F); + uby = IROUND(127.0F * a[1] + 128.0F); + ubz = IROUND(127.0F * a[2] + 128.0F); + ubw = IROUND(127.0F * a[3] + 128.0F); + result[0] = + result[1] = + result[2] = + result[3] = ubx | (uby << 8) | (ubz << 16) | (ubw << 24); + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_PK4UB: /* pack four GLubytes into one 32-bit float */ + { + GLfloat a[4]; + GLuint result[4], ubx, uby, ubz, ubw; + fetch_vector4(&inst->SrcReg[0], machine, a); + a[0] = CLAMP(a[0], 0.0F, 1.0F); + a[1] = CLAMP(a[1], 0.0F, 1.0F); + a[2] = CLAMP(a[2], 0.0F, 1.0F); + a[3] = CLAMP(a[3], 0.0F, 1.0F); + ubx = IROUND(255.0F * a[0]); + uby = IROUND(255.0F * a[1]); + ubz = IROUND(255.0F * a[2]); + ubw = IROUND(255.0F * a[3]); + result[0] = + result[1] = + result[2] = + result[3] = ubx | (uby << 8) | (ubz << 16) | (ubw << 24); + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_POW: + { + GLfloat a[4], b[4], result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + fetch_vector1(&inst->SrcReg[1], machine, b); + result[0] = result[1] = result[2] = result[3] + = (GLfloat) pow(a[0], b[0]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_RCC: /* clamped riciprocal */ + { + const float largest = 1.884467e+19, smallest = 5.42101e-20; + GLfloat a[4], r, result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + if (DEBUG_PROG) { + if (a[0] == 0) + printf("RCC(0)\n"); + else if (IS_INF_OR_NAN(a[0])) + printf("RCC(inf)\n"); + } + if (a[0] == 1.0F) { + r = 1.0F; + } + else { + r = 1.0F / a[0]; + } + if (positive(r)) { + if (r > largest) { + r = largest; + } + else if (r < smallest) { + r = smallest; + } + } + else { + if (r < -largest) { + r = -largest; + } + else if (r > -smallest) { + r = -smallest; + } + } + result[0] = result[1] = result[2] = result[3] = r; + store_vector4(inst, machine, result); + } + break; + + case OPCODE_RCP: + { + GLfloat a[4], result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + if (DEBUG_PROG) { + if (a[0] == 0) + printf("RCP(0)\n"); + else if (IS_INF_OR_NAN(a[0])) + printf("RCP(inf)\n"); + } + result[0] = result[1] = result[2] = result[3] = 1.0F / a[0]; + store_vector4(inst, machine, result); + } + break; + case OPCODE_RET: /* return from subroutine (conditional) */ + if (eval_condition(machine, inst)) { + if (machine->StackDepth == 0) { + return GL_TRUE; /* Per GL_NV_vertex_program2 spec */ + } + /* subtract one because of pc++ in the for loop */ + pc = machine->CallStack[--machine->StackDepth] - 1; + } + break; + case OPCODE_RFL: /* reflection vector */ + { + GLfloat axis[4], dir[4], result[4], tmpX, tmpW; + fetch_vector4(&inst->SrcReg[0], machine, axis); + fetch_vector4(&inst->SrcReg[1], machine, dir); + tmpW = DOT3(axis, axis); + tmpX = (2.0F * DOT3(axis, dir)) / tmpW; + result[0] = tmpX * axis[0] - dir[0]; + result[1] = tmpX * axis[1] - dir[1]; + result[2] = tmpX * axis[2] - dir[2]; + /* result[3] is never written! XXX enforce in parser! */ + store_vector4(inst, machine, result); + } + break; + case OPCODE_RSQ: /* 1 / sqrt() */ + { + GLfloat a[4], result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + a[0] = FABSF(a[0]); + result[0] = result[1] = result[2] = result[3] = INV_SQRTF(a[0]); + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("RSQ %g = 1/sqrt(|%g|)\n", result[0], a[0]); + } + } + break; + case OPCODE_SCS: /* sine and cos */ + { + GLfloat a[4], result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + result[0] = (GLfloat) cos(a[0]); + result[1] = (GLfloat) sin(a[0]); + result[2] = 0.0; /* undefined! */ + result[3] = 0.0; /* undefined! */ + store_vector4(inst, machine, result); + } + break; + case OPCODE_SEQ: /* set on equal */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = (a[0] == b[0]) ? 1.0F : 0.0F; + result[1] = (a[1] == b[1]) ? 1.0F : 0.0F; + result[2] = (a[2] == b[2]) ? 1.0F : 0.0F; + result[3] = (a[3] == b[3]) ? 1.0F : 0.0F; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("SEQ (%g %g %g %g) = (%g %g %g %g) == (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_SFL: /* set false, operands ignored */ + { + static const GLfloat result[4] = { 0.0F, 0.0F, 0.0F, 0.0F }; + store_vector4(inst, machine, result); + } + break; + case OPCODE_SGE: /* set on greater or equal */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = (a[0] >= b[0]) ? 1.0F : 0.0F; + result[1] = (a[1] >= b[1]) ? 1.0F : 0.0F; + result[2] = (a[2] >= b[2]) ? 1.0F : 0.0F; + result[3] = (a[3] >= b[3]) ? 1.0F : 0.0F; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("SGE (%g %g %g %g) = (%g %g %g %g) >= (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_SGT: /* set on greater */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = (a[0] > b[0]) ? 1.0F : 0.0F; + result[1] = (a[1] > b[1]) ? 1.0F : 0.0F; + result[2] = (a[2] > b[2]) ? 1.0F : 0.0F; + result[3] = (a[3] > b[3]) ? 1.0F : 0.0F; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("SGT (%g %g %g %g) = (%g %g %g %g) > (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_SIN: + { + GLfloat a[4], result[4]; + fetch_vector1(&inst->SrcReg[0], machine, a); + result[0] = result[1] = result[2] = result[3] + = (GLfloat) sin(a[0]); + store_vector4(inst, machine, result); + } + break; + case OPCODE_SLE: /* set on less or equal */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = (a[0] <= b[0]) ? 1.0F : 0.0F; + result[1] = (a[1] <= b[1]) ? 1.0F : 0.0F; + result[2] = (a[2] <= b[2]) ? 1.0F : 0.0F; + result[3] = (a[3] <= b[3]) ? 1.0F : 0.0F; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("SLE (%g %g %g %g) = (%g %g %g %g) <= (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_SLT: /* set on less */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = (a[0] < b[0]) ? 1.0F : 0.0F; + result[1] = (a[1] < b[1]) ? 1.0F : 0.0F; + result[2] = (a[2] < b[2]) ? 1.0F : 0.0F; + result[3] = (a[3] < b[3]) ? 1.0F : 0.0F; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("SLT (%g %g %g %g) = (%g %g %g %g) < (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_SNE: /* set on not equal */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = (a[0] != b[0]) ? 1.0F : 0.0F; + result[1] = (a[1] != b[1]) ? 1.0F : 0.0F; + result[2] = (a[2] != b[2]) ? 1.0F : 0.0F; + result[3] = (a[3] != b[3]) ? 1.0F : 0.0F; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("SNE (%g %g %g %g) = (%g %g %g %g) != (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], + b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_SSG: /* set sign (-1, 0 or +1) */ + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = (GLfloat) ((a[0] > 0.0F) - (a[0] < 0.0F)); + result[1] = (GLfloat) ((a[1] > 0.0F) - (a[1] < 0.0F)); + result[2] = (GLfloat) ((a[2] > 0.0F) - (a[2] < 0.0F)); + result[3] = (GLfloat) ((a[3] > 0.0F) - (a[3] < 0.0F)); + store_vector4(inst, machine, result); + } + break; + case OPCODE_STR: /* set true, operands ignored */ + { + static const GLfloat result[4] = { 1.0F, 1.0F, 1.0F, 1.0F }; + store_vector4(inst, machine, result); + } + break; + case OPCODE_SUB: + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = a[0] - b[0]; + result[1] = a[1] - b[1]; + result[2] = a[2] - b[2]; + result[3] = a[3] - b[3]; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("SUB (%g %g %g %g) = (%g %g %g %g) - (%g %g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], a[3], b[0], b[1], b[2], b[3]); + } + } + break; + case OPCODE_SWZ: /* extended swizzle */ + { + const struct prog_src_register *source = &inst->SrcReg[0]; + const GLfloat *src = get_src_register_pointer(source, machine); + GLfloat result[4]; + GLuint i; + for (i = 0; i < 4; i++) { + const GLuint swz = GET_SWZ(source->Swizzle, i); + if (swz == SWIZZLE_ZERO) + result[i] = 0.0; + else if (swz == SWIZZLE_ONE) + result[i] = 1.0; + else { + ASSERT(swz >= 0); + ASSERT(swz <= 3); + result[i] = src[swz]; + } + if (source->Negate & (1 << i)) + result[i] = -result[i]; + } + store_vector4(inst, machine, result); + } + break; + case OPCODE_TEX: /* Both ARB and NV frag prog */ + /* Simple texel lookup */ + { + GLfloat texcoord[4], color[4]; + fetch_vector4(&inst->SrcReg[0], machine, texcoord); + + fetch_texel(ctx, machine, inst, texcoord, 0.0, color); + + if (DEBUG_PROG) { + printf("TEX (%g, %g, %g, %g) = texture[%d][%g, %g, %g, %g]\n", + color[0], color[1], color[2], color[3], + inst->TexSrcUnit, + texcoord[0], texcoord[1], texcoord[2], texcoord[3]); + } + store_vector4(inst, machine, color); + } + break; + case OPCODE_TXB: /* GL_ARB_fragment_program only */ + /* Texel lookup with LOD bias */ + { + GLfloat texcoord[4], color[4], lodBias; + + fetch_vector4(&inst->SrcReg[0], machine, texcoord); + + /* texcoord[3] is the bias to add to lambda */ + lodBias = texcoord[3]; + + fetch_texel(ctx, machine, inst, texcoord, lodBias, color); + + if (DEBUG_PROG) { + printf("TXB (%g, %g, %g, %g) = texture[%d][%g %g %g %g]" + " bias %g\n", + color[0], color[1], color[2], color[3], + inst->TexSrcUnit, + texcoord[0], + texcoord[1], + texcoord[2], + texcoord[3], + lodBias); + } + + store_vector4(inst, machine, color); + } + break; + case OPCODE_TXD: /* GL_NV_fragment_program only */ + /* Texture lookup w/ partial derivatives for LOD */ + { + GLfloat texcoord[4], dtdx[4], dtdy[4], color[4]; + fetch_vector4(&inst->SrcReg[0], machine, texcoord); + fetch_vector4(&inst->SrcReg[1], machine, dtdx); + fetch_vector4(&inst->SrcReg[2], machine, dtdy); + machine->FetchTexelDeriv(ctx, texcoord, dtdx, dtdy, + 0.0, /* lodBias */ + inst->TexSrcUnit, color); + store_vector4(inst, machine, color); + } + break; + case OPCODE_TXL: + /* Texel lookup with explicit LOD */ + { + GLfloat texcoord[4], color[4], lod; + + fetch_vector4(&inst->SrcReg[0], machine, texcoord); + + /* texcoord[3] is the LOD */ + lod = texcoord[3]; + + machine->FetchTexelLod(ctx, texcoord, lod, + machine->Samplers[inst->TexSrcUnit], color); + + store_vector4(inst, machine, color); + } + break; + case OPCODE_TXP: /* GL_ARB_fragment_program only */ + /* Texture lookup w/ projective divide */ + { + GLfloat texcoord[4], color[4]; + + fetch_vector4(&inst->SrcReg[0], machine, texcoord); + /* Not so sure about this test - if texcoord[3] is + * zero, we'd probably be fine except for an ASSERT in + * IROUND_POS() which gets triggered by the inf values created. + */ + if (texcoord[3] != 0.0) { + texcoord[0] /= texcoord[3]; + texcoord[1] /= texcoord[3]; + texcoord[2] /= texcoord[3]; + } + + fetch_texel(ctx, machine, inst, texcoord, 0.0, color); + + store_vector4(inst, machine, color); + } + break; + case OPCODE_TXP_NV: /* GL_NV_fragment_program only */ + /* Texture lookup w/ projective divide, as above, but do not + * do the divide by w if sampling from a cube map. + */ + { + GLfloat texcoord[4], color[4]; + + fetch_vector4(&inst->SrcReg[0], machine, texcoord); + if (inst->TexSrcTarget != TEXTURE_CUBE_INDEX && + texcoord[3] != 0.0) { + texcoord[0] /= texcoord[3]; + texcoord[1] /= texcoord[3]; + texcoord[2] /= texcoord[3]; + } + + fetch_texel(ctx, machine, inst, texcoord, 0.0, color); + + store_vector4(inst, machine, color); + } + break; + case OPCODE_TRUNC: /* truncate toward zero */ + { + GLfloat a[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + result[0] = (GLfloat) (GLint) a[0]; + result[1] = (GLfloat) (GLint) a[1]; + result[2] = (GLfloat) (GLint) a[2]; + result[3] = (GLfloat) (GLint) a[3]; + store_vector4(inst, machine, result); + } + break; + case OPCODE_UP2H: /* unpack two 16-bit floats */ + { + const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine); + GLfloat result[4]; + GLushort hx, hy; + hx = raw & 0xffff; + hy = raw >> 16; + result[0] = result[2] = _mesa_half_to_float(hx); + result[1] = result[3] = _mesa_half_to_float(hy); + store_vector4(inst, machine, result); + } + break; + case OPCODE_UP2US: /* unpack two GLushorts */ + { + const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine); + GLfloat result[4]; + GLushort usx, usy; + usx = raw & 0xffff; + usy = raw >> 16; + result[0] = result[2] = usx * (1.0f / 65535.0f); + result[1] = result[3] = usy * (1.0f / 65535.0f); + store_vector4(inst, machine, result); + } + break; + case OPCODE_UP4B: /* unpack four GLbytes */ + { + const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine); + GLfloat result[4]; + result[0] = (((raw >> 0) & 0xff) - 128) / 127.0F; + result[1] = (((raw >> 8) & 0xff) - 128) / 127.0F; + result[2] = (((raw >> 16) & 0xff) - 128) / 127.0F; + result[3] = (((raw >> 24) & 0xff) - 128) / 127.0F; + store_vector4(inst, machine, result); + } + break; + case OPCODE_UP4UB: /* unpack four GLubytes */ + { + const GLuint raw = fetch_vector1ui(&inst->SrcReg[0], machine); + GLfloat result[4]; + result[0] = ((raw >> 0) & 0xff) / 255.0F; + result[1] = ((raw >> 8) & 0xff) / 255.0F; + result[2] = ((raw >> 16) & 0xff) / 255.0F; + result[3] = ((raw >> 24) & 0xff) / 255.0F; + store_vector4(inst, machine, result); + } + break; + case OPCODE_XOR: /* bitwise XOR */ + { + GLuint a[4], b[4], result[4]; + fetch_vector4ui(&inst->SrcReg[0], machine, a); + fetch_vector4ui(&inst->SrcReg[1], machine, b); + result[0] = a[0] ^ b[0]; + result[1] = a[1] ^ b[1]; + result[2] = a[2] ^ b[2]; + result[3] = a[3] ^ b[3]; + store_vector4ui(inst, machine, result); + } + break; + case OPCODE_XPD: /* cross product */ + { + GLfloat a[4], b[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + result[0] = a[1] * b[2] - a[2] * b[1]; + result[1] = a[2] * b[0] - a[0] * b[2]; + result[2] = a[0] * b[1] - a[1] * b[0]; + result[3] = 1.0; + store_vector4(inst, machine, result); + if (DEBUG_PROG) { + printf("XPD (%g %g %g %g) = (%g %g %g) X (%g %g %g)\n", + result[0], result[1], result[2], result[3], + a[0], a[1], a[2], b[0], b[1], b[2]); + } + } + break; + case OPCODE_X2D: /* 2-D matrix transform */ + { + GLfloat a[4], b[4], c[4], result[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + fetch_vector4(&inst->SrcReg[1], machine, b); + fetch_vector4(&inst->SrcReg[2], machine, c); + result[0] = a[0] + b[0] * c[0] + b[1] * c[1]; + result[1] = a[1] + b[0] * c[2] + b[1] * c[3]; + result[2] = a[2] + b[0] * c[0] + b[1] * c[1]; + result[3] = a[3] + b[0] * c[2] + b[1] * c[3]; + store_vector4(inst, machine, result); + } + break; + case OPCODE_PRINT: + { + if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) { + GLfloat a[4]; + fetch_vector4(&inst->SrcReg[0], machine, a); + printf("%s%g, %g, %g, %g\n", (const char *) inst->Data, + a[0], a[1], a[2], a[3]); + } + else { + printf("%s\n", (const char *) inst->Data); + } + } + break; + case OPCODE_END: + return GL_TRUE; + default: + _mesa_problem(ctx, "Bad opcode %d in _mesa_execute_program", + inst->Opcode); + return GL_TRUE; /* return value doesn't matter */ + } + + numExec++; + if (numExec > maxExec) { + static GLboolean reported = GL_FALSE; + if (!reported) { + _mesa_problem(ctx, "Infinite loop detected in fragment program"); + reported = GL_TRUE; + } + return GL_TRUE; + } + + } /* for pc */ + + return GL_TRUE; +} diff --git a/mesalib/src/mesa/program/prog_parameter.c b/mesalib/src/mesa/program/prog_parameter.c index 157e31b56..49b3ffbdd 100644 --- a/mesalib/src/mesa/program/prog_parameter.c +++ b/mesalib/src/mesa/program/prog_parameter.c @@ -1,656 +1,680 @@ -/*
- * Mesa 3-D graphics library
- * Version: 7.3
- *
- * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/**
- * \file prog_parameter.c
- * Program parameter lists and functions.
- * \author Brian Paul
- */
-
-
-#include "main/glheader.h"
-#include "main/imports.h"
-#include "main/macros.h"
-#include "prog_instruction.h"
-#include "prog_parameter.h"
-#include "prog_statevars.h"
-
-
-struct gl_program_parameter_list *
-_mesa_new_parameter_list(void)
-{
- return CALLOC_STRUCT(gl_program_parameter_list);
-}
-
-
-struct gl_program_parameter_list *
-_mesa_new_parameter_list_sized(unsigned size)
-{
- struct gl_program_parameter_list *p = _mesa_new_parameter_list();
-
- if ((p != NULL) && (size != 0)) {
- p->Size = size;
-
- /* alloc arrays */
- p->Parameters = (struct gl_program_parameter *)
- calloc(1, size * sizeof(struct gl_program_parameter));
-
- p->ParameterValues = (GLfloat (*)[4])
- _mesa_align_malloc(size * 4 *sizeof(GLfloat), 16);
-
-
- if ((p->Parameters == NULL) || (p->ParameterValues == NULL)) {
- free(p->Parameters);
- _mesa_align_free(p->ParameterValues);
- free(p);
- p = NULL;
- }
- }
-
- return p;
-}
-
-
-/**
- * Free a parameter list and all its parameters
- */
-void
-_mesa_free_parameter_list(struct gl_program_parameter_list *paramList)
-{
- GLuint i;
- for (i = 0; i < paramList->NumParameters; i++) {
- if (paramList->Parameters[i].Name)
- free((void *) paramList->Parameters[i].Name);
- }
- free(paramList->Parameters);
- if (paramList->ParameterValues)
- _mesa_align_free(paramList->ParameterValues);
- free(paramList);
-}
-
-
-/**
- * Add a new parameter to a parameter list.
- * Note that parameter values are usually 4-element GLfloat vectors.
- * When size > 4 we'll allocate a sequential block of parameters to
- * store all the values (in blocks of 4).
- *
- * \param paramList the list to add the parameter to
- * \param type type of parameter, such as
- * \param name the parameter name, will be duplicated/copied!
- * \param size number of elements in 'values' vector (1..4, or more)
- * \param datatype GL_FLOAT, GL_FLOAT_VECx, GL_INT, GL_INT_VECx or GL_NONE.
- * \param values initial parameter value, up to 4 GLfloats, or NULL
- * \param state state indexes, or NULL
- * \return index of new parameter in the list, or -1 if error (out of mem)
- */
-GLint
-_mesa_add_parameter(struct gl_program_parameter_list *paramList,
- gl_register_file type, const char *name,
- GLuint size, GLenum datatype, const GLfloat *values,
- const gl_state_index state[STATE_LENGTH],
- GLbitfield flags)
-{
- const GLuint oldNum = paramList->NumParameters;
- const GLuint sz4 = (size + 3) / 4; /* no. of new param slots needed */
-
- assert(size > 0);
-
- if (oldNum + sz4 > paramList->Size) {
- /* Need to grow the parameter list array (alloc some extra) */
- paramList->Size = paramList->Size + 4 * sz4;
-
- /* realloc arrays */
- paramList->Parameters = (struct gl_program_parameter *)
- _mesa_realloc(paramList->Parameters,
- oldNum * sizeof(struct gl_program_parameter),
- paramList->Size * sizeof(struct gl_program_parameter));
-
- paramList->ParameterValues = (GLfloat (*)[4])
- _mesa_align_realloc(paramList->ParameterValues, /* old buf */
- oldNum * 4 * sizeof(GLfloat), /* old size */
- paramList->Size * 4 *sizeof(GLfloat), /* new sz */
- 16);
- }
-
- if (!paramList->Parameters ||
- !paramList->ParameterValues) {
- /* out of memory */
- paramList->NumParameters = 0;
- paramList->Size = 0;
- return -1;
- }
- else {
- GLuint i;
-
- paramList->NumParameters = oldNum + sz4;
-
- memset(¶mList->Parameters[oldNum], 0,
- sz4 * sizeof(struct gl_program_parameter));
-
- for (i = 0; i < sz4; i++) {
- struct gl_program_parameter *p = paramList->Parameters + oldNum + i;
- p->Name = name ? _mesa_strdup(name) : NULL;
- p->Type = type;
- p->Size = size;
- p->DataType = datatype;
- p->Flags = flags;
- if (values) {
- COPY_4V(paramList->ParameterValues[oldNum + i], values);
- values += 4;
- p->Initialized = GL_TRUE;
- }
- else {
- /* silence valgrind */
- ASSIGN_4V(paramList->ParameterValues[oldNum + i], 0, 0, 0, 0);
- }
- size -= 4;
- }
-
- if (state) {
- for (i = 0; i < STATE_LENGTH; i++)
- paramList->Parameters[oldNum].StateIndexes[i] = state[i];
- }
-
- return (GLint) oldNum;
- }
-}
-
-
-/**
- * Add a new named program parameter (Ex: NV_fragment_program DEFINE statement)
- * \return index of the new entry in the parameter list
- */
-GLint
-_mesa_add_named_parameter(struct gl_program_parameter_list *paramList,
- const char *name, const GLfloat values[4])
-{
- return _mesa_add_parameter(paramList, PROGRAM_NAMED_PARAM, name,
- 4, GL_NONE, values, NULL, 0x0);
-
-}
-
-
-/**
- * Add a new named constant to the parameter list.
- * This will be used when the program contains something like this:
- * PARAM myVals = { 0, 1, 2, 3 };
- *
- * \param paramList the parameter list
- * \param name the name for the constant
- * \param values four float values
- * \return index/position of the new parameter in the parameter list
- */
-GLint
-_mesa_add_named_constant(struct gl_program_parameter_list *paramList,
- const char *name, const GLfloat values[4],
- GLuint size)
-{
- /* first check if this is a duplicate constant */
- GLint pos;
- for (pos = 0; pos < (GLint)paramList->NumParameters; pos++) {
- const GLfloat *pvals = paramList->ParameterValues[pos];
- if (pvals[0] == values[0] &&
- pvals[1] == values[1] &&
- pvals[2] == values[2] &&
- pvals[3] == values[3] &&
- strcmp(paramList->Parameters[pos].Name, name) == 0) {
- /* Same name and value is already in the param list - reuse it */
- return pos;
- }
- }
- /* not found, add new parameter */
- return _mesa_add_parameter(paramList, PROGRAM_CONSTANT, name,
- size, GL_NONE, values, NULL, 0x0);
-}
-
-
-/**
- * Add a new unnamed constant to the parameter list. This will be used
- * when a fragment/vertex program contains something like this:
- * MOV r, { 0, 1, 2, 3 };
- * If swizzleOut is non-null we'll search the parameter list for an
- * existing instance of the constant which matches with a swizzle.
- *
- * \param paramList the parameter list
- * \param values four float values
- * \param swizzleOut returns swizzle mask for accessing the constant
- * \return index/position of the new parameter in the parameter list.
- */
-GLint
-_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList,
- const GLfloat values[4], GLuint size,
- GLuint *swizzleOut)
-{
- GLint pos;
- ASSERT(size >= 1);
- ASSERT(size <= 4);
-
- if (swizzleOut &&
- _mesa_lookup_parameter_constant(paramList, values,
- size, &pos, swizzleOut)) {
- return pos;
- }
-
- /* Look for empty space in an already unnamed constant parameter
- * to add this constant. This will only work for single-element
- * constants because we rely on smearing (i.e. .yyyy or .zzzz).
- */
- if (size == 1 && swizzleOut) {
- for (pos = 0; pos < (GLint) paramList->NumParameters; pos++) {
- struct gl_program_parameter *p = paramList->Parameters + pos;
- if (p->Type == PROGRAM_CONSTANT && p->Size + size <= 4) {
- /* ok, found room */
- GLfloat *pVal = paramList->ParameterValues[pos];
- GLuint swz = p->Size; /* 1, 2 or 3 for Y, Z, W */
- pVal[p->Size] = values[0];
- p->Size++;
- *swizzleOut = MAKE_SWIZZLE4(swz, swz, swz, swz);
- return pos;
- }
- }
- }
-
- /* add a new parameter to store this constant */
- pos = _mesa_add_parameter(paramList, PROGRAM_CONSTANT, NULL,
- size, GL_NONE, values, NULL, 0x0);
- if (pos >= 0 && swizzleOut) {
- if (size == 1)
- *swizzleOut = SWIZZLE_XXXX;
- else
- *swizzleOut = SWIZZLE_NOOP;
- }
- return pos;
-}
-
-/**
- * Add parameter representing a varying variable.
- */
-GLint
-_mesa_add_varying(struct gl_program_parameter_list *paramList,
- const char *name, GLuint size, GLenum datatype,
- GLbitfield flags)
-{
- GLint i = _mesa_lookup_parameter_index(paramList, -1, name);
- if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_VARYING) {
- /* already in list */
- return i;
- }
- else {
- /*assert(size == 4);*/
- i = _mesa_add_parameter(paramList, PROGRAM_VARYING, name,
- size, datatype, NULL, NULL, flags);
- return i;
- }
-}
-
-
-/**
- * Add parameter representing a vertex program attribute.
- * \param size size of attribute (in floats), may be -1 if unknown
- * \param attrib the attribute index, or -1 if unknown
- */
-GLint
-_mesa_add_attribute(struct gl_program_parameter_list *paramList,
- const char *name, GLint size, GLenum datatype, GLint attrib)
-{
- GLint i = _mesa_lookup_parameter_index(paramList, -1, name);
- if (i >= 0) {
- /* replace */
- if (attrib < 0)
- attrib = i;
- paramList->Parameters[i].StateIndexes[0] = attrib;
- }
- else {
- /* add */
- gl_state_index state[STATE_LENGTH];
- state[0] = (gl_state_index) attrib;
- if (size < 0)
- size = 4;
- i = _mesa_add_parameter(paramList, PROGRAM_INPUT, name,
- size, datatype, NULL, state, 0x0);
- }
- return i;
-}
-
-
-
-#if 0 /* not used yet */
-/**
- * Returns the number of 4-component registers needed to store a piece
- * of GL state. For matrices this may be as many as 4 registers,
- * everything else needs
- * just 1 register.
- */
-static GLuint
-sizeof_state_reference(const GLint *stateTokens)
-{
- if (stateTokens[0] == STATE_MATRIX) {
- GLuint rows = stateTokens[4] - stateTokens[3] + 1;
- assert(rows >= 1);
- assert(rows <= 4);
- return rows;
- }
- else {
- return 1;
- }
-}
-#endif
-
-
-/**
- * Add a new state reference to the parameter list.
- * This will be used when the program contains something like this:
- * PARAM ambient = state.material.front.ambient;
- *
- * \param paramList the parameter list
- * \param stateTokens an array of 5 (STATE_LENGTH) state tokens
- * \return index of the new parameter.
- */
-GLint
-_mesa_add_state_reference(struct gl_program_parameter_list *paramList,
- const gl_state_index stateTokens[STATE_LENGTH])
-{
- const GLuint size = 4; /* XXX fix */
- char *name;
- GLint index;
-
- /* Check if the state reference is already in the list */
- for (index = 0; index < (GLint) paramList->NumParameters; index++) {
- if (!memcmp(paramList->Parameters[index].StateIndexes,
- stateTokens, STATE_LENGTH * sizeof(gl_state_index))) {
- return index;
- }
- }
-
- name = _mesa_program_state_string(stateTokens);
- index = _mesa_add_parameter(paramList, PROGRAM_STATE_VAR, name,
- size, GL_NONE,
- NULL, (gl_state_index *) stateTokens, 0x0);
- paramList->StateFlags |= _mesa_program_state_flags(stateTokens);
-
- /* free name string here since we duplicated it in add_parameter() */
- free(name);
-
- return index;
-}
-
-
-/**
- * Lookup a parameter value by name in the given parameter list.
- * \return pointer to the float[4] values.
- */
-GLfloat *
-_mesa_lookup_parameter_value(const struct gl_program_parameter_list *paramList,
- GLsizei nameLen, const char *name)
-{
- GLint i = _mesa_lookup_parameter_index(paramList, nameLen, name);
- if (i < 0)
- return NULL;
- else
- return paramList->ParameterValues[i];
-}
-
-
-/**
- * Given a program parameter name, find its position in the list of parameters.
- * \param paramList the parameter list to search
- * \param nameLen length of name (in chars).
- * If length is negative, assume that name is null-terminated.
- * \param name the name to search for
- * \return index of parameter in the list.
- */
-GLint
-_mesa_lookup_parameter_index(const struct gl_program_parameter_list *paramList,
- GLsizei nameLen, const char *name)
-{
- GLint i;
-
- if (!paramList)
- return -1;
-
- if (nameLen == -1) {
- /* name is null-terminated */
- for (i = 0; i < (GLint) paramList->NumParameters; i++) {
- if (paramList->Parameters[i].Name &&
- strcmp(paramList->Parameters[i].Name, name) == 0)
- return i;
- }
- }
- else {
- /* name is not null-terminated, use nameLen */
- for (i = 0; i < (GLint) paramList->NumParameters; i++) {
- if (paramList->Parameters[i].Name &&
- strncmp(paramList->Parameters[i].Name, name, nameLen) == 0
- && strlen(paramList->Parameters[i].Name) == (size_t)nameLen)
- return i;
- }
- }
- return -1;
-}
-
-
-/**
- * Look for a float vector in the given parameter list. The float vector
- * may be of length 1, 2, 3 or 4. If swizzleOut is non-null, we'll try
- * swizzling to find a match.
- * \param list the parameter list to search
- * \param v the float vector to search for
- * \param vSize number of element in v
- * \param posOut returns the position of the constant, if found
- * \param swizzleOut returns a swizzle mask describing location of the
- * vector elements if found.
- * \return GL_TRUE if found, GL_FALSE if not found
- */
-GLboolean
-_mesa_lookup_parameter_constant(const struct gl_program_parameter_list *list,
- const GLfloat v[], GLuint vSize,
- GLint *posOut, GLuint *swizzleOut)
-{
- GLuint i;
-
- assert(vSize >= 1);
- assert(vSize <= 4);
-
- if (!list) {
- *posOut = -1;
- return GL_FALSE;
- }
-
- for (i = 0; i < list->NumParameters; i++) {
- if (list->Parameters[i].Type == PROGRAM_CONSTANT) {
- if (!swizzleOut) {
- /* swizzle not allowed */
- GLuint j, match = 0;
- for (j = 0; j < vSize; j++) {
- if (v[j] == list->ParameterValues[i][j])
- match++;
- }
- if (match == vSize) {
- *posOut = i;
- return GL_TRUE;
- }
- }
- else {
- /* try matching w/ swizzle */
- if (vSize == 1) {
- /* look for v[0] anywhere within float[4] value */
- GLuint j;
- for (j = 0; j < list->Parameters[i].Size; j++) {
- if (list->ParameterValues[i][j] == v[0]) {
- /* found it */
- *posOut = i;
- *swizzleOut = MAKE_SWIZZLE4(j, j, j, j);
- return GL_TRUE;
- }
- }
- }
- else if (vSize <= list->Parameters[i].Size) {
- /* see if we can match this constant (with a swizzle) */
- GLuint swz[4];
- GLuint match = 0, j, k;
- for (j = 0; j < vSize; j++) {
- if (v[j] == list->ParameterValues[i][j]) {
- swz[j] = j;
- match++;
- }
- else {
- for (k = 0; k < list->Parameters[i].Size; k++) {
- if (v[j] == list->ParameterValues[i][k]) {
- swz[j] = k;
- match++;
- break;
- }
- }
- }
- }
- /* smear last value to remaining positions */
- for (; j < 4; j++)
- swz[j] = swz[j-1];
-
- if (match == vSize) {
- *posOut = i;
- *swizzleOut = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
- return GL_TRUE;
- }
- }
- }
- }
- }
-
- *posOut = -1;
- return GL_FALSE;
-}
-
-
-struct gl_program_parameter_list *
-_mesa_clone_parameter_list(const struct gl_program_parameter_list *list)
-{
- struct gl_program_parameter_list *clone;
- GLuint i;
-
- clone = _mesa_new_parameter_list();
- if (!clone)
- return NULL;
-
- /** Not too efficient, but correct */
- for (i = 0; i < list->NumParameters; i++) {
- struct gl_program_parameter *p = list->Parameters + i;
- struct gl_program_parameter *pCopy;
- GLuint size = MIN2(p->Size, 4);
- GLint j = _mesa_add_parameter(clone, p->Type, p->Name, size, p->DataType,
- list->ParameterValues[i], NULL, 0x0);
- ASSERT(j >= 0);
- pCopy = clone->Parameters + j;
- pCopy->Flags = p->Flags;
- /* copy state indexes */
- if (p->Type == PROGRAM_STATE_VAR) {
- GLint k;
- for (k = 0; k < STATE_LENGTH; k++) {
- pCopy->StateIndexes[k] = p->StateIndexes[k];
- }
- }
- else {
- clone->Parameters[j].Size = p->Size;
- }
-
- }
-
- clone->StateFlags = list->StateFlags;
-
- return clone;
-}
-
-
-/**
- * Return a new parameter list which is listA + listB.
- */
-struct gl_program_parameter_list *
-_mesa_combine_parameter_lists(const struct gl_program_parameter_list *listA,
- const struct gl_program_parameter_list *listB)
-{
- struct gl_program_parameter_list *list;
-
- if (listA) {
- list = _mesa_clone_parameter_list(listA);
- if (list && listB) {
- GLuint i;
- for (i = 0; i < listB->NumParameters; i++) {
- struct gl_program_parameter *param = listB->Parameters + i;
- _mesa_add_parameter(list, param->Type, param->Name, param->Size,
- param->DataType,
- listB->ParameterValues[i],
- param->StateIndexes,
- param->Flags);
- }
- }
- }
- else if (listB) {
- list = _mesa_clone_parameter_list(listB);
- }
- else {
- list = NULL;
- }
- return list;
-}
-
-
-
-/**
- * Find longest name of all uniform parameters in list.
- */
-GLuint
-_mesa_longest_parameter_name(const struct gl_program_parameter_list *list,
- gl_register_file type)
-{
- GLuint i, maxLen = 0;
- if (!list)
- return 0;
- for (i = 0; i < list->NumParameters; i++) {
- if (list->Parameters[i].Type == type) {
- GLuint len = strlen(list->Parameters[i].Name);
- if (len > maxLen)
- maxLen = len;
- }
- }
- return maxLen;
-}
-
-
-/**
- * Count the number of parameters in the last that match the given type.
- */
-GLuint
-_mesa_num_parameters_of_type(const struct gl_program_parameter_list *list,
- gl_register_file type)
-{
- GLuint i, count = 0;
- if (list) {
- for (i = 0; i < list->NumParameters; i++) {
- if (list->Parameters[i].Type == type)
- count++;
- }
- }
- return count;
-}
+/* + * Mesa 3-D graphics library + * Version: 7.3 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file prog_parameter.c + * Program parameter lists and functions. + * \author Brian Paul + */ + + +#include "main/glheader.h" +#include "main/imports.h" +#include "main/macros.h" +#include "prog_instruction.h" +#include "prog_parameter.h" +#include "prog_statevars.h" + + +struct gl_program_parameter_list * +_mesa_new_parameter_list(void) +{ + return CALLOC_STRUCT(gl_program_parameter_list); +} + + +struct gl_program_parameter_list * +_mesa_new_parameter_list_sized(unsigned size) +{ + struct gl_program_parameter_list *p = _mesa_new_parameter_list(); + + if ((p != NULL) && (size != 0)) { + p->Size = size; + + /* alloc arrays */ + p->Parameters = (struct gl_program_parameter *) + calloc(1, size * sizeof(struct gl_program_parameter)); + + p->ParameterValues = (gl_constant_value (*)[4]) + _mesa_align_malloc(size * 4 *sizeof(gl_constant_value), 16); + + + if ((p->Parameters == NULL) || (p->ParameterValues == NULL)) { + free(p->Parameters); + _mesa_align_free(p->ParameterValues); + free(p); + p = NULL; + } + } + + return p; +} + + +/** + * Free a parameter list and all its parameters + */ +void +_mesa_free_parameter_list(struct gl_program_parameter_list *paramList) +{ + GLuint i; + for (i = 0; i < paramList->NumParameters; i++) { + if (paramList->Parameters[i].Name) + free((void *) paramList->Parameters[i].Name); + } + free(paramList->Parameters); + if (paramList->ParameterValues) + _mesa_align_free(paramList->ParameterValues); + free(paramList); +} + + +/** + * Add a new parameter to a parameter list. + * Note that parameter values are usually 4-element GLfloat vectors. + * When size > 4 we'll allocate a sequential block of parameters to + * store all the values (in blocks of 4). + * + * \param paramList the list to add the parameter to + * \param type type of parameter, such as + * \param name the parameter name, will be duplicated/copied! + * \param size number of elements in 'values' vector (1..4, or more) + * \param datatype GL_FLOAT, GL_FLOAT_VECx, GL_INT, GL_INT_VECx or GL_NONE. + * \param values initial parameter value, up to 4 gl_constant_values, 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 gl_constant_value *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 = (gl_constant_value (*)[4]) + _mesa_align_realloc(paramList->ParameterValues, /* old buf */ + oldNum * 4 * sizeof(gl_constant_value),/* old sz */ + paramList->Size*4*sizeof(gl_constant_value),/*new*/ + 16); + } + + if (!paramList->Parameters || + !paramList->ParameterValues) { + /* out of memory */ + paramList->NumParameters = 0; + paramList->Size = 0; + return -1; + } + else { + GLuint i, j; + + paramList->NumParameters = oldNum + sz4; + + memset(¶mList->Parameters[oldNum], 0, + sz4 * sizeof(struct gl_program_parameter)); + + for (i = 0; i < sz4; i++) { + struct gl_program_parameter *p = paramList->Parameters + oldNum + i; + p->Name = name ? _mesa_strdup(name) : NULL; + p->Type = type; + p->Size = size; + p->DataType = datatype; + p->Flags = flags; + if (values) { + COPY_4V(paramList->ParameterValues[oldNum + i], values); + values += 4; + p->Initialized = GL_TRUE; + } + else { + /* silence valgrind */ + for (j = 0; j < 4; j++) + paramList->ParameterValues[oldNum + i][j].f = 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 gl_constant_value 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 gl_constant_value values[4], + GLuint size) +{ + /* first check if this is a duplicate constant */ + GLint pos; + for (pos = 0; pos < (GLint)paramList->NumParameters; pos++) { + const gl_constant_value *pvals = paramList->ParameterValues[pos]; + if (pvals[0].u == values[0].u && + pvals[1].u == values[1].u && + pvals[2].u == values[2].u && + pvals[3].u == values[3].u && + strcmp(paramList->Parameters[pos].Name, name) == 0) { + /* Same name and value is already in the param list - reuse it */ + return pos; + } + } + /* not found, add new parameter */ + return _mesa_add_parameter(paramList, PROGRAM_CONSTANT, name, + size, GL_NONE, values, NULL, 0x0); +} + + +/** + * Add a new unnamed constant to the parameter list. This will be used + * when a fragment/vertex program contains something like this: + * MOV r, { 0, 1, 2, 3 }; + * If swizzleOut is non-null we'll search the parameter list for an + * existing instance of the constant which matches with a swizzle. + * + * \param paramList the parameter list + * \param values four float values + * \param swizzleOut returns swizzle mask for accessing the constant + * \return index/position of the new parameter in the parameter list. + */ +GLint +_mesa_add_typed_unnamed_constant(struct gl_program_parameter_list *paramList, + const gl_constant_value values[4], GLuint size, + GLenum datatype, GLuint *swizzleOut) +{ + GLint pos; + ASSERT(size >= 1); + ASSERT(size <= 4); + + if (swizzleOut && + _mesa_lookup_parameter_constant(paramList, values, + size, &pos, swizzleOut)) { + return pos; + } + + /* Look for empty space in an already unnamed constant parameter + * to add this constant. This will only work for single-element + * constants because we rely on smearing (i.e. .yyyy or .zzzz). + */ + if (size == 1 && swizzleOut) { + for (pos = 0; pos < (GLint) paramList->NumParameters; pos++) { + struct gl_program_parameter *p = paramList->Parameters + pos; + if (p->Type == PROGRAM_CONSTANT && p->Size + size <= 4) { + /* ok, found room */ + gl_constant_value *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, datatype, values, NULL, 0x0); + if (pos >= 0 && swizzleOut) { + if (size == 1) + *swizzleOut = SWIZZLE_XXXX; + else + *swizzleOut = SWIZZLE_NOOP; + } + return pos; +} + +/** + * Add a new unnamed constant to the parameter list. This will be used + * when a fragment/vertex program contains something like this: + * MOV r, { 0, 1, 2, 3 }; + * If swizzleOut is non-null we'll search the parameter list for an + * existing instance of the constant which matches with a swizzle. + * + * \param paramList the parameter list + * \param values four float values + * \param swizzleOut returns swizzle mask for accessing the constant + * \return index/position of the new parameter in the parameter list. + * \sa _mesa_add_typed_unnamed_constant + */ +GLint +_mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList, + const gl_constant_value values[4], GLuint size, + GLuint *swizzleOut) +{ + return _mesa_add_typed_unnamed_constant(paramList, values, size, GL_NONE, + swizzleOut); +} + +/** + * Add parameter representing a varying variable. + */ +GLint +_mesa_add_varying(struct gl_program_parameter_list *paramList, + const char *name, GLuint size, GLenum datatype, + GLbitfield flags) +{ + GLint i = _mesa_lookup_parameter_index(paramList, -1, name); + if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_VARYING) { + /* already in list */ + return i; + } + else { + /*assert(size == 4);*/ + i = _mesa_add_parameter(paramList, PROGRAM_VARYING, name, + size, datatype, NULL, NULL, flags); + return i; + } +} + + +/** + * Add parameter representing a vertex program attribute. + * \param size size of attribute (in floats), may be -1 if unknown + * \param attrib the attribute index, or -1 if unknown + */ +GLint +_mesa_add_attribute(struct gl_program_parameter_list *paramList, + const char *name, GLint size, GLenum datatype, GLint attrib) +{ + GLint i = _mesa_lookup_parameter_index(paramList, -1, name); + if (i >= 0) { + /* replace */ + if (attrib < 0) + attrib = i; + paramList->Parameters[i].StateIndexes[0] = attrib; + } + else { + /* add */ + gl_state_index state[STATE_LENGTH]; + state[0] = (gl_state_index) attrib; + if (size < 0) + size = 4; + i = _mesa_add_parameter(paramList, PROGRAM_INPUT, name, + size, datatype, NULL, state, 0x0); + } + return i; +} + + + +#if 0 /* not used yet */ +/** + * Returns the number of 4-component registers needed to store a piece + * of GL state. For matrices this may be as many as 4 registers, + * everything else needs + * just 1 register. + */ +static GLuint +sizeof_state_reference(const GLint *stateTokens) +{ + if (stateTokens[0] == STATE_MATRIX) { + GLuint rows = stateTokens[4] - stateTokens[3] + 1; + assert(rows >= 1); + assert(rows <= 4); + return rows; + } + else { + return 1; + } +} +#endif + + +/** + * Add a new state reference to the parameter list. + * This will be used when the program contains something like this: + * PARAM ambient = state.material.front.ambient; + * + * \param paramList the parameter list + * \param stateTokens an array of 5 (STATE_LENGTH) state tokens + * \return index of the new parameter. + */ +GLint +_mesa_add_state_reference(struct gl_program_parameter_list *paramList, + const gl_state_index stateTokens[STATE_LENGTH]) +{ + const GLuint size = 4; /* XXX fix */ + char *name; + GLint index; + + /* Check if the state reference is already in the list */ + for (index = 0; index < (GLint) paramList->NumParameters; index++) { + if (!memcmp(paramList->Parameters[index].StateIndexes, + stateTokens, STATE_LENGTH * sizeof(gl_state_index))) { + return index; + } + } + + name = _mesa_program_state_string(stateTokens); + index = _mesa_add_parameter(paramList, PROGRAM_STATE_VAR, name, + size, GL_NONE, + NULL, (gl_state_index *) stateTokens, 0x0); + paramList->StateFlags |= _mesa_program_state_flags(stateTokens); + + /* free name string here since we duplicated it in add_parameter() */ + free(name); + + return index; +} + + +/** + * Lookup a parameter value by name in the given parameter list. + * \return pointer to the float[4] values. + */ +gl_constant_value * +_mesa_lookup_parameter_value(const struct gl_program_parameter_list *paramList, + GLsizei nameLen, const char *name) +{ + GLint i = _mesa_lookup_parameter_index(paramList, nameLen, name); + if (i < 0) + return NULL; + else + return paramList->ParameterValues[i]; +} + + +/** + * Given a program parameter name, find its position in the list of parameters. + * \param paramList the parameter list to search + * \param nameLen length of name (in chars). + * If length is negative, assume that name is null-terminated. + * \param name the name to search for + * \return index of parameter in the list. + */ +GLint +_mesa_lookup_parameter_index(const struct gl_program_parameter_list *paramList, + GLsizei nameLen, const char *name) +{ + GLint i; + + if (!paramList) + return -1; + + if (nameLen == -1) { + /* name is null-terminated */ + for (i = 0; i < (GLint) paramList->NumParameters; i++) { + if (paramList->Parameters[i].Name && + strcmp(paramList->Parameters[i].Name, name) == 0) + return i; + } + } + else { + /* name is not null-terminated, use nameLen */ + for (i = 0; i < (GLint) paramList->NumParameters; i++) { + if (paramList->Parameters[i].Name && + strncmp(paramList->Parameters[i].Name, name, nameLen) == 0 + && strlen(paramList->Parameters[i].Name) == (size_t)nameLen) + return i; + } + } + return -1; +} + + +/** + * Look for a float vector in the given parameter list. The float vector + * may be of length 1, 2, 3 or 4. If swizzleOut is non-null, we'll try + * swizzling to find a match. + * \param list the parameter list to search + * \param v the float vector to search for + * \param vSize number of element in v + * \param posOut returns the position of the constant, if found + * \param swizzleOut returns a swizzle mask describing location of the + * vector elements if found. + * \return GL_TRUE if found, GL_FALSE if not found + */ +GLboolean +_mesa_lookup_parameter_constant(const struct gl_program_parameter_list *list, + const gl_constant_value v[], GLuint vSize, + GLint *posOut, GLuint *swizzleOut) +{ + GLuint i; + + assert(vSize >= 1); + assert(vSize <= 4); + + if (!list) { + *posOut = -1; + return GL_FALSE; + } + + for (i = 0; i < list->NumParameters; i++) { + if (list->Parameters[i].Type == PROGRAM_CONSTANT) { + if (!swizzleOut) { + /* swizzle not allowed */ + GLuint j, match = 0; + for (j = 0; j < vSize; j++) { + if (v[j].u == list->ParameterValues[i][j].u) + match++; + } + if (match == vSize) { + *posOut = i; + return GL_TRUE; + } + } + else { + /* try matching w/ swizzle */ + if (vSize == 1) { + /* look for v[0] anywhere within float[4] value */ + GLuint j; + for (j = 0; j < list->Parameters[i].Size; j++) { + if (list->ParameterValues[i][j].u == v[0].u) { + /* 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].u == list->ParameterValues[i][j].u) { + swz[j] = j; + match++; + } + else { + for (k = 0; k < list->Parameters[i].Size; k++) { + if (v[j].u == list->ParameterValues[i][k].u) { + swz[j] = k; + match++; + break; + } + } + } + } + /* smear last value to remaining positions */ + for (; j < 4; j++) + swz[j] = swz[j-1]; + + if (match == vSize) { + *posOut = i; + *swizzleOut = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]); + return GL_TRUE; + } + } + } + } + } + + *posOut = -1; + return GL_FALSE; +} + + +struct gl_program_parameter_list * +_mesa_clone_parameter_list(const struct gl_program_parameter_list *list) +{ + struct gl_program_parameter_list *clone; + GLuint i; + + clone = _mesa_new_parameter_list(); + if (!clone) + return NULL; + + /** Not too efficient, but correct */ + for (i = 0; i < list->NumParameters; i++) { + struct gl_program_parameter *p = list->Parameters + i; + struct gl_program_parameter *pCopy; + GLuint size = MIN2(p->Size, 4); + GLint j = _mesa_add_parameter(clone, p->Type, p->Name, size, p->DataType, + list->ParameterValues[i], NULL, 0x0); + ASSERT(j >= 0); + pCopy = clone->Parameters + j; + pCopy->Flags = p->Flags; + /* copy state indexes */ + if (p->Type == PROGRAM_STATE_VAR) { + GLint k; + for (k = 0; k < STATE_LENGTH; k++) { + pCopy->StateIndexes[k] = p->StateIndexes[k]; + } + } + else { + clone->Parameters[j].Size = p->Size; + } + + } + + clone->StateFlags = list->StateFlags; + + return clone; +} + + +/** + * Return a new parameter list which is listA + listB. + */ +struct gl_program_parameter_list * +_mesa_combine_parameter_lists(const struct gl_program_parameter_list *listA, + const struct gl_program_parameter_list *listB) +{ + struct gl_program_parameter_list *list; + + if (listA) { + list = _mesa_clone_parameter_list(listA); + if (list && listB) { + GLuint i; + for (i = 0; i < listB->NumParameters; i++) { + struct gl_program_parameter *param = listB->Parameters + i; + _mesa_add_parameter(list, param->Type, param->Name, param->Size, + param->DataType, + listB->ParameterValues[i], + param->StateIndexes, + param->Flags); + } + } + } + else if (listB) { + list = _mesa_clone_parameter_list(listB); + } + else { + list = NULL; + } + return list; +} + + + +/** + * Find longest name of all uniform parameters in list. + */ +GLuint +_mesa_longest_parameter_name(const struct gl_program_parameter_list *list, + gl_register_file type) +{ + GLuint i, maxLen = 0; + if (!list) + return 0; + for (i = 0; i < list->NumParameters; i++) { + if (list->Parameters[i].Type == type) { + GLuint len = strlen(list->Parameters[i].Name); + if (len > maxLen) + maxLen = len; + } + } + return maxLen; +} + + +/** + * Count the number of parameters in the last that match the given type. + */ +GLuint +_mesa_num_parameters_of_type(const struct gl_program_parameter_list *list, + gl_register_file type) +{ + GLuint i, count = 0; + if (list) { + for (i = 0; i < list->NumParameters; i++) { + if (list->Parameters[i].Type == type) + count++; + } + } + return count; +} diff --git a/mesalib/src/mesa/program/prog_parameter.h b/mesalib/src/mesa/program/prog_parameter.h index 10cbbe57a..f858cf0fa 100644 --- a/mesalib/src/mesa/program/prog_parameter.h +++ b/mesalib/src/mesa/program/prog_parameter.h @@ -46,7 +46,15 @@ #define PROG_PARAM_BIT_CYL_WRAP 0x10 /**< XXX gallium debug */ /*@}*/ - +/** + * Actual data for constant values of parameters. + */ +typedef union gl_constant_value { + GLfloat f; + GLboolean b; + GLint i; + GLuint u; +} gl_constant_value; /** * Program parameter. @@ -81,7 +89,7 @@ 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] */ + gl_constant_value (*ParameterValues)[4]; /**< Array [Size] of constant[4] */ GLbitfield StateFlags; /**< _NEW_* flags indicating which state changes might invalidate ParameterValues[] */ }; @@ -112,22 +120,28 @@ _mesa_num_parameters(const struct gl_program_parameter_list *list) 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, + GLuint size, GLenum datatype, + const gl_constant_value *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]); + const char *name, const gl_constant_value values[4]); extern GLint _mesa_add_named_constant(struct gl_program_parameter_list *paramList, - const char *name, const GLfloat values[4], + const char *name, const gl_constant_value values[4], GLuint size); extern GLint +_mesa_add_typed_unnamed_constant(struct gl_program_parameter_list *paramList, + const gl_constant_value values[4], GLuint size, + GLenum datatype, GLuint *swizzleOut); + +extern GLint _mesa_add_unnamed_constant(struct gl_program_parameter_list *paramList, - const GLfloat values[4], GLuint size, + const gl_constant_value values[4], GLuint size, GLuint *swizzleOut); extern GLint @@ -143,7 +157,7 @@ extern GLint _mesa_add_state_reference(struct gl_program_parameter_list *paramList, const gl_state_index stateTokens[STATE_LENGTH]); -extern GLfloat * +extern gl_constant_value * _mesa_lookup_parameter_value(const struct gl_program_parameter_list *paramList, GLsizei nameLen, const char *name); @@ -153,7 +167,7 @@ _mesa_lookup_parameter_index(const struct gl_program_parameter_list *paramList, extern GLboolean _mesa_lookup_parameter_constant(const struct gl_program_parameter_list *list, - const GLfloat v[], GLuint vSize, + const gl_constant_value v[], GLuint vSize, GLint *posOut, GLuint *swizzleOut); extern GLuint diff --git a/mesalib/src/mesa/program/prog_parameter_layout.c b/mesalib/src/mesa/program/prog_parameter_layout.c index 90a977108..28fca3b92 100644 --- a/mesalib/src/mesa/program/prog_parameter_layout.c +++ b/mesalib/src/mesa/program/prog_parameter_layout.c @@ -182,7 +182,7 @@ _mesa_layout_parameters(struct asm_parser_state *state) switch (p->Type) { case PROGRAM_CONSTANT: { - const float *const v = + const gl_constant_value *const v = state->prog->Parameters->ParameterValues[idx]; inst->Base.SrcReg[i].Index = diff --git a/mesalib/src/mesa/program/prog_print.c b/mesalib/src/mesa/program/prog_print.c index 248f4d730..2cfec13ec 100644 --- a/mesalib/src/mesa/program/prog_print.c +++ b/mesalib/src/mesa/program/prog_print.c @@ -985,7 +985,7 @@ _mesa_fprint_parameter_list(FILE *f, 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];
+ const GLfloat *v = (GLfloat *) list->ParameterValues[i];
fprintf(f, "param[%d] sz=%d %s %s = {%.3g, %.3g, %.3g, %.3g}",
i, param->Size,
_mesa_register_file_name(list->Parameters[i].Type),
diff --git a/mesalib/src/mesa/program/prog_statevars.c b/mesalib/src/mesa/program/prog_statevars.c index ddda78e19..c68e1643a 100644 --- a/mesalib/src/mesa/program/prog_statevars.c +++ b/mesalib/src/mesa/program/prog_statevars.c @@ -1111,7 +1111,7 @@ _mesa_load_state_parameters(struct gl_context *ctx, if (paramList->Parameters[i].Type == PROGRAM_STATE_VAR) {
_mesa_fetch_state(ctx,
paramList->Parameters[i].StateIndexes,
- paramList->ParameterValues[i]);
+ ¶mList->ParameterValues[i][0].f);
}
}
}
diff --git a/mesalib/src/mesa/program/program.c b/mesalib/src/mesa/program/program.c index 2393a6386..5a9bc0fae 100644 --- a/mesalib/src/mesa/program/program.c +++ b/mesalib/src/mesa/program/program.c @@ -388,8 +388,9 @@ _mesa_delete_program(struct gl_context *ctx, struct gl_program *prog) if (prog->String)
free(prog->String);
- _mesa_free_instructions(prog->Instructions, prog->NumInstructions);
-
+ if (prog->Instructions) {
+ _mesa_free_instructions(prog->Instructions, prog->NumInstructions);
+ }
if (prog->Parameters) {
_mesa_free_parameter_list(prog->Parameters);
}
@@ -1031,7 +1032,8 @@ _mesa_postprocess_program(struct gl_context *ctx, struct gl_program *prog) GLuint i;
GLuint whiteSwizzle;
GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters,
- white, 4, &whiteSwizzle);
+ (gl_constant_value *) white,
+ 4, &whiteSwizzle);
(void) whiteIndex;
diff --git a/mesalib/src/mesa/program/program_parse.y b/mesalib/src/mesa/program/program_parse.y index e7752fcbd..4efdc0184 100644 --- a/mesalib/src/mesa/program/program_parse.y +++ b/mesalib/src/mesa/program/program_parse.y @@ -1854,64 +1854,64 @@ paramConstUse: paramConstScalarUse | paramConstVector; paramConstScalarDecl: signedFloatConstant
{
$$.count = 4;
- $$.data[0] = $1;
- $$.data[1] = $1;
- $$.data[2] = $1;
- $$.data[3] = $1;
+ $$.data[0].f = $1;
+ $$.data[1].f = $1;
+ $$.data[2].f = $1;
+ $$.data[3].f = $1;
}
;
paramConstScalarUse: REAL
{
$$.count = 1;
- $$.data[0] = $1;
- $$.data[1] = $1;
- $$.data[2] = $1;
- $$.data[3] = $1;
+ $$.data[0].f = $1;
+ $$.data[1].f = $1;
+ $$.data[2].f = $1;
+ $$.data[3].f = $1;
}
| INTEGER
{
$$.count = 1;
- $$.data[0] = (float) $1;
- $$.data[1] = (float) $1;
- $$.data[2] = (float) $1;
- $$.data[3] = (float) $1;
+ $$.data[0].f = (float) $1;
+ $$.data[1].f = (float) $1;
+ $$.data[2].f = (float) $1;
+ $$.data[3].f = (float) $1;
}
;
paramConstVector: '{' signedFloatConstant '}'
{
$$.count = 4;
- $$.data[0] = $2;
- $$.data[1] = 0.0f;
- $$.data[2] = 0.0f;
- $$.data[3] = 1.0f;
+ $$.data[0].f = $2;
+ $$.data[1].f = 0.0f;
+ $$.data[2].f = 0.0f;
+ $$.data[3].f = 1.0f;
}
| '{' signedFloatConstant ',' signedFloatConstant '}'
{
$$.count = 4;
- $$.data[0] = $2;
- $$.data[1] = $4;
- $$.data[2] = 0.0f;
- $$.data[3] = 1.0f;
+ $$.data[0].f = $2;
+ $$.data[1].f = $4;
+ $$.data[2].f = 0.0f;
+ $$.data[3].f = 1.0f;
}
| '{' signedFloatConstant ',' signedFloatConstant ','
signedFloatConstant '}'
{
$$.count = 4;
- $$.data[0] = $2;
- $$.data[1] = $4;
- $$.data[2] = $6;
- $$.data[3] = 1.0f;
+ $$.data[0].f = $2;
+ $$.data[1].f = $4;
+ $$.data[2].f = $6;
+ $$.data[3].f = 1.0f;
}
| '{' signedFloatConstant ',' signedFloatConstant ','
signedFloatConstant ',' signedFloatConstant '}'
{
$$.count = 4;
- $$.data[0] = $2;
- $$.data[1] = $4;
- $$.data[2] = $6;
- $$.data[3] = $8;
+ $$.data[0].f = $2;
+ $$.data[1].f = $4;
+ $$.data[2].f = $6;
+ $$.data[3].f = $8;
}
;
diff --git a/mesalib/src/mesa/program/program_parser.h b/mesalib/src/mesa/program/program_parser.h index cbbb2677d..b6853a229 100644 --- a/mesalib/src/mesa/program/program_parser.h +++ b/mesalib/src/mesa/program/program_parser.h @@ -23,6 +23,7 @@ #pragma once
#include "main/config.h"
+#include "program/prog_parameter.h"
struct gl_context;
@@ -96,7 +97,7 @@ struct asm_symbol { struct asm_vector {
unsigned count;
- float data[4];
+ gl_constant_value data[4];
};
diff --git a/mesalib/src/mesa/program/sampler.cpp b/mesalib/src/mesa/program/sampler.cpp index b219d7016..9a2616743 100644 --- a/mesalib/src/mesa/program/sampler.cpp +++ b/mesalib/src/mesa/program/sampler.cpp @@ -132,6 +132,6 @@ _mesa_get_sampler_uniform_value(class ir_dereference *sampler, index += getname.offset;
- return prog->Parameters->ParameterValues[index][0];
+ return prog->Parameters->ParameterValues[index][0].f;
}
}
|