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 * 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 /* IRIX defines some of these */
62 /* Optional suffixes */
63 #define _R FLOAT32 /* float */
64 #define _H FLOAT16 /* half-float */
65 #define _X FIXED12 /* fixed */
66 #define _C 0x08 /* set cond codes */
67 #define _S 0x10 /* saturate, clamp result to [0,1] */
69 struct instruction_pattern
{
71 enum fp_opcode opcode
;
77 static const struct instruction_pattern Instructions
[] = {
78 { "ADD", FP_OPCODE_ADD
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
79 { "COS", FP_OPCODE_COS
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
80 { "DDX", FP_OPCODE_DDX
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
81 { "DDY", FP_OPCODE_DDY
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
82 { "DP3", FP_OPCODE_DP3
, INPUT_2V
, OUTPUT_S
, _R
| _H
| _X
| _C
| _S
},
83 { "DP4", FP_OPCODE_DP4
, INPUT_2V
, OUTPUT_S
, _R
| _H
| _X
| _C
| _S
},
84 { "DST", FP_OPCODE_DP4
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
85 { "EX2", FP_OPCODE_DP4
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
86 { "FLR", FP_OPCODE_FLR
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
87 { "FRC", FP_OPCODE_FRC
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
88 { "KIL", FP_OPCODE_KIL
, INPUT_CC
, OUTPUT_NONE
, 0 },
89 { "LG2", FP_OPCODE_LG2
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
90 { "LIT", FP_OPCODE_LIT
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
91 { "LRP", FP_OPCODE_LRP
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
92 { "MAD", FP_OPCODE_MAD
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
93 { "MAX", FP_OPCODE_MAX
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
94 { "MIN", FP_OPCODE_MIN
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
95 { "MOV", FP_OPCODE_MOV
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
96 { "MUL", FP_OPCODE_MUL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
97 { "PK2H", FP_OPCODE_PK2H
, INPUT_1V
, OUTPUT_S
, 0 },
98 { "PK2US", FP_OPCODE_PK2US
, INPUT_1V
, OUTPUT_S
, 0 },
99 { "PK4B", FP_OPCODE_PK4B
, INPUT_1V
, OUTPUT_S
, 0 },
100 { "PK4UB", FP_OPCODE_PK4UB
, INPUT_1V
, OUTPUT_S
, 0 },
101 { "POW", FP_OPCODE_POW
, INPUT_2S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
102 { "RCP", FP_OPCODE_RCP
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
103 { "RFL", FP_OPCODE_RFL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
104 { "RSQ", FP_OPCODE_RSQ
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
105 { "SEQ", FP_OPCODE_SEQ
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
106 { "SFL", FP_OPCODE_SFL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
107 { "SGE", FP_OPCODE_SGE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
108 { "SGT", FP_OPCODE_SGT
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
109 { "SIN", FP_OPCODE_SIN
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
110 { "SLE", FP_OPCODE_SLE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
111 { "SLT", FP_OPCODE_SLT
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
112 { "SNE", FP_OPCODE_SNE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
113 { "STR", FP_OPCODE_STR
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
114 { "SUB", FP_OPCODE_SUB
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
115 { "TEX", FP_OPCODE_TEX
, INPUT_1V_T
, OUTPUT_V
, _C
| _S
},
116 { "TXD", FP_OPCODE_TXD
, INPUT_3V_T
, OUTPUT_V
, _C
| _S
},
117 { "TXP", FP_OPCODE_TXP
, INPUT_1V_T
, OUTPUT_V
, _C
| _S
},
118 { "UP2H", FP_OPCODE_UP2H
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
119 { "UP2US", FP_OPCODE_UP2US
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
120 { "UP4B", FP_OPCODE_UP4B
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
121 { "UP4UB", FP_OPCODE_UP4UB
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
122 { "X2D", FP_OPCODE_X2D
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
123 { NULL
, (enum fp_opcode
) -1, 0, 0, 0 }
128 * Information needed or computed during parsing.
129 * Remember, we can't modify the target program object until we've
130 * _successfully_ parsed the program text.
134 const GLubyte
*start
; /* start of program string */
135 const GLubyte
*pos
; /* current position */
136 const GLubyte
*curLine
;
137 struct fragment_program
*program
; /* current program */
139 GLuint numParameters
;
140 struct program_parameter
*parameters
; /* DECLARE */
143 struct program_parameter
*constants
; /* DEFINE */
145 GLuint numInst
; /* number of instructions parsed */
146 GLuint inputsRead
; /* bitmask of input registers used */
147 GLuint outputsWritten
; /* bitmask of 1 << FRAG_OUTPUT_* bits */
148 GLuint texturesUsed
[MAX_TEXTURE_IMAGE_UNITS
];
153 * Add a new program parameter (via DEFINE statement)
154 * \return index of the new entry in the parameter list
157 add_parameter(struct parse_state
*parseState
,
158 const char *name
, const GLfloat values
[4], GLboolean constant
)
160 const GLuint n
= parseState
->numParameters
;
162 parseState
->parameters
= _mesa_realloc(parseState
->parameters
,
163 n
* sizeof(struct program_parameter
),
164 (n
+ 1) * sizeof(struct program_parameter
));
165 parseState
->numParameters
= n
+ 1;
166 parseState
->parameters
[n
].Name
= _mesa_strdup(name
);
167 COPY_4V(parseState
->parameters
[n
].Values
, values
);
168 parseState
->parameters
[n
].Constant
= constant
;
174 * Add a new unnamed constant to the parameter lists.
175 * \param parseState parsing state
176 * \param values four float values
177 * \return index of the new parameter.
180 add_unnamed_constant(struct parse_state
*parseState
, const GLfloat values
[4])
182 /* generate a new dummy name */
185 _mesa_sprintf(name
, "constant%d", n
);
188 return add_parameter(parseState
, name
, values
, GL_TRUE
);
192 static const GLfloat
*
193 lookup_parameter(struct parse_state
*parseState
, const char *name
)
196 for (i
= 0; i
< parseState
->numParameters
; i
++) {
197 if (_mesa_strcmp(parseState
->parameters
[i
].Name
, name
) == 0)
198 return parseState
->parameters
[i
].Values
;
205 lookup_parameter_index(struct parse_state
*parseState
, const char *name
)
208 for (i
= 0; i
< parseState
->numParameters
; i
++) {
209 if (_mesa_strcmp(parseState
->parameters
[i
].Name
, name
) == 0)
217 * Called whenever we find an error during parsing.
220 record_error(struct parse_state
*parseState
, const char *msg
, int lineNo
)
224 const GLubyte
*lineStr
;
225 lineStr
= _mesa_find_line_column(parseState
->start
,
226 parseState
->pos
, &line
, &column
);
227 _mesa_debug(parseState
->ctx
,
228 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
229 lineNo
, line
, column
, (char *) lineStr
, msg
);
230 _mesa_free((void *) lineStr
);
235 /* Check that no error was already recorded. Only record the first one. */
236 if (parseState
->ctx
->Program
.ErrorString
[0] == 0) {
237 _mesa_set_program_error(parseState
->ctx
,
238 parseState
->pos
- parseState
->start
,
244 #define RETURN_ERROR \
246 record_error(parseState, "Unexpected end of input.", __LINE__); \
250 #define RETURN_ERROR1(msg) \
252 record_error(parseState, msg, __LINE__); \
256 #define RETURN_ERROR2(msg1, msg2) \
259 _mesa_sprintf(err, "%s %s", msg1, msg2); \
260 record_error(parseState, err, __LINE__); \
268 * Search a list of instruction structures for a match.
270 static struct instruction_pattern
271 MatchInstruction(const GLubyte
*token
)
273 const struct instruction_pattern
*inst
;
274 struct instruction_pattern result
;
276 for (inst
= Instructions
; inst
->name
; inst
++) {
277 if (_mesa_strncmp((const char *) token
, inst
->name
, 3) == 0) {
283 if (token
[i
] == 'R') {
284 result
.suffixes
|= _R
;
287 else if (token
[i
] == 'H') {
288 result
.suffixes
|= _H
;
291 else if (token
[i
] == 'X') {
292 result
.suffixes
|= _X
;
295 if (token
[i
] == 'C') {
296 result
.suffixes
|= _C
;
299 if (token
[i
] == '_' && token
[i
+1] == 'S' &&
300 token
[i
+2] == 'A' && token
[i
+3] == 'T') {
301 result
.suffixes
|= _S
;
306 result
.opcode
= (enum fp_opcode
) -1;
313 /**********************************************************************/
316 static GLboolean
IsLetter(GLubyte b
)
318 return (b
>= 'a' && b
<= 'z') ||
319 (b
>= 'A' && b
<= 'Z') ||
325 static GLboolean
IsDigit(GLubyte b
)
327 return b
>= '0' && b
<= '9';
331 static GLboolean
IsWhitespace(GLubyte b
)
333 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
338 * Starting at 'str' find the next token. A token can be an integer,
339 * an identifier or punctuation symbol.
340 * \return <= 0 we found an error, else, return number of characters parsed.
343 GetToken(struct parse_state
*parseState
, GLubyte
*token
)
345 const GLubyte
*str
= parseState
->pos
;
350 /* skip whitespace and comments */
351 while (str
[i
] && (IsWhitespace(str
[i
]) || str
[i
] == '#')) {
354 while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
357 if (str
[i
] == '\n' || str
[i
] == '\r')
358 parseState
->curLine
= str
+ i
+ 1;
361 /* skip whitespace */
362 if (str
[i
] == '\n' || str
[i
] == '\r')
363 parseState
->curLine
= str
+ i
+ 1;
371 /* try matching an integer */
372 while (str
[i
] && IsDigit(str
[i
])) {
373 token
[j
++] = str
[i
++];
375 if (j
> 0 || !str
[i
]) {
380 /* try matching an identifier */
381 if (IsLetter(str
[i
])) {
382 while (str
[i
] && (IsLetter(str
[i
]) || IsDigit(str
[i
]))) {
383 token
[j
++] = str
[i
++];
389 /* punctuation character */
403 * Get next token from input stream and increment stream pointer past token.
406 Parse_Token(struct parse_state
*parseState
, GLubyte
*token
)
409 i
= GetToken(parseState
, token
);
411 parseState
->pos
+= (-i
);
414 parseState
->pos
+= i
;
420 * Get next token from input stream but don't increment stream pointer.
423 Peek_Token(struct parse_state
*parseState
, GLubyte
*token
)
426 i
= GetToken(parseState
, token
);
428 parseState
->pos
+= (-i
);
431 len
= _mesa_strlen((const char *) token
);
432 parseState
->pos
+= (i
- len
);
437 /**********************************************************************/
439 static const char *InputRegisters
[MAX_NV_FRAGMENT_PROGRAM_INPUTS
+ 1] = {
440 "WPOS", "COL0", "COL1", "FOGC",
441 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
444 static const char *OutputRegisters
[MAX_NV_FRAGMENT_PROGRAM_OUTPUTS
+ 1] = {
446 /* These are only allows for register combiners */
448 "TEX0", "TEX1", "TEX2", "TEX3",
456 /**********************************************************************/
459 * Try to match 'pattern' as the next token after any whitespace/comments.
462 Parse_String(struct parse_state
*parseState
, const char *pattern
)
467 /* skip whitespace and comments */
468 while (IsWhitespace(*parseState
->pos
) || *parseState
->pos
== '#') {
469 if (*parseState
->pos
== '#') {
470 while (*parseState
->pos
&& (*parseState
->pos
!= '\n' && *parseState
->pos
!= '\r')) {
471 parseState
->pos
+= 1;
473 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
474 parseState
->curLine
= parseState
->pos
+ 1;
477 /* skip whitespace */
478 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
479 parseState
->curLine
= parseState
->pos
+ 1;
480 parseState
->pos
+= 1;
484 /* Try to match the pattern */
486 for (i
= 0; pattern
[i
]; i
++) {
487 if (*m
!= (GLubyte
) pattern
[i
])
493 return GL_TRUE
; /* success */
498 Parse_Identifier(struct parse_state
*parseState
, GLubyte
*ident
)
500 if (!Parse_Token(parseState
, ident
))
502 if (IsLetter(ident
[0]))
505 RETURN_ERROR1("Expected an identfier");
510 * Parse a floating point constant, or a defined symbol name.
512 * Output: number[0 .. 3] will get the value.
515 Parse_ScalarConstant(struct parse_state
*parseState
, GLfloat
*number
)
519 *number
= (GLfloat
) _mesa_strtod((const char *) parseState
->pos
, &end
);
521 if (end
&& end
> (char *) parseState
->pos
) {
523 parseState
->pos
= (GLubyte
*) end
;
530 /* should be an identifier */
532 const GLfloat
*constant
;
533 if (!Parse_Identifier(parseState
, ident
))
534 RETURN_ERROR1("Expected an identifier");
535 constant
= lookup_parameter(parseState
, (const char *) ident
);
536 /* XXX Check that it's a constant and not a parameter */
538 RETURN_ERROR1("Undefined symbol");
541 COPY_4V(number
, constant
);
550 * Parse a vector constant, one of:
553 * { float, float, float }
554 * { float, float, float, float }
557 Parse_VectorConstant(struct parse_state
*parseState
, GLfloat
*vec
)
559 /* "{" was already consumed */
561 ASSIGN_4V(vec
, 0.0, 0.0, 0.0, 1.0);
563 if (!Parse_ScalarConstant(parseState
, vec
+0)) /* X */
566 if (Parse_String(parseState
, "}")) {
570 if (!Parse_String(parseState
, ","))
571 RETURN_ERROR1("Expected comma in vector constant");
573 if (!Parse_ScalarConstant(parseState
, vec
+1)) /* Y */
576 if (Parse_String(parseState
, "}")) {
580 if (!Parse_String(parseState
, ","))
581 RETURN_ERROR1("Expected comma in vector constant");
583 if (!Parse_ScalarConstant(parseState
, vec
+2)) /* Z */
586 if (Parse_String(parseState
, "}")) {
590 if (!Parse_String(parseState
, ","))
591 RETURN_ERROR1("Expected comma in vector constant");
593 if (!Parse_ScalarConstant(parseState
, vec
+3)) /* W */
596 if (!Parse_String(parseState
, "}"))
597 RETURN_ERROR1("Expected closing brace in vector constant");
604 * Parse <number>, <varname> or {a, b, c, d}.
605 * Return number of values in the vector or scalar, or zero if parse error.
608 Parse_VectorOrScalarConstant(struct parse_state
*parseState
, GLfloat
*vec
)
610 if (Parse_String(parseState
, "{")) {
611 return Parse_VectorConstant(parseState
, vec
);
614 GLboolean b
= Parse_ScalarConstant(parseState
, vec
);
616 vec
[1] = vec
[2] = vec
[3] = vec
[0];
624 * Parse a texture image source:
625 * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
628 Parse_TextureImageId(struct parse_state
*parseState
,
629 GLubyte
*texUnit
, GLubyte
*texTargetBit
)
631 GLubyte imageSrc
[100];
634 if (!Parse_Token(parseState
, imageSrc
))
637 if (imageSrc
[0] != 'T' ||
638 imageSrc
[1] != 'E' ||
639 imageSrc
[2] != 'X') {
640 RETURN_ERROR1("Expected TEX# source");
642 unit
= _mesa_atoi((const char *) imageSrc
+ 3);
643 if ((unit
< 0 || unit
> MAX_TEXTURE_IMAGE_UNITS
) ||
644 (unit
== 0 && (imageSrc
[3] != '0' || imageSrc
[4] != 0))) {
645 RETURN_ERROR1("Invalied TEX# source index");
649 if (!Parse_String(parseState
, ","))
650 RETURN_ERROR1("Expected ,");
652 if (Parse_String(parseState
, "1D")) {
653 *texTargetBit
= TEXTURE_1D_BIT
;
655 else if (Parse_String(parseState
, "2D")) {
656 *texTargetBit
= TEXTURE_2D_BIT
;
658 else if (Parse_String(parseState
, "3D")) {
659 *texTargetBit
= TEXTURE_3D_BIT
;
661 else if (Parse_String(parseState
, "CUBE")) {
662 *texTargetBit
= TEXTURE_CUBE_BIT
;
664 else if (Parse_String(parseState
, "RECT")) {
665 *texTargetBit
= TEXTURE_RECT_BIT
;
668 RETURN_ERROR1("Invalid texture target token");
671 /* update record of referenced texture units */
672 parseState
->texturesUsed
[*texUnit
] |= *texTargetBit
;
673 if (_mesa_bitcount(parseState
->texturesUsed
[*texUnit
]) > 1) {
674 RETURN_ERROR1("Only one texture target can be used per texture unit.");
682 * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
683 * like .wxyz, .xxyy, etc and return the swizzle indexes.
686 Parse_SwizzleSuffix(const GLubyte
*token
, GLuint swizzle
[4])
689 /* single letter swizzle (scalar) */
691 ASSIGN_4V(swizzle
, 0, 0, 0, 0);
692 else if (token
[0] == 'y')
693 ASSIGN_4V(swizzle
, 1, 1, 1, 1);
694 else if (token
[0] == 'z')
695 ASSIGN_4V(swizzle
, 2, 2, 2, 2);
696 else if (token
[0] == 'w')
697 ASSIGN_4V(swizzle
, 3, 3, 3, 3);
702 /* 4-component swizzle (vector) */
704 for (k
= 0; token
[k
] && k
< 4; k
++) {
707 else if (token
[k
] == 'y')
709 else if (token
[k
] == 'z')
711 else if (token
[k
] == 'w')
724 Parse_CondCodeMask(struct parse_state
*parseState
,
725 struct fp_dst_register
*dstReg
)
727 if (Parse_String(parseState
, "EQ"))
728 dstReg
->CondMask
= COND_EQ
;
729 else if (Parse_String(parseState
, "GE"))
730 dstReg
->CondMask
= COND_GE
;
731 else if (Parse_String(parseState
, "GT"))
732 dstReg
->CondMask
= COND_GT
;
733 else if (Parse_String(parseState
, "LE"))
734 dstReg
->CondMask
= COND_LE
;
735 else if (Parse_String(parseState
, "LT"))
736 dstReg
->CondMask
= COND_LT
;
737 else if (Parse_String(parseState
, "NE"))
738 dstReg
->CondMask
= COND_NE
;
739 else if (Parse_String(parseState
, "TR"))
740 dstReg
->CondMask
= COND_TR
;
741 else if (Parse_String(parseState
, "FL"))
742 dstReg
->CondMask
= COND_FL
;
744 RETURN_ERROR1("Invalid condition code mask");
746 /* look for optional .xyzw swizzle */
747 if (Parse_String(parseState
, ".")) {
749 if (!Parse_Token(parseState
, token
)) /* get xyzw suffix */
752 if (!Parse_SwizzleSuffix(token
, dstReg
->CondSwizzle
))
753 RETURN_ERROR1("Invalid swizzle suffix");
761 * Parse a temporary register: Rnn or Hnn
764 Parse_TempReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
768 /* Should be 'R##' or 'H##' */
769 if (!Parse_Token(parseState
, token
))
771 if (token
[0] != 'R' && token
[0] != 'H')
772 RETURN_ERROR1("Expected R## or H##");
774 if (IsDigit(token
[1])) {
775 GLint reg
= _mesa_atoi((const char *) (token
+ 1));
778 if (reg
>= MAX_NV_FRAGMENT_PROGRAM_TEMPS
)
779 RETURN_ERROR1("Invalid temporary register name");
783 RETURN_ERROR1("Invalid temporary register name");
791 * Parse a write-only dummy register: RC or HC.
794 Parse_DummyReg(struct parse_state
*parseState
, GLint
*regNum
)
796 if (Parse_String(parseState
, "RC")) {
799 else if (Parse_String(parseState
, "HC")) {
803 RETURN_ERROR1("Invalid write-only register name");
811 * Parse a program local parameter register "p[##]"
814 Parse_ProgramParamReg(struct parse_state
*parseState
, GLint
*regNum
)
818 if (!Parse_String(parseState
, "p["))
819 RETURN_ERROR1("Expected p[");
821 if (!Parse_Token(parseState
, token
))
824 if (IsDigit(token
[0])) {
825 /* a numbered program parameter register */
826 GLint reg
= _mesa_atoi((const char *) token
);
827 if (reg
>= MAX_NV_FRAGMENT_PROGRAM_PARAMS
)
828 RETURN_ERROR1("Invalid constant program number");
835 if (!Parse_String(parseState
, "]"))
836 RETURN_ERROR1("Expected ]");
843 * Parse f[name] - fragment input register
846 Parse_FragReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
852 if (!Parse_String(parseState
, "f["))
853 RETURN_ERROR1("Expected f[");
855 /* get <name> and look for match */
856 if (!Parse_Token(parseState
, token
)) {
859 for (j
= 0; InputRegisters
[j
]; j
++) {
860 if (_mesa_strcmp((const char *) token
, InputRegisters
[j
]) == 0) {
862 parseState
->inputsRead
|= (1 << j
);
866 if (!InputRegisters
[j
]) {
867 /* unknown input register label */
868 RETURN_ERROR2("Invalid register name", token
);
872 if (!Parse_String(parseState
, "]"))
873 RETURN_ERROR1("Expected ]");
880 Parse_OutputReg(struct parse_state
*parseState
, GLint
*outputRegNum
)
886 if (!Parse_String(parseState
, "o["))
887 RETURN_ERROR1("Expected o[");
889 /* Get output reg name */
890 if (!Parse_Token(parseState
, token
))
893 /* try to match an output register name */
894 for (j
= 0; OutputRegisters
[j
]; j
++) {
895 if (_mesa_strcmp((const char *) token
, OutputRegisters
[j
]) == 0) {
896 static GLuint bothColors
= (1 << FRAG_OUTPUT_COLR
) | (1 << FRAG_OUTPUT_COLH
);
898 parseState
->outputsWritten
|= (1 << j
);
899 if ((parseState
->outputsWritten
& bothColors
) == bothColors
) {
900 RETURN_ERROR1("Illegal to write to both o[COLR] and o[COLH]");
905 if (!OutputRegisters
[j
])
906 RETURN_ERROR1("Invalid output register name");
909 if (!Parse_String(parseState
, "]"))
910 RETURN_ERROR1("Expected ]");
917 Parse_MaskedDstReg(struct parse_state
*parseState
,
918 struct fp_dst_register
*dstReg
)
922 /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
923 if (!Peek_Token(parseState
, token
))
926 if (_mesa_strcmp((const char *) token
, "RC") == 0 ||
927 _mesa_strcmp((const char *) token
, "HC") == 0) {
928 /* a write-only register */
929 dstReg
->File
= PROGRAM_WRITE_ONLY
;
930 if (!Parse_DummyReg(parseState
, &dstReg
->Index
))
933 else if (token
[0] == 'R' || token
[0] == 'H') {
934 /* a temporary register */
935 dstReg
->File
= PROGRAM_TEMPORARY
;
936 if (!Parse_TempReg(parseState
, &dstReg
->Index
))
939 else if (token
[0] == 'o') {
940 /* an output register */
941 dstReg
->File
= PROGRAM_OUTPUT
;
942 if (!Parse_OutputReg(parseState
, &dstReg
->Index
))
946 RETURN_ERROR1("Invalid destination register name");
949 /* Parse optional write mask */
950 if (Parse_String(parseState
, ".")) {
954 if (!Parse_Token(parseState
, token
)) /* get xyzw writemask */
957 dstReg
->WriteMask
[0] = GL_FALSE
;
958 dstReg
->WriteMask
[1] = GL_FALSE
;
959 dstReg
->WriteMask
[2] = GL_FALSE
;
960 dstReg
->WriteMask
[3] = GL_FALSE
;
962 if (token
[k
] == 'x') {
963 dstReg
->WriteMask
[0] = GL_TRUE
;
966 if (token
[k
] == 'y') {
967 dstReg
->WriteMask
[1] = GL_TRUE
;
970 if (token
[k
] == 'z') {
971 dstReg
->WriteMask
[2] = GL_TRUE
;
974 if (token
[k
] == 'w') {
975 dstReg
->WriteMask
[3] = GL_TRUE
;
979 RETURN_ERROR1("Invalid writemask character");
984 dstReg
->WriteMask
[0] = GL_TRUE
;
985 dstReg
->WriteMask
[1] = GL_TRUE
;
986 dstReg
->WriteMask
[2] = GL_TRUE
;
987 dstReg
->WriteMask
[3] = GL_TRUE
;
990 /* optional condition code mask */
991 if (Parse_String(parseState
, "(")) {
992 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
993 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
994 if (!Parse_CondCodeMask(parseState
, dstReg
))
997 if (!Parse_String(parseState
, ")")) /* consume ")" */
998 RETURN_ERROR1("Expected )");
1003 /* no cond code mask */
1004 dstReg
->CondMask
= COND_TR
;
1005 dstReg
->CondSwizzle
[0] = 0;
1006 dstReg
->CondSwizzle
[1] = 1;
1007 dstReg
->CondSwizzle
[2] = 2;
1008 dstReg
->CondSwizzle
[3] = 3;
1015 * Parse a vector source (register, constant, etc):
1016 * <vectorSrc> ::= <absVectorSrc>
1018 * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
1021 Parse_VectorSrc(struct parse_state
*parseState
,
1022 struct fp_src_register
*srcReg
)
1024 GLfloat sign
= 1.0F
;
1028 * First, take care of +/- and absolute value stuff.
1030 if (Parse_String(parseState
, "-"))
1032 else if (Parse_String(parseState
, "+"))
1035 if (Parse_String(parseState
, "|")) {
1036 srcReg
->Abs
= GL_TRUE
;
1037 srcReg
->NegateAbs
= (sign
< 0.0F
) ? GL_TRUE
: GL_FALSE
;
1039 if (Parse_String(parseState
, "-"))
1040 srcReg
->NegateBase
= GL_TRUE
;
1041 else if (Parse_String(parseState
, "+"))
1042 srcReg
->NegateBase
= GL_FALSE
;
1044 srcReg
->NegateBase
= GL_FALSE
;
1047 srcReg
->Abs
= GL_FALSE
;
1048 srcReg
->NegateAbs
= GL_FALSE
;
1049 srcReg
->NegateBase
= (sign
< 0.0F
) ? GL_TRUE
: GL_FALSE
;
1052 /* This should be the real src vector/register name */
1053 if (!Peek_Token(parseState
, token
))
1056 /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
1057 * literal or vector literal.
1059 if (token
[0] == 'R' || token
[0] == 'H') {
1060 srcReg
->File
= PROGRAM_TEMPORARY
;
1061 if (!Parse_TempReg(parseState
, &srcReg
->Index
))
1064 else if (token
[0] == 'f') {
1065 /* XXX this might be an identier! */
1066 srcReg
->File
= PROGRAM_INPUT
;
1067 if (!Parse_FragReg(parseState
, &srcReg
->Index
))
1070 else if (token
[0] == 'p') {
1071 /* XXX this might be an identier! */
1072 srcReg
->File
= PROGRAM_LOCAL_PARAM
;
1073 if (!Parse_ProgramParamReg(parseState
, &srcReg
->Index
))
1076 else if (IsLetter(token
[0])){
1079 if (!Parse_Identifier(parseState
, ident
))
1081 paramIndex
= lookup_parameter_index(parseState
, (const char *) ident
);
1082 if (paramIndex
< 0) {
1083 RETURN_ERROR2("Undefined constant or parameter: ", ident
);
1085 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1086 srcReg
->Index
= paramIndex
;
1088 else if (IsDigit(token
[0]) || token
[0] == '-' || token
[0] == '+' || token
[0] == '.'){
1089 /* literal scalar constant */
1092 if (!Parse_ScalarConstant(parseState
, values
))
1094 paramIndex
= add_unnamed_constant(parseState
, values
);
1095 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1096 srcReg
->Index
= paramIndex
;
1098 else if (token
[0] == '{'){
1099 /* literal vector constant */
1102 (void) Parse_String(parseState
, "{");
1103 if (!Parse_VectorConstant(parseState
, values
))
1105 paramIndex
= add_unnamed_constant(parseState
, values
);
1106 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1107 srcReg
->Index
= paramIndex
;
1110 RETURN_ERROR2("Invalid source register name", token
);
1113 /* init swizzle fields */
1114 srcReg
->Swizzle
[0] = 0;
1115 srcReg
->Swizzle
[1] = 1;
1116 srcReg
->Swizzle
[2] = 2;
1117 srcReg
->Swizzle
[3] = 3;
1119 /* Look for optional swizzle suffix */
1120 if (Parse_String(parseState
, ".")) {
1121 if (!Parse_Token(parseState
, token
))
1124 if (!Parse_SwizzleSuffix(token
, srcReg
->Swizzle
))
1125 RETURN_ERROR1("Invalid swizzle suffix");
1128 /* Finish absolute value */
1129 if (srcReg
->Abs
&& !Parse_String(parseState
, "|")) {
1130 RETURN_ERROR1("Expected |");
1138 Parse_ScalarSrcReg(struct parse_state
*parseState
,
1139 struct fp_src_register
*srcReg
)
1142 GLfloat sign
= 1.0F
;
1143 GLboolean needSuffix
= GL_TRUE
;
1146 * First, take care of +/- and absolute value stuff.
1148 if (Parse_String(parseState
, "-"))
1150 else if (Parse_String(parseState
, "+"))
1153 if (Parse_String(parseState
, "|")) {
1154 srcReg
->Abs
= GL_TRUE
;
1155 srcReg
->NegateAbs
= (sign
< 0.0F
) ? GL_TRUE
: GL_FALSE
;
1157 if (Parse_String(parseState
, "-"))
1158 srcReg
->NegateBase
= GL_TRUE
;
1159 else if (Parse_String(parseState
, "+"))
1160 srcReg
->NegateBase
= GL_FALSE
;
1162 srcReg
->NegateBase
= GL_FALSE
;
1165 srcReg
->Abs
= GL_FALSE
;
1166 srcReg
->NegateAbs
= GL_FALSE
;
1167 srcReg
->NegateBase
= (sign
< 0.0F
) ? GL_TRUE
: GL_FALSE
;
1170 if (!Peek_Token(parseState
, token
))
1173 /* Src reg can be R<n>, H<n> or a named fragment attrib */
1174 if (token
[0] == 'R' || token
[0] == 'H') {
1175 srcReg
->File
= PROGRAM_TEMPORARY
;
1176 if (!Parse_TempReg(parseState
, &srcReg
->Index
))
1179 else if (token
[0] == 'f') {
1180 srcReg
->File
= PROGRAM_INPUT
;
1181 if (!Parse_FragReg(parseState
, &srcReg
->Index
))
1184 else if (token
[0] == '{') {
1185 /* vector literal */
1188 (void) Parse_String(parseState
, "{");
1189 if (!Parse_VectorConstant(parseState
, values
))
1191 paramIndex
= add_unnamed_constant(parseState
, values
);
1192 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1193 srcReg
->Index
= paramIndex
;
1195 else if (IsDigit(token
[0])) {
1196 /* scalar literal */
1199 if (!Parse_ScalarConstant(parseState
, values
))
1201 paramIndex
= add_unnamed_constant(parseState
, values
);
1202 srcReg
->Index
= paramIndex
;
1203 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1204 needSuffix
= GL_FALSE
;
1207 RETURN_ERROR2("Invalid scalar source argument", token
);
1211 /* parse .[xyzw] suffix */
1212 if (!Parse_String(parseState
, "."))
1213 RETURN_ERROR1("Expected .");
1215 if (!Parse_Token(parseState
, token
))
1218 if (token
[0] == 'x' && token
[1] == 0) {
1219 srcReg
->Swizzle
[0] = 0;
1221 else if (token
[0] == 'y' && token
[1] == 0) {
1222 srcReg
->Swizzle
[0] = 1;
1224 else if (token
[0] == 'z' && token
[1] == 0) {
1225 srcReg
->Swizzle
[0] = 2;
1227 else if (token
[0] == 'w' && token
[1] == 0) {
1228 srcReg
->Swizzle
[0] = 3;
1231 RETURN_ERROR1("Invalid scalar source suffix");
1235 srcReg
->Swizzle
[0] = 0;
1237 srcReg
->Swizzle
[1] = srcReg
->Swizzle
[2] = srcReg
->Swizzle
[3] = 0;
1239 /* Finish absolute value */
1240 if (srcReg
->Abs
&& !Parse_String(parseState
, "|")) {
1241 RETURN_ERROR1("Expected |");
1250 Parse_InstructionSequence(struct parse_state
*parseState
,
1251 struct fp_instruction program
[])
1254 struct fp_instruction
*inst
= program
+ parseState
->numInst
;
1255 struct instruction_pattern instMatch
;
1258 /* Initialize the instruction */
1259 inst
->SrcReg
[0].File
= (enum register_file
) -1;
1260 inst
->SrcReg
[1].File
= (enum register_file
) -1;
1261 inst
->SrcReg
[2].File
= (enum register_file
) -1;
1262 inst
->DstReg
.File
= (enum register_file
) -1;
1263 inst
->DstReg
.CondSwizzle
[0] = 0;
1264 inst
->DstReg
.CondSwizzle
[1] = 1;
1265 inst
->DstReg
.CondSwizzle
[2] = 2;
1266 inst
->DstReg
.CondSwizzle
[3] = 3;
1268 /* special instructions */
1269 if (Parse_String(parseState
, "DEFINE")) {
1271 GLfloat value
[7]; /* yes, 7 to be safe */
1272 if (!Parse_Identifier(parseState
, id
))
1274 /* XXX make sure id is not a reserved identifer, like R9 */
1275 if (!Parse_String(parseState
, "="))
1276 RETURN_ERROR1("Expected =");
1277 if (!Parse_VectorOrScalarConstant(parseState
, value
))
1279 if (!Parse_String(parseState
, ";"))
1280 RETURN_ERROR1("Expected ;");
1281 if (lookup_parameter(parseState
, (const char *) id
)) {
1282 RETURN_ERROR2(id
, "already defined");
1284 add_parameter(parseState
, (const char *) id
, value
, GL_TRUE
);
1286 else if (Parse_String(parseState
, "DECLARE")) {
1288 GLfloat value
[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */
1289 if (!Parse_Identifier(parseState
, id
))
1291 /* XXX make sure id is not a reserved identifer, like R9 */
1292 if (Parse_String(parseState
, "=")) {
1293 if (!Parse_VectorOrScalarConstant(parseState
, value
))
1296 if (!Parse_String(parseState
, ";"))
1297 RETURN_ERROR1("Expected ;");
1298 if (lookup_parameter(parseState
, (const char *) id
)) {
1299 RETURN_ERROR2(id
, "already declared");
1301 add_parameter(parseState
, (const char *) id
, value
, GL_FALSE
);
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 ASSERT(instMatch
.opcode
== FP_OPCODE_KIL
);
1346 /* This is a little weird, the cond code info is in the dest register */
1347 if (!Parse_CondCodeMask(parseState
, &inst
->DstReg
))
1351 if (instMatch
.inputs
== INPUT_1V
) {
1352 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1355 else if (instMatch
.inputs
== INPUT_2V
) {
1356 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1358 if (!Parse_String(parseState
, ","))
1359 RETURN_ERROR1("Expected ,");
1360 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[1]))
1363 else if (instMatch
.inputs
== INPUT_3V
) {
1364 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1366 if (!Parse_String(parseState
, ","))
1367 RETURN_ERROR1("Expected ,");
1368 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[1]))
1370 if (!Parse_String(parseState
, ","))
1371 RETURN_ERROR1("Expected ,");
1372 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[2]))
1375 else if (instMatch
.inputs
== INPUT_1S
) {
1376 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
1379 else if (instMatch
.inputs
== INPUT_2S
) {
1380 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
1382 if (!Parse_String(parseState
, ","))
1383 RETURN_ERROR1("Expected ,");
1384 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[1]))
1387 else if (instMatch
.inputs
== INPUT_CC
) {
1390 else if (instMatch
.inputs
== INPUT_1V_T
) {
1391 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1393 if (!Parse_String(parseState
, ","))
1394 RETURN_ERROR1("Expected ,");
1395 if (!Parse_TextureImageId(parseState
, &inst
->TexSrcUnit
,
1399 else if (instMatch
.inputs
== INPUT_3V_T
) {
1400 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1402 if (!Parse_String(parseState
, ","))
1403 RETURN_ERROR1("Expected ,");
1404 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[1]))
1406 if (!Parse_String(parseState
, ","))
1407 RETURN_ERROR1("Expected ,");
1408 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[2]))
1410 if (!Parse_String(parseState
, ","))
1411 RETURN_ERROR1("Expected ,");
1412 if (!Parse_TextureImageId(parseState
, &inst
->TexSrcUnit
,
1417 /* end of statement semicolon */
1418 if (!Parse_String(parseState
, ";"))
1419 RETURN_ERROR1("Expected ;");
1421 parseState
->numInst
++;
1423 if (parseState
->numInst
>= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
)
1424 RETURN_ERROR1("Program too long");
1433 * Parse/compile the 'str' returning the compiled 'program'.
1434 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1435 * indicates the position of the error in 'str'.
1438 _mesa_parse_nv_fragment_program(GLcontext
*ctx
, GLenum dstTarget
,
1439 const GLubyte
*str
, GLsizei len
,
1440 struct fragment_program
*program
)
1442 struct parse_state parseState
;
1443 struct fp_instruction instBuffer
[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
];
1444 struct fp_instruction
*newInst
;
1446 GLubyte
*programString
;
1448 /* Make a null-terminated copy of the program string */
1449 programString
= (GLubyte
*) MALLOC(len
+ 1);
1450 if (!programString
) {
1451 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1454 MEMCPY(programString
, str
, len
);
1455 programString
[len
] = 0;
1457 /* Get ready to parse */
1458 _mesa_bzero(&parseState
, sizeof(struct parse_state
));
1459 parseState
.ctx
= ctx
;
1460 parseState
.start
= programString
;
1461 parseState
.program
= program
;
1462 parseState
.numInst
= 0;
1463 parseState
.curLine
= programString
;
1465 /* Reset error state */
1466 _mesa_set_program_error(ctx
, -1, NULL
);
1468 /* check the program header */
1469 if (_mesa_strncmp((const char *) programString
, "!!FP1.0", 7) == 0) {
1470 target
= GL_FRAGMENT_PROGRAM_NV
;
1471 parseState
.pos
= programString
+ 7;
1473 else if (_mesa_strncmp((const char *) programString
, "!!FCP1.0", 8) == 0) {
1474 /* fragment / register combiner program - not supported */
1475 _mesa_set_program_error(ctx
, 0, "Invalid fragment program header");
1476 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1480 /* invalid header */
1481 _mesa_set_program_error(ctx
, 0, "Invalid fragment program header");
1482 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1486 /* make sure target and header match */
1487 if (target
!= dstTarget
) {
1488 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1489 "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1494 if (Parse_InstructionSequence(&parseState
, instBuffer
)) {
1496 /* successful parse! */
1498 if (parseState
.outputsWritten
== 0) {
1499 /* must write at least one output! */
1500 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1501 "Invalid fragment program - no outputs written.");
1505 /* copy the compiled instructions */
1506 assert(parseState
.numInst
<= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
);
1507 newInst
= (struct fp_instruction
*)
1508 MALLOC(parseState
.numInst
* sizeof(struct fp_instruction
));
1510 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1511 return; /* out of memory */
1513 MEMCPY(newInst
, instBuffer
,
1514 parseState
.numInst
* sizeof(struct fp_instruction
));
1516 /* install the program */
1517 program
->Base
.Target
= target
;
1518 if (program
->Base
.String
) {
1519 FREE(program
->Base
.String
);
1521 program
->Base
.String
= programString
;
1522 program
->Base
.Format
= GL_PROGRAM_FORMAT_ASCII_ARB
;
1523 if (program
->Instructions
) {
1524 FREE(program
->Instructions
);
1526 program
->Instructions
= newInst
;
1527 program
->InputsRead
= parseState
.inputsRead
;
1528 program
->OutputsWritten
= parseState
.outputsWritten
;
1529 for (u
= 0; u
< ctx
->Const
.MaxTextureImageUnits
; u
++)
1530 program
->TexturesUsed
[u
] = parseState
.texturesUsed
[u
];
1532 /* save program parameters */
1533 if (program
->Parameters
) {
1535 for (i
= 0; i
< program
->NumParameters
; i
++)
1536 _mesa_free((void *) program
->Parameters
[i
].Name
);
1537 _mesa_free(program
->Parameters
);
1539 program
->NumParameters
= parseState
.numParameters
;
1540 program
->Parameters
= parseState
.parameters
;
1542 /* free program constants */
1543 if (parseState
.constants
) {
1545 for (i
= 0; i
< parseState
.numConstants
; i
++)
1546 _mesa_free((void *) parseState
.constants
[i
].Name
);
1547 _mesa_free(parseState
.constants
);
1551 /* allocate registers for declared program parameters */
1553 _mesa_assign_program_registers(&(program
->SymbolTable
));
1557 _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program
->Base
.Id
);
1558 _mesa_print_nv_fragment_program(program
);
1559 _mesa_printf("----------------------------------\n");
1564 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1565 /* NOTE: _mesa_set_program_error would have been called already */
1571 PrintSrcReg(const struct fragment_program
*program
,
1572 const struct fp_src_register
*src
)
1574 static const char comps
[5] = "xyzw";
1576 if (src
->NegateAbs
) {
1582 if (src
->NegateBase
) {
1585 if (src
->File
== PROGRAM_NAMED_PARAM
) {
1586 if (program
->Parameters
[src
->Index
].Constant
) {
1587 printf("{%g, %g, %g, %g}",
1588 program
->Parameters
[src
->Index
].Values
[0],
1589 program
->Parameters
[src
->Index
].Values
[1],
1590 program
->Parameters
[src
->Index
].Values
[2],
1591 program
->Parameters
[src
->Index
].Values
[3]);
1594 printf("%s", program
->Parameters
[src
->Index
].Name
);
1597 else if (src
->File
== PROGRAM_OUTPUT
) {
1598 _mesa_printf("o[%s]", OutputRegisters
[src
->Index
]);
1600 else if (src
->File
== PROGRAM_INPUT
) {
1601 _mesa_printf("f[%s]", InputRegisters
[src
->Index
]);
1603 else if (src
->File
== PROGRAM_LOCAL_PARAM
) {
1604 _mesa_printf("p[%d]", src
->Index
);
1606 else if (src
->File
== PROGRAM_TEMPORARY
) {
1607 if (src
->Index
>= 32)
1608 _mesa_printf("H%d", src
->Index
);
1610 _mesa_printf("R%d", src
->Index
);
1612 else if (src
->File
== PROGRAM_WRITE_ONLY
) {
1613 _mesa_printf("%cC", "HR"[src
->Index
]);
1616 _mesa_problem(NULL
, "Invalid fragment register %d", src
->Index
);
1619 if (src
->Swizzle
[0] == src
->Swizzle
[1] &&
1620 src
->Swizzle
[0] == src
->Swizzle
[2] &&
1621 src
->Swizzle
[0] == src
->Swizzle
[3]) {
1622 _mesa_printf(".%c", comps
[src
->Swizzle
[0]]);
1624 else if (src
->Swizzle
[0] != 0 ||
1625 src
->Swizzle
[1] != 1 ||
1626 src
->Swizzle
[2] != 2 ||
1627 src
->Swizzle
[3] != 3) {
1628 _mesa_printf(".%c%c%c%c",
1629 comps
[src
->Swizzle
[0]],
1630 comps
[src
->Swizzle
[1]],
1631 comps
[src
->Swizzle
[2]],
1632 comps
[src
->Swizzle
[3]]);
1640 PrintTextureSrc(const struct fp_instruction
*inst
)
1642 _mesa_printf("TEX%d, ", inst
->TexSrcUnit
);
1643 switch (inst
->TexSrcBit
) {
1644 case TEXTURE_1D_BIT
:
1647 case TEXTURE_2D_BIT
:
1650 case TEXTURE_3D_BIT
:
1653 case TEXTURE_RECT_BIT
:
1654 _mesa_printf("RECT");
1656 case TEXTURE_CUBE_BIT
:
1657 _mesa_printf("CUBE");
1660 _mesa_problem(NULL
, "Invalid textue target in PrintTextureSrc");
1665 PrintCondCode(const struct fp_dst_register
*dst
)
1667 static const char *comps
= "xyzw";
1668 static const char *ccString
[] = {
1669 "??", "GT", "EQ", "LT", "UN", "GE", "LE", "NE", "TR", "FL", "??"
1672 _mesa_printf("%s", ccString
[dst
->CondMask
]);
1673 if (dst
->CondSwizzle
[0] == dst
->CondSwizzle
[1] &&
1674 dst
->CondSwizzle
[0] == dst
->CondSwizzle
[2] &&
1675 dst
->CondSwizzle
[0] == dst
->CondSwizzle
[3]) {
1676 _mesa_printf(".%c", comps
[dst
->CondSwizzle
[0]]);
1678 else if (dst
->CondSwizzle
[0] != 0 ||
1679 dst
->CondSwizzle
[1] != 1 ||
1680 dst
->CondSwizzle
[2] != 2 ||
1681 dst
->CondSwizzle
[3] != 3) {
1682 _mesa_printf(".%c%c%c%c",
1683 comps
[dst
->CondSwizzle
[0]],
1684 comps
[dst
->CondSwizzle
[1]],
1685 comps
[dst
->CondSwizzle
[2]],
1686 comps
[dst
->CondSwizzle
[3]]);
1692 PrintDstReg(const struct fp_dst_register
*dst
)
1694 GLint w
= dst
->WriteMask
[0] + dst
->WriteMask
[1]
1695 + dst
->WriteMask
[2] + dst
->WriteMask
[3];
1697 if (dst
->File
== PROGRAM_OUTPUT
) {
1698 _mesa_printf("o[%s]", OutputRegisters
[dst
->Index
]);
1700 else if (dst
->File
== PROGRAM_TEMPORARY
) {
1701 if (dst
->Index
>= 32)
1702 _mesa_printf("H%d", dst
->Index
);
1704 _mesa_printf("R%d", dst
->Index
);
1706 else if (dst
->File
== PROGRAM_LOCAL_PARAM
) {
1707 _mesa_printf("p[%d]", dst
->Index
);
1709 else if (dst
->File
== PROGRAM_WRITE_ONLY
) {
1710 _mesa_printf("%cC", "HR"[dst
->Index
]);
1713 _mesa_printf("???");
1716 if (w
!= 0 && w
!= 4) {
1718 if (dst
->WriteMask
[0])
1720 if (dst
->WriteMask
[1])
1722 if (dst
->WriteMask
[2])
1724 if (dst
->WriteMask
[3])
1728 if (dst
->CondMask
!= COND_TR
||
1729 dst
->CondSwizzle
[0] != 0 ||
1730 dst
->CondSwizzle
[1] != 1 ||
1731 dst
->CondSwizzle
[2] != 2 ||
1732 dst
->CondSwizzle
[3] != 3) {
1741 * Print (unparse) the given vertex program. Just for debugging.
1744 _mesa_print_nv_fragment_program(const struct fragment_program
*program
)
1746 const struct fp_instruction
*inst
;
1748 for (inst
= program
->Instructions
; inst
->Opcode
!= FP_OPCODE_END
; inst
++) {
1750 for (i
= 0; Instructions
[i
].name
; i
++) {
1751 if (inst
->Opcode
== Instructions
[i
].opcode
) {
1752 /* print instruction name */
1753 _mesa_printf("%s", Instructions
[i
].name
);
1754 if (inst
->Precision
== FLOAT16
)
1756 else if (inst
->Precision
== FIXED12
)
1758 if (inst
->UpdateCondRegister
)
1761 _mesa_printf("_SAT");
1764 if (Instructions
[i
].inputs
== INPUT_CC
) {
1765 PrintCondCode(&inst
->DstReg
);
1767 else if (Instructions
[i
].outputs
== OUTPUT_V
||
1768 Instructions
[i
].outputs
== OUTPUT_S
) {
1769 /* print dest register */
1770 PrintDstReg(&inst
->DstReg
);
1774 /* print source register(s) */
1775 if (Instructions
[i
].inputs
== INPUT_1V
||
1776 Instructions
[i
].inputs
== INPUT_1S
) {
1777 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1779 else if (Instructions
[i
].inputs
== INPUT_2V
||
1780 Instructions
[i
].inputs
== INPUT_2S
) {
1781 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1783 PrintSrcReg(program
, &inst
->SrcReg
[1]);
1785 else if (Instructions
[i
].inputs
== INPUT_3V
) {
1786 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1788 PrintSrcReg(program
, &inst
->SrcReg
[1]);
1790 PrintSrcReg(program
, &inst
->SrcReg
[2]);
1792 else if (Instructions
[i
].inputs
== INPUT_1V_T
) {
1793 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1795 PrintTextureSrc(inst
);
1797 else if (Instructions
[i
].inputs
== INPUT_3V_T
) {
1798 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1800 PrintSrcReg(program
, &inst
->SrcReg
[1]);
1802 PrintSrcReg(program
, &inst
->SrcReg
[2]);
1804 PrintTextureSrc(inst
);
1806 _mesa_printf(";\n");
1810 if (!Instructions
[i
].name
) {
1811 _mesa_printf("Invalid opcode %d\n", inst
->Opcode
);
1814 _mesa_printf("END\n");
1819 _mesa_nv_fragment_input_register_name(GLuint i
)
1821 ASSERT(i
< MAX_NV_FRAGMENT_PROGRAM_INPUTS
);
1822 return InputRegisters
[i
];
1827 _mesa_nv_fragment_output_register_name(GLuint i
)
1829 ASSERT(i
< MAX_NV_FRAGMENT_PROGRAM_OUTPUTS
);
1830 return OutputRegisters
[i
];