1 /* $Id: nvfragparse.c,v 1.2 2003/01/19 15:27:37 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 * \brief NVIDIA fragment program parser.
41 #include "nvfragprog.h"
42 #include "nvfragparse.h"
43 #include "nvprogram.h"
46 #define FRAG_ATTRIB_WPOS 0
47 #define FRAG_ATTRIB_COL0 1
48 #define FRAG_ATTRIB_COL1 2
49 #define FRAG_ATTRIB_FOGC 3
50 #define FRAG_ATTRIB_TEX0 4
51 #define FRAG_ATTRIB_TEX1 5
52 #define FRAG_ATTRIB_TEX2 6
53 #define FRAG_ATTRIB_TEX3 7
54 #define FRAG_ATTRIB_TEX4 8
55 #define FRAG_ATTRIB_TEX5 9
56 #define FRAG_ATTRIB_TEX6 10
57 #define FRAG_ATTRIB_TEX7 11
66 #define INPUT_1V_T 7 /* one source vector, plus textureId */
67 #define INPUT_3V_T 8 /* one source vector, plus textureId */
71 #define OUTPUT_NONE 22
73 /* Optional suffixes */
74 #define _R 0x01 /* real */
75 #define _H 0x02 /* half */
76 #define _X 0x04 /* fixed */
77 #define _C 0x08 /* set cond codes */
78 #define _S 0x10 /* saturate */
84 struct instruction_pattern
{
86 enum fp_opcode opcode
;
92 static const struct instruction_pattern Instructions
[] = {
93 { "ADD", FP_OPCODE_ADD
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
94 { "COS", FP_OPCODE_COS
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
95 { "DDX", FP_OPCODE_DDX
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
96 { "DDY", FP_OPCODE_DDY
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
97 { "DP3", FP_OPCODE_DP3
, INPUT_2V
, OUTPUT_S
, _R
| _H
| _X
| _C
| _S
},
98 { "DP4", FP_OPCODE_DP4
, INPUT_2V
, OUTPUT_S
, _R
| _H
| _X
| _C
| _S
},
99 { "DST", FP_OPCODE_DP4
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
100 { "EX2", FP_OPCODE_DP4
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
101 { "FLR", FP_OPCODE_FLR
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
102 { "FRC", FP_OPCODE_FRC
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
103 { "KIL", FP_OPCODE_KIL
, INPUT_CC
, OUTPUT_NONE
, 0 },
104 { "LG2", FP_OPCODE_LG2
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
105 { "LIT", FP_OPCODE_LIT
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
106 { "LRP", FP_OPCODE_LRP
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
107 { "MAD", FP_OPCODE_MAD
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
108 { "MAX", FP_OPCODE_MAX
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
109 { "MIN", FP_OPCODE_MIN
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
110 { "MOV", FP_OPCODE_MOV
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
111 { "MUL", FP_OPCODE_MUL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
112 { "PK2H", FP_OPCODE_PK2H
, INPUT_1V
, OUTPUT_S
, 0 },
113 { "PK2US", FP_OPCODE_PK2US
, INPUT_1V
, OUTPUT_S
, 0 },
114 { "PK4B", FP_OPCODE_PK4B
, INPUT_1V
, OUTPUT_S
, 0 },
115 { "PK2UB", FP_OPCODE_PK4UB
, INPUT_1V
, OUTPUT_S
, 0 },
116 { "POW", FP_OPCODE_POW
, INPUT_2S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
117 { "RCP", FP_OPCODE_RCP
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
118 { "RFL", FP_OPCODE_RFL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
119 { "RSQ", FP_OPCODE_RSQ
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
120 { "SEQ", FP_OPCODE_SEQ
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
121 { "SFL", FP_OPCODE_SFL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
122 { "SGE", FP_OPCODE_SGE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
123 { "SGT", FP_OPCODE_SGT
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
124 { "SIN", FP_OPCODE_SIN
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
125 { "SLE", FP_OPCODE_SLE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
126 { "SLT", FP_OPCODE_SLT
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
127 { "SNE", FP_OPCODE_SNE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
128 { "STR", FP_OPCODE_STR
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
129 { "SUB", FP_OPCODE_SUB
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
130 { "TEX", FP_OPCODE_SUB
, INPUT_1V_T
, OUTPUT_V
, _C
| _S
},
131 { "TXD", FP_OPCODE_SUB
, INPUT_3V_T
, OUTPUT_V
, _C
| _S
},
132 { "TXP", FP_OPCODE_SUB
, INPUT_1V_T
, OUTPUT_V
, _C
| _S
},
133 { "UP2H", FP_OPCODE_UP2H
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
134 { "UP2US", FP_OPCODE_UP2US
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
135 { "UP4B", FP_OPCODE_UP4B
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
136 { "UP4UB", FP_OPCODE_UP4UB
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
137 { "X2D", FP_OPCODE_X2D
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
138 { NULL
, -1, 0, 0, 0 }
142 /**********************************************************************/
146 const GLubyte
*start
; /* start of program */
147 const GLubyte
*end
; /* one char past end of the program */
148 const GLubyte
*s
; /* current position */
149 GLboolean IsStateProgram
;
150 GLboolean IsVersion1_1
;
156 * Search a list of instruction structures for a match.
158 static struct instruction_pattern
159 MatchInstruction(const char *token
)
161 const struct instruction_pattern
*inst
;
162 struct instruction_pattern result
;
164 for (inst
= Instructions
; inst
->name
; inst
++) {
165 if (_mesa_strncmp(token
, inst
->name
, 3) == 0) {
171 if (token
[i
] == 'R') {
172 result
.suffixes
|= _R
;
175 else if (token
[i
] == 'H') {
176 result
.suffixes
|= _H
;
179 else if (token
[i
] == 'X') {
180 result
.suffixes
|= _X
;
183 if (token
[i
] == 'C') {
184 result
.suffixes
|= _C
;
187 if (token
[i
] == '_' && token
[i
+1] == 'S' &&
188 token
[i
+2] == 'A' && token
[i
+3] == 'T') {
189 result
.suffixes
|= _S
;
194 result
.opcode
= (enum fp_opcode
) -1;
201 /**********************************************************************/
204 static GLboolean
IsLetter(char b
)
206 return (b
>= 'a' && b
<= 'z') || (b
>= 'A' && b
<= 'Z') || (b
== '_');
210 static GLboolean
IsDigit(char b
)
212 return b
>= '0' && b
<= '9';
216 static GLboolean
IsWhitespace(char b
)
218 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
223 * Starting at 'str' find the next token. A token can be an integer,
224 * an identifier or punctuation symbol.
225 * \return <= 0 we found an error, else, return number of characters parsed.
228 GetToken(const char *str
, char *token
)
234 /* skip whitespace and comments */
235 while (str
[i
] && (IsWhitespace(str
[i
]) || str
[i
] == '#')) {
238 while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
243 /* skip whitespace */
251 /* try matching an integer */
252 while (str
[i
] && IsDigit(str
[i
])) {
253 token
[j
++] = str
[i
++];
255 if (j
> 0 || !str
[i
]) {
260 /* try matching an identifier */
261 if (IsLetter(str
[i
])) {
262 while (str
[i
] && (IsLetter(str
[i
]) || IsDigit(str
[i
]))) {
263 token
[j
++] = str
[i
++];
283 * Get next token from input stream and increment stream pointer past token.
286 Parse_Token(const char **s
, char *token
)
289 i
= GetToken(*s
, token
);
300 * Get next token from input stream but don't increment stream pointer.
303 Peek_Token(const char **s
, char *token
)
306 i
= GetToken(*s
, token
);
311 len
= _mesa_strlen(token
);
318 * String equality test
321 StrEq(const char *a
, const char *b
)
324 for (i
= 0; a
[i
] && b
[i
] && a
[i
] == (char) b
[i
]; i
++)
326 if (a
[i
] == 0 && b
[i
] == 0)
334 /**********************************************************************/
336 static const char *InputRegisters
[] = {
337 "WPOS", "COL0", "COL1", "FOGC",
338 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
341 static const char *OutputRegisters
[] = {
342 "COLR", "COLH", "TEX0", "TEX1", "TEX2", "TEX3", "DEPR", NULL
348 #define PARSE_ERROR \
350 _mesa_printf("fpparse.c error at %d: parse error\n", __LINE__); \
354 #define PARSE_ERROR1(msg) \
356 _mesa_printf("fpparse.c error at %d: %s\n", __LINE__, msg); \
360 #define PARSE_ERROR2(msg1, msg2) \
362 _mesa_printf("fpparse.c error at %d: %s %s\n", __LINE__, msg1, msg2);\
368 #define PARSE_ERROR return GL_FALSE
369 #define PARSE_ERROR1(msg1) return GL_FALSE
370 #define PARSE_ERROR2(msg1, msg2) return GL_FALSE
376 TempRegisterNumber(GLuint r
)
378 if (r
>= FP_TEMP_REG_START
&& r
<= FP_TEMP_REG_END
)
379 return r
- FP_TEMP_REG_START
;
385 HalfTempRegisterNumber(GLuint r
)
387 if (r
>= FP_TEMP_REG_START
+ 32 && r
<= FP_TEMP_REG_END
)
388 return r
- FP_TEMP_REG_START
- 32;
394 InputRegisterNumber(GLuint r
)
396 if (r
>= FP_INPUT_REG_START
&& r
<= FP_INPUT_REG_END
)
397 return r
- FP_INPUT_REG_START
;
403 OutputRegisterNumber(GLuint r
)
405 if (r
>= FP_OUTPUT_REG_START
&& r
<= FP_OUTPUT_REG_END
)
406 return r
- FP_OUTPUT_REG_START
;
412 ProgramRegisterNumber(GLuint r
)
414 if (r
>= FP_PROG_REG_START
&& r
<= FP_PROG_REG_END
)
415 return r
- FP_PROG_REG_START
;
421 DummyRegisterNumber(GLuint r
)
423 if (r
>= FP_DUMMY_REG_START
&& r
<= FP_DUMMY_REG_END
)
424 return r
- FP_DUMMY_REG_START
;
431 /**********************************************************************/
435 * Try to match 'pattern' as the next token after any whitespace/comments.
438 Parse_String(const char **s
, const char *pattern
)
442 /* skip whitespace and comments */
443 while (IsWhitespace(**s
) || **s
== '#') {
445 while (**s
&& (**s
!= '\n' && **s
!= '\r')) {
450 /* skip whitespace */
455 /* Try to match the pattern */
456 for (i
= 0; pattern
[i
]; i
++) {
457 if (**s
!= pattern
[i
])
458 PARSE_ERROR2("failed to match", pattern
); /* failure */
462 return GL_TRUE
; /* success */
467 Parse_Identifier(const char **s
, char *ident
)
469 if (!Parse_Token(s
, ident
))
471 if (IsLetter(ident
[0]))
474 PARSE_ERROR1("Expected an identfier");
479 * Parse a floating point constant.
483 Parse_ScalarConstant(const char **s
, GLfloat
*number
)
487 *number
= _mesa_strtof(*s
, &end
);
489 if (end
&& end
> *s
) {
495 /* should be an identifier */
497 if (!Parse_Identifier(s
, ident
))
498 PARSE_ERROR1("Expected an identifier");
499 /* XXX Look up the value in the symbol table */
508 * Parse a vector constant, one of:
511 * { float, float, float }
512 * { float, float, float, float }
515 Parse_VectorConstant(const char **s
, GLfloat
*vec
)
519 if (!Parse_String(s
, "{"))
522 if (!Parse_ScalarConstant(s
, vec
+0)) /* X */
525 if (!Parse_Token(s
, token
)) /* , or } */
528 if (token
[0] == '}') {
529 vec
[1] = vec
[2] = vec
[3] = vec
[0];
534 PARSE_ERROR1("Expected comma in vector constant");
536 if (!Parse_ScalarConstant(s
, vec
+1)) /* Y */
539 if (!Parse_Token(s
, token
)) /* , or } */
542 if (token
[0] == '}') {
543 vec
[2] = vec
[3] = vec
[1];
548 PARSE_ERROR1("Expected comma in vector constant");
550 if (!Parse_ScalarConstant(s
, vec
+2)) /* Z */
553 if (!Parse_Token(s
, token
)) /* , or } */
556 if (token
[0] == '}') {
562 PARSE_ERROR1("Expected comma in vector constant");
564 if (!Parse_ScalarConstant(s
, vec
+3)) /* W */
567 if (!Parse_String(s
, "}"))
568 PARSE_ERROR1("Expected closing brace in vector constant");
575 Parse_VectorOrScalarConstant(const char **s
, GLfloat
*vec
)
578 if (!Peek_Token(s
, token
))
580 if (token
[0] == '{') {
581 return Parse_VectorConstant(s
, vec
);
584 GLboolean b
= Parse_ScalarConstant(s
, vec
);
586 vec
[1] = vec
[2] = vec
[3] = vec
[0];
594 * Parse a texture image source:
595 * [TEX0 | TEX1 | .. | TEX15]
596 * [TEX0 | TEX1 | .. | TEX15] . [1D | 2D | 3D | CUBE | RECT]
599 Parse_TextureImageId(const char **s
, GLuint
*unit
, GLenum
*target
)
606 * Parse a swizzle suffix like .x or .z or .wxyz or .xxyy etc and return
607 * the swizzle indexes.
610 Parse_SwizzleSuffix(const char *token
, GLuint swizzle
[4])
613 /* single letter swizzle (scalar) */
615 ASSIGN_4V(swizzle
, 0, 0, 0, 0);
616 else if (token
[0] == 'y')
617 ASSIGN_4V(swizzle
, 1, 1, 1, 1);
618 else if (token
[0] == 'z')
619 ASSIGN_4V(swizzle
, 2, 2, 2, 2);
620 else if (token
[0] == 'w')
621 ASSIGN_4V(swizzle
, 3, 3, 3, 3);
626 /* 4-component swizzle (vector) */
628 for (k
= 0; token
[k
] && k
< 4; k
++) {
631 else if (token
[k
] == 'y')
633 else if (token
[k
] == 'z')
635 else if (token
[k
] == 'w')
648 Parse_CondCodeMask(const char **s
, struct fp_dst_register
*dstReg
)
652 if (!Parse_Token(s
, token
))
655 if (StrEq(token
, "EQ"))
656 dstReg
->CondMask
= COND_EQ
;
657 else if (StrEq(token
, "GE"))
658 dstReg
->CondMask
= COND_GE
;
659 else if (StrEq(token
, "GT"))
660 dstReg
->CondMask
= COND_GT
;
661 else if (StrEq(token
, "LE"))
662 dstReg
->CondMask
= COND_LE
;
663 else if (StrEq(token
, "LT"))
664 dstReg
->CondMask
= COND_LT
;
665 else if (StrEq(token
, "NE"))
666 dstReg
->CondMask
= COND_NE
;
667 else if (StrEq(token
, "TR"))
668 dstReg
->CondMask
= COND_TR
;
669 else if (StrEq(token
, "FL"))
670 dstReg
->CondMask
= COND_FL
;
672 PARSE_ERROR1("Invalid condition code mask");
674 /* look for optional .xyzw swizzle */
675 if (!Peek_Token(s
, token
))
678 if (token
[0] == '.') {
679 Parse_String(s
, "."); /* consume '.' */
680 if (!Parse_Token(s
, token
)) /* get xyzw suffix */
683 if (!Parse_SwizzleSuffix(token
, dstReg
->CondSwizzle
))
684 PARSE_ERROR1("Bad swizzle suffix");
692 * Parse a temporary register: Rnn or Hnn
695 Parse_TempReg(const char **s
, GLint
*tempRegNum
)
699 /* Should be 'R##' or 'H##' */
700 if (!Parse_Token(s
, token
))
702 if (token
[0] != 'R' && token
[0] != 'H')
703 PARSE_ERROR1("Expected R## or H##");
705 if (IsDigit(token
[1])) {
706 GLint reg
= _mesa_atoi((token
+ 1));
709 if (reg
>= MAX_NV_FRAGMENT_PROGRAM_TEMPS
)
710 PARSE_ERROR1("Bad temporary register name");
711 *tempRegNum
= FP_TEMP_REG_START
+ reg
;
714 PARSE_ERROR1("Bad temporary register name");
722 Parse_DummyReg(const char **s
, GLint
*regNum
)
726 /* Should be 'RC' or 'HC' */
727 if (!Parse_Token(s
, token
))
730 if (_mesa_strcmp(token
, "RC")) {
731 *regNum
= FP_DUMMY_REG_START
;
733 else if (_mesa_strcmp(token
, "HC")) {
734 *regNum
= FP_DUMMY_REG_START
+ 1;
737 PARSE_ERROR1("Bad write-only register name");
745 * Parse a program local parameter register "p[##]"
748 Parse_ProgramParamReg(const char **s
, GLint
*regNum
)
752 if (!Parse_String(s
, "p"))
755 if (!Parse_String(s
, "["))
758 if (!Parse_Token(s
, token
))
761 if (IsDigit(token
[0])) {
762 /* a numbered program parameter register */
763 GLint reg
= _mesa_atoi(token
);
764 if (reg
>= MAX_NV_FRAGMENT_PROGRAM_PARAMS
)
765 PARSE_ERROR1("Bad constant program number");
766 *regNum
= FP_PROG_REG_START
+ reg
;
772 if (!Parse_String(s
, "]"))
780 * Parse f[name] - fragment input register
783 Parse_AttribReg(const char **s
, GLint
*tempRegNum
)
789 if (!Parse_String(s
, "f"))
793 if (!Parse_String(s
, "["))
796 /* get <name> and look for match */
797 if (!Parse_Token(s
, token
)) {
800 for (j
= 0; InputRegisters
[j
]; j
++) {
801 if (StrEq(token
, InputRegisters
[j
])) {
802 *tempRegNum
= FP_INPUT_REG_START
+ j
;
806 if (!InputRegisters
[j
]) {
807 /* unknown input register label */
808 PARSE_ERROR2("Bad register name", token
);
812 if (!Parse_String(s
, "]"))
820 Parse_OutputReg(const char **s
, GLint
*outputRegNum
)
826 if (!Parse_String(s
, "o"))
830 if (!Parse_String(s
, "["))
833 /* Get output reg name */
834 if (!Parse_Token(s
, token
))
837 /* try to match an output register name */
838 for (j
= 0; OutputRegisters
[j
]; j
++) {
839 if (StrEq(token
, OutputRegisters
[j
])) {
840 *outputRegNum
= FP_OUTPUT_REG_START
+ j
;
844 if (!OutputRegisters
[j
])
845 PARSE_ERROR1("Unrecognized output register name");
848 if (!Parse_String(s
, "]"))
849 PARSE_ERROR1("Expected ]");
856 Parse_MaskedDstReg(const char **s
, struct fp_dst_register
*dstReg
)
860 /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
861 if (!Peek_Token(s
, token
))
864 if (_mesa_strcmp(token
, "RC") == 0 ||
865 _mesa_strcmp(token
, "HC") == 0) {
866 /* a write-only register */
867 if (!Parse_DummyReg(s
, &dstReg
->Register
))
870 else if (token
[0] == 'R' || token
[0] == 'H') {
871 /* a temporary register */
872 if (!Parse_TempReg(s
, &dstReg
->Register
))
875 else if (token
[0] == 'o') {
876 /* an output register */
877 if (!Parse_OutputReg(s
, &dstReg
->Register
))
881 PARSE_ERROR1("Bad destination register name");
884 /* Parse optional write mask */
885 if (!Peek_Token(s
, token
))
888 if (token
[0] == '.') {
892 if (!Parse_String(s
, "."))
895 if (!Parse_Token(s
, token
)) /* get xyzw writemask */
898 dstReg
->WriteMask
[0] = GL_FALSE
;
899 dstReg
->WriteMask
[1] = GL_FALSE
;
900 dstReg
->WriteMask
[2] = GL_FALSE
;
901 dstReg
->WriteMask
[3] = GL_FALSE
;
903 if (token
[k
] == 'x') {
904 dstReg
->WriteMask
[0] = GL_TRUE
;
907 if (token
[k
] == 'y') {
908 dstReg
->WriteMask
[1] = GL_TRUE
;
911 if (token
[k
] == 'z') {
912 dstReg
->WriteMask
[2] = GL_TRUE
;
915 if (token
[k
] == 'w') {
916 dstReg
->WriteMask
[3] = GL_TRUE
;
920 PARSE_ERROR1("Bad writemask character");
923 /* peek optional cc mask */
924 if (!Peek_Token(s
, token
))
928 dstReg
->WriteMask
[0] = GL_TRUE
;
929 dstReg
->WriteMask
[1] = GL_TRUE
;
930 dstReg
->WriteMask
[2] = GL_TRUE
;
931 dstReg
->WriteMask
[3] = GL_TRUE
;
934 /* optional condition code mask */
935 if (token
[0] == '(') {
936 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
937 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
938 Parse_String(s
, "(");
940 if (!Parse_CondCodeMask(s
, dstReg
))
943 if (!Parse_String(s
, ")")) /* consume ")" */
949 /* no cond code mask */
950 dstReg
->CondMask
= COND_TR
;
951 dstReg
->CondSwizzle
[0] = 0;
952 dstReg
->CondSwizzle
[1] = 1;
953 dstReg
->CondSwizzle
[2] = 2;
954 dstReg
->CondSwizzle
[3] = 3;
961 Parse_SwizzleSrcReg(const char **s
, struct fp_src_register
*srcReg
)
965 /* XXX need to parse absolute value and another negation ***/
966 srcReg
->NegateBase
= GL_FALSE
;
967 srcReg
->Abs
= GL_FALSE
;
968 srcReg
->NegateAbs
= GL_FALSE
;
971 if (!Peek_Token(s
, token
))
973 if (token
[0] == '-') {
974 (void) Parse_String(s
, "-");
975 srcReg
->NegateBase
= GL_TRUE
;
976 if (!Peek_Token(s
, token
))
980 srcReg
->NegateBase
= GL_FALSE
;
983 /* Src reg can be R<n>, H<n> or a named fragment attrib */
984 if (token
[0] == 'R' || token
[0] == 'H') {
985 if (!Parse_TempReg(s
, &srcReg
->Register
))
988 else if (token
[0] == 'f') {
989 if (!Parse_AttribReg(s
, &srcReg
->Register
))
992 else if (token
[0] == 'p') {
993 if (!Parse_ProgramParamReg(s
, &srcReg
->Register
))
997 /* Also parse defined/declared constant or vector literal */
998 PARSE_ERROR2("Bad source register name", token
);
1001 /* init swizzle fields */
1002 srcReg
->Swizzle
[0] = 0;
1003 srcReg
->Swizzle
[1] = 1;
1004 srcReg
->Swizzle
[2] = 2;
1005 srcReg
->Swizzle
[3] = 3;
1007 /* Look for optional swizzle suffix */
1008 if (!Peek_Token(s
, token
))
1010 if (token
[0] == '.') {
1011 (void) Parse_String(s
, "."); /* consume . */
1013 if (!Parse_Token(s
, token
))
1016 if (!Parse_SwizzleSuffix(token
, srcReg
->Swizzle
))
1017 PARSE_ERROR1("Bad swizzle suffix");
1025 Parse_ScalarSrcReg(const char **s
, struct fp_src_register
*srcReg
)
1030 if (!Peek_Token(s
, token
))
1032 if (token
[0] == '-') {
1033 srcReg
->NegateBase
= GL_TRUE
;
1034 (void) Parse_String(s
, "-"); /* consume '-' */
1035 if (!Peek_Token(s
, token
))
1039 srcReg
->NegateBase
= GL_FALSE
;
1042 /* Src reg can be R<n>, H<n> or a named fragment attrib */
1043 if (token
[0] == 'R' || token
[0] == 'H') {
1044 if (!Parse_TempReg(s
, &srcReg
->Register
))
1047 else if (token
[0] == 'f') {
1048 if (!Parse_AttribReg(s
, &srcReg
->Register
))
1052 PARSE_ERROR2("Bad source register name", token
);
1055 /* Look for .[xyzw] suffix */
1056 if (!Parse_String(s
, "."))
1059 if (!Parse_Token(s
, token
))
1062 if (token
[0] == 'x' && token
[1] == 0) {
1063 srcReg
->Swizzle
[0] = 0;
1065 else if (token
[0] == 'y' && token
[1] == 0) {
1066 srcReg
->Swizzle
[0] = 1;
1068 else if (token
[0] == 'z' && token
[1] == 0) {
1069 srcReg
->Swizzle
[0] = 2;
1071 else if (token
[0] == 'w' && token
[1] == 0) {
1072 srcReg
->Swizzle
[0] = 3;
1075 PARSE_ERROR1("Bad scalar source suffix");
1077 srcReg
->Swizzle
[1] = srcReg
->Swizzle
[2] = srcReg
->Swizzle
[3] = 0;
1085 Parse_InstructionSequence(const char **s
, struct fp_instruction program
[])
1091 struct fp_instruction
*inst
= program
+ count
;
1092 struct instruction_pattern instMatch
;
1094 /* Initialize the instruction */
1095 inst
->SrcReg
[0].Register
= -1;
1096 inst
->SrcReg
[1].Register
= -1;
1097 inst
->SrcReg
[2].Register
= -1;
1098 inst
->DstReg
.Register
= -1;
1101 if (!Parse_Token(s
, token
)) {
1102 inst
->Opcode
= FP_OPCODE_END
;
1103 printf("END OF PROGRAM %d\n", count
);
1107 /* special instructions */
1108 if (StrEq(token
, "DEFINE")) {
1111 if (!Parse_Identifier(s
, id
))
1113 if (!Parse_String(s
, "="))
1114 PARSE_ERROR1("Expected = symbol");
1115 if (!Parse_VectorOrScalarConstant(s
, value
))
1117 printf("Parsed DEFINE %s = %f %f %f %f\n", id
, value
[0], value
[1],
1118 value
[2], value
[3]);
1120 else if (StrEq(token
, "DECLARE")) {
1123 if (!Parse_Identifier(s
, id
))
1125 if (!Peek_Token(s
, token
))
1127 if (token
[0] == '=') {
1128 Parse_String(s
, "=");
1129 if (!Parse_VectorOrScalarConstant(s
, value
))
1131 printf("Parsed DECLARE %s = %f %f %f %f\n", id
, value
[0], value
[1],
1132 value
[2], value
[3]);
1135 printf("Parsed DECLARE %s\n", id
);
1139 /* try to find matching instuction */
1140 instMatch
= MatchInstruction(token
);
1141 if (instMatch
.opcode
< 0) {
1142 /* bad instruction name */
1143 PARSE_ERROR2("Unexpected token: ", token
);
1146 inst
->Opcode
= instMatch
.opcode
;
1147 inst
->Precision
= instMatch
.suffixes
& (_R
| _H
| _X
);
1148 inst
->Saturate
= (instMatch
.suffixes
& (_S
)) ? GL_TRUE
: GL_FALSE
;
1149 inst
->UpdateCondRegister
= (instMatch
.suffixes
& (_C
)) ? GL_TRUE
: GL_FALSE
;
1152 * parse the input and output operands
1154 if (instMatch
.outputs
== OUTPUT_S
|| instMatch
.outputs
== OUTPUT_V
) {
1155 if (!Parse_MaskedDstReg(s
, &inst
->DstReg
))
1157 if (!Parse_String(s
, ","))
1160 else if (instMatch
.outputs
== OUTPUT_NONE
) {
1161 ASSERT(instMatch
.opcode
== FP_OPCODE_KIL
);
1162 /* This is a little weird, the cond code info is in the dest register */
1163 if (!Parse_CondCodeMask(s
, &inst
->DstReg
))
1167 if (instMatch
.inputs
== INPUT_1V
) {
1168 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[0]))
1171 else if (instMatch
.inputs
== INPUT_2V
) {
1172 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[0]))
1174 if (!Parse_String(s
, ","))
1176 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[1]))
1179 else if (instMatch
.inputs
== INPUT_3V
) {
1180 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[1]))
1182 if (!Parse_String(s
, ","))
1184 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[1]))
1186 if (!Parse_String(s
, ","))
1188 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[1]))
1191 else if (instMatch
.inputs
== INPUT_1S
) {
1192 if (!Parse_ScalarSrcReg(s
, &inst
->SrcReg
[1]))
1195 else if (instMatch
.inputs
== INPUT_2S
) {
1196 if (!Parse_ScalarSrcReg(s
, &inst
->SrcReg
[0]))
1198 if (!Parse_String(s
, ","))
1200 if (!Parse_ScalarSrcReg(s
, &inst
->SrcReg
[1]))
1203 else if (instMatch
.inputs
== INPUT_CC
) {
1205 if (!ParseCondCodeSrc(s
, &inst
->srcReg
[0]))
1209 else if (instMatch
.inputs
== INPUT_1V_T
) {
1210 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[0]))
1212 if (!Parse_String(s
, ","))
1214 if (!Parse_TextureImageId(s
, &inst
->TexSrcUnit
, &inst
->TexSrcTarget
))
1217 else if (instMatch
.inputs
== INPUT_1V_T
) {
1218 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[0]))
1220 if (!Parse_String(s
, ","))
1222 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[1]))
1224 if (!Parse_String(s
, ","))
1226 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[2]))
1228 if (!Parse_String(s
, ","))
1230 if (!Parse_TextureImageId(s
, &inst
->TexSrcUnit
, &inst
->TexSrcTarget
))
1234 /* end of statement semicolon */
1235 if (!Parse_String(s
, ";"))
1239 if (count
>= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
)
1240 PARSE_ERROR1("Program too long");
1247 Parse_Program(const char **s
, struct fp_instruction instBuffer
[])
1249 return Parse_InstructionSequence(s
, instBuffer
);
1254 * Parse/compile the 'str' returning the compiled 'program'.
1255 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1256 * indicates the position of the error in 'str'.
1259 _mesa_parse_nv_fragment_program(GLcontext
*ctx
, GLenum dstTarget
,
1260 const GLubyte
*str
, GLsizei len
,
1261 struct fragment_program
*program
)
1264 struct fp_instruction instBuffer
[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
];
1266 struct fp_instruction
*newInst
;
1268 GLubyte
*programString
;
1270 /* Make a null-terminated copy of the program string */
1271 programString
= (GLubyte
*) MALLOC(len
+ 1);
1272 if (!programString
) {
1273 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1276 MEMCPY(programString
, str
, len
);
1277 programString
[len
] = 0;
1280 /* check the program header */
1281 if (_mesa_strncmp((const char *) programString
, "!!FP1.0", 7) == 0) {
1282 target
= GL_FRAGMENT_PROGRAM_NV
;
1283 s
= (const char *) programString
+ 7;
1286 /* invalid header */
1287 _mesa_set_program_error(ctx
, 0, "Invalid fragment program header");
1288 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1292 /* make sure target and header match */
1293 if (target
!= dstTarget
) {
1294 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1295 "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1300 if (Parse_Program(&s
, instBuffer
)) {
1303 GLuint inputsRead
= 0;
1304 GLuint outputsWritten
= 0;
1305 /**GLuint progRegsWritten = 0;**/
1307 /* Find length of the program and compute bitmasks to indicate which
1308 * vertex input registers are read, which vertex result registers are
1309 * written to, and which program registers are written to.
1310 * We could actually do this while we parse the program.
1312 for (numInst
= 0; instBuffer
[numInst
].Opcode
!= FP_OPCODE_END
; numInst
++) {
1314 const GLint srcReg0
= instBuffer
[numInst
].SrcReg
[0].Register
;
1315 const GLint srcReg1
= instBuffer
[numInst
].SrcReg
[1].Register
;
1316 const GLint srcReg2
= instBuffer
[numInst
].SrcReg
[2].Register
;
1317 const GLint dstReg
= instBuffer
[numInst
].DstReg
.Register
;
1319 if ((r
= OutputRegisterNumber(dstReg
)) >= 0)
1320 outputsWritten
|= (1 << r
);
1321 else if (IsProgRegister(dstReg
))
1322 progRegsWritten
|= (1 << (dstReg
- FP_PROG_REG_START
));
1323 if ((r
= InputRegisterNumber(srcReg0
)) >= 0
1324 && !instBuffer
[numInst
].SrcReg
[0].RelAddr
)
1325 inputsRead
|= (1 << r
);
1326 if ((r
= InputRegisterNumber(srcReg1
) >= 0
1327 && !instBuffer
[numInst
].SrcReg
[1].RelAddr
)
1328 inputsRead
|= (1 << r
);
1329 if ((r
= InputRegisterNumber(srcReg2
) >= 0
1330 && !instBuffer
[numInst
].SrcReg
[2].RelAddr
)
1331 inputsRead
|= (1 << r
);
1335 printf("numInst %d\n", numInst
);
1337 program
->InputsRead
= inputsRead
;
1338 program
->OutputsWritten
= outputsWritten
;
1340 /* make copy of the input program string */
1341 strLen
= _mesa_strlen((const char *) str
);
1342 newString
= (GLubyte
*) MALLOC(strLen
+ 1);
1344 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1347 MEMCPY(newString
, str
, strLen
);
1348 newString
[strLen
] = 0; /* terminate */
1350 /* copy the compiled instructions */
1351 assert(numInst
<= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
);
1352 newInst
= (struct fp_instruction
*) MALLOC(numInst
* sizeof(struct fp_instruction
));
1354 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1355 return; /* out of memory */
1357 MEMCPY(newInst
, instBuffer
, numInst
* sizeof(struct fp_instruction
));
1359 /* install the program */
1360 program
->Base
.Target
= target
;
1361 if (program
->Base
.String
) {
1362 FREE(program
->Base
.String
);
1364 program
->Base
.String
= newString
;
1365 if (program
->Instructions
) {
1366 FREE(program
->Instructions
);
1368 program
->Instructions
= newInst
;
1371 _mesa_printf("--- glLoadProgramNV result ---\n");
1372 _mesa_print_nv_fragment_program(program
);
1373 _mesa_printf("------------------------------\n");
1379 /* print a message showing the program line containing the error */
1380 ctx
->Program
.ErrorPos
= (GLubyte
*) s
- str
;
1382 const GLubyte
*p
= str
, *line
= str
;
1383 int lineNum
= 1, statementNum
= 1, column
= 0;
1384 char errorLine
[1000];
1386 while (*p
&& p
< (const GLubyte
*) s
) { /* s is the error position */
1392 else if (*p
== ';') {
1400 /* Copy the line with the error into errorLine so we can null-
1403 for (i
= 0; line
[i
] != '\n' && line
[i
]; i
++)
1404 errorLine
[i
] = (char) line
[i
];
1408 _mesa_debug("Error pos = %d (%c) col %d\n",
1409 ctx->Program.ErrorPos, *s, column);
1411 _mesa_debug(ctx
, "Fragment program error on line %2d: %s\n", lineNum
, errorLine
);
1412 _mesa_debug(ctx
, " (statement %2d) near column %2d: ", statementNum
, column
+1);
1413 for (i
= 0; i
< column
; i
++)
1414 _mesa_debug(ctx
, " ");
1415 _mesa_debug(ctx
, "^\n");
1418 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1424 PrintSrcReg(const struct fp_src_register
*src
)
1426 static const char comps
[5] = "xyzw";
1429 if (src
->NegateAbs
) {
1435 if (src
->NegateBase
) {
1438 if ((r
= OutputRegisterNumber(src
->Register
)) >= 0) {
1439 _mesa_printf("o[%s]", OutputRegisters
[r
]);
1441 else if ((r
= InputRegisterNumber(src
->Register
)) >= 0) {
1442 _mesa_printf("f[%s]", InputRegisters
[r
]);
1444 else if ((r
= ProgramRegisterNumber(src
->Register
)) >= 0) {
1445 _mesa_printf("p[%d]", r
);
1447 else if ((r
= HalfTempRegisterNumber(src
->Register
)) >= 0) {
1448 _mesa_printf("H%d", r
);
1450 else if ((r
= TempRegisterNumber(src
->Register
)) >= 0) {
1451 _mesa_printf("R%d", r
);
1453 else if ((r
= DummyRegisterNumber(src
->Register
)) >= 0) {
1454 _mesa_printf("%cC", "HR"[r
]);
1457 _mesa_problem(NULL
, "Bad fragment register");
1460 if (src
->Swizzle
[0] == src
->Swizzle
[1] &&
1461 src
->Swizzle
[0] == src
->Swizzle
[2] &&
1462 src
->Swizzle
[0] == src
->Swizzle
[3]) {
1463 _mesa_printf(".%c", comps
[src
->Swizzle
[0]]);
1465 else if (src
->Swizzle
[0] != 0 ||
1466 src
->Swizzle
[1] != 1 ||
1467 src
->Swizzle
[2] != 2 ||
1468 src
->Swizzle
[3] != 3) {
1469 _mesa_printf(".%c%c%c%c",
1470 comps
[src
->Swizzle
[0]],
1471 comps
[src
->Swizzle
[1]],
1472 comps
[src
->Swizzle
[2]],
1473 comps
[src
->Swizzle
[3]]);
1481 PrintCondCode(const struct fp_dst_register
*dst
)
1483 static const char *comps
= "xyzw";
1484 static const char *ccString
[] = {
1485 "??", "GT", "EQ", "LT", "UN", "GE", "LE", "NE", "TR", "FL", "??"
1488 _mesa_printf("%s", ccString
[dst
->CondMask
]);
1489 if (dst
->CondSwizzle
[0] == dst
->CondSwizzle
[1] &&
1490 dst
->CondSwizzle
[0] == dst
->CondSwizzle
[2] &&
1491 dst
->CondSwizzle
[0] == dst
->CondSwizzle
[3]) {
1492 _mesa_printf(".%c", comps
[dst
->CondSwizzle
[0]]);
1494 else if (dst
->CondSwizzle
[0] != 0 ||
1495 dst
->CondSwizzle
[1] != 1 ||
1496 dst
->CondSwizzle
[2] != 2 ||
1497 dst
->CondSwizzle
[3] != 3) {
1498 _mesa_printf(".%c%c%c%c",
1499 comps
[dst
->CondSwizzle
[0]],
1500 comps
[dst
->CondSwizzle
[1]],
1501 comps
[dst
->CondSwizzle
[2]],
1502 comps
[dst
->CondSwizzle
[3]]);
1508 PrintDstReg(const struct fp_dst_register
*dst
)
1510 GLint w
= dst
->WriteMask
[0] + dst
->WriteMask
[1]
1511 + dst
->WriteMask
[2] + dst
->WriteMask
[3];
1514 if ((r
= OutputRegisterNumber(dst
->Register
)) >= 0) {
1515 _mesa_printf("o[%s]", OutputRegisters
[r
]);
1517 else if ((r
= HalfTempRegisterNumber(dst
->Register
)) >= 0) {
1518 _mesa_printf("H[%s]", InputRegisters
[r
]);
1520 else if ((r
= TempRegisterNumber(dst
->Register
)) >= 0) {
1521 _mesa_printf("R[%s]", InputRegisters
[r
]);
1523 else if ((r
= ProgramRegisterNumber(dst
->Register
)) >= 0) {
1524 _mesa_printf("p[%d]", r
);
1526 else if ((r
= DummyRegisterNumber(dst
->Register
)) >= 0) {
1527 _mesa_printf("%cC", "HR"[r
]);
1530 _mesa_printf("???");
1533 if (w
!= 0 && w
!= 4) {
1535 if (dst
->WriteMask
[0])
1537 if (dst
->WriteMask
[1])
1539 if (dst
->WriteMask
[2])
1541 if (dst
->WriteMask
[3])
1545 if (dst
->CondMask
!= COND_TR
||
1546 dst
->CondSwizzle
[0] != 0 ||
1547 dst
->CondSwizzle
[1] != 1 ||
1548 dst
->CondSwizzle
[2] != 2 ||
1549 dst
->CondSwizzle
[3] != 3) {
1558 * Print (unparse) the given vertex program. Just for debugging.
1561 _mesa_print_nv_fragment_program(const struct fragment_program
*program
)
1563 const struct fp_instruction
*inst
;
1565 for (inst
= program
->Instructions
; inst
->Opcode
!= FP_OPCODE_END
; inst
++) {
1567 for (i
= 0; Instructions
[i
].name
; i
++) {
1568 if (inst
->Opcode
== Instructions
[i
].opcode
) {
1569 /* print instruction name */
1570 _mesa_printf("%s", Instructions
[i
].name
);
1571 if (inst
->Precision
== HALF
)
1573 else if (inst
->Precision
== FIXED
)
1575 if (inst
->UpdateCondRegister
)
1578 _mesa_printf("_SAT");
1581 if (Instructions
[i
].inputs
== INPUT_CC
) {
1582 PrintCondCode(&inst
->DstReg
);
1584 else if (Instructions
[i
].outputs
== OUTPUT_V
||
1585 Instructions
[i
].outputs
== OUTPUT_S
) {
1586 /* print dest register */
1587 PrintDstReg(&inst
->DstReg
);
1591 /* print source register(s) */
1592 if (Instructions
[i
].inputs
== INPUT_1V
||
1593 Instructions
[i
].inputs
== INPUT_1S
) {
1594 PrintSrcReg(&inst
->SrcReg
[0]);
1596 else if (Instructions
[i
].inputs
== INPUT_2V
||
1597 Instructions
[i
].inputs
== INPUT_2S
) {
1598 PrintSrcReg(&inst
->SrcReg
[0]);
1600 PrintSrcReg(&inst
->SrcReg
[1]);
1602 else if (Instructions
[i
].inputs
== INPUT_3V
) {
1603 PrintSrcReg(&inst
->SrcReg
[0]);
1605 PrintSrcReg(&inst
->SrcReg
[1]);
1607 PrintSrcReg(&inst
->SrcReg
[2]);
1610 _mesa_printf(";\n");
1614 if (!Instructions
[i
].name
) {
1615 _mesa_printf("Bad opcode %d\n", inst
->Opcode
);