2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2003 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 * \brief NVIDIA fragment program parser.
37 #include "nvfragprog.h"
38 #include "nvfragparse.h"
39 #include "nvprogram.h"
48 #define INPUT_1V_T 7 /* one source vector, plus textureId */
49 #define INPUT_3V_T 8 /* one source vector, plus textureId */
53 #define OUTPUT_NONE 22
55 /* Optional suffixes */
56 #define _R FLOAT32 /* float */
57 #define _H FLOAT16 /* half-float */
58 #define _X FIXED12 /* fixed */
59 #define _C 0x08 /* set cond codes */
60 #define _S 0x10 /* saturate, clamp result to [0,1] */
62 struct instruction_pattern
{
64 enum fp_opcode opcode
;
70 static const struct instruction_pattern Instructions
[] = {
71 { "ADD", FP_OPCODE_ADD
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
72 { "COS", FP_OPCODE_COS
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
73 { "DDX", FP_OPCODE_DDX
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
74 { "DDY", FP_OPCODE_DDY
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
75 { "DP3", FP_OPCODE_DP3
, INPUT_2V
, OUTPUT_S
, _R
| _H
| _X
| _C
| _S
},
76 { "DP4", FP_OPCODE_DP4
, INPUT_2V
, OUTPUT_S
, _R
| _H
| _X
| _C
| _S
},
77 { "DST", FP_OPCODE_DP4
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
78 { "EX2", FP_OPCODE_DP4
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
79 { "FLR", FP_OPCODE_FLR
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
80 { "FRC", FP_OPCODE_FRC
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
81 { "KIL", FP_OPCODE_KIL
, INPUT_CC
, OUTPUT_NONE
, 0 },
82 { "LG2", FP_OPCODE_LG2
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
83 { "LIT", FP_OPCODE_LIT
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
84 { "LRP", FP_OPCODE_LRP
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
85 { "MAD", FP_OPCODE_MAD
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
86 { "MAX", FP_OPCODE_MAX
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
87 { "MIN", FP_OPCODE_MIN
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
88 { "MOV", FP_OPCODE_MOV
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
89 { "MUL", FP_OPCODE_MUL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
90 { "PK2H", FP_OPCODE_PK2H
, INPUT_1V
, OUTPUT_S
, 0 },
91 { "PK2US", FP_OPCODE_PK2US
, INPUT_1V
, OUTPUT_S
, 0 },
92 { "PK4B", FP_OPCODE_PK4B
, INPUT_1V
, OUTPUT_S
, 0 },
93 { "PK4UB", FP_OPCODE_PK4UB
, INPUT_1V
, OUTPUT_S
, 0 },
94 { "POW", FP_OPCODE_POW
, INPUT_2S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
95 { "RCP", FP_OPCODE_RCP
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
96 { "RFL", FP_OPCODE_RFL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
97 { "RSQ", FP_OPCODE_RSQ
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
98 { "SEQ", FP_OPCODE_SEQ
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
99 { "SFL", FP_OPCODE_SFL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
100 { "SGE", FP_OPCODE_SGE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
101 { "SGT", FP_OPCODE_SGT
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
102 { "SIN", FP_OPCODE_SIN
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
103 { "SLE", FP_OPCODE_SLE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
104 { "SLT", FP_OPCODE_SLT
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
105 { "SNE", FP_OPCODE_SNE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
106 { "STR", FP_OPCODE_STR
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
107 { "SUB", FP_OPCODE_SUB
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
108 { "TEX", FP_OPCODE_TEX
, INPUT_1V_T
, OUTPUT_V
, _C
| _S
},
109 { "TXD", FP_OPCODE_TXD
, INPUT_3V_T
, OUTPUT_V
, _C
| _S
},
110 { "TXP", FP_OPCODE_TXP
, INPUT_1V_T
, OUTPUT_V
, _C
| _S
},
111 { "UP2H", FP_OPCODE_UP2H
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
112 { "UP2US", FP_OPCODE_UP2US
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
113 { "UP4B", FP_OPCODE_UP4B
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
114 { "UP4UB", FP_OPCODE_UP4UB
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
115 { "X2D", FP_OPCODE_X2D
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
116 { NULL
, (enum fp_opcode
) -1, 0, 0, 0 }
121 * Information needed or computed during parsing.
122 * Remember, we can't modify the target program object until we've
123 * _successfully_ parsed the program text.
127 const GLubyte
*start
; /* start of program string */
128 const GLubyte
*pos
; /* current position */
129 struct fragment_program
*program
; /* current program */
131 GLuint numParameters
;
132 struct program_parameter
*parameters
; /* DECLARE */
135 struct program_parameter
*constants
; /* DEFINE */
137 GLuint numInst
; /* number of instructions parsed */
138 GLuint inputsRead
; /* bitmask of input registers used */
139 GLuint outputsWritten
; /* bitmask of 1 << FRAG_OUTPUT_* bits */
140 GLuint texturesUsed
[MAX_TEXTURE_IMAGE_UNITS
];
145 * Add a new program parameter (via DEFINE statement)
146 * \return index of the new entry in the parameter list
149 add_parameter(struct parse_state
*parseState
,
150 const char *name
, const GLfloat values
[4], GLboolean constant
)
152 const GLuint n
= parseState
->numParameters
;
154 parseState
->parameters
= _mesa_realloc(parseState
->parameters
,
155 n
* sizeof(struct program_parameter
),
156 (n
+ 1) * sizeof(struct program_parameter
));
157 parseState
->numParameters
= n
+ 1;
158 parseState
->parameters
[n
].Name
= _mesa_strdup(name
);
159 COPY_4V(parseState
->parameters
[n
].Values
, values
);
160 parseState
->parameters
[n
].Constant
= constant
;
166 * Add a new unnamed constant to the parameter lists.
167 * \param parseState parsing state
168 * \param values four float values
169 * \return index of the new parameter.
172 add_unnamed_constant(struct parse_state
*parseState
, const GLfloat values
[4])
174 /* generate a new dummy name */
177 _mesa_sprintf(name
, "constant%d", n
);
180 return add_parameter(parseState
, name
, values
, GL_TRUE
);
184 static const GLfloat
*
185 lookup_parameter(struct parse_state
*parseState
, const char *name
)
188 for (i
= 0; i
< parseState
->numParameters
; i
++) {
189 if (_mesa_strcmp(parseState
->parameters
[i
].Name
, name
) == 0)
190 return parseState
->parameters
[i
].Values
;
197 lookup_parameter_index(struct parse_state
*parseState
, const char *name
)
200 for (i
= 0; i
< parseState
->numParameters
; i
++) {
201 if (_mesa_strcmp(parseState
->parameters
[i
].Name
, name
) == 0)
209 * Called whenever we find an error during parsing.
212 record_error(struct parse_state
*parseState
, const char *msg
, int lineNo
)
216 const GLubyte
*lineStr
;
217 lineStr
= _mesa_find_line_column(parseState
->start
,
218 parseState
->pos
, &line
, &column
);
219 _mesa_debug(parseState
->ctx
,
220 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
221 lineNo
, line
, column
, (char *) lineStr
, msg
);
222 _mesa_free((void *) lineStr
);
227 /* Check that no error was already recorded. Only record the first one. */
228 if (parseState
->ctx
->Program
.ErrorString
[0] == 0) {
229 _mesa_set_program_error(parseState
->ctx
,
230 parseState
->pos
- parseState
->start
,
236 #define RETURN_ERROR \
238 record_error(parseState, "Unexpected end of input.", __LINE__); \
242 #define RETURN_ERROR1(msg) \
244 record_error(parseState, msg, __LINE__); \
248 #define RETURN_ERROR2(msg1, msg2) \
251 _mesa_sprintf(err, "%s %s", msg1, msg2); \
252 record_error(parseState, err, __LINE__); \
260 * Search a list of instruction structures for a match.
262 static struct instruction_pattern
263 MatchInstruction(const GLubyte
*token
)
265 const struct instruction_pattern
*inst
;
266 struct instruction_pattern result
;
268 for (inst
= Instructions
; inst
->name
; inst
++) {
269 if (_mesa_strncmp((const char *) token
, inst
->name
, 3) == 0) {
275 if (token
[i
] == 'R') {
276 result
.suffixes
|= _R
;
279 else if (token
[i
] == 'H') {
280 result
.suffixes
|= _H
;
283 else if (token
[i
] == 'X') {
284 result
.suffixes
|= _X
;
287 if (token
[i
] == 'C') {
288 result
.suffixes
|= _C
;
291 if (token
[i
] == '_' && token
[i
+1] == 'S' &&
292 token
[i
+2] == 'A' && token
[i
+3] == 'T') {
293 result
.suffixes
|= _S
;
298 result
.opcode
= (enum fp_opcode
) -1;
305 /**********************************************************************/
308 static GLboolean
IsLetter(GLubyte b
)
310 return (b
>= 'a' && b
<= 'z') ||
311 (b
>= 'A' && b
<= 'Z') ||
317 static GLboolean
IsDigit(GLubyte b
)
319 return b
>= '0' && b
<= '9';
323 static GLboolean
IsWhitespace(GLubyte b
)
325 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
330 * Starting at 'str' find the next token. A token can be an integer,
331 * an identifier or punctuation symbol.
332 * \return <= 0 we found an error, else, return number of characters parsed.
335 GetToken(const GLubyte
*str
, GLubyte
*token
)
341 /* skip whitespace and comments */
342 while (str
[i
] && (IsWhitespace(str
[i
]) || str
[i
] == '#')) {
345 while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
350 /* skip whitespace */
358 /* try matching an integer */
359 while (str
[i
] && IsDigit(str
[i
])) {
360 token
[j
++] = str
[i
++];
362 if (j
> 0 || !str
[i
]) {
367 /* try matching an identifier */
368 if (IsLetter(str
[i
])) {
369 while (str
[i
] && (IsLetter(str
[i
]) || IsDigit(str
[i
]))) {
370 token
[j
++] = str
[i
++];
376 /* punctuation character */
390 * Get next token from input stream and increment stream pointer past token.
393 Parse_Token(struct parse_state
*parseState
, GLubyte
*token
)
396 i
= GetToken(parseState
->pos
, token
);
398 parseState
->pos
+= (-i
);
401 parseState
->pos
+= i
;
407 * Get next token from input stream but don't increment stream pointer.
410 Peek_Token(struct parse_state
*parseState
, GLubyte
*token
)
413 i
= GetToken(parseState
->pos
, token
);
415 parseState
->pos
+= (-i
);
418 len
= _mesa_strlen((const char *) token
);
419 parseState
->pos
+= (i
- len
);
424 /**********************************************************************/
426 static const char *InputRegisters
[MAX_NV_FRAGMENT_PROGRAM_INPUTS
+ 1] = {
427 "WPOS", "COL0", "COL1", "FOGC",
428 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
431 static const char *OutputRegisters
[MAX_NV_FRAGMENT_PROGRAM_OUTPUTS
+ 1] = {
433 /* These are only allows for register combiners */
435 "TEX0", "TEX1", "TEX2", "TEX3",
442 TempRegisterNumber(GLuint r
)
444 if (r
>= FP_TEMP_REG_START
&& r
<= FP_TEMP_REG_END
)
445 return r
- FP_TEMP_REG_START
;
451 HalfTempRegisterNumber(GLuint r
)
453 if (r
>= FP_TEMP_REG_START
+ 32 && r
<= FP_TEMP_REG_END
)
454 return r
- FP_TEMP_REG_START
- 32;
460 InputRegisterNumber(GLuint r
)
462 if (r
>= FP_INPUT_REG_START
&& r
<= FP_INPUT_REG_END
)
463 return r
- FP_INPUT_REG_START
;
469 OutputRegisterNumber(GLuint r
)
471 if (r
>= FP_OUTPUT_REG_START
&& r
<= FP_OUTPUT_REG_END
)
472 return r
- FP_OUTPUT_REG_START
;
478 ProgramRegisterNumber(GLuint r
)
480 if (r
>= FP_PROG_REG_START
&& r
<= FP_PROG_REG_END
)
481 return r
- FP_PROG_REG_START
;
487 DummyRegisterNumber(GLuint r
)
489 if (r
>= FP_DUMMY_REG_START
&& r
<= FP_DUMMY_REG_END
)
490 return r
- FP_DUMMY_REG_START
;
496 /**********************************************************************/
499 * Try to match 'pattern' as the next token after any whitespace/comments.
502 Parse_String(struct parse_state
*parseState
, const char *pattern
)
507 /* skip whitespace and comments */
508 while (IsWhitespace(*parseState
->pos
) || *parseState
->pos
== '#') {
509 if (*parseState
->pos
== '#') {
510 while (*parseState
->pos
&& (*parseState
->pos
!= '\n' && *parseState
->pos
!= '\r')) {
511 parseState
->pos
+= 1;
515 /* skip whitespace */
516 parseState
->pos
+= 1;
520 /* Try to match the pattern */
522 for (i
= 0; pattern
[i
]; i
++) {
523 if (*m
!= (GLubyte
) pattern
[i
])
529 return GL_TRUE
; /* success */
534 Parse_Identifier(struct parse_state
*parseState
, GLubyte
*ident
)
536 if (!Parse_Token(parseState
, ident
))
538 if (IsLetter(ident
[0]))
541 RETURN_ERROR1("Expected an identfier");
546 * Parse a floating point constant, or a defined symbol name.
548 * Output: number[0 .. 3] will get the value.
551 Parse_ScalarConstant(struct parse_state
*parseState
, GLfloat
*number
)
555 *number
= (GLfloat
) _mesa_strtod((const char *) parseState
->pos
, &end
);
557 if (end
&& end
> (char *) parseState
->pos
) {
559 parseState
->pos
= (GLubyte
*) end
;
566 /* should be an identifier */
568 const GLfloat
*constant
;
569 if (!Parse_Identifier(parseState
, ident
))
570 RETURN_ERROR1("Expected an identifier");
571 constant
= lookup_parameter(parseState
, (const char *) ident
);
572 /* XXX Check that it's a constant and not a parameter */
574 RETURN_ERROR1("Undefined symbol");
577 COPY_4V(number
, constant
);
586 * Parse a vector constant, one of:
589 * { float, float, float }
590 * { float, float, float, float }
593 Parse_VectorConstant(struct parse_state
*parseState
, GLfloat
*vec
)
595 /* "{" was already consumed */
597 ASSIGN_4V(vec
, 0.0, 0.0, 0.0, 1.0);
599 if (!Parse_ScalarConstant(parseState
, vec
+0)) /* X */
602 if (Parse_String(parseState
, "}")) {
606 if (!Parse_String(parseState
, ","))
607 RETURN_ERROR1("Expected comma in vector constant");
609 if (!Parse_ScalarConstant(parseState
, vec
+1)) /* Y */
612 if (Parse_String(parseState
, "}")) {
616 if (!Parse_String(parseState
, ","))
617 RETURN_ERROR1("Expected comma in vector constant");
619 if (!Parse_ScalarConstant(parseState
, vec
+2)) /* Z */
622 if (Parse_String(parseState
, "}")) {
626 if (!Parse_String(parseState
, ","))
627 RETURN_ERROR1("Expected comma in vector constant");
629 if (!Parse_ScalarConstant(parseState
, vec
+3)) /* W */
632 if (!Parse_String(parseState
, "}"))
633 RETURN_ERROR1("Expected closing brace in vector constant");
640 * Parse <number>, <varname> or {a, b, c, d}.
641 * Return number of values in the vector or scalar, or zero if parse error.
644 Parse_VectorOrScalarConstant(struct parse_state
*parseState
, GLfloat
*vec
)
646 if (Parse_String(parseState
, "{")) {
647 return Parse_VectorConstant(parseState
, vec
);
650 GLboolean b
= Parse_ScalarConstant(parseState
, vec
);
652 vec
[1] = vec
[2] = vec
[3] = vec
[0];
660 * Parse a texture image source:
661 * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
664 Parse_TextureImageId(struct parse_state
*parseState
,
665 GLubyte
*texUnit
, GLubyte
*texTargetBit
)
667 GLubyte imageSrc
[100];
670 if (!Parse_Token(parseState
, imageSrc
))
673 if (imageSrc
[0] != 'T' ||
674 imageSrc
[1] != 'E' ||
675 imageSrc
[2] != 'X') {
676 RETURN_ERROR1("Expected TEX# source");
678 unit
= _mesa_atoi((const char *) imageSrc
+ 3);
679 if ((unit
< 0 || unit
> MAX_TEXTURE_IMAGE_UNITS
) ||
680 (unit
== 0 && (imageSrc
[3] != '0' || imageSrc
[4] != 0))) {
681 RETURN_ERROR1("Invalied TEX# source index");
685 if (!Parse_String(parseState
, ","))
686 RETURN_ERROR1("Expected ,");
688 if (Parse_String(parseState
, "1D")) {
689 *texTargetBit
= TEXTURE_1D_BIT
;
691 else if (Parse_String(parseState
, "2D")) {
692 *texTargetBit
= TEXTURE_2D_BIT
;
694 else if (Parse_String(parseState
, "3D")) {
695 *texTargetBit
= TEXTURE_3D_BIT
;
697 else if (Parse_String(parseState
, "CUBE")) {
698 *texTargetBit
= TEXTURE_CUBE_BIT
;
700 else if (Parse_String(parseState
, "RECT")) {
701 *texTargetBit
= TEXTURE_RECT_BIT
;
704 RETURN_ERROR1("Invalid texture target token");
707 /* update record of referenced texture units */
708 parseState
->texturesUsed
[*texUnit
] |= *texTargetBit
;
709 if (_mesa_bitcount(parseState
->texturesUsed
[*texUnit
]) > 1) {
710 RETURN_ERROR1("Only one texture target can be used per texture unit.");
718 * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
719 * like .wxyz, .xxyy, etc and return the swizzle indexes.
722 Parse_SwizzleSuffix(const GLubyte
*token
, GLuint swizzle
[4])
725 /* single letter swizzle (scalar) */
727 ASSIGN_4V(swizzle
, 0, 0, 0, 0);
728 else if (token
[0] == 'y')
729 ASSIGN_4V(swizzle
, 1, 1, 1, 1);
730 else if (token
[0] == 'z')
731 ASSIGN_4V(swizzle
, 2, 2, 2, 2);
732 else if (token
[0] == 'w')
733 ASSIGN_4V(swizzle
, 3, 3, 3, 3);
738 /* 4-component swizzle (vector) */
740 for (k
= 0; token
[k
] && k
< 4; k
++) {
743 else if (token
[k
] == 'y')
745 else if (token
[k
] == 'z')
747 else if (token
[k
] == 'w')
760 Parse_CondCodeMask(struct parse_state
*parseState
,
761 struct fp_dst_register
*dstReg
)
763 if (Parse_String(parseState
, "EQ"))
764 dstReg
->CondMask
= COND_EQ
;
765 else if (Parse_String(parseState
, "GE"))
766 dstReg
->CondMask
= COND_GE
;
767 else if (Parse_String(parseState
, "GT"))
768 dstReg
->CondMask
= COND_GT
;
769 else if (Parse_String(parseState
, "LE"))
770 dstReg
->CondMask
= COND_LE
;
771 else if (Parse_String(parseState
, "LT"))
772 dstReg
->CondMask
= COND_LT
;
773 else if (Parse_String(parseState
, "NE"))
774 dstReg
->CondMask
= COND_NE
;
775 else if (Parse_String(parseState
, "TR"))
776 dstReg
->CondMask
= COND_TR
;
777 else if (Parse_String(parseState
, "FL"))
778 dstReg
->CondMask
= COND_FL
;
780 RETURN_ERROR1("Invalid condition code mask");
782 /* look for optional .xyzw swizzle */
783 if (Parse_String(parseState
, ".")) {
785 if (!Parse_Token(parseState
, token
)) /* get xyzw suffix */
788 if (!Parse_SwizzleSuffix(token
, dstReg
->CondSwizzle
))
789 RETURN_ERROR1("Invalid swizzle suffix");
797 * Parse a temporary register: Rnn or Hnn
800 Parse_TempReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
804 /* Should be 'R##' or 'H##' */
805 if (!Parse_Token(parseState
, token
))
807 if (token
[0] != 'R' && token
[0] != 'H')
808 RETURN_ERROR1("Expected R## or H##");
810 if (IsDigit(token
[1])) {
811 GLint reg
= _mesa_atoi((const char *) (token
+ 1));
814 if (reg
>= MAX_NV_FRAGMENT_PROGRAM_TEMPS
)
815 RETURN_ERROR1("Invalid temporary register name");
816 *tempRegNum
= FP_TEMP_REG_START
+ reg
;
819 RETURN_ERROR1("Invalid temporary register name");
827 * Parse a write-only dummy register: RC or HC.
830 Parse_DummyReg(struct parse_state
*parseState
, GLint
*regNum
)
832 if (Parse_String(parseState
, "RC")) {
833 *regNum
= FP_DUMMY_REG_START
;
835 else if (Parse_String(parseState
, "HC")) {
836 *regNum
= FP_DUMMY_REG_START
+ 1;
839 RETURN_ERROR1("Invalid write-only register name");
847 * Parse a program local parameter register "p[##]"
850 Parse_ProgramParamReg(struct parse_state
*parseState
, GLint
*regNum
)
854 if (!Parse_String(parseState
, "p["))
855 RETURN_ERROR1("Expected p[");
857 if (!Parse_Token(parseState
, token
))
860 if (IsDigit(token
[0])) {
861 /* a numbered program parameter register */
862 GLint reg
= _mesa_atoi((const char *) token
);
863 if (reg
>= MAX_NV_FRAGMENT_PROGRAM_PARAMS
)
864 RETURN_ERROR1("Invalid constant program number");
865 *regNum
= FP_PROG_REG_START
+ reg
;
871 if (!Parse_String(parseState
, "]"))
872 RETURN_ERROR1("Expected ]");
879 * Parse f[name] - fragment input register
882 Parse_FragReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
888 if (!Parse_String(parseState
, "f["))
889 RETURN_ERROR1("Expected f[");
891 /* get <name> and look for match */
892 if (!Parse_Token(parseState
, token
)) {
895 for (j
= 0; InputRegisters
[j
]; j
++) {
896 if (_mesa_strcmp((const char *) token
, InputRegisters
[j
]) == 0) {
897 *tempRegNum
= FP_INPUT_REG_START
+ j
;
898 parseState
->inputsRead
|= (1 << j
);
902 if (!InputRegisters
[j
]) {
903 /* unknown input register label */
904 RETURN_ERROR2("Invalid register name", token
);
908 if (!Parse_String(parseState
, "]"))
909 RETURN_ERROR1("Expected ]");
916 Parse_OutputReg(struct parse_state
*parseState
, GLint
*outputRegNum
)
922 if (!Parse_String(parseState
, "o["))
923 RETURN_ERROR1("Expected o[");
925 /* Get output reg name */
926 if (!Parse_Token(parseState
, token
))
929 /* try to match an output register name */
930 for (j
= 0; OutputRegisters
[j
]; j
++) {
931 if (_mesa_strcmp((const char *) token
, OutputRegisters
[j
]) == 0) {
932 static GLuint bothColors
= (1 << FRAG_OUTPUT_COLR
) | (1 << FRAG_OUTPUT_COLH
);
933 *outputRegNum
= FP_OUTPUT_REG_START
+ j
;
934 parseState
->outputsWritten
|= (1 << j
);
935 if ((parseState
->outputsWritten
& bothColors
) == bothColors
) {
936 RETURN_ERROR1("Illegal to write to both o[COLR] and o[COLH]");
941 if (!OutputRegisters
[j
])
942 RETURN_ERROR1("Invalid output register name");
945 if (!Parse_String(parseState
, "]"))
946 RETURN_ERROR1("Expected ]");
953 Parse_MaskedDstReg(struct parse_state
*parseState
,
954 struct fp_dst_register
*dstReg
)
958 /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
959 if (!Peek_Token(parseState
, token
))
962 if (_mesa_strcmp((const char *) token
, "RC") == 0 ||
963 _mesa_strcmp((const char *) token
, "HC") == 0) {
964 /* a write-only register */
965 if (!Parse_DummyReg(parseState
, &dstReg
->Register
))
968 else if (token
[0] == 'R' || token
[0] == 'H') {
969 /* a temporary register */
970 if (!Parse_TempReg(parseState
, &dstReg
->Register
))
973 else if (token
[0] == 'o') {
974 /* an output register */
975 if (!Parse_OutputReg(parseState
, &dstReg
->Register
))
979 RETURN_ERROR1("Invalid destination register name");
982 /* Parse optional write mask */
983 if (Parse_String(parseState
, ".")) {
987 if (!Parse_Token(parseState
, token
)) /* get xyzw writemask */
990 dstReg
->WriteMask
[0] = GL_FALSE
;
991 dstReg
->WriteMask
[1] = GL_FALSE
;
992 dstReg
->WriteMask
[2] = GL_FALSE
;
993 dstReg
->WriteMask
[3] = GL_FALSE
;
995 if (token
[k
] == 'x') {
996 dstReg
->WriteMask
[0] = GL_TRUE
;
999 if (token
[k
] == 'y') {
1000 dstReg
->WriteMask
[1] = GL_TRUE
;
1003 if (token
[k
] == 'z') {
1004 dstReg
->WriteMask
[2] = GL_TRUE
;
1007 if (token
[k
] == 'w') {
1008 dstReg
->WriteMask
[3] = GL_TRUE
;
1012 RETURN_ERROR1("Invalid writemask character");
1017 dstReg
->WriteMask
[0] = GL_TRUE
;
1018 dstReg
->WriteMask
[1] = GL_TRUE
;
1019 dstReg
->WriteMask
[2] = GL_TRUE
;
1020 dstReg
->WriteMask
[3] = GL_TRUE
;
1023 /* optional condition code mask */
1024 if (Parse_String(parseState
, "(")) {
1025 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
1026 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
1027 if (!Parse_CondCodeMask(parseState
, dstReg
))
1030 if (!Parse_String(parseState
, ")")) /* consume ")" */
1031 RETURN_ERROR1("Expected )");
1036 /* no cond code mask */
1037 dstReg
->CondMask
= COND_TR
;
1038 dstReg
->CondSwizzle
[0] = 0;
1039 dstReg
->CondSwizzle
[1] = 1;
1040 dstReg
->CondSwizzle
[2] = 2;
1041 dstReg
->CondSwizzle
[3] = 3;
1048 * Parse a vector source (register, constant, etc):
1049 * <vectorSrc> ::= <absVectorSrc>
1051 * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
1054 Parse_VectorSrc(struct parse_state
*parseState
,
1055 struct fp_src_register
*srcReg
)
1057 GLfloat sign
= 1.0F
;
1061 * First, take care of +/- and absolute value stuff.
1063 if (Parse_String(parseState
, "-"))
1065 else if (Parse_String(parseState
, "+"))
1068 if (Parse_String(parseState
, "|")) {
1069 srcReg
->Abs
= GL_TRUE
;
1070 srcReg
->NegateAbs
= (sign
< 0.0F
) ? GL_TRUE
: GL_FALSE
;
1072 if (Parse_String(parseState
, "-"))
1073 srcReg
->NegateBase
= GL_TRUE
;
1074 else if (Parse_String(parseState
, "+"))
1075 srcReg
->NegateBase
= GL_FALSE
;
1077 srcReg
->NegateBase
= GL_FALSE
;
1080 srcReg
->Abs
= GL_FALSE
;
1081 srcReg
->NegateAbs
= GL_FALSE
;
1082 srcReg
->NegateBase
= (sign
< 0.0F
) ? GL_TRUE
: GL_FALSE
;
1085 /* This should be the real src vector/register name */
1086 if (!Peek_Token(parseState
, token
))
1089 /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
1090 * literal or vector literal.
1092 if (token
[0] == 'R' || token
[0] == 'H') {
1093 if (!Parse_TempReg(parseState
, &srcReg
->Register
))
1096 else if (token
[0] == 'f') {
1097 /* XXX this might be an identier! */
1098 if (!Parse_FragReg(parseState
, &srcReg
->Register
))
1101 else if (token
[0] == 'p') {
1102 /* XXX this might be an identier! */
1103 if (!Parse_ProgramParamReg(parseState
, &srcReg
->Register
))
1106 else if (IsLetter(token
[0])){
1109 if (!Parse_Identifier(parseState
, ident
))
1111 paramIndex
= lookup_parameter_index(parseState
, (const char *) ident
);
1112 if (paramIndex
< 0) {
1113 RETURN_ERROR2("Undefined constant or parameter: ", ident
);
1115 srcReg
->IsParameter
= GL_TRUE
;
1116 srcReg
->Register
= paramIndex
;
1118 else if (IsDigit(token
[0]) || token
[0] == '-' || token
[0] == '+' || token
[0] == '.'){
1119 /* literal scalar constant */
1122 if (!Parse_ScalarConstant(parseState
, values
))
1125 srcReg
->Register
= 0; /* XXX fix */
1127 paramIndex
= add_unnamed_constant(parseState
, values
);
1128 srcReg
->IsParameter
= GL_TRUE
;
1129 srcReg
->Register
= paramIndex
;
1132 else if (token
[0] == '{'){
1133 /* literal vector constant */
1136 (void) Parse_String(parseState
, "{");
1137 if (!Parse_VectorConstant(parseState
, values
))
1139 paramIndex
= add_unnamed_constant(parseState
, values
);
1140 srcReg
->IsParameter
= GL_TRUE
;
1141 srcReg
->Register
= paramIndex
;
1144 RETURN_ERROR2("Invalid source register name", token
);
1147 /* init swizzle fields */
1148 srcReg
->Swizzle
[0] = 0;
1149 srcReg
->Swizzle
[1] = 1;
1150 srcReg
->Swizzle
[2] = 2;
1151 srcReg
->Swizzle
[3] = 3;
1153 /* Look for optional swizzle suffix */
1154 if (Parse_String(parseState
, ".")) {
1155 if (!Parse_Token(parseState
, token
))
1158 if (!Parse_SwizzleSuffix(token
, srcReg
->Swizzle
))
1159 RETURN_ERROR1("Invalid swizzle suffix");
1162 /* Finish absolute value */
1163 if (srcReg
->Abs
&& !Parse_String(parseState
, "|")) {
1164 RETURN_ERROR1("Expected |");
1172 Parse_ScalarSrcReg(struct parse_state
*parseState
,
1173 struct fp_src_register
*srcReg
)
1176 GLfloat sign
= 1.0F
;
1177 GLboolean needSuffix
= GL_TRUE
;
1180 * First, take care of +/- and absolute value stuff.
1182 if (Parse_String(parseState
, "-"))
1184 else if (Parse_String(parseState
, "+"))
1187 if (Parse_String(parseState
, "|")) {
1188 srcReg
->Abs
= GL_TRUE
;
1189 srcReg
->NegateAbs
= (sign
< 0.0F
) ? GL_TRUE
: GL_FALSE
;
1191 if (Parse_String(parseState
, "-"))
1192 srcReg
->NegateBase
= GL_TRUE
;
1193 else if (Parse_String(parseState
, "+"))
1194 srcReg
->NegateBase
= GL_FALSE
;
1196 srcReg
->NegateBase
= GL_FALSE
;
1199 srcReg
->Abs
= GL_FALSE
;
1200 srcReg
->NegateAbs
= GL_FALSE
;
1201 srcReg
->NegateBase
= (sign
< 0.0F
) ? GL_TRUE
: GL_FALSE
;
1204 if (!Peek_Token(parseState
, token
))
1207 /* Src reg can be R<n>, H<n> or a named fragment attrib */
1208 if (token
[0] == 'R' || token
[0] == 'H') {
1209 if (!Parse_TempReg(parseState
, &srcReg
->Register
))
1212 else if (token
[0] == 'f') {
1213 if (!Parse_FragReg(parseState
, &srcReg
->Register
))
1216 else if (token
[0] == '{') {
1217 /* vector literal */
1220 (void) Parse_String(parseState
, "{");
1221 if (!Parse_VectorConstant(parseState
, values
))
1223 paramIndex
= add_unnamed_constant(parseState
, values
);
1224 srcReg
->IsParameter
= GL_TRUE
;
1225 srcReg
->Register
= paramIndex
;
1227 else if (IsDigit(token
[0])) {
1228 /* scalar literal */
1231 if (!Parse_ScalarConstant(parseState
, values
))
1233 paramIndex
= add_unnamed_constant(parseState
, values
);
1234 srcReg
->IsParameter
= GL_TRUE
;
1235 srcReg
->Register
= paramIndex
;
1236 needSuffix
= GL_FALSE
;
1239 RETURN_ERROR2("Invalid scalar source argument", token
);
1243 /* parse .[xyzw] suffix */
1244 if (!Parse_String(parseState
, "."))
1245 RETURN_ERROR1("Expected .");
1247 if (!Parse_Token(parseState
, token
))
1250 if (token
[0] == 'x' && token
[1] == 0) {
1251 srcReg
->Swizzle
[0] = 0;
1253 else if (token
[0] == 'y' && token
[1] == 0) {
1254 srcReg
->Swizzle
[0] = 1;
1256 else if (token
[0] == 'z' && token
[1] == 0) {
1257 srcReg
->Swizzle
[0] = 2;
1259 else if (token
[0] == 'w' && token
[1] == 0) {
1260 srcReg
->Swizzle
[0] = 3;
1263 RETURN_ERROR1("Invalid scalar source suffix");
1267 srcReg
->Swizzle
[0] = 0;
1269 srcReg
->Swizzle
[1] = srcReg
->Swizzle
[2] = srcReg
->Swizzle
[3] = 0;
1271 /* Finish absolute value */
1272 if (srcReg
->Abs
&& !Parse_String(parseState
, "|")) {
1273 RETURN_ERROR1("Expected |");
1282 Parse_InstructionSequence(struct parse_state
*parseState
,
1283 struct fp_instruction program
[])
1286 struct fp_instruction
*inst
= program
+ parseState
->numInst
;
1287 struct instruction_pattern instMatch
;
1290 /* Initialize the instruction */
1291 inst
->SrcReg
[0].Register
= -1;
1292 inst
->SrcReg
[1].Register
= -1;
1293 inst
->SrcReg
[2].Register
= -1;
1294 inst
->SrcReg
[0].IsParameter
= GL_FALSE
;
1295 inst
->SrcReg
[1].IsParameter
= GL_FALSE
;
1296 inst
->SrcReg
[2].IsParameter
= GL_FALSE
;
1297 inst
->DstReg
.Register
= -1;
1298 inst
->DstReg
.CondSwizzle
[0] = 0;
1299 inst
->DstReg
.CondSwizzle
[1] = 1;
1300 inst
->DstReg
.CondSwizzle
[2] = 2;
1301 inst
->DstReg
.CondSwizzle
[3] = 3;
1303 /* special instructions */
1304 if (Parse_String(parseState
, "DEFINE")) {
1306 GLfloat value
[7]; /* yes, 7 to be safe */
1307 if (!Parse_Identifier(parseState
, id
))
1309 /* XXX make sure id is not a reserved identifer, like R9 */
1310 if (!Parse_String(parseState
, "="))
1311 RETURN_ERROR1("Expected =");
1312 if (!Parse_VectorOrScalarConstant(parseState
, value
))
1314 if (!Parse_String(parseState
, ";"))
1315 RETURN_ERROR1("Expected ;");
1316 if (lookup_parameter(parseState
, (const char *) id
)) {
1317 RETURN_ERROR2(id
, "already defined");
1319 add_parameter(parseState
, (const char *) id
, value
, GL_TRUE
);
1321 else if (Parse_String(parseState
, "DECLARE")) {
1323 GLfloat value
[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */
1324 if (!Parse_Identifier(parseState
, id
))
1326 /* XXX make sure id is not a reserved identifer, like R9 */
1327 if (Parse_String(parseState
, "=")) {
1328 if (!Parse_VectorOrScalarConstant(parseState
, value
))
1331 if (!Parse_String(parseState
, ";"))
1332 RETURN_ERROR1("Expected ;");
1333 if (lookup_parameter(parseState
, (const char *) id
)) {
1334 RETURN_ERROR2(id
, "already declared");
1336 add_parameter(parseState
, (const char *) id
, value
, GL_FALSE
);
1338 else if (Parse_String(parseState
, "END")) {
1339 inst
->Opcode
= FP_OPCODE_END
;
1340 parseState
->numInst
++;
1341 if (Parse_Token(parseState
, token
)) {
1342 RETURN_ERROR1("Code after END opcode.");
1347 /* general/arithmetic instruction */
1350 if (!Parse_Token(parseState
, token
)) {
1351 RETURN_ERROR1("Missing END instruction.");
1354 /* try to find matching instuction */
1355 instMatch
= MatchInstruction(token
);
1356 if (instMatch
.opcode
< 0) {
1357 /* bad instruction name */
1358 RETURN_ERROR2("Unexpected token: ", token
);
1361 inst
->Opcode
= instMatch
.opcode
;
1362 inst
->Precision
= instMatch
.suffixes
& (_R
| _H
| _X
);
1363 inst
->Saturate
= (instMatch
.suffixes
& (_S
)) ? GL_TRUE
: GL_FALSE
;
1364 inst
->UpdateCondRegister
= (instMatch
.suffixes
& (_C
)) ? GL_TRUE
: GL_FALSE
;
1367 * parse the input and output operands
1369 if (instMatch
.outputs
== OUTPUT_S
|| instMatch
.outputs
== OUTPUT_V
) {
1370 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
1372 if (!Parse_String(parseState
, ","))
1373 RETURN_ERROR1("Expected ,");
1375 else if (instMatch
.outputs
== OUTPUT_NONE
) {
1376 ASSERT(instMatch
.opcode
== FP_OPCODE_KIL
);
1377 /* This is a little weird, the cond code info is in the dest register */
1378 if (!Parse_CondCodeMask(parseState
, &inst
->DstReg
))
1382 if (instMatch
.inputs
== INPUT_1V
) {
1383 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1386 else if (instMatch
.inputs
== INPUT_2V
) {
1387 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1389 if (!Parse_String(parseState
, ","))
1390 RETURN_ERROR1("Expected ,");
1391 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[1]))
1394 else if (instMatch
.inputs
== INPUT_3V
) {
1395 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1397 if (!Parse_String(parseState
, ","))
1398 RETURN_ERROR1("Expected ,");
1399 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[1]))
1401 if (!Parse_String(parseState
, ","))
1402 RETURN_ERROR1("Expected ,");
1403 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[2]))
1406 else if (instMatch
.inputs
== INPUT_1S
) {
1407 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
1410 else if (instMatch
.inputs
== INPUT_2S
) {
1411 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
1413 if (!Parse_String(parseState
, ","))
1414 RETURN_ERROR1("Expected ,");
1415 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[1]))
1418 else if (instMatch
.inputs
== INPUT_CC
) {
1421 else if (instMatch
.inputs
== INPUT_1V_T
) {
1422 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1424 if (!Parse_String(parseState
, ","))
1425 RETURN_ERROR1("Expected ,");
1426 if (!Parse_TextureImageId(parseState
, &inst
->TexSrcUnit
,
1430 else if (instMatch
.inputs
== INPUT_3V_T
) {
1431 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1433 if (!Parse_String(parseState
, ","))
1434 RETURN_ERROR1("Expected ,");
1435 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[1]))
1437 if (!Parse_String(parseState
, ","))
1438 RETURN_ERROR1("Expected ,");
1439 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[2]))
1441 if (!Parse_String(parseState
, ","))
1442 RETURN_ERROR1("Expected ,");
1443 if (!Parse_TextureImageId(parseState
, &inst
->TexSrcUnit
,
1448 /* end of statement semicolon */
1449 if (!Parse_String(parseState
, ";"))
1450 RETURN_ERROR1("Expected ;");
1452 parseState
->numInst
++;
1454 if (parseState
->numInst
>= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
)
1455 RETURN_ERROR1("Program too long");
1464 * Parse/compile the 'str' returning the compiled 'program'.
1465 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1466 * indicates the position of the error in 'str'.
1469 _mesa_parse_nv_fragment_program(GLcontext
*ctx
, GLenum dstTarget
,
1470 const GLubyte
*str
, GLsizei len
,
1471 struct fragment_program
*program
)
1473 struct parse_state parseState
;
1474 struct fp_instruction instBuffer
[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
];
1475 struct fp_instruction
*newInst
;
1477 GLubyte
*programString
;
1479 /* Make a null-terminated copy of the program string */
1480 programString
= (GLubyte
*) MALLOC(len
+ 1);
1481 if (!programString
) {
1482 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1485 MEMCPY(programString
, str
, len
);
1486 programString
[len
] = 0;
1488 /* Get ready to parse */
1489 _mesa_bzero(&parseState
, sizeof(struct parse_state
));
1490 parseState
.ctx
= ctx
;
1491 parseState
.start
= programString
;
1492 parseState
.program
= program
;
1493 parseState
.numInst
= 0;
1495 /* Reset error state */
1496 _mesa_set_program_error(ctx
, -1, NULL
);
1498 /* check the program header */
1499 if (_mesa_strncmp((const char *) programString
, "!!FP1.0", 7) == 0) {
1500 target
= GL_FRAGMENT_PROGRAM_NV
;
1501 parseState
.pos
= programString
+ 7;
1503 else if (_mesa_strncmp((const char *) programString
, "!!FCP1.0", 8) == 0) {
1504 /* fragment / register combiner program - not supported */
1505 _mesa_set_program_error(ctx
, 0, "Invalid fragment program header");
1506 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1510 /* invalid header */
1511 _mesa_set_program_error(ctx
, 0, "Invalid fragment program header");
1512 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1516 /* make sure target and header match */
1517 if (target
!= dstTarget
) {
1518 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1519 "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1524 if (Parse_InstructionSequence(&parseState
, instBuffer
)) {
1526 /* successful parse! */
1528 if (parseState
.outputsWritten
== 0) {
1529 /* must write at least one output! */
1530 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1531 "Invalid fragment program - no outputs written.");
1535 /* copy the compiled instructions */
1536 assert(parseState
.numInst
<= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
);
1537 newInst
= (struct fp_instruction
*)
1538 MALLOC(parseState
.numInst
* sizeof(struct fp_instruction
));
1540 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1541 return; /* out of memory */
1543 MEMCPY(newInst
, instBuffer
,
1544 parseState
.numInst
* sizeof(struct fp_instruction
));
1546 /* install the program */
1547 program
->Base
.Target
= target
;
1548 if (program
->Base
.String
) {
1549 FREE(program
->Base
.String
);
1551 program
->Base
.String
= programString
;
1552 program
->Base
.Format
= GL_PROGRAM_FORMAT_ASCII_ARB
;
1553 if (program
->Instructions
) {
1554 FREE(program
->Instructions
);
1556 program
->Instructions
= newInst
;
1557 program
->InputsRead
= parseState
.inputsRead
;
1558 program
->OutputsWritten
= parseState
.outputsWritten
;
1559 for (u
= 0; u
< ctx
->Const
.MaxTextureImageUnits
; u
++)
1560 program
->TexturesUsed
[u
] = parseState
.texturesUsed
[u
];
1562 /* save program parameters */
1563 if (program
->Parameters
) {
1565 for (i
= 0; i
< program
->NumParameters
; i
++)
1566 _mesa_free((void *) program
->Parameters
[i
].Name
);
1567 _mesa_free(program
->Parameters
);
1569 program
->NumParameters
= parseState
.numParameters
;
1570 program
->Parameters
= parseState
.parameters
;
1572 /* free program constants */
1573 if (parseState
.constants
) {
1575 for (i
= 0; i
< parseState
.numConstants
; i
++)
1576 _mesa_free((void *) parseState
.constants
[i
].Name
);
1577 _mesa_free(parseState
.constants
);
1581 /* allocate registers for declared program parameters */
1583 _mesa_assign_program_registers(&(program
->SymbolTable
));
1587 _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program
->Base
.Id
);
1588 _mesa_print_nv_fragment_program(program
);
1589 _mesa_printf("----------------------------------\n");
1594 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1595 /* NOTE: _mesa_set_program_error would have been called already */
1601 PrintSrcReg(const struct fragment_program
*program
,
1602 const struct fp_src_register
*src
)
1604 static const char comps
[5] = "xyzw";
1607 if (src
->NegateAbs
) {
1613 if (src
->NegateBase
) {
1616 if (src
->IsParameter
) {
1617 if (program
->Parameters
[src
->Register
].Constant
) {
1618 printf("{%g, %g, %g, %g}",
1619 program
->Parameters
[src
->Register
].Values
[0],
1620 program
->Parameters
[src
->Register
].Values
[1],
1621 program
->Parameters
[src
->Register
].Values
[2],
1622 program
->Parameters
[src
->Register
].Values
[3]);
1625 printf("%s", program
->Parameters
[src
->Register
].Name
);
1628 else if ((r
= OutputRegisterNumber(src
->Register
)) >= 0) {
1629 _mesa_printf("o[%s]", OutputRegisters
[r
]);
1631 else if ((r
= InputRegisterNumber(src
->Register
)) >= 0) {
1632 _mesa_printf("f[%s]", InputRegisters
[r
]);
1634 else if ((r
= ProgramRegisterNumber(src
->Register
)) >= 0) {
1635 _mesa_printf("p[%d]", r
);
1637 else if ((r
= HalfTempRegisterNumber(src
->Register
)) >= 0) {
1638 _mesa_printf("H%d", r
);
1640 else if ((r
= TempRegisterNumber(src
->Register
)) >= 0) {
1641 _mesa_printf("R%d", r
);
1643 else if ((r
= DummyRegisterNumber(src
->Register
)) >= 0) {
1644 _mesa_printf("%cC", "HR"[r
]);
1647 _mesa_problem(NULL
, "Invalid fragment register %d", src
->Register
);
1650 if (src
->Swizzle
[0] == src
->Swizzle
[1] &&
1651 src
->Swizzle
[0] == src
->Swizzle
[2] &&
1652 src
->Swizzle
[0] == src
->Swizzle
[3]) {
1653 _mesa_printf(".%c", comps
[src
->Swizzle
[0]]);
1655 else if (src
->Swizzle
[0] != 0 ||
1656 src
->Swizzle
[1] != 1 ||
1657 src
->Swizzle
[2] != 2 ||
1658 src
->Swizzle
[3] != 3) {
1659 _mesa_printf(".%c%c%c%c",
1660 comps
[src
->Swizzle
[0]],
1661 comps
[src
->Swizzle
[1]],
1662 comps
[src
->Swizzle
[2]],
1663 comps
[src
->Swizzle
[3]]);
1671 PrintTextureSrc(const struct fp_instruction
*inst
)
1673 _mesa_printf("TEX%d, ", inst
->TexSrcUnit
);
1674 switch (inst
->TexSrcBit
) {
1675 case TEXTURE_1D_BIT
:
1678 case TEXTURE_2D_BIT
:
1681 case TEXTURE_3D_BIT
:
1684 case TEXTURE_RECT_BIT
:
1685 _mesa_printf("RECT");
1687 case TEXTURE_CUBE_BIT
:
1688 _mesa_printf("CUBE");
1691 _mesa_problem(NULL
, "Invalid textue target in PrintTextureSrc");
1696 PrintCondCode(const struct fp_dst_register
*dst
)
1698 static const char *comps
= "xyzw";
1699 static const char *ccString
[] = {
1700 "??", "GT", "EQ", "LT", "UN", "GE", "LE", "NE", "TR", "FL", "??"
1703 _mesa_printf("%s", ccString
[dst
->CondMask
]);
1704 if (dst
->CondSwizzle
[0] == dst
->CondSwizzle
[1] &&
1705 dst
->CondSwizzle
[0] == dst
->CondSwizzle
[2] &&
1706 dst
->CondSwizzle
[0] == dst
->CondSwizzle
[3]) {
1707 _mesa_printf(".%c", comps
[dst
->CondSwizzle
[0]]);
1709 else if (dst
->CondSwizzle
[0] != 0 ||
1710 dst
->CondSwizzle
[1] != 1 ||
1711 dst
->CondSwizzle
[2] != 2 ||
1712 dst
->CondSwizzle
[3] != 3) {
1713 _mesa_printf(".%c%c%c%c",
1714 comps
[dst
->CondSwizzle
[0]],
1715 comps
[dst
->CondSwizzle
[1]],
1716 comps
[dst
->CondSwizzle
[2]],
1717 comps
[dst
->CondSwizzle
[3]]);
1723 PrintDstReg(const struct fp_dst_register
*dst
)
1725 GLint w
= dst
->WriteMask
[0] + dst
->WriteMask
[1]
1726 + dst
->WriteMask
[2] + dst
->WriteMask
[3];
1729 if ((r
= OutputRegisterNumber(dst
->Register
)) >= 0) {
1730 _mesa_printf("o[%s]", OutputRegisters
[r
]);
1732 else if ((r
= HalfTempRegisterNumber(dst
->Register
)) >= 0) {
1733 _mesa_printf("H%d", r
);
1735 else if ((r
= TempRegisterNumber(dst
->Register
)) >= 0) {
1736 _mesa_printf("R%d", r
);
1738 else if ((r
= ProgramRegisterNumber(dst
->Register
)) >= 0) {
1739 _mesa_printf("p[%d]", r
);
1741 else if ((r
= DummyRegisterNumber(dst
->Register
)) >= 0) {
1742 _mesa_printf("%cC", "HR"[r
]);
1745 _mesa_printf("???");
1748 if (w
!= 0 && w
!= 4) {
1750 if (dst
->WriteMask
[0])
1752 if (dst
->WriteMask
[1])
1754 if (dst
->WriteMask
[2])
1756 if (dst
->WriteMask
[3])
1760 if (dst
->CondMask
!= COND_TR
||
1761 dst
->CondSwizzle
[0] != 0 ||
1762 dst
->CondSwizzle
[1] != 1 ||
1763 dst
->CondSwizzle
[2] != 2 ||
1764 dst
->CondSwizzle
[3] != 3) {
1773 * Print (unparse) the given vertex program. Just for debugging.
1776 _mesa_print_nv_fragment_program(const struct fragment_program
*program
)
1778 const struct fp_instruction
*inst
;
1780 for (inst
= program
->Instructions
; inst
->Opcode
!= FP_OPCODE_END
; inst
++) {
1782 for (i
= 0; Instructions
[i
].name
; i
++) {
1783 if (inst
->Opcode
== Instructions
[i
].opcode
) {
1784 /* print instruction name */
1785 _mesa_printf("%s", Instructions
[i
].name
);
1786 if (inst
->Precision
== FLOAT16
)
1788 else if (inst
->Precision
== FIXED12
)
1790 if (inst
->UpdateCondRegister
)
1793 _mesa_printf("_SAT");
1796 if (Instructions
[i
].inputs
== INPUT_CC
) {
1797 PrintCondCode(&inst
->DstReg
);
1799 else if (Instructions
[i
].outputs
== OUTPUT_V
||
1800 Instructions
[i
].outputs
== OUTPUT_S
) {
1801 /* print dest register */
1802 PrintDstReg(&inst
->DstReg
);
1806 /* print source register(s) */
1807 if (Instructions
[i
].inputs
== INPUT_1V
||
1808 Instructions
[i
].inputs
== INPUT_1S
) {
1809 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1811 else if (Instructions
[i
].inputs
== INPUT_2V
||
1812 Instructions
[i
].inputs
== INPUT_2S
) {
1813 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1815 PrintSrcReg(program
, &inst
->SrcReg
[1]);
1817 else if (Instructions
[i
].inputs
== INPUT_3V
) {
1818 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1820 PrintSrcReg(program
, &inst
->SrcReg
[1]);
1822 PrintSrcReg(program
, &inst
->SrcReg
[2]);
1824 else if (Instructions
[i
].inputs
== INPUT_1V_T
) {
1825 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1827 PrintTextureSrc(inst
);
1829 else if (Instructions
[i
].inputs
== INPUT_3V_T
) {
1830 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1832 PrintSrcReg(program
, &inst
->SrcReg
[1]);
1834 PrintSrcReg(program
, &inst
->SrcReg
[2]);
1836 PrintTextureSrc(inst
);
1838 _mesa_printf(";\n");
1842 if (!Instructions
[i
].name
) {
1843 _mesa_printf("Invalid opcode %d\n", inst
->Opcode
);
1846 _mesa_printf("END\n");