2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2004 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.
46 #include "nvfragprog.h"
47 #include "nvfragparse.h"
48 #include "nvprogram.h"
58 #define INPUT_1V_T 7 /* one source vector, plus textureId */
59 #define INPUT_3V_T 8 /* one source vector, plus textureId */
61 #define INPUT_1V_S 10 /* a string and a vector register */
64 #define OUTPUT_NONE 22
66 /* IRIX defines some of these */
73 /* Optional suffixes */
74 #define _R FLOAT32 /* float */
75 #define _H FLOAT16 /* half-float */
76 #define _X FIXED12 /* fixed */
77 #define _C 0x08 /* set cond codes */
78 #define _S 0x10 /* saturate, clamp result to [0,1] */
80 struct instruction_pattern
{
82 enum fp_opcode opcode
;
88 static const struct instruction_pattern Instructions
[] = {
89 { "ADD", FP_OPCODE_ADD
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
90 { "COS", FP_OPCODE_COS
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
91 { "DDX", FP_OPCODE_DDX
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
92 { "DDY", FP_OPCODE_DDY
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
93 { "DP3", FP_OPCODE_DP3
, INPUT_2V
, OUTPUT_S
, _R
| _H
| _X
| _C
| _S
},
94 { "DP4", FP_OPCODE_DP4
, INPUT_2V
, OUTPUT_S
, _R
| _H
| _X
| _C
| _S
},
95 { "DST", FP_OPCODE_DP4
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
96 { "EX2", FP_OPCODE_DP4
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
97 { "FLR", FP_OPCODE_FLR
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
98 { "FRC", FP_OPCODE_FRC
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
99 { "KIL", FP_OPCODE_KIL_NV
, INPUT_CC
, OUTPUT_NONE
, 0 },
100 { "LG2", FP_OPCODE_LG2
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
101 { "LIT", FP_OPCODE_LIT
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
102 { "LRP", FP_OPCODE_LRP
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
103 { "MAD", FP_OPCODE_MAD
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
104 { "MAX", FP_OPCODE_MAX
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
105 { "MIN", FP_OPCODE_MIN
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
106 { "MOV", FP_OPCODE_MOV
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
107 { "MUL", FP_OPCODE_MUL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
108 { "PK2H", FP_OPCODE_PK2H
, INPUT_1V
, OUTPUT_S
, 0 },
109 { "PK2US", FP_OPCODE_PK2US
, INPUT_1V
, OUTPUT_S
, 0 },
110 { "PK4B", FP_OPCODE_PK4B
, INPUT_1V
, OUTPUT_S
, 0 },
111 { "PK4UB", FP_OPCODE_PK4UB
, INPUT_1V
, OUTPUT_S
, 0 },
112 { "POW", FP_OPCODE_POW
, INPUT_2S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
113 { "RCP", FP_OPCODE_RCP
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
114 { "RFL", FP_OPCODE_RFL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
115 { "RSQ", FP_OPCODE_RSQ
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
116 { "SEQ", FP_OPCODE_SEQ
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
117 { "SFL", FP_OPCODE_SFL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
118 { "SGE", FP_OPCODE_SGE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
119 { "SGT", FP_OPCODE_SGT
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
120 { "SIN", FP_OPCODE_SIN
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
121 { "SLE", FP_OPCODE_SLE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
122 { "SLT", FP_OPCODE_SLT
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
123 { "SNE", FP_OPCODE_SNE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
124 { "STR", FP_OPCODE_STR
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
125 { "SUB", FP_OPCODE_SUB
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
126 { "TEX", FP_OPCODE_TEX
, INPUT_1V_T
, OUTPUT_V
, _C
| _S
},
127 { "TXD", FP_OPCODE_TXD
, INPUT_3V_T
, OUTPUT_V
, _C
| _S
},
128 { "TXP", FP_OPCODE_TXP_NV
, INPUT_1V_T
, OUTPUT_V
, _C
| _S
},
129 { "UP2H", FP_OPCODE_UP2H
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
130 { "UP2US", FP_OPCODE_UP2US
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
131 { "UP4B", FP_OPCODE_UP4B
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
132 { "UP4UB", FP_OPCODE_UP4UB
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
133 { "X2D", FP_OPCODE_X2D
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
134 { "PRINT", FP_OPCODE_PRINT
, INPUT_1V_S
, OUTPUT_NONE
, 0 },
135 { NULL
, (enum fp_opcode
) -1, 0, 0, 0 }
140 * Information needed or computed during parsing.
141 * Remember, we can't modify the target program object until we've
142 * _successfully_ parsed the program text.
146 const GLubyte
*start
; /* start of program string */
147 const GLubyte
*pos
; /* current position */
148 const GLubyte
*curLine
;
149 struct fragment_program
*program
; /* current program */
151 struct program_parameter_list
*parameters
;
153 GLuint numInst
; /* number of instructions parsed */
154 GLuint inputsRead
; /* bitmask of input registers used */
155 GLuint outputsWritten
; /* bitmask of 1 << FRAG_OUTPUT_* bits */
156 GLuint texturesUsed
[MAX_TEXTURE_IMAGE_UNITS
];
162 * Called whenever we find an error during parsing.
165 record_error(struct parse_state
*parseState
, const char *msg
, int lineNo
)
169 const GLubyte
*lineStr
;
170 lineStr
= _mesa_find_line_column(parseState
->start
,
171 parseState
->pos
, &line
, &column
);
172 _mesa_debug(parseState
->ctx
,
173 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
174 lineNo
, line
, column
, (char *) lineStr
, msg
);
175 _mesa_free((void *) lineStr
);
180 /* Check that no error was already recorded. Only record the first one. */
181 if (parseState
->ctx
->Program
.ErrorString
[0] == 0) {
182 _mesa_set_program_error(parseState
->ctx
,
183 parseState
->pos
- parseState
->start
,
189 #define RETURN_ERROR \
191 record_error(parseState, "Unexpected end of input.", __LINE__); \
195 #define RETURN_ERROR1(msg) \
197 record_error(parseState, msg, __LINE__); \
201 #define RETURN_ERROR2(msg1, msg2) \
204 _mesa_sprintf(err, "%s %s", msg1, msg2); \
205 record_error(parseState, err, __LINE__); \
213 * Search a list of instruction structures for a match.
215 static struct instruction_pattern
216 MatchInstruction(const GLubyte
*token
)
218 const struct instruction_pattern
*inst
;
219 struct instruction_pattern result
;
221 for (inst
= Instructions
; inst
->name
; inst
++) {
222 if (_mesa_strncmp((const char *) token
, inst
->name
, 3) == 0) {
228 if (token
[i
] == 'R') {
229 result
.suffixes
|= _R
;
232 else if (token
[i
] == 'H') {
233 result
.suffixes
|= _H
;
236 else if (token
[i
] == 'X') {
237 result
.suffixes
|= _X
;
240 if (token
[i
] == 'C') {
241 result
.suffixes
|= _C
;
244 if (token
[i
] == '_' && token
[i
+1] == 'S' &&
245 token
[i
+2] == 'A' && token
[i
+3] == 'T') {
246 result
.suffixes
|= _S
;
251 result
.opcode
= (enum fp_opcode
) -1;
258 /**********************************************************************/
261 static GLboolean
IsLetter(GLubyte b
)
263 return (b
>= 'a' && b
<= 'z') ||
264 (b
>= 'A' && b
<= 'Z') ||
270 static GLboolean
IsDigit(GLubyte b
)
272 return b
>= '0' && b
<= '9';
276 static GLboolean
IsWhitespace(GLubyte b
)
278 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
283 * Starting at 'str' find the next token. A token can be an integer,
284 * an identifier or punctuation symbol.
285 * \return <= 0 we found an error, else, return number of characters parsed.
288 GetToken(struct parse_state
*parseState
, GLubyte
*token
)
290 const GLubyte
*str
= parseState
->pos
;
295 /* skip whitespace and comments */
296 while (str
[i
] && (IsWhitespace(str
[i
]) || str
[i
] == '#')) {
299 while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
302 if (str
[i
] == '\n' || str
[i
] == '\r')
303 parseState
->curLine
= str
+ i
+ 1;
306 /* skip whitespace */
307 if (str
[i
] == '\n' || str
[i
] == '\r')
308 parseState
->curLine
= str
+ i
+ 1;
316 /* try matching an integer */
317 while (str
[i
] && IsDigit(str
[i
])) {
318 token
[j
++] = str
[i
++];
320 if (j
> 0 || !str
[i
]) {
325 /* try matching an identifier */
326 if (IsLetter(str
[i
])) {
327 while (str
[i
] && (IsLetter(str
[i
]) || IsDigit(str
[i
]))) {
328 token
[j
++] = str
[i
++];
334 /* punctuation character */
348 * Get next token from input stream and increment stream pointer past token.
351 Parse_Token(struct parse_state
*parseState
, GLubyte
*token
)
354 i
= GetToken(parseState
, token
);
356 parseState
->pos
+= (-i
);
359 parseState
->pos
+= i
;
365 * Get next token from input stream but don't increment stream pointer.
368 Peek_Token(struct parse_state
*parseState
, GLubyte
*token
)
371 i
= GetToken(parseState
, token
);
373 parseState
->pos
+= (-i
);
376 len
= (GLint
)_mesa_strlen((const char *) token
);
377 parseState
->pos
+= (i
- len
);
382 /**********************************************************************/
384 static const char *InputRegisters
[MAX_NV_FRAGMENT_PROGRAM_INPUTS
+ 1] = {
385 "WPOS", "COL0", "COL1", "FOGC",
386 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
389 static const char *OutputRegisters
[MAX_NV_FRAGMENT_PROGRAM_OUTPUTS
+ 1] = {
391 /* These are only allows for register combiners */
393 "TEX0", "TEX1", "TEX2", "TEX3",
401 /**********************************************************************/
404 * Try to match 'pattern' as the next token after any whitespace/comments.
407 Parse_String(struct parse_state
*parseState
, const char *pattern
)
412 /* skip whitespace and comments */
413 while (IsWhitespace(*parseState
->pos
) || *parseState
->pos
== '#') {
414 if (*parseState
->pos
== '#') {
415 while (*parseState
->pos
&& (*parseState
->pos
!= '\n' && *parseState
->pos
!= '\r')) {
416 parseState
->pos
+= 1;
418 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
419 parseState
->curLine
= parseState
->pos
+ 1;
422 /* skip whitespace */
423 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
424 parseState
->curLine
= parseState
->pos
+ 1;
425 parseState
->pos
+= 1;
429 /* Try to match the pattern */
431 for (i
= 0; pattern
[i
]; i
++) {
432 if (*m
!= (GLubyte
) pattern
[i
])
438 return GL_TRUE
; /* success */
443 Parse_Identifier(struct parse_state
*parseState
, GLubyte
*ident
)
445 if (!Parse_Token(parseState
, ident
))
447 if (IsLetter(ident
[0]))
450 RETURN_ERROR1("Expected an identfier");
455 * Parse a floating point constant, or a defined symbol name.
457 * Output: number[0 .. 3] will get the value.
460 Parse_ScalarConstant(struct parse_state
*parseState
, GLfloat
*number
)
464 *number
= (GLfloat
) _mesa_strtod((const char *) parseState
->pos
, &end
);
466 if (end
&& end
> (char *) parseState
->pos
) {
468 parseState
->pos
= (GLubyte
*) end
;
475 /* should be an identifier */
477 const GLfloat
*constant
;
478 if (!Parse_Identifier(parseState
, ident
))
479 RETURN_ERROR1("Expected an identifier");
480 constant
= _mesa_lookup_parameter_value(parseState
->parameters
,
481 -1, (const char *) ident
);
482 /* XXX Check that it's a constant and not a parameter */
484 RETURN_ERROR1("Undefined symbol");
487 COPY_4V(number
, constant
);
496 * Parse a vector constant, one of:
499 * { float, float, float }
500 * { float, float, float, float }
503 Parse_VectorConstant(struct parse_state
*parseState
, GLfloat
*vec
)
505 /* "{" was already consumed */
507 ASSIGN_4V(vec
, 0.0, 0.0, 0.0, 1.0);
509 if (!Parse_ScalarConstant(parseState
, vec
+0)) /* X */
512 if (Parse_String(parseState
, "}")) {
516 if (!Parse_String(parseState
, ","))
517 RETURN_ERROR1("Expected comma in vector constant");
519 if (!Parse_ScalarConstant(parseState
, vec
+1)) /* Y */
522 if (Parse_String(parseState
, "}")) {
526 if (!Parse_String(parseState
, ","))
527 RETURN_ERROR1("Expected comma in vector constant");
529 if (!Parse_ScalarConstant(parseState
, vec
+2)) /* Z */
532 if (Parse_String(parseState
, "}")) {
536 if (!Parse_String(parseState
, ","))
537 RETURN_ERROR1("Expected comma in vector constant");
539 if (!Parse_ScalarConstant(parseState
, vec
+3)) /* W */
542 if (!Parse_String(parseState
, "}"))
543 RETURN_ERROR1("Expected closing brace in vector constant");
550 * Parse <number>, <varname> or {a, b, c, d}.
551 * Return number of values in the vector or scalar, or zero if parse error.
554 Parse_VectorOrScalarConstant(struct parse_state
*parseState
, GLfloat
*vec
)
556 if (Parse_String(parseState
, "{")) {
557 return Parse_VectorConstant(parseState
, vec
);
560 GLboolean b
= Parse_ScalarConstant(parseState
, vec
);
562 vec
[1] = vec
[2] = vec
[3] = vec
[0];
570 * Parse a texture image source:
571 * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
574 Parse_TextureImageId(struct parse_state
*parseState
,
575 GLubyte
*texUnit
, GLubyte
*texTargetBit
)
577 GLubyte imageSrc
[100];
580 if (!Parse_Token(parseState
, imageSrc
))
583 if (imageSrc
[0] != 'T' ||
584 imageSrc
[1] != 'E' ||
585 imageSrc
[2] != 'X') {
586 RETURN_ERROR1("Expected TEX# source");
588 unit
= _mesa_atoi((const char *) imageSrc
+ 3);
589 if ((unit
< 0 || unit
> MAX_TEXTURE_IMAGE_UNITS
) ||
590 (unit
== 0 && (imageSrc
[3] != '0' || imageSrc
[4] != 0))) {
591 RETURN_ERROR1("Invalied TEX# source index");
595 if (!Parse_String(parseState
, ","))
596 RETURN_ERROR1("Expected ,");
598 if (Parse_String(parseState
, "1D")) {
599 *texTargetBit
= TEXTURE_1D_BIT
;
601 else if (Parse_String(parseState
, "2D")) {
602 *texTargetBit
= TEXTURE_2D_BIT
;
604 else if (Parse_String(parseState
, "3D")) {
605 *texTargetBit
= TEXTURE_3D_BIT
;
607 else if (Parse_String(parseState
, "CUBE")) {
608 *texTargetBit
= TEXTURE_CUBE_BIT
;
610 else if (Parse_String(parseState
, "RECT")) {
611 *texTargetBit
= TEXTURE_RECT_BIT
;
614 RETURN_ERROR1("Invalid texture target token");
617 /* update record of referenced texture units */
618 parseState
->texturesUsed
[*texUnit
] |= *texTargetBit
;
619 if (_mesa_bitcount(parseState
->texturesUsed
[*texUnit
]) > 1) {
620 RETURN_ERROR1("Only one texture target can be used per texture unit.");
628 * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
629 * like .wxyz, .xxyy, etc and return the swizzle indexes.
632 Parse_SwizzleSuffix(const GLubyte
*token
, GLuint swizzle
[4])
635 /* single letter swizzle (scalar) */
637 ASSIGN_4V(swizzle
, 0, 0, 0, 0);
638 else if (token
[0] == 'y')
639 ASSIGN_4V(swizzle
, 1, 1, 1, 1);
640 else if (token
[0] == 'z')
641 ASSIGN_4V(swizzle
, 2, 2, 2, 2);
642 else if (token
[0] == 'w')
643 ASSIGN_4V(swizzle
, 3, 3, 3, 3);
648 /* 4-component swizzle (vector) */
650 for (k
= 0; token
[k
] && k
< 4; k
++) {
653 else if (token
[k
] == 'y')
655 else if (token
[k
] == 'z')
657 else if (token
[k
] == 'w')
670 Parse_CondCodeMask(struct parse_state
*parseState
,
671 struct fp_dst_register
*dstReg
)
673 if (Parse_String(parseState
, "EQ"))
674 dstReg
->CondMask
= COND_EQ
;
675 else if (Parse_String(parseState
, "GE"))
676 dstReg
->CondMask
= COND_GE
;
677 else if (Parse_String(parseState
, "GT"))
678 dstReg
->CondMask
= COND_GT
;
679 else if (Parse_String(parseState
, "LE"))
680 dstReg
->CondMask
= COND_LE
;
681 else if (Parse_String(parseState
, "LT"))
682 dstReg
->CondMask
= COND_LT
;
683 else if (Parse_String(parseState
, "NE"))
684 dstReg
->CondMask
= COND_NE
;
685 else if (Parse_String(parseState
, "TR"))
686 dstReg
->CondMask
= COND_TR
;
687 else if (Parse_String(parseState
, "FL"))
688 dstReg
->CondMask
= COND_FL
;
690 RETURN_ERROR1("Invalid condition code mask");
692 /* look for optional .xyzw swizzle */
693 if (Parse_String(parseState
, ".")) {
697 if (!Parse_Token(parseState
, token
)) /* get xyzw suffix */
700 if (!Parse_SwizzleSuffix(token
, swz
))
701 RETURN_ERROR1("Invalid swizzle suffix");
703 dstReg
->CondSwizzle
= MAKE_SWIZZLE(swz
);
711 * Parse a temporary register: Rnn or Hnn
714 Parse_TempReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
718 /* Should be 'R##' or 'H##' */
719 if (!Parse_Token(parseState
, token
))
721 if (token
[0] != 'R' && token
[0] != 'H')
722 RETURN_ERROR1("Expected R## or H##");
724 if (IsDigit(token
[1])) {
725 GLint reg
= _mesa_atoi((const char *) (token
+ 1));
728 if (reg
>= MAX_NV_FRAGMENT_PROGRAM_TEMPS
)
729 RETURN_ERROR1("Invalid temporary register name");
733 RETURN_ERROR1("Invalid temporary register name");
741 * Parse a write-only dummy register: RC or HC.
744 Parse_DummyReg(struct parse_state
*parseState
, GLint
*regNum
)
746 if (Parse_String(parseState
, "RC")) {
749 else if (Parse_String(parseState
, "HC")) {
753 RETURN_ERROR1("Invalid write-only register name");
761 * Parse a program local parameter register "p[##]"
764 Parse_ProgramParamReg(struct parse_state
*parseState
, GLint
*regNum
)
768 if (!Parse_String(parseState
, "p["))
769 RETURN_ERROR1("Expected p[");
771 if (!Parse_Token(parseState
, token
))
774 if (IsDigit(token
[0])) {
775 /* a numbered program parameter register */
776 GLint reg
= _mesa_atoi((const char *) token
);
777 if (reg
>= MAX_NV_FRAGMENT_PROGRAM_PARAMS
)
778 RETURN_ERROR1("Invalid constant program number");
785 if (!Parse_String(parseState
, "]"))
786 RETURN_ERROR1("Expected ]");
793 * Parse f[name] - fragment input register
796 Parse_FragReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
802 if (!Parse_String(parseState
, "f["))
803 RETURN_ERROR1("Expected f[");
805 /* get <name> and look for match */
806 if (!Parse_Token(parseState
, token
)) {
809 for (j
= 0; InputRegisters
[j
]; j
++) {
810 if (_mesa_strcmp((const char *) token
, InputRegisters
[j
]) == 0) {
812 parseState
->inputsRead
|= (1 << j
);
816 if (!InputRegisters
[j
]) {
817 /* unknown input register label */
818 RETURN_ERROR2("Invalid register name", token
);
822 if (!Parse_String(parseState
, "]"))
823 RETURN_ERROR1("Expected ]");
830 Parse_OutputReg(struct parse_state
*parseState
, GLint
*outputRegNum
)
836 if (!Parse_String(parseState
, "o["))
837 RETURN_ERROR1("Expected o[");
839 /* Get output reg name */
840 if (!Parse_Token(parseState
, token
))
843 /* try to match an output register name */
844 for (j
= 0; OutputRegisters
[j
]; j
++) {
845 if (_mesa_strcmp((const char *) token
, OutputRegisters
[j
]) == 0) {
846 static GLuint bothColors
= (1 << FRAG_OUTPUT_COLR
) | (1 << FRAG_OUTPUT_COLH
);
848 parseState
->outputsWritten
|= (1 << j
);
849 if ((parseState
->outputsWritten
& bothColors
) == bothColors
) {
850 RETURN_ERROR1("Illegal to write to both o[COLR] and o[COLH]");
855 if (!OutputRegisters
[j
])
856 RETURN_ERROR1("Invalid output register name");
859 if (!Parse_String(parseState
, "]"))
860 RETURN_ERROR1("Expected ]");
867 Parse_MaskedDstReg(struct parse_state
*parseState
,
868 struct fp_dst_register
*dstReg
)
873 /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
874 if (!Peek_Token(parseState
, token
))
877 if (_mesa_strcmp((const char *) token
, "RC") == 0 ||
878 _mesa_strcmp((const char *) token
, "HC") == 0) {
879 /* a write-only register */
880 dstReg
->File
= PROGRAM_WRITE_ONLY
;
881 if (!Parse_DummyReg(parseState
, &idx
))
885 else if (token
[0] == 'R' || token
[0] == 'H') {
886 /* a temporary register */
887 dstReg
->File
= PROGRAM_TEMPORARY
;
888 if (!Parse_TempReg(parseState
, &idx
))
892 else if (token
[0] == 'o') {
893 /* an output register */
894 dstReg
->File
= PROGRAM_OUTPUT
;
895 if (!Parse_OutputReg(parseState
, &idx
))
900 RETURN_ERROR1("Invalid destination register name");
903 /* Parse optional write mask */
904 if (Parse_String(parseState
, ".")) {
908 if (!Parse_Token(parseState
, token
)) /* get xyzw writemask */
911 dstReg
->WriteMask
= 0;
913 if (token
[k
] == 'x') {
914 dstReg
->WriteMask
|= WRITEMASK_X
;
917 if (token
[k
] == 'y') {
918 dstReg
->WriteMask
|= WRITEMASK_Y
;
921 if (token
[k
] == 'z') {
922 dstReg
->WriteMask
|= WRITEMASK_Z
;
925 if (token
[k
] == 'w') {
926 dstReg
->WriteMask
|= WRITEMASK_W
;
930 RETURN_ERROR1("Invalid writemask character");
935 dstReg
->WriteMask
= WRITEMASK_XYZW
;
938 /* optional condition code mask */
939 if (Parse_String(parseState
, "(")) {
940 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
941 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
942 if (!Parse_CondCodeMask(parseState
, dstReg
))
945 if (!Parse_String(parseState
, ")")) /* consume ")" */
946 RETURN_ERROR1("Expected )");
951 /* no cond code mask */
952 dstReg
->CondMask
= COND_TR
;
953 dstReg
->CondSwizzle
= SWIZZLE_NOOP
;
960 * Parse a vector source (register, constant, etc):
961 * <vectorSrc> ::= <absVectorSrc>
963 * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
966 Parse_VectorSrc(struct parse_state
*parseState
,
967 struct fp_src_register
*srcReg
)
974 * First, take care of +/- and absolute value stuff.
976 if (Parse_String(parseState
, "-"))
978 else if (Parse_String(parseState
, "+"))
981 if (Parse_String(parseState
, "|")) {
982 srcReg
->Abs
= GL_TRUE
;
983 srcReg
->NegateAbs
= (sign
< 0.0F
) ? GL_TRUE
: GL_FALSE
;
985 if (Parse_String(parseState
, "-"))
986 srcReg
->NegateBase
= 0xf;
987 else if (Parse_String(parseState
, "+"))
988 srcReg
->NegateBase
= 0;
990 srcReg
->NegateBase
= 0;
993 srcReg
->Abs
= GL_FALSE
;
994 srcReg
->NegateAbs
= GL_FALSE
;
995 srcReg
->NegateBase
= (sign
< 0.0F
) ? 0xf : 0x0;
998 /* This should be the real src vector/register name */
999 if (!Peek_Token(parseState
, token
))
1002 /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
1003 * literal or vector literal.
1005 if (token
[0] == 'R' || token
[0] == 'H') {
1006 srcReg
->File
= PROGRAM_TEMPORARY
;
1007 if (!Parse_TempReg(parseState
, &idx
))
1009 srcReg
->Index
= idx
;
1011 else if (token
[0] == 'f') {
1012 /* XXX this might be an identier! */
1013 srcReg
->File
= PROGRAM_INPUT
;
1014 if (!Parse_FragReg(parseState
, &idx
))
1016 srcReg
->Index
= idx
;
1018 else if (token
[0] == 'p') {
1019 /* XXX this might be an identier! */
1020 srcReg
->File
= PROGRAM_LOCAL_PARAM
;
1021 if (!Parse_ProgramParamReg(parseState
, &idx
))
1023 srcReg
->Index
= idx
;
1025 else if (IsLetter(token
[0])){
1028 if (!Parse_Identifier(parseState
, ident
))
1030 paramIndex
= _mesa_lookup_parameter_index(parseState
->parameters
,
1031 -1, (const char *) ident
);
1032 if (paramIndex
< 0) {
1033 RETURN_ERROR2("Undefined constant or parameter: ", ident
);
1035 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1036 srcReg
->Index
= paramIndex
;
1038 else if (IsDigit(token
[0]) || token
[0] == '-' || token
[0] == '+' || token
[0] == '.'){
1039 /* literal scalar constant */
1042 if (!Parse_ScalarConstant(parseState
, values
))
1044 paramIndex
= _mesa_add_unnamed_constant(parseState
->parameters
, values
);
1045 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1046 srcReg
->Index
= paramIndex
;
1048 else if (token
[0] == '{'){
1049 /* literal vector constant */
1052 (void) Parse_String(parseState
, "{");
1053 if (!Parse_VectorConstant(parseState
, values
))
1055 paramIndex
= _mesa_add_unnamed_constant(parseState
->parameters
, values
);
1056 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1057 srcReg
->Index
= paramIndex
;
1060 RETURN_ERROR2("Invalid source register name", token
);
1063 /* init swizzle fields */
1064 srcReg
->Swizzle
= SWIZZLE_NOOP
;
1066 /* Look for optional swizzle suffix */
1067 if (Parse_String(parseState
, ".")) {
1070 if (!Parse_Token(parseState
, token
))
1073 if (!Parse_SwizzleSuffix(token
, swz
))
1074 RETURN_ERROR1("Invalid swizzle suffix");
1076 srcReg
->Swizzle
= MAKE_SWIZZLE(swz
);
1079 /* Finish absolute value */
1080 if (srcReg
->Abs
&& !Parse_String(parseState
, "|")) {
1081 RETURN_ERROR1("Expected |");
1089 Parse_ScalarSrcReg(struct parse_state
*parseState
,
1090 struct fp_src_register
*srcReg
)
1093 GLfloat sign
= 1.0F
;
1094 GLboolean needSuffix
= GL_TRUE
;
1098 * First, take care of +/- and absolute value stuff.
1100 if (Parse_String(parseState
, "-"))
1102 else if (Parse_String(parseState
, "+"))
1105 if (Parse_String(parseState
, "|")) {
1106 srcReg
->Abs
= GL_TRUE
;
1107 srcReg
->NegateAbs
= (sign
< 0.0F
) ? GL_TRUE
: GL_FALSE
;
1109 if (Parse_String(parseState
, "-"))
1110 srcReg
->NegateBase
= 0xf;
1111 else if (Parse_String(parseState
, "+"))
1112 srcReg
->NegateBase
= 0x0;
1114 srcReg
->NegateBase
= 0x0;
1117 srcReg
->Abs
= GL_FALSE
;
1118 srcReg
->NegateAbs
= GL_FALSE
;
1119 srcReg
->NegateBase
= (sign
< 0.0F
) ? 0xf : 0x0;
1122 if (!Peek_Token(parseState
, token
))
1125 /* Src reg can be R<n>, H<n> or a named fragment attrib */
1126 if (token
[0] == 'R' || token
[0] == 'H') {
1127 srcReg
->File
= PROGRAM_TEMPORARY
;
1128 if (!Parse_TempReg(parseState
, &idx
))
1130 srcReg
->Index
= idx
;
1132 else if (token
[0] == 'f') {
1133 srcReg
->File
= PROGRAM_INPUT
;
1134 if (!Parse_FragReg(parseState
, &idx
))
1136 srcReg
->Index
= idx
;
1138 else if (token
[0] == '{') {
1139 /* vector literal */
1142 (void) Parse_String(parseState
, "{");
1143 if (!Parse_VectorConstant(parseState
, values
))
1145 paramIndex
= _mesa_add_unnamed_constant(parseState
->parameters
, values
);
1146 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1147 srcReg
->Index
= paramIndex
;
1149 else if (IsDigit(token
[0])) {
1150 /* scalar literal */
1153 if (!Parse_ScalarConstant(parseState
, values
))
1155 paramIndex
= _mesa_add_unnamed_constant(parseState
->parameters
, values
);
1156 srcReg
->Index
= paramIndex
;
1157 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1158 needSuffix
= GL_FALSE
;
1161 RETURN_ERROR2("Invalid scalar source argument", token
);
1164 srcReg
->Swizzle
= 0;
1166 /* parse .[xyzw] suffix */
1167 if (!Parse_String(parseState
, "."))
1168 RETURN_ERROR1("Expected .");
1170 if (!Parse_Token(parseState
, token
))
1173 if (token
[0] == 'x' && token
[1] == 0) {
1174 srcReg
->Swizzle
= 0;
1176 else if (token
[0] == 'y' && token
[1] == 0) {
1177 srcReg
->Swizzle
= 1;
1179 else if (token
[0] == 'z' && token
[1] == 0) {
1180 srcReg
->Swizzle
= 2;
1182 else if (token
[0] == 'w' && token
[1] == 0) {
1183 srcReg
->Swizzle
= 3;
1186 RETURN_ERROR1("Invalid scalar source suffix");
1190 /* Finish absolute value */
1191 if (srcReg
->Abs
&& !Parse_String(parseState
, "|")) {
1192 RETURN_ERROR1("Expected |");
1200 Parse_PrintInstruction(struct parse_state
*parseState
,
1201 struct fp_instruction
*inst
)
1208 /* The first argument is a literal string 'just like this' */
1209 if (!Parse_String(parseState
, "'"))
1210 RETURN_ERROR1("Expected '");
1212 str
= parseState
->pos
;
1213 for (len
= 0; str
[len
] != '\''; len
++) /* find closing quote */
1215 parseState
->pos
+= len
+ 1;
1216 msg
= _mesa_malloc(len
+ 1);
1218 _mesa_memcpy(msg
, str
, len
);
1222 if (Parse_String(parseState
, ",")) {
1223 /* got an optional register to print */
1225 GetToken(parseState
, token
);
1226 if (token
[0] == 'o') {
1228 if (!Parse_OutputReg(parseState
, &idx
))
1230 inst
->SrcReg
[0].Index
= idx
;
1231 inst
->SrcReg
[0].File
= PROGRAM_OUTPUT
;
1235 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1240 inst
->SrcReg
[0].File
= PROGRAM_UNDEFINED
;
1243 inst
->SrcReg
[0].Swizzle
= SWIZZLE_NOOP
;
1244 inst
->SrcReg
[0].NegateBase
= 0x0;
1245 inst
->SrcReg
[0].Abs
= GL_FALSE
;
1246 inst
->SrcReg
[0].NegateAbs
= GL_FALSE
;
1253 Parse_InstructionSequence(struct parse_state
*parseState
,
1254 struct fp_instruction program
[])
1257 struct fp_instruction
*inst
= program
+ parseState
->numInst
;
1258 struct instruction_pattern instMatch
;
1261 /* Initialize the instruction */
1262 _mesa_init_fp_instruction(inst
);
1264 /* special instructions */
1265 if (Parse_String(parseState
, "DEFINE")) {
1267 GLfloat value
[7]; /* yes, 7 to be safe */
1268 if (!Parse_Identifier(parseState
, id
))
1270 /* XXX make sure id is not a reserved identifer, like R9 */
1271 if (!Parse_String(parseState
, "="))
1272 RETURN_ERROR1("Expected =");
1273 if (!Parse_VectorOrScalarConstant(parseState
, value
))
1275 if (!Parse_String(parseState
, ";"))
1276 RETURN_ERROR1("Expected ;");
1277 if (_mesa_lookup_parameter_index(parseState
->parameters
,
1278 -1, (const char *) id
) >= 0) {
1279 RETURN_ERROR2(id
, "already defined");
1281 _mesa_add_named_parameter(parseState
->parameters
,
1282 (const char *) id
, value
);
1284 else if (Parse_String(parseState
, "DECLARE")) {
1286 GLfloat value
[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */
1287 if (!Parse_Identifier(parseState
, id
))
1289 /* XXX make sure id is not a reserved identifer, like R9 */
1290 if (Parse_String(parseState
, "=")) {
1291 if (!Parse_VectorOrScalarConstant(parseState
, value
))
1294 if (!Parse_String(parseState
, ";"))
1295 RETURN_ERROR1("Expected ;");
1296 if (_mesa_lookup_parameter_index(parseState
->parameters
,
1297 -1, (const char *) id
) >= 0) {
1298 RETURN_ERROR2(id
, "already declared");
1300 _mesa_add_named_parameter(parseState
->parameters
,
1301 (const char *) id
, value
);
1303 else if (Parse_String(parseState
, "END")) {
1304 inst
->Opcode
= FP_OPCODE_END
;
1305 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
1306 assert(inst
->StringPos
>= 0);
1307 parseState
->numInst
++;
1308 if (Parse_Token(parseState
, token
)) {
1309 RETURN_ERROR1("Code after END opcode.");
1314 /* general/arithmetic instruction */
1317 if (!Parse_Token(parseState
, token
)) {
1318 RETURN_ERROR1("Missing END instruction.");
1321 /* try to find matching instuction */
1322 instMatch
= MatchInstruction(token
);
1323 if (instMatch
.opcode
< 0) {
1324 /* bad instruction name */
1325 RETURN_ERROR2("Unexpected token: ", token
);
1328 inst
->Opcode
= instMatch
.opcode
;
1329 inst
->Precision
= instMatch
.suffixes
& (_R
| _H
| _X
);
1330 inst
->Saturate
= (instMatch
.suffixes
& (_S
)) ? GL_TRUE
: GL_FALSE
;
1331 inst
->UpdateCondRegister
= (instMatch
.suffixes
& (_C
)) ? GL_TRUE
: GL_FALSE
;
1332 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
1333 assert(inst
->StringPos
>= 0);
1336 * parse the input and output operands
1338 if (instMatch
.outputs
== OUTPUT_S
|| instMatch
.outputs
== OUTPUT_V
) {
1339 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
1341 if (!Parse_String(parseState
, ","))
1342 RETURN_ERROR1("Expected ,");
1344 else if (instMatch
.outputs
== OUTPUT_NONE
) {
1345 if (instMatch
.opcode
== FP_OPCODE_KIL_NV
) {
1346 /* This is a little weird, the cond code info is in
1347 * the dest register.
1349 if (!Parse_CondCodeMask(parseState
, &inst
->DstReg
))
1353 ASSERT(instMatch
.opcode
== FP_OPCODE_PRINT
);
1357 if (instMatch
.inputs
== INPUT_1V
) {
1358 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1361 else if (instMatch
.inputs
== INPUT_2V
) {
1362 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1364 if (!Parse_String(parseState
, ","))
1365 RETURN_ERROR1("Expected ,");
1366 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[1]))
1369 else if (instMatch
.inputs
== INPUT_3V
) {
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]))
1376 if (!Parse_String(parseState
, ","))
1377 RETURN_ERROR1("Expected ,");
1378 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[2]))
1381 else if (instMatch
.inputs
== INPUT_1S
) {
1382 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
1385 else if (instMatch
.inputs
== INPUT_2S
) {
1386 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
1388 if (!Parse_String(parseState
, ","))
1389 RETURN_ERROR1("Expected ,");
1390 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[1]))
1393 else if (instMatch
.inputs
== INPUT_CC
) {
1396 else if (instMatch
.inputs
== INPUT_1V_T
) {
1398 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1400 if (!Parse_String(parseState
, ","))
1401 RETURN_ERROR1("Expected ,");
1402 if (!Parse_TextureImageId(parseState
, &unit
, &idx
))
1404 inst
->TexSrcUnit
= unit
;
1405 inst
->TexSrcIdx
= idx
;
1407 else if (instMatch
.inputs
== INPUT_3V_T
) {
1409 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1411 if (!Parse_String(parseState
, ","))
1412 RETURN_ERROR1("Expected ,");
1413 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[1]))
1415 if (!Parse_String(parseState
, ","))
1416 RETURN_ERROR1("Expected ,");
1417 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[2]))
1419 if (!Parse_String(parseState
, ","))
1420 RETURN_ERROR1("Expected ,");
1421 if (!Parse_TextureImageId(parseState
, &unit
, &idx
))
1423 inst
->TexSrcUnit
= unit
;
1424 inst
->TexSrcIdx
= idx
;
1426 else if (instMatch
.inputs
== INPUT_1V_S
) {
1427 if (!Parse_PrintInstruction(parseState
, inst
))
1431 /* end of statement semicolon */
1432 if (!Parse_String(parseState
, ";"))
1433 RETURN_ERROR1("Expected ;");
1435 parseState
->numInst
++;
1437 if (parseState
->numInst
>= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
)
1438 RETURN_ERROR1("Program too long");
1447 * Parse/compile the 'str' returning the compiled 'program'.
1448 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1449 * indicates the position of the error in 'str'.
1452 _mesa_parse_nv_fragment_program(GLcontext
*ctx
, GLenum dstTarget
,
1453 const GLubyte
*str
, GLsizei len
,
1454 struct fragment_program
*program
)
1456 struct parse_state parseState
;
1457 struct fp_instruction instBuffer
[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
];
1458 struct fp_instruction
*newInst
;
1460 GLubyte
*programString
;
1462 /* Make a null-terminated copy of the program string */
1463 programString
= (GLubyte
*) MALLOC(len
+ 1);
1464 if (!programString
) {
1465 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1468 MEMCPY(programString
, str
, len
);
1469 programString
[len
] = 0;
1471 /* Get ready to parse */
1472 _mesa_bzero(&parseState
, sizeof(struct parse_state
));
1473 parseState
.ctx
= ctx
;
1474 parseState
.start
= programString
;
1475 parseState
.program
= program
;
1476 parseState
.numInst
= 0;
1477 parseState
.curLine
= programString
;
1478 parseState
.parameters
= _mesa_new_parameter_list();
1480 /* Reset error state */
1481 _mesa_set_program_error(ctx
, -1, NULL
);
1483 /* check the program header */
1484 if (_mesa_strncmp((const char *) programString
, "!!FP1.0", 7) == 0) {
1485 target
= GL_FRAGMENT_PROGRAM_NV
;
1486 parseState
.pos
= programString
+ 7;
1488 else if (_mesa_strncmp((const char *) programString
, "!!FCP1.0", 8) == 0) {
1489 /* fragment / register combiner program - not supported */
1490 _mesa_set_program_error(ctx
, 0, "Invalid fragment program header");
1491 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1495 /* invalid header */
1496 _mesa_set_program_error(ctx
, 0, "Invalid fragment program header");
1497 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1501 /* make sure target and header match */
1502 if (target
!= dstTarget
) {
1503 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1504 "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1509 if (Parse_InstructionSequence(&parseState
, instBuffer
)) {
1511 /* successful parse! */
1513 if (parseState
.outputsWritten
== 0) {
1514 /* must write at least one output! */
1515 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1516 "Invalid fragment program - no outputs written.");
1520 /* copy the compiled instructions */
1521 assert(parseState
.numInst
<= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
);
1522 newInst
= (struct fp_instruction
*)
1523 MALLOC(parseState
.numInst
* sizeof(struct fp_instruction
));
1525 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1526 return; /* out of memory */
1528 MEMCPY(newInst
, instBuffer
,
1529 parseState
.numInst
* sizeof(struct fp_instruction
));
1531 /* install the program */
1532 program
->Base
.Target
= target
;
1533 if (program
->Base
.String
) {
1534 FREE(program
->Base
.String
);
1536 program
->Base
.String
= programString
;
1537 program
->Base
.Format
= GL_PROGRAM_FORMAT_ASCII_ARB
;
1538 if (program
->Instructions
) {
1539 FREE(program
->Instructions
);
1541 program
->Instructions
= newInst
;
1542 program
->InputsRead
= parseState
.inputsRead
;
1543 program
->OutputsWritten
= parseState
.outputsWritten
;
1544 for (u
= 0; u
< ctx
->Const
.MaxTextureImageUnits
; u
++)
1545 program
->TexturesUsed
[u
] = parseState
.texturesUsed
[u
];
1547 /* save program parameters */
1548 program
->Parameters
= parseState
.parameters
;
1550 /* allocate registers for declared program parameters */
1552 _mesa_assign_program_registers(&(program
->SymbolTable
));
1556 _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program
->Base
.Id
);
1557 _mesa_print_nv_fragment_program(program
);
1558 _mesa_printf("----------------------------------\n");
1563 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1564 /* NOTE: _mesa_set_program_error would have been called already */
1570 PrintSrcReg(const struct fragment_program
*program
,
1571 const struct fp_src_register
*src
)
1573 static const char comps
[5] = "xyzw";
1575 if (src
->NegateAbs
) {
1581 if (src
->NegateBase
) {
1584 if (src
->File
== PROGRAM_NAMED_PARAM
) {
1585 if (program
->Parameters
->Parameters
[src
->Index
].Type
== CONSTANT
) {
1586 _mesa_printf("{%g, %g, %g, %g}",
1587 program
->Parameters
->ParameterValues
[src
->Index
][0],
1588 program
->Parameters
->ParameterValues
[src
->Index
][1],
1589 program
->Parameters
->ParameterValues
[src
->Index
][2],
1590 program
->Parameters
->ParameterValues
[src
->Index
][3]);
1593 ASSERT(program
->Parameters
->Parameters
[src
->Index
].Type
1594 == NAMED_PARAMETER
);
1595 _mesa_printf("%s", program
->Parameters
->Parameters
[src
->Index
].Name
);
1598 else if (src
->File
== PROGRAM_OUTPUT
) {
1599 _mesa_printf("o[%s]", OutputRegisters
[src
->Index
]);
1601 else if (src
->File
== PROGRAM_INPUT
) {
1602 _mesa_printf("f[%s]", InputRegisters
[src
->Index
]);
1604 else if (src
->File
== PROGRAM_LOCAL_PARAM
) {
1605 _mesa_printf("p[%d]", src
->Index
);
1607 else if (src
->File
== PROGRAM_TEMPORARY
) {
1608 if (src
->Index
>= 32)
1609 _mesa_printf("H%d", src
->Index
);
1611 _mesa_printf("R%d", src
->Index
);
1613 else if (src
->File
== PROGRAM_WRITE_ONLY
) {
1614 _mesa_printf("%cC", "HR"[src
->Index
]);
1617 _mesa_problem(NULL
, "Invalid fragment register %d", src
->Index
);
1620 if (GET_SWZ(src
->Swizzle
, 0) == GET_SWZ(src
->Swizzle
, 1) &&
1621 GET_SWZ(src
->Swizzle
, 0) == GET_SWZ(src
->Swizzle
, 2) &&
1622 GET_SWZ(src
->Swizzle
, 0) == GET_SWZ(src
->Swizzle
, 3)) {
1623 _mesa_printf(".%c", comps
[GET_SWZ(src
->Swizzle
, 0)]);
1625 else if (src
->Swizzle
!= SWIZZLE_NOOP
) {
1626 _mesa_printf(".%c%c%c%c",
1627 comps
[GET_SWZ(src
->Swizzle
, 0)],
1628 comps
[GET_SWZ(src
->Swizzle
, 1)],
1629 comps
[GET_SWZ(src
->Swizzle
, 2)],
1630 comps
[GET_SWZ(src
->Swizzle
, 3)]);
1638 PrintTextureSrc(const struct fp_instruction
*inst
)
1640 _mesa_printf("TEX%d, ", inst
->TexSrcUnit
);
1641 switch (inst
->TexSrcIdx
) {
1642 case TEXTURE_1D_INDEX
:
1645 case TEXTURE_2D_INDEX
:
1648 case TEXTURE_3D_INDEX
:
1651 case TEXTURE_RECT_INDEX
:
1652 _mesa_printf("RECT");
1654 case TEXTURE_CUBE_INDEX
:
1655 _mesa_printf("CUBE");
1658 _mesa_problem(NULL
, "Invalid textue target in PrintTextureSrc");
1663 PrintCondCode(const struct fp_dst_register
*dst
)
1665 static const char *comps
= "xyzw";
1666 static const char *ccString
[] = {
1667 "??", "GT", "EQ", "LT", "UN", "GE", "LE", "NE", "TR", "FL", "??"
1670 _mesa_printf("%s", ccString
[dst
->CondMask
]);
1671 if (GET_SWZ(dst
->CondSwizzle
, 0) == GET_SWZ(dst
->CondSwizzle
, 1) &&
1672 GET_SWZ(dst
->CondSwizzle
, 0) == GET_SWZ(dst
->CondSwizzle
, 2) &&
1673 GET_SWZ(dst
->CondSwizzle
, 0) == GET_SWZ(dst
->CondSwizzle
, 3)) {
1674 _mesa_printf(".%c", comps
[GET_SWZ(dst
->CondSwizzle
, 0)]);
1676 else if (dst
->CondSwizzle
!= SWIZZLE_NOOP
) {
1677 _mesa_printf(".%c%c%c%c",
1678 comps
[GET_SWZ(dst
->CondSwizzle
, 0)],
1679 comps
[GET_SWZ(dst
->CondSwizzle
, 1)],
1680 comps
[GET_SWZ(dst
->CondSwizzle
, 2)],
1681 comps
[GET_SWZ(dst
->CondSwizzle
, 3)]);
1687 PrintDstReg(const struct fp_dst_register
*dst
)
1689 if (dst
->File
== PROGRAM_OUTPUT
) {
1690 _mesa_printf("o[%s]", OutputRegisters
[dst
->Index
]);
1692 else if (dst
->File
== PROGRAM_TEMPORARY
) {
1693 if (dst
->Index
>= 32)
1694 _mesa_printf("H%d", dst
->Index
);
1696 _mesa_printf("R%d", dst
->Index
);
1698 else if (dst
->File
== PROGRAM_LOCAL_PARAM
) {
1699 _mesa_printf("p[%d]", dst
->Index
);
1701 else if (dst
->File
== PROGRAM_WRITE_ONLY
) {
1702 _mesa_printf("%cC", "HR"[dst
->Index
]);
1705 _mesa_printf("???");
1708 if (dst
->WriteMask
!= 0 && dst
->WriteMask
!= 0xf) {
1710 if (dst
->WriteMask
& 0x1)
1712 if (dst
->WriteMask
& 0x2)
1714 if (dst
->WriteMask
& 0x4)
1716 if (dst
->WriteMask
& 0x8)
1720 if (dst
->CondMask
!= COND_TR
||
1721 dst
->CondSwizzle
!= SWIZZLE_NOOP
) {
1730 * Print (unparse) the given vertex program. Just for debugging.
1733 _mesa_print_nv_fragment_program(const struct fragment_program
*program
)
1735 const struct fp_instruction
*inst
;
1737 for (inst
= program
->Instructions
; inst
->Opcode
!= FP_OPCODE_END
; inst
++) {
1739 for (i
= 0; Instructions
[i
].name
; i
++) {
1740 if (inst
->Opcode
== Instructions
[i
].opcode
) {
1741 /* print instruction name */
1742 _mesa_printf("%s", Instructions
[i
].name
);
1743 if (inst
->Precision
== FLOAT16
)
1745 else if (inst
->Precision
== FIXED12
)
1747 if (inst
->UpdateCondRegister
)
1750 _mesa_printf("_SAT");
1753 if (Instructions
[i
].inputs
== INPUT_CC
) {
1754 PrintCondCode(&inst
->DstReg
);
1756 else if (Instructions
[i
].outputs
== OUTPUT_V
||
1757 Instructions
[i
].outputs
== OUTPUT_S
) {
1758 /* print dest register */
1759 PrintDstReg(&inst
->DstReg
);
1763 /* print source register(s) */
1764 if (Instructions
[i
].inputs
== INPUT_1V
||
1765 Instructions
[i
].inputs
== INPUT_1S
) {
1766 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1768 else if (Instructions
[i
].inputs
== INPUT_2V
||
1769 Instructions
[i
].inputs
== INPUT_2S
) {
1770 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1772 PrintSrcReg(program
, &inst
->SrcReg
[1]);
1774 else if (Instructions
[i
].inputs
== INPUT_3V
) {
1775 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1777 PrintSrcReg(program
, &inst
->SrcReg
[1]);
1779 PrintSrcReg(program
, &inst
->SrcReg
[2]);
1781 else if (Instructions
[i
].inputs
== INPUT_1V_T
) {
1782 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1784 PrintTextureSrc(inst
);
1786 else if (Instructions
[i
].inputs
== INPUT_3V_T
) {
1787 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1789 PrintSrcReg(program
, &inst
->SrcReg
[1]);
1791 PrintSrcReg(program
, &inst
->SrcReg
[2]);
1793 PrintTextureSrc(inst
);
1795 _mesa_printf(";\n");
1799 if (!Instructions
[i
].name
) {
1800 _mesa_printf("Invalid opcode %d\n", inst
->Opcode
);
1803 _mesa_printf("END\n");
1808 _mesa_nv_fragment_input_register_name(GLuint i
)
1810 ASSERT(i
< MAX_NV_FRAGMENT_PROGRAM_INPUTS
);
1811 return InputRegisters
[i
];
1816 _mesa_nv_fragment_output_register_name(GLuint i
)
1818 ASSERT(i
< MAX_NV_FRAGMENT_PROGRAM_OUTPUTS
);
1819 return OutputRegisters
[i
];
1824 * Initialize fragment program instruction fields to defaults.
1827 _mesa_init_fp_instruction(struct fp_instruction
*inst
)
1829 _mesa_bzero(inst
, sizeof(struct fp_instruction
));
1830 inst
->SrcReg
[0].File
= PROGRAM_UNDEFINED
;
1831 inst
->SrcReg
[0].Swizzle
= SWIZZLE_NOOP
;
1832 inst
->SrcReg
[1].File
= PROGRAM_UNDEFINED
;
1833 inst
->SrcReg
[1].Swizzle
= SWIZZLE_NOOP
;
1834 inst
->SrcReg
[2].File
= PROGRAM_UNDEFINED
;
1835 inst
->SrcReg
[2].Swizzle
= SWIZZLE_NOOP
;
1836 inst
->DstReg
.File
= PROGRAM_UNDEFINED
;
1837 inst
->DstReg
.WriteMask
= 0xf;
1838 inst
->DstReg
.CondSwizzle
= SWIZZLE_NOOP
;
1839 inst
->Precision
= FLOAT32
;
1840 inst
->DstReg
.CondMask
= COND_TR
;