2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * NVIDIA fragment program parser.
32 * Regarding GL_NV_fragment_program:
34 * Portions of this software may use or implement intellectual
35 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
36 * any and all warranties with respect to such intellectual property,
37 * including any use thereof or modifications thereto.
40 #include "main/glheader.h"
41 #include "main/context.h"
42 #include "main/imports.h"
43 #include "main/macros.h"
45 #include "prog_parameter.h"
46 #include "prog_print.h"
47 #include "prog_instruction.h"
48 #include "nvfragparse.h"
57 #define INPUT_1V_T 7 /* one source vector, plus textureId */
58 #define INPUT_3V_T 8 /* one source vector, plus textureId */
60 #define INPUT_1V_S 10 /* a string and a vector register */
63 #define OUTPUT_NONE 22
65 /* IRIX defines some of these */
72 /* Optional suffixes */
73 #define _R FLOAT32 /* float */
74 #define _H FLOAT16 /* half-float */
75 #define _X FIXED12 /* fixed */
76 #define _C 0x08 /* set cond codes */
77 #define _S 0x10 /* saturate, clamp result to [0,1] */
79 struct instruction_pattern
{
81 enum prog_opcode opcode
;
87 static const struct instruction_pattern Instructions
[] = {
88 { "ADD", OPCODE_ADD
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
89 { "COS", OPCODE_COS
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
90 { "DDX", OPCODE_DDX
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
91 { "DDY", OPCODE_DDY
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
92 { "DP3", OPCODE_DP3
, INPUT_2V
, OUTPUT_S
, _R
| _H
| _X
| _C
| _S
},
93 { "DP4", OPCODE_DP4
, INPUT_2V
, OUTPUT_S
, _R
| _H
| _X
| _C
| _S
},
94 { "DST", OPCODE_DP4
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
95 { "EX2", OPCODE_DP4
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
96 { "FLR", OPCODE_FLR
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
97 { "FRC", OPCODE_FRC
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
98 { "KIL", OPCODE_KIL_NV
, INPUT_CC
, OUTPUT_NONE
, 0 },
99 { "LG2", OPCODE_LG2
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
100 { "LIT", OPCODE_LIT
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
101 { "LRP", OPCODE_LRP
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
102 { "MAD", OPCODE_MAD
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
103 { "MAX", OPCODE_MAX
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
104 { "MIN", OPCODE_MIN
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
105 { "MOV", OPCODE_MOV
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
106 { "MUL", OPCODE_MUL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
107 { "PK2H", OPCODE_PK2H
, INPUT_1V
, OUTPUT_S
, 0 },
108 { "PK2US", OPCODE_PK2US
, INPUT_1V
, OUTPUT_S
, 0 },
109 { "PK4B", OPCODE_PK4B
, INPUT_1V
, OUTPUT_S
, 0 },
110 { "PK4UB", OPCODE_PK4UB
, INPUT_1V
, OUTPUT_S
, 0 },
111 { "POW", OPCODE_POW
, INPUT_2S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
112 { "RCP", OPCODE_RCP
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
113 { "RFL", OPCODE_RFL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
114 { "RSQ", OPCODE_RSQ
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
115 { "SEQ", OPCODE_SEQ
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
116 { "SFL", OPCODE_SFL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
117 { "SGE", OPCODE_SGE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
118 { "SGT", OPCODE_SGT
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
119 { "SIN", OPCODE_SIN
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
120 { "SLE", OPCODE_SLE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
121 { "SLT", OPCODE_SLT
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
122 { "SNE", OPCODE_SNE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
123 { "STR", OPCODE_STR
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
124 { "SUB", OPCODE_SUB
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
125 { "TEX", OPCODE_TEX
, INPUT_1V_T
, OUTPUT_V
, _C
| _S
},
126 { "TXD", OPCODE_TXD
, INPUT_3V_T
, OUTPUT_V
, _C
| _S
},
127 { "TXP", OPCODE_TXP_NV
, INPUT_1V_T
, OUTPUT_V
, _C
| _S
},
128 { "UP2H", OPCODE_UP2H
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
129 { "UP2US", OPCODE_UP2US
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
130 { "UP4B", OPCODE_UP4B
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
131 { "UP4UB", OPCODE_UP4UB
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
132 { "X2D", OPCODE_X2D
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
133 { "PRINT", OPCODE_PRINT
, INPUT_1V_S
, OUTPUT_NONE
, 0 },
134 { NULL
, (enum prog_opcode
) -1, 0, 0, 0 }
139 * Information needed or computed during parsing.
140 * Remember, we can't modify the target program object until we've
141 * _successfully_ parsed the program text.
145 const GLubyte
*start
; /* start of program string */
146 const GLubyte
*pos
; /* current position */
147 const GLubyte
*curLine
;
148 struct gl_fragment_program
*program
; /* current program */
150 struct gl_program_parameter_list
*parameters
;
152 GLuint numInst
; /* number of instructions parsed */
153 GLuint inputsRead
; /* bitmask of input registers used */
154 GLuint outputsWritten
; /* bitmask of 1 << FRAG_OUTPUT_* bits */
155 GLuint texturesUsed
[MAX_TEXTURE_IMAGE_UNITS
];
161 * Called whenever we find an error during parsing.
164 record_error(struct parse_state
*parseState
, const char *msg
, int lineNo
)
168 const GLubyte
*lineStr
;
169 lineStr
= _mesa_find_line_column(parseState
->start
,
170 parseState
->pos
, &line
, &column
);
171 _mesa_debug(parseState
->ctx
,
172 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
173 lineNo
, line
, column
, (char *) lineStr
, msg
);
174 _mesa_free((void *) lineStr
);
179 /* Check that no error was already recorded. Only record the first one. */
180 if (parseState
->ctx
->Program
.ErrorString
[0] == 0) {
181 _mesa_set_program_error(parseState
->ctx
,
182 parseState
->pos
- parseState
->start
,
188 #define RETURN_ERROR \
190 record_error(parseState, "Unexpected end of input.", __LINE__); \
194 #define RETURN_ERROR1(msg) \
196 record_error(parseState, msg, __LINE__); \
200 #define RETURN_ERROR2(msg1, msg2) \
203 _mesa_sprintf(err, "%s %s", msg1, msg2); \
204 record_error(parseState, err, __LINE__); \
212 * Search a list of instruction structures for a match.
214 static struct instruction_pattern
215 MatchInstruction(const GLubyte
*token
)
217 const struct instruction_pattern
*inst
;
218 struct instruction_pattern result
;
220 for (inst
= Instructions
; inst
->name
; inst
++) {
221 if (_mesa_strncmp((const char *) token
, inst
->name
, 3) == 0) {
227 if (token
[i
] == 'R') {
228 result
.suffixes
|= _R
;
231 else if (token
[i
] == 'H') {
232 result
.suffixes
|= _H
;
235 else if (token
[i
] == 'X') {
236 result
.suffixes
|= _X
;
239 if (token
[i
] == 'C') {
240 result
.suffixes
|= _C
;
243 if (token
[i
] == '_' && token
[i
+1] == 'S' &&
244 token
[i
+2] == 'A' && token
[i
+3] == 'T') {
245 result
.suffixes
|= _S
;
250 result
.opcode
= MAX_OPCODE
; /* i.e. invalid instruction */
257 /**********************************************************************/
260 static GLboolean
IsLetter(GLubyte b
)
262 return (b
>= 'a' && b
<= 'z') ||
263 (b
>= 'A' && b
<= 'Z') ||
269 static GLboolean
IsDigit(GLubyte b
)
271 return b
>= '0' && b
<= '9';
275 static GLboolean
IsWhitespace(GLubyte b
)
277 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
282 * Starting at 'str' find the next token. A token can be an integer,
283 * an identifier or punctuation symbol.
284 * \return <= 0 we found an error, else, return number of characters parsed.
287 GetToken(struct parse_state
*parseState
, GLubyte
*token
)
289 const GLubyte
*str
= parseState
->pos
;
294 /* skip whitespace and comments */
295 while (str
[i
] && (IsWhitespace(str
[i
]) || str
[i
] == '#')) {
298 while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
301 if (str
[i
] == '\n' || str
[i
] == '\r')
302 parseState
->curLine
= str
+ i
+ 1;
305 /* skip whitespace */
306 if (str
[i
] == '\n' || str
[i
] == '\r')
307 parseState
->curLine
= str
+ i
+ 1;
315 /* try matching an integer */
316 while (str
[i
] && IsDigit(str
[i
])) {
317 token
[j
++] = str
[i
++];
319 if (j
> 0 || !str
[i
]) {
324 /* try matching an identifier */
325 if (IsLetter(str
[i
])) {
326 while (str
[i
] && (IsLetter(str
[i
]) || IsDigit(str
[i
]))) {
327 token
[j
++] = str
[i
++];
333 /* punctuation character */
347 * Get next token from input stream and increment stream pointer past token.
350 Parse_Token(struct parse_state
*parseState
, GLubyte
*token
)
353 i
= GetToken(parseState
, token
);
355 parseState
->pos
+= (-i
);
358 parseState
->pos
+= i
;
364 * Get next token from input stream but don't increment stream pointer.
367 Peek_Token(struct parse_state
*parseState
, GLubyte
*token
)
370 i
= GetToken(parseState
, token
);
372 parseState
->pos
+= (-i
);
375 len
= (GLint
)_mesa_strlen((const char *) token
);
376 parseState
->pos
+= (i
- len
);
381 /**********************************************************************/
383 static const char *InputRegisters
[MAX_NV_FRAGMENT_PROGRAM_INPUTS
+ 1] = {
384 "WPOS", "COL0", "COL1", "FOGC",
385 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
390 /**********************************************************************/
393 * Try to match 'pattern' as the next token after any whitespace/comments.
396 Parse_String(struct parse_state
*parseState
, const char *pattern
)
401 /* skip whitespace and comments */
402 while (IsWhitespace(*parseState
->pos
) || *parseState
->pos
== '#') {
403 if (*parseState
->pos
== '#') {
404 while (*parseState
->pos
&& (*parseState
->pos
!= '\n' && *parseState
->pos
!= '\r')) {
405 parseState
->pos
+= 1;
407 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
408 parseState
->curLine
= parseState
->pos
+ 1;
411 /* skip whitespace */
412 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
413 parseState
->curLine
= parseState
->pos
+ 1;
414 parseState
->pos
+= 1;
418 /* Try to match the pattern */
420 for (i
= 0; pattern
[i
]; i
++) {
421 if (*m
!= (GLubyte
) pattern
[i
])
427 return GL_TRUE
; /* success */
432 Parse_Identifier(struct parse_state
*parseState
, GLubyte
*ident
)
434 if (!Parse_Token(parseState
, ident
))
436 if (IsLetter(ident
[0]))
439 RETURN_ERROR1("Expected an identfier");
444 * Parse a floating point constant, or a defined symbol name.
446 * Output: number[0 .. 3] will get the value.
449 Parse_ScalarConstant(struct parse_state
*parseState
, GLfloat
*number
)
453 *number
= (GLfloat
) _mesa_strtod((const char *) parseState
->pos
, &end
);
455 if (end
&& end
> (char *) parseState
->pos
) {
457 parseState
->pos
= (GLubyte
*) end
;
464 /* should be an identifier */
466 const GLfloat
*constant
;
467 if (!Parse_Identifier(parseState
, ident
))
468 RETURN_ERROR1("Expected an identifier");
469 constant
= _mesa_lookup_parameter_value(parseState
->parameters
,
470 -1, (const char *) ident
);
471 /* XXX Check that it's a constant and not a parameter */
473 RETURN_ERROR1("Undefined symbol");
476 COPY_4V(number
, constant
);
485 * Parse a vector constant, one of:
488 * { float, float, float }
489 * { float, float, float, float }
492 Parse_VectorConstant(struct parse_state
*parseState
, GLfloat
*vec
)
494 /* "{" was already consumed */
496 ASSIGN_4V(vec
, 0.0, 0.0, 0.0, 1.0);
498 if (!Parse_ScalarConstant(parseState
, vec
+0)) /* X */
501 if (Parse_String(parseState
, "}")) {
505 if (!Parse_String(parseState
, ","))
506 RETURN_ERROR1("Expected comma in vector constant");
508 if (!Parse_ScalarConstant(parseState
, vec
+1)) /* Y */
511 if (Parse_String(parseState
, "}")) {
515 if (!Parse_String(parseState
, ","))
516 RETURN_ERROR1("Expected comma in vector constant");
518 if (!Parse_ScalarConstant(parseState
, vec
+2)) /* Z */
521 if (Parse_String(parseState
, "}")) {
525 if (!Parse_String(parseState
, ","))
526 RETURN_ERROR1("Expected comma in vector constant");
528 if (!Parse_ScalarConstant(parseState
, vec
+3)) /* W */
531 if (!Parse_String(parseState
, "}"))
532 RETURN_ERROR1("Expected closing brace in vector constant");
539 * Parse <number>, <varname> or {a, b, c, d}.
540 * Return number of values in the vector or scalar, or zero if parse error.
543 Parse_VectorOrScalarConstant(struct parse_state
*parseState
, GLfloat
*vec
)
545 if (Parse_String(parseState
, "{")) {
546 return Parse_VectorConstant(parseState
, vec
);
549 GLboolean b
= Parse_ScalarConstant(parseState
, vec
);
551 vec
[1] = vec
[2] = vec
[3] = vec
[0];
559 * Parse a texture image source:
560 * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
563 Parse_TextureImageId(struct parse_state
*parseState
,
564 GLubyte
*texUnit
, GLubyte
*texTargetBit
)
566 GLubyte imageSrc
[100];
569 if (!Parse_Token(parseState
, imageSrc
))
572 if (imageSrc
[0] != 'T' ||
573 imageSrc
[1] != 'E' ||
574 imageSrc
[2] != 'X') {
575 RETURN_ERROR1("Expected TEX# source");
577 unit
= _mesa_atoi((const char *) imageSrc
+ 3);
578 if ((unit
< 0 || unit
> MAX_TEXTURE_IMAGE_UNITS
) ||
579 (unit
== 0 && (imageSrc
[3] != '0' || imageSrc
[4] != 0))) {
580 RETURN_ERROR1("Invalied TEX# source index");
584 if (!Parse_String(parseState
, ","))
585 RETURN_ERROR1("Expected ,");
587 if (Parse_String(parseState
, "1D")) {
588 *texTargetBit
= TEXTURE_1D_BIT
;
590 else if (Parse_String(parseState
, "2D")) {
591 *texTargetBit
= TEXTURE_2D_BIT
;
593 else if (Parse_String(parseState
, "3D")) {
594 *texTargetBit
= TEXTURE_3D_BIT
;
596 else if (Parse_String(parseState
, "CUBE")) {
597 *texTargetBit
= TEXTURE_CUBE_BIT
;
599 else if (Parse_String(parseState
, "RECT")) {
600 *texTargetBit
= TEXTURE_RECT_BIT
;
603 RETURN_ERROR1("Invalid texture target token");
606 /* update record of referenced texture units */
607 parseState
->texturesUsed
[*texUnit
] |= *texTargetBit
;
608 if (_mesa_bitcount(parseState
->texturesUsed
[*texUnit
]) > 1) {
609 RETURN_ERROR1("Only one texture target can be used per texture unit.");
617 * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
618 * like .wxyz, .xxyy, etc and return the swizzle indexes.
621 Parse_SwizzleSuffix(const GLubyte
*token
, GLuint swizzle
[4])
624 /* single letter swizzle (scalar) */
626 ASSIGN_4V(swizzle
, 0, 0, 0, 0);
627 else if (token
[0] == 'y')
628 ASSIGN_4V(swizzle
, 1, 1, 1, 1);
629 else if (token
[0] == 'z')
630 ASSIGN_4V(swizzle
, 2, 2, 2, 2);
631 else if (token
[0] == 'w')
632 ASSIGN_4V(swizzle
, 3, 3, 3, 3);
637 /* 4-component swizzle (vector) */
639 for (k
= 0; token
[k
] && k
< 4; k
++) {
642 else if (token
[k
] == 'y')
644 else if (token
[k
] == 'z')
646 else if (token
[k
] == 'w')
659 Parse_CondCodeMask(struct parse_state
*parseState
,
660 struct prog_dst_register
*dstReg
)
662 if (Parse_String(parseState
, "EQ"))
663 dstReg
->CondMask
= COND_EQ
;
664 else if (Parse_String(parseState
, "GE"))
665 dstReg
->CondMask
= COND_GE
;
666 else if (Parse_String(parseState
, "GT"))
667 dstReg
->CondMask
= COND_GT
;
668 else if (Parse_String(parseState
, "LE"))
669 dstReg
->CondMask
= COND_LE
;
670 else if (Parse_String(parseState
, "LT"))
671 dstReg
->CondMask
= COND_LT
;
672 else if (Parse_String(parseState
, "NE"))
673 dstReg
->CondMask
= COND_NE
;
674 else if (Parse_String(parseState
, "TR"))
675 dstReg
->CondMask
= COND_TR
;
676 else if (Parse_String(parseState
, "FL"))
677 dstReg
->CondMask
= COND_FL
;
679 RETURN_ERROR1("Invalid condition code mask");
681 /* look for optional .xyzw swizzle */
682 if (Parse_String(parseState
, ".")) {
686 if (!Parse_Token(parseState
, token
)) /* get xyzw suffix */
689 if (!Parse_SwizzleSuffix(token
, swz
))
690 RETURN_ERROR1("Invalid swizzle suffix");
692 dstReg
->CondSwizzle
= MAKE_SWIZZLE4(swz
[0], swz
[1], swz
[2], swz
[3]);
700 * Parse a temporary register: Rnn or Hnn
703 Parse_TempReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
707 /* Should be 'R##' or 'H##' */
708 if (!Parse_Token(parseState
, token
))
710 if (token
[0] != 'R' && token
[0] != 'H')
711 RETURN_ERROR1("Expected R## or H##");
713 if (IsDigit(token
[1])) {
714 GLint reg
= _mesa_atoi((const char *) (token
+ 1));
717 if (reg
>= MAX_NV_FRAGMENT_PROGRAM_TEMPS
)
718 RETURN_ERROR1("Invalid temporary register name");
722 RETURN_ERROR1("Invalid temporary register name");
730 * Parse a write-only dummy register: RC or HC.
733 Parse_DummyReg(struct parse_state
*parseState
, GLint
*regNum
)
735 if (Parse_String(parseState
, "RC")) {
738 else if (Parse_String(parseState
, "HC")) {
742 RETURN_ERROR1("Invalid write-only register name");
750 * Parse a program local parameter register "p[##]"
753 Parse_ProgramParamReg(struct parse_state
*parseState
, GLint
*regNum
)
757 if (!Parse_String(parseState
, "p["))
758 RETURN_ERROR1("Expected p[");
760 if (!Parse_Token(parseState
, token
))
763 if (IsDigit(token
[0])) {
764 /* a numbered program parameter register */
765 GLint reg
= _mesa_atoi((const char *) token
);
766 if (reg
>= MAX_NV_FRAGMENT_PROGRAM_PARAMS
)
767 RETURN_ERROR1("Invalid constant program number");
774 if (!Parse_String(parseState
, "]"))
775 RETURN_ERROR1("Expected ]");
782 * Parse f[name] - fragment input register
785 Parse_FragReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
791 if (!Parse_String(parseState
, "f["))
792 RETURN_ERROR1("Expected f[");
794 /* get <name> and look for match */
795 if (!Parse_Token(parseState
, token
)) {
798 for (j
= 0; InputRegisters
[j
]; j
++) {
799 if (_mesa_strcmp((const char *) token
, InputRegisters
[j
]) == 0) {
801 parseState
->inputsRead
|= (1 << j
);
805 if (!InputRegisters
[j
]) {
806 /* unknown input register label */
807 RETURN_ERROR2("Invalid register name", token
);
811 if (!Parse_String(parseState
, "]"))
812 RETURN_ERROR1("Expected ]");
819 Parse_OutputReg(struct parse_state
*parseState
, GLint
*outputRegNum
)
824 if (!Parse_String(parseState
, "o["))
825 RETURN_ERROR1("Expected o[");
827 /* Get output reg name */
828 if (!Parse_Token(parseState
, token
))
831 /* try to match an output register name */
832 if (_mesa_strcmp((char *) token
, "COLR") == 0 ||
833 _mesa_strcmp((char *) token
, "COLH") == 0) {
834 /* note that we don't distinguish between COLR and COLH */
835 *outputRegNum
= FRAG_RESULT_COLOR
;
836 parseState
->outputsWritten
|= (1 << FRAG_RESULT_COLOR
);
838 else if (_mesa_strcmp((char *) token
, "DEPR") == 0) {
839 *outputRegNum
= FRAG_RESULT_DEPTH
;
840 parseState
->outputsWritten
|= (1 << FRAG_RESULT_DEPTH
);
843 RETURN_ERROR1("Invalid output register name");
847 if (!Parse_String(parseState
, "]"))
848 RETURN_ERROR1("Expected ]");
855 Parse_MaskedDstReg(struct parse_state
*parseState
,
856 struct prog_dst_register
*dstReg
)
861 /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
862 if (!Peek_Token(parseState
, token
))
865 if (_mesa_strcmp((const char *) token
, "RC") == 0 ||
866 _mesa_strcmp((const char *) token
, "HC") == 0) {
867 /* a write-only register */
868 dstReg
->File
= PROGRAM_WRITE_ONLY
;
869 if (!Parse_DummyReg(parseState
, &idx
))
873 else if (token
[0] == 'R' || token
[0] == 'H') {
874 /* a temporary register */
875 dstReg
->File
= PROGRAM_TEMPORARY
;
876 if (!Parse_TempReg(parseState
, &idx
))
880 else if (token
[0] == 'o') {
881 /* an output register */
882 dstReg
->File
= PROGRAM_OUTPUT
;
883 if (!Parse_OutputReg(parseState
, &idx
))
888 RETURN_ERROR1("Invalid destination register name");
891 /* Parse optional write mask */
892 if (Parse_String(parseState
, ".")) {
896 if (!Parse_Token(parseState
, token
)) /* get xyzw writemask */
899 dstReg
->WriteMask
= 0;
901 if (token
[k
] == 'x') {
902 dstReg
->WriteMask
|= WRITEMASK_X
;
905 if (token
[k
] == 'y') {
906 dstReg
->WriteMask
|= WRITEMASK_Y
;
909 if (token
[k
] == 'z') {
910 dstReg
->WriteMask
|= WRITEMASK_Z
;
913 if (token
[k
] == 'w') {
914 dstReg
->WriteMask
|= WRITEMASK_W
;
918 RETURN_ERROR1("Invalid writemask character");
923 dstReg
->WriteMask
= WRITEMASK_XYZW
;
926 /* optional condition code mask */
927 if (Parse_String(parseState
, "(")) {
928 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
929 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
930 if (!Parse_CondCodeMask(parseState
, dstReg
))
933 if (!Parse_String(parseState
, ")")) /* consume ")" */
934 RETURN_ERROR1("Expected )");
939 /* no cond code mask */
940 dstReg
->CondMask
= COND_TR
;
941 dstReg
->CondSwizzle
= SWIZZLE_NOOP
;
948 * Parse a vector source (register, constant, etc):
949 * <vectorSrc> ::= <absVectorSrc>
951 * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
954 Parse_VectorSrc(struct parse_state
*parseState
,
955 struct prog_src_register
*srcReg
)
960 GLuint negateBase
, negateAbs
;
963 * First, take care of +/- and absolute value stuff.
965 if (Parse_String(parseState
, "-"))
967 else if (Parse_String(parseState
, "+"))
970 if (Parse_String(parseState
, "|")) {
971 srcReg
->Abs
= GL_TRUE
;
972 negateAbs
= (sign
< 0.0F
) ? NEGATE_XYZW
: NEGATE_NONE
;
974 if (Parse_String(parseState
, "-"))
975 negateBase
= NEGATE_XYZW
;
976 else if (Parse_String(parseState
, "+"))
977 negateBase
= NEGATE_NONE
;
979 negateBase
= NEGATE_NONE
;
982 srcReg
->Abs
= GL_FALSE
;
983 negateAbs
= NEGATE_NONE
;
984 negateBase
= (sign
< 0.0F
) ? NEGATE_XYZW
: NEGATE_NONE
;
987 srcReg
->Negate
= srcReg
->Abs
? negateAbs
: negateBase
;
989 /* This should be the real src vector/register name */
990 if (!Peek_Token(parseState
, token
))
993 /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
994 * literal or vector literal.
996 if (token
[0] == 'R' || token
[0] == 'H') {
997 srcReg
->File
= PROGRAM_TEMPORARY
;
998 if (!Parse_TempReg(parseState
, &idx
))
1000 srcReg
->Index
= idx
;
1002 else if (token
[0] == 'f') {
1003 /* XXX this might be an identifier! */
1004 srcReg
->File
= PROGRAM_INPUT
;
1005 if (!Parse_FragReg(parseState
, &idx
))
1007 srcReg
->Index
= idx
;
1009 else if (token
[0] == 'p') {
1010 /* XXX this might be an identifier! */
1011 srcReg
->File
= PROGRAM_LOCAL_PARAM
;
1012 if (!Parse_ProgramParamReg(parseState
, &idx
))
1014 srcReg
->Index
= idx
;
1016 else if (IsLetter(token
[0])){
1019 if (!Parse_Identifier(parseState
, ident
))
1021 paramIndex
= _mesa_lookup_parameter_index(parseState
->parameters
,
1022 -1, (const char *) ident
);
1023 if (paramIndex
< 0) {
1024 RETURN_ERROR2("Undefined constant or parameter: ", ident
);
1026 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1027 srcReg
->Index
= paramIndex
;
1029 else if (IsDigit(token
[0]) || token
[0] == '-' || token
[0] == '+' || token
[0] == '.'){
1030 /* literal scalar constant */
1033 if (!Parse_ScalarConstant(parseState
, values
))
1035 paramIndex
= _mesa_add_unnamed_constant(parseState
->parameters
,
1037 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1038 srcReg
->Index
= paramIndex
;
1040 else if (token
[0] == '{'){
1041 /* literal vector constant */
1044 (void) Parse_String(parseState
, "{");
1045 if (!Parse_VectorConstant(parseState
, values
))
1047 paramIndex
= _mesa_add_unnamed_constant(parseState
->parameters
,
1049 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1050 srcReg
->Index
= paramIndex
;
1053 RETURN_ERROR2("Invalid source register name", token
);
1056 /* init swizzle fields */
1057 srcReg
->Swizzle
= SWIZZLE_NOOP
;
1059 /* Look for optional swizzle suffix */
1060 if (Parse_String(parseState
, ".")) {
1063 if (!Parse_Token(parseState
, token
))
1066 if (!Parse_SwizzleSuffix(token
, swz
))
1067 RETURN_ERROR1("Invalid swizzle suffix");
1069 srcReg
->Swizzle
= MAKE_SWIZZLE4(swz
[0], swz
[1], swz
[2], swz
[3]);
1072 /* Finish absolute value */
1073 if (srcReg
->Abs
&& !Parse_String(parseState
, "|")) {
1074 RETURN_ERROR1("Expected |");
1082 Parse_ScalarSrcReg(struct parse_state
*parseState
,
1083 struct prog_src_register
*srcReg
)
1086 GLfloat sign
= 1.0F
;
1087 GLboolean needSuffix
= GL_TRUE
;
1089 GLuint negateBase
, negateAbs
;
1092 * First, take care of +/- and absolute value stuff.
1094 if (Parse_String(parseState
, "-"))
1096 else if (Parse_String(parseState
, "+"))
1099 if (Parse_String(parseState
, "|")) {
1100 srcReg
->Abs
= GL_TRUE
;
1101 negateAbs
= (sign
< 0.0F
) ? NEGATE_XYZW
: NEGATE_NONE
;
1103 if (Parse_String(parseState
, "-"))
1104 negateBase
= NEGATE_XYZW
;
1105 else if (Parse_String(parseState
, "+"))
1106 negateBase
= NEGATE_NONE
;
1108 negateBase
= NEGATE_NONE
;
1111 srcReg
->Abs
= GL_FALSE
;
1112 negateAbs
= NEGATE_NONE
;
1113 negateBase
= (sign
< 0.0F
) ? NEGATE_XYZW
: NEGATE_NONE
;
1116 srcReg
->Negate
= srcReg
->Abs
? negateAbs
: negateBase
;
1118 if (!Peek_Token(parseState
, token
))
1121 /* Src reg can be R<n>, H<n> or a named fragment attrib */
1122 if (token
[0] == 'R' || token
[0] == 'H') {
1123 srcReg
->File
= PROGRAM_TEMPORARY
;
1124 if (!Parse_TempReg(parseState
, &idx
))
1126 srcReg
->Index
= idx
;
1128 else if (token
[0] == 'f') {
1129 srcReg
->File
= PROGRAM_INPUT
;
1130 if (!Parse_FragReg(parseState
, &idx
))
1132 srcReg
->Index
= idx
;
1134 else if (token
[0] == '{') {
1135 /* vector literal */
1138 (void) Parse_String(parseState
, "{");
1139 if (!Parse_VectorConstant(parseState
, values
))
1141 paramIndex
= _mesa_add_unnamed_constant(parseState
->parameters
,
1143 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1144 srcReg
->Index
= paramIndex
;
1146 else if (IsLetter(token
[0])){
1147 /* named param/constant */
1150 if (!Parse_Identifier(parseState
, ident
))
1152 paramIndex
= _mesa_lookup_parameter_index(parseState
->parameters
,
1153 -1, (const char *) ident
);
1154 if (paramIndex
< 0) {
1155 RETURN_ERROR2("Undefined constant or parameter: ", ident
);
1157 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1158 srcReg
->Index
= paramIndex
;
1160 else if (IsDigit(token
[0])) {
1161 /* scalar literal */
1164 if (!Parse_ScalarConstant(parseState
, values
))
1166 paramIndex
= _mesa_add_unnamed_constant(parseState
->parameters
,
1168 srcReg
->Index
= paramIndex
;
1169 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1170 needSuffix
= GL_FALSE
;
1173 RETURN_ERROR2("Invalid scalar source argument", token
);
1176 srcReg
->Swizzle
= 0;
1178 /* parse .[xyzw] suffix */
1179 if (!Parse_String(parseState
, "."))
1180 RETURN_ERROR1("Expected .");
1182 if (!Parse_Token(parseState
, token
))
1185 if (token
[0] == 'x' && token
[1] == 0) {
1186 srcReg
->Swizzle
= 0;
1188 else if (token
[0] == 'y' && token
[1] == 0) {
1189 srcReg
->Swizzle
= 1;
1191 else if (token
[0] == 'z' && token
[1] == 0) {
1192 srcReg
->Swizzle
= 2;
1194 else if (token
[0] == 'w' && token
[1] == 0) {
1195 srcReg
->Swizzle
= 3;
1198 RETURN_ERROR1("Invalid scalar source suffix");
1202 /* Finish absolute value */
1203 if (srcReg
->Abs
&& !Parse_String(parseState
, "|")) {
1204 RETURN_ERROR1("Expected |");
1212 Parse_PrintInstruction(struct parse_state
*parseState
,
1213 struct prog_instruction
*inst
)
1220 /* The first argument is a literal string 'just like this' */
1221 if (!Parse_String(parseState
, "'"))
1222 RETURN_ERROR1("Expected '");
1224 str
= parseState
->pos
;
1225 for (len
= 0; str
[len
] != '\''; len
++) /* find closing quote */
1227 parseState
->pos
+= len
+ 1;
1228 msg
= (GLubyte
*) _mesa_malloc(len
+ 1);
1230 _mesa_memcpy(msg
, str
, len
);
1234 if (Parse_String(parseState
, ",")) {
1235 /* got an optional register to print */
1237 GetToken(parseState
, token
);
1238 if (token
[0] == 'o') {
1240 if (!Parse_OutputReg(parseState
, &idx
))
1242 inst
->SrcReg
[0].Index
= idx
;
1243 inst
->SrcReg
[0].File
= PROGRAM_OUTPUT
;
1247 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1252 inst
->SrcReg
[0].File
= PROGRAM_UNDEFINED
;
1255 inst
->SrcReg
[0].Swizzle
= SWIZZLE_NOOP
;
1256 inst
->SrcReg
[0].Abs
= GL_FALSE
;
1257 inst
->SrcReg
[0].Negate
= NEGATE_NONE
;
1264 Parse_InstructionSequence(struct parse_state
*parseState
,
1265 struct prog_instruction program
[])
1268 struct prog_instruction
*inst
= program
+ parseState
->numInst
;
1269 struct instruction_pattern instMatch
;
1272 /* Initialize the instruction */
1273 _mesa_init_instructions(inst
, 1);
1275 /* special instructions */
1276 if (Parse_String(parseState
, "DEFINE")) {
1278 GLfloat value
[7]; /* yes, 7 to be safe */
1279 if (!Parse_Identifier(parseState
, id
))
1281 /* XXX make sure id is not a reserved identifer, like R9 */
1282 if (!Parse_String(parseState
, "="))
1283 RETURN_ERROR1("Expected =");
1284 if (!Parse_VectorOrScalarConstant(parseState
, value
))
1286 if (!Parse_String(parseState
, ";"))
1287 RETURN_ERROR1("Expected ;");
1288 if (_mesa_lookup_parameter_index(parseState
->parameters
,
1289 -1, (const char *) id
) >= 0) {
1290 RETURN_ERROR2(id
, "already defined");
1292 _mesa_add_named_parameter(parseState
->parameters
,
1293 (const char *) id
, value
);
1295 else if (Parse_String(parseState
, "DECLARE")) {
1297 GLfloat value
[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */
1298 if (!Parse_Identifier(parseState
, id
))
1300 /* XXX make sure id is not a reserved identifer, like R9 */
1301 if (Parse_String(parseState
, "=")) {
1302 if (!Parse_VectorOrScalarConstant(parseState
, value
))
1305 if (!Parse_String(parseState
, ";"))
1306 RETURN_ERROR1("Expected ;");
1307 if (_mesa_lookup_parameter_index(parseState
->parameters
,
1308 -1, (const char *) id
) >= 0) {
1309 RETURN_ERROR2(id
, "already declared");
1311 _mesa_add_named_parameter(parseState
->parameters
,
1312 (const char *) id
, value
);
1314 else if (Parse_String(parseState
, "END")) {
1315 inst
->Opcode
= OPCODE_END
;
1316 parseState
->numInst
++;
1317 if (Parse_Token(parseState
, token
)) {
1318 RETURN_ERROR1("Code after END opcode.");
1323 /* general/arithmetic instruction */
1326 if (!Parse_Token(parseState
, token
)) {
1327 RETURN_ERROR1("Missing END instruction.");
1330 /* try to find matching instuction */
1331 instMatch
= MatchInstruction(token
);
1332 if (instMatch
.opcode
>= MAX_OPCODE
) {
1333 /* bad instruction name */
1334 RETURN_ERROR2("Unexpected token: ", token
);
1337 inst
->Opcode
= instMatch
.opcode
;
1338 inst
->Precision
= instMatch
.suffixes
& (_R
| _H
| _X
);
1339 inst
->SaturateMode
= (instMatch
.suffixes
& (_S
))
1340 ? SATURATE_ZERO_ONE
: SATURATE_OFF
;
1341 inst
->CondUpdate
= (instMatch
.suffixes
& (_C
)) ? GL_TRUE
: GL_FALSE
;
1344 * parse the input and output operands
1346 if (instMatch
.outputs
== OUTPUT_S
|| instMatch
.outputs
== OUTPUT_V
) {
1347 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
1349 if (!Parse_String(parseState
, ","))
1350 RETURN_ERROR1("Expected ,");
1352 else if (instMatch
.outputs
== OUTPUT_NONE
) {
1353 if (instMatch
.opcode
== OPCODE_KIL_NV
) {
1354 /* This is a little weird, the cond code info is in
1355 * the dest register.
1357 if (!Parse_CondCodeMask(parseState
, &inst
->DstReg
))
1361 ASSERT(instMatch
.opcode
== OPCODE_PRINT
);
1365 if (instMatch
.inputs
== INPUT_1V
) {
1366 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1369 else if (instMatch
.inputs
== INPUT_2V
) {
1370 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1372 if (!Parse_String(parseState
, ","))
1373 RETURN_ERROR1("Expected ,");
1374 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[1]))
1377 else if (instMatch
.inputs
== INPUT_3V
) {
1378 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1380 if (!Parse_String(parseState
, ","))
1381 RETURN_ERROR1("Expected ,");
1382 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[1]))
1384 if (!Parse_String(parseState
, ","))
1385 RETURN_ERROR1("Expected ,");
1386 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[2]))
1389 else if (instMatch
.inputs
== INPUT_1S
) {
1390 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
1393 else if (instMatch
.inputs
== INPUT_2S
) {
1394 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
1396 if (!Parse_String(parseState
, ","))
1397 RETURN_ERROR1("Expected ,");
1398 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[1]))
1401 else if (instMatch
.inputs
== INPUT_CC
) {
1404 else if (instMatch
.inputs
== INPUT_1V_T
) {
1406 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1408 if (!Parse_String(parseState
, ","))
1409 RETURN_ERROR1("Expected ,");
1410 if (!Parse_TextureImageId(parseState
, &unit
, &idx
))
1412 inst
->TexSrcUnit
= unit
;
1413 inst
->TexSrcTarget
= idx
;
1415 else if (instMatch
.inputs
== INPUT_3V_T
) {
1417 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1419 if (!Parse_String(parseState
, ","))
1420 RETURN_ERROR1("Expected ,");
1421 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[1]))
1423 if (!Parse_String(parseState
, ","))
1424 RETURN_ERROR1("Expected ,");
1425 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[2]))
1427 if (!Parse_String(parseState
, ","))
1428 RETURN_ERROR1("Expected ,");
1429 if (!Parse_TextureImageId(parseState
, &unit
, &idx
))
1431 inst
->TexSrcUnit
= unit
;
1432 inst
->TexSrcTarget
= idx
;
1434 else if (instMatch
.inputs
== INPUT_1V_S
) {
1435 if (!Parse_PrintInstruction(parseState
, inst
))
1439 /* end of statement semicolon */
1440 if (!Parse_String(parseState
, ";"))
1441 RETURN_ERROR1("Expected ;");
1443 parseState
->numInst
++;
1445 if (parseState
->numInst
>= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
)
1446 RETURN_ERROR1("Program too long");
1455 * Parse/compile the 'str' returning the compiled 'program'.
1456 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1457 * indicates the position of the error in 'str'.
1460 _mesa_parse_nv_fragment_program(GLcontext
*ctx
, GLenum dstTarget
,
1461 const GLubyte
*str
, GLsizei len
,
1462 struct gl_fragment_program
*program
)
1464 struct parse_state parseState
;
1465 struct prog_instruction instBuffer
[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
];
1466 struct prog_instruction
*newInst
;
1468 GLubyte
*programString
;
1470 /* Make a null-terminated copy of the program string */
1471 programString
= (GLubyte
*) MALLOC(len
+ 1);
1472 if (!programString
) {
1473 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1476 MEMCPY(programString
, str
, len
);
1477 programString
[len
] = 0;
1479 /* Get ready to parse */
1480 _mesa_bzero(&parseState
, sizeof(struct parse_state
));
1481 parseState
.ctx
= ctx
;
1482 parseState
.start
= programString
;
1483 parseState
.program
= program
;
1484 parseState
.numInst
= 0;
1485 parseState
.curLine
= programString
;
1486 parseState
.parameters
= _mesa_new_parameter_list();
1488 /* Reset error state */
1489 _mesa_set_program_error(ctx
, -1, NULL
);
1491 /* check the program header */
1492 if (_mesa_strncmp((const char *) programString
, "!!FP1.0", 7) == 0) {
1493 target
= GL_FRAGMENT_PROGRAM_NV
;
1494 parseState
.pos
= programString
+ 7;
1496 else if (_mesa_strncmp((const char *) programString
, "!!FCP1.0", 8) == 0) {
1497 /* fragment / register combiner program - not supported */
1498 _mesa_set_program_error(ctx
, 0, "Invalid fragment program header");
1499 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1503 /* invalid header */
1504 _mesa_set_program_error(ctx
, 0, "Invalid fragment program header");
1505 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1509 /* make sure target and header match */
1510 if (target
!= dstTarget
) {
1511 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1512 "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1517 if (Parse_InstructionSequence(&parseState
, instBuffer
)) {
1519 /* successful parse! */
1521 if (parseState
.outputsWritten
== 0) {
1522 /* must write at least one output! */
1523 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1524 "Invalid fragment program - no outputs written.");
1528 /* copy the compiled instructions */
1529 assert(parseState
.numInst
<= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
);
1530 newInst
= _mesa_alloc_instructions(parseState
.numInst
);
1532 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1533 return; /* out of memory */
1535 _mesa_copy_instructions(newInst
, instBuffer
, parseState
.numInst
);
1537 /* install the program */
1538 program
->Base
.Target
= target
;
1539 if (program
->Base
.String
) {
1540 FREE(program
->Base
.String
);
1542 program
->Base
.String
= programString
;
1543 program
->Base
.Format
= GL_PROGRAM_FORMAT_ASCII_ARB
;
1544 if (program
->Base
.Instructions
) {
1545 _mesa_free(program
->Base
.Instructions
);
1547 program
->Base
.Instructions
= newInst
;
1548 program
->Base
.NumInstructions
= parseState
.numInst
;
1549 program
->Base
.InputsRead
= parseState
.inputsRead
;
1550 program
->Base
.OutputsWritten
= parseState
.outputsWritten
;
1551 for (u
= 0; u
< ctx
->Const
.MaxTextureImageUnits
; u
++)
1552 program
->Base
.TexturesUsed
[u
] = parseState
.texturesUsed
[u
];
1554 /* save program parameters */
1555 program
->Base
.Parameters
= parseState
.parameters
;
1557 /* allocate registers for declared program parameters */
1559 _mesa_assign_program_registers(&(program
->SymbolTable
));
1563 _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program
->Base
.Id
);
1564 _mesa_fprint_program_opt(stdout
, &program
->Base
, PROG_PRINT_NV
, 0);
1565 _mesa_printf("----------------------------------\n");
1570 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1571 /* NOTE: _mesa_set_program_error would have been called already */
1577 _mesa_nv_fragment_input_register_name(GLuint i
)
1579 ASSERT(i
< MAX_NV_FRAGMENT_PROGRAM_INPUTS
);
1580 return InputRegisters
[i
];