2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * NVIDIA fragment program parser.
32 * Regarding GL_NV_fragment_program:
34 * Portions of this software may use or implement intellectual
35 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
36 * any and all warranties with respect to such intellectual property,
37 * including any use thereof or modifications thereto.
44 #include "prog_parameter.h"
45 #include "prog_instruction.h"
46 #include "nvfragparse.h"
56 #define INPUT_1V_T 7 /* one source vector, plus textureId */
57 #define INPUT_3V_T 8 /* one source vector, plus textureId */
59 #define INPUT_1V_S 10 /* a string and a vector register */
62 #define OUTPUT_NONE 22
64 /* IRIX defines some of these */
71 /* Optional suffixes */
72 #define _R FLOAT32 /* float */
73 #define _H FLOAT16 /* half-float */
74 #define _X FIXED12 /* fixed */
75 #define _C 0x08 /* set cond codes */
76 #define _S 0x10 /* saturate, clamp result to [0,1] */
78 struct instruction_pattern
{
80 enum prog_opcode opcode
;
86 static const struct instruction_pattern Instructions
[] = {
87 { "ADD", OPCODE_ADD
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
88 { "COS", OPCODE_COS
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
89 { "DDX", OPCODE_DDX
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
90 { "DDY", OPCODE_DDY
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
91 { "DP3", OPCODE_DP3
, INPUT_2V
, OUTPUT_S
, _R
| _H
| _X
| _C
| _S
},
92 { "DP4", OPCODE_DP4
, INPUT_2V
, OUTPUT_S
, _R
| _H
| _X
| _C
| _S
},
93 { "DST", OPCODE_DP4
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
94 { "EX2", OPCODE_DP4
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
95 { "FLR", OPCODE_FLR
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
96 { "FRC", OPCODE_FRC
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
97 { "KIL", OPCODE_KIL_NV
, INPUT_CC
, OUTPUT_NONE
, 0 },
98 { "LG2", OPCODE_LG2
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
99 { "LIT", OPCODE_LIT
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
100 { "LRP", OPCODE_LRP
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
101 { "MAD", OPCODE_MAD
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
102 { "MAX", OPCODE_MAX
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
103 { "MIN", OPCODE_MIN
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
104 { "MOV", OPCODE_MOV
, INPUT_1V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
105 { "MUL", OPCODE_MUL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
106 { "PK2H", OPCODE_PK2H
, INPUT_1V
, OUTPUT_S
, 0 },
107 { "PK2US", OPCODE_PK2US
, INPUT_1V
, OUTPUT_S
, 0 },
108 { "PK4B", OPCODE_PK4B
, INPUT_1V
, OUTPUT_S
, 0 },
109 { "PK4UB", OPCODE_PK4UB
, INPUT_1V
, OUTPUT_S
, 0 },
110 { "POW", OPCODE_POW
, INPUT_2S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
111 { "RCP", OPCODE_RCP
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
112 { "RFL", OPCODE_RFL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
113 { "RSQ", OPCODE_RSQ
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
114 { "SEQ", OPCODE_SEQ
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
115 { "SFL", OPCODE_SFL
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
116 { "SGE", OPCODE_SGE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
117 { "SGT", OPCODE_SGT
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
118 { "SIN", OPCODE_SIN
, INPUT_1S
, OUTPUT_S
, _R
| _H
| _C
| _S
},
119 { "SLE", OPCODE_SLE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
120 { "SLT", OPCODE_SLT
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
121 { "SNE", OPCODE_SNE
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
122 { "STR", OPCODE_STR
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
123 { "SUB", OPCODE_SUB
, INPUT_2V
, OUTPUT_V
, _R
| _H
| _X
| _C
| _S
},
124 { "TEX", OPCODE_TEX
, INPUT_1V_T
, OUTPUT_V
, _C
| _S
},
125 { "TXD", OPCODE_TXD
, INPUT_3V_T
, OUTPUT_V
, _C
| _S
},
126 { "TXP", OPCODE_TXP_NV
, INPUT_1V_T
, OUTPUT_V
, _C
| _S
},
127 { "UP2H", OPCODE_UP2H
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
128 { "UP2US", OPCODE_UP2US
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
129 { "UP4B", OPCODE_UP4B
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
130 { "UP4UB", OPCODE_UP4UB
, INPUT_1S
, OUTPUT_V
, _C
| _S
},
131 { "X2D", OPCODE_X2D
, INPUT_3V
, OUTPUT_V
, _R
| _H
| _C
| _S
},
132 { "PRINT", OPCODE_PRINT
, INPUT_1V_S
, OUTPUT_NONE
, 0 },
133 { NULL
, (enum prog_opcode
) -1, 0, 0, 0 }
138 * Information needed or computed during parsing.
139 * Remember, we can't modify the target program object until we've
140 * _successfully_ parsed the program text.
144 const GLubyte
*start
; /* start of program string */
145 const GLubyte
*pos
; /* current position */
146 const GLubyte
*curLine
;
147 struct gl_fragment_program
*program
; /* current program */
149 struct gl_program_parameter_list
*parameters
;
151 GLuint numInst
; /* number of instructions parsed */
152 GLuint inputsRead
; /* bitmask of input registers used */
153 GLuint outputsWritten
; /* bitmask of 1 << FRAG_OUTPUT_* bits */
154 GLuint texturesUsed
[MAX_TEXTURE_IMAGE_UNITS
];
160 * Called whenever we find an error during parsing.
163 record_error(struct parse_state
*parseState
, const char *msg
, int lineNo
)
167 const GLubyte
*lineStr
;
168 lineStr
= _mesa_find_line_column(parseState
->start
,
169 parseState
->pos
, &line
, &column
);
170 _mesa_debug(parseState
->ctx
,
171 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
172 lineNo
, line
, column
, (char *) lineStr
, msg
);
173 _mesa_free((void *) lineStr
);
178 /* Check that no error was already recorded. Only record the first one. */
179 if (parseState
->ctx
->Program
.ErrorString
[0] == 0) {
180 _mesa_set_program_error(parseState
->ctx
,
181 parseState
->pos
- parseState
->start
,
187 #define RETURN_ERROR \
189 record_error(parseState, "Unexpected end of input.", __LINE__); \
193 #define RETURN_ERROR1(msg) \
195 record_error(parseState, msg, __LINE__); \
199 #define RETURN_ERROR2(msg1, msg2) \
202 _mesa_sprintf(err, "%s %s", msg1, msg2); \
203 record_error(parseState, err, __LINE__); \
211 * Search a list of instruction structures for a match.
213 static struct instruction_pattern
214 MatchInstruction(const GLubyte
*token
)
216 const struct instruction_pattern
*inst
;
217 struct instruction_pattern result
;
219 for (inst
= Instructions
; inst
->name
; inst
++) {
220 if (_mesa_strncmp((const char *) token
, inst
->name
, 3) == 0) {
226 if (token
[i
] == 'R') {
227 result
.suffixes
|= _R
;
230 else if (token
[i
] == 'H') {
231 result
.suffixes
|= _H
;
234 else if (token
[i
] == 'X') {
235 result
.suffixes
|= _X
;
238 if (token
[i
] == 'C') {
239 result
.suffixes
|= _C
;
242 if (token
[i
] == '_' && token
[i
+1] == 'S' &&
243 token
[i
+2] == 'A' && token
[i
+3] == 'T') {
244 result
.suffixes
|= _S
;
249 result
.opcode
= MAX_OPCODE
; /* i.e. invalid instruction */
256 /**********************************************************************/
259 static GLboolean
IsLetter(GLubyte b
)
261 return (b
>= 'a' && b
<= 'z') ||
262 (b
>= 'A' && b
<= 'Z') ||
268 static GLboolean
IsDigit(GLubyte b
)
270 return b
>= '0' && b
<= '9';
274 static GLboolean
IsWhitespace(GLubyte b
)
276 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
281 * Starting at 'str' find the next token. A token can be an integer,
282 * an identifier or punctuation symbol.
283 * \return <= 0 we found an error, else, return number of characters parsed.
286 GetToken(struct parse_state
*parseState
, GLubyte
*token
)
288 const GLubyte
*str
= parseState
->pos
;
293 /* skip whitespace and comments */
294 while (str
[i
] && (IsWhitespace(str
[i
]) || str
[i
] == '#')) {
297 while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
300 if (str
[i
] == '\n' || str
[i
] == '\r')
301 parseState
->curLine
= str
+ i
+ 1;
304 /* skip whitespace */
305 if (str
[i
] == '\n' || str
[i
] == '\r')
306 parseState
->curLine
= str
+ i
+ 1;
314 /* try matching an integer */
315 while (str
[i
] && IsDigit(str
[i
])) {
316 token
[j
++] = str
[i
++];
318 if (j
> 0 || !str
[i
]) {
323 /* try matching an identifier */
324 if (IsLetter(str
[i
])) {
325 while (str
[i
] && (IsLetter(str
[i
]) || IsDigit(str
[i
]))) {
326 token
[j
++] = str
[i
++];
332 /* punctuation character */
346 * Get next token from input stream and increment stream pointer past token.
349 Parse_Token(struct parse_state
*parseState
, GLubyte
*token
)
352 i
= GetToken(parseState
, token
);
354 parseState
->pos
+= (-i
);
357 parseState
->pos
+= i
;
363 * Get next token from input stream but don't increment stream pointer.
366 Peek_Token(struct parse_state
*parseState
, GLubyte
*token
)
369 i
= GetToken(parseState
, token
);
371 parseState
->pos
+= (-i
);
374 len
= (GLint
)_mesa_strlen((const char *) token
);
375 parseState
->pos
+= (i
- len
);
380 /**********************************************************************/
382 static const char *InputRegisters
[MAX_NV_FRAGMENT_PROGRAM_INPUTS
+ 1] = {
383 "WPOS", "COL0", "COL1", "FOGC",
384 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
387 static const char *OutputRegisters
[MAX_NV_FRAGMENT_PROGRAM_OUTPUTS
+ 1] = {
389 /* These are only allows for register combiners */
391 "TEX0", "TEX1", "TEX2", "TEX3",
399 /**********************************************************************/
402 * Try to match 'pattern' as the next token after any whitespace/comments.
405 Parse_String(struct parse_state
*parseState
, const char *pattern
)
410 /* skip whitespace and comments */
411 while (IsWhitespace(*parseState
->pos
) || *parseState
->pos
== '#') {
412 if (*parseState
->pos
== '#') {
413 while (*parseState
->pos
&& (*parseState
->pos
!= '\n' && *parseState
->pos
!= '\r')) {
414 parseState
->pos
+= 1;
416 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
417 parseState
->curLine
= parseState
->pos
+ 1;
420 /* skip whitespace */
421 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
422 parseState
->curLine
= parseState
->pos
+ 1;
423 parseState
->pos
+= 1;
427 /* Try to match the pattern */
429 for (i
= 0; pattern
[i
]; i
++) {
430 if (*m
!= (GLubyte
) pattern
[i
])
436 return GL_TRUE
; /* success */
441 Parse_Identifier(struct parse_state
*parseState
, GLubyte
*ident
)
443 if (!Parse_Token(parseState
, ident
))
445 if (IsLetter(ident
[0]))
448 RETURN_ERROR1("Expected an identfier");
453 * Parse a floating point constant, or a defined symbol name.
455 * Output: number[0 .. 3] will get the value.
458 Parse_ScalarConstant(struct parse_state
*parseState
, GLfloat
*number
)
462 *number
= (GLfloat
) _mesa_strtod((const char *) parseState
->pos
, &end
);
464 if (end
&& end
> (char *) parseState
->pos
) {
466 parseState
->pos
= (GLubyte
*) end
;
473 /* should be an identifier */
475 const GLfloat
*constant
;
476 if (!Parse_Identifier(parseState
, ident
))
477 RETURN_ERROR1("Expected an identifier");
478 constant
= _mesa_lookup_parameter_value(parseState
->parameters
,
479 -1, (const char *) ident
);
480 /* XXX Check that it's a constant and not a parameter */
482 RETURN_ERROR1("Undefined symbol");
485 COPY_4V(number
, constant
);
494 * Parse a vector constant, one of:
497 * { float, float, float }
498 * { float, float, float, float }
501 Parse_VectorConstant(struct parse_state
*parseState
, GLfloat
*vec
)
503 /* "{" was already consumed */
505 ASSIGN_4V(vec
, 0.0, 0.0, 0.0, 1.0);
507 if (!Parse_ScalarConstant(parseState
, vec
+0)) /* X */
510 if (Parse_String(parseState
, "}")) {
514 if (!Parse_String(parseState
, ","))
515 RETURN_ERROR1("Expected comma in vector constant");
517 if (!Parse_ScalarConstant(parseState
, vec
+1)) /* Y */
520 if (Parse_String(parseState
, "}")) {
524 if (!Parse_String(parseState
, ","))
525 RETURN_ERROR1("Expected comma in vector constant");
527 if (!Parse_ScalarConstant(parseState
, vec
+2)) /* Z */
530 if (Parse_String(parseState
, "}")) {
534 if (!Parse_String(parseState
, ","))
535 RETURN_ERROR1("Expected comma in vector constant");
537 if (!Parse_ScalarConstant(parseState
, vec
+3)) /* W */
540 if (!Parse_String(parseState
, "}"))
541 RETURN_ERROR1("Expected closing brace in vector constant");
548 * Parse <number>, <varname> or {a, b, c, d}.
549 * Return number of values in the vector or scalar, or zero if parse error.
552 Parse_VectorOrScalarConstant(struct parse_state
*parseState
, GLfloat
*vec
)
554 if (Parse_String(parseState
, "{")) {
555 return Parse_VectorConstant(parseState
, vec
);
558 GLboolean b
= Parse_ScalarConstant(parseState
, vec
);
560 vec
[1] = vec
[2] = vec
[3] = vec
[0];
568 * Parse a texture image source:
569 * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
572 Parse_TextureImageId(struct parse_state
*parseState
,
573 GLubyte
*texUnit
, GLubyte
*texTargetBit
)
575 GLubyte imageSrc
[100];
578 if (!Parse_Token(parseState
, imageSrc
))
581 if (imageSrc
[0] != 'T' ||
582 imageSrc
[1] != 'E' ||
583 imageSrc
[2] != 'X') {
584 RETURN_ERROR1("Expected TEX# source");
586 unit
= _mesa_atoi((const char *) imageSrc
+ 3);
587 if ((unit
< 0 || unit
> MAX_TEXTURE_IMAGE_UNITS
) ||
588 (unit
== 0 && (imageSrc
[3] != '0' || imageSrc
[4] != 0))) {
589 RETURN_ERROR1("Invalied TEX# source index");
593 if (!Parse_String(parseState
, ","))
594 RETURN_ERROR1("Expected ,");
596 if (Parse_String(parseState
, "1D")) {
597 *texTargetBit
= TEXTURE_1D_BIT
;
599 else if (Parse_String(parseState
, "2D")) {
600 *texTargetBit
= TEXTURE_2D_BIT
;
602 else if (Parse_String(parseState
, "3D")) {
603 *texTargetBit
= TEXTURE_3D_BIT
;
605 else if (Parse_String(parseState
, "CUBE")) {
606 *texTargetBit
= TEXTURE_CUBE_BIT
;
608 else if (Parse_String(parseState
, "RECT")) {
609 *texTargetBit
= TEXTURE_RECT_BIT
;
612 RETURN_ERROR1("Invalid texture target token");
615 /* update record of referenced texture units */
616 parseState
->texturesUsed
[*texUnit
] |= *texTargetBit
;
617 if (_mesa_bitcount(parseState
->texturesUsed
[*texUnit
]) > 1) {
618 RETURN_ERROR1("Only one texture target can be used per texture unit.");
626 * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
627 * like .wxyz, .xxyy, etc and return the swizzle indexes.
630 Parse_SwizzleSuffix(const GLubyte
*token
, GLuint swizzle
[4])
633 /* single letter swizzle (scalar) */
635 ASSIGN_4V(swizzle
, 0, 0, 0, 0);
636 else if (token
[0] == 'y')
637 ASSIGN_4V(swizzle
, 1, 1, 1, 1);
638 else if (token
[0] == 'z')
639 ASSIGN_4V(swizzle
, 2, 2, 2, 2);
640 else if (token
[0] == 'w')
641 ASSIGN_4V(swizzle
, 3, 3, 3, 3);
646 /* 4-component swizzle (vector) */
648 for (k
= 0; token
[k
] && k
< 4; k
++) {
651 else if (token
[k
] == 'y')
653 else if (token
[k
] == 'z')
655 else if (token
[k
] == 'w')
668 Parse_CondCodeMask(struct parse_state
*parseState
,
669 struct prog_dst_register
*dstReg
)
671 if (Parse_String(parseState
, "EQ"))
672 dstReg
->CondMask
= COND_EQ
;
673 else if (Parse_String(parseState
, "GE"))
674 dstReg
->CondMask
= COND_GE
;
675 else if (Parse_String(parseState
, "GT"))
676 dstReg
->CondMask
= COND_GT
;
677 else if (Parse_String(parseState
, "LE"))
678 dstReg
->CondMask
= COND_LE
;
679 else if (Parse_String(parseState
, "LT"))
680 dstReg
->CondMask
= COND_LT
;
681 else if (Parse_String(parseState
, "NE"))
682 dstReg
->CondMask
= COND_NE
;
683 else if (Parse_String(parseState
, "TR"))
684 dstReg
->CondMask
= COND_TR
;
685 else if (Parse_String(parseState
, "FL"))
686 dstReg
->CondMask
= COND_FL
;
688 RETURN_ERROR1("Invalid condition code mask");
690 /* look for optional .xyzw swizzle */
691 if (Parse_String(parseState
, ".")) {
695 if (!Parse_Token(parseState
, token
)) /* get xyzw suffix */
698 if (!Parse_SwizzleSuffix(token
, swz
))
699 RETURN_ERROR1("Invalid swizzle suffix");
701 dstReg
->CondSwizzle
= MAKE_SWIZZLE4(swz
[0], swz
[1], swz
[2], swz
[3]);
709 * Parse a temporary register: Rnn or Hnn
712 Parse_TempReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
716 /* Should be 'R##' or 'H##' */
717 if (!Parse_Token(parseState
, token
))
719 if (token
[0] != 'R' && token
[0] != 'H')
720 RETURN_ERROR1("Expected R## or H##");
722 if (IsDigit(token
[1])) {
723 GLint reg
= _mesa_atoi((const char *) (token
+ 1));
726 if (reg
>= MAX_NV_FRAGMENT_PROGRAM_TEMPS
)
727 RETURN_ERROR1("Invalid temporary register name");
731 RETURN_ERROR1("Invalid temporary register name");
739 * Parse a write-only dummy register: RC or HC.
742 Parse_DummyReg(struct parse_state
*parseState
, GLint
*regNum
)
744 if (Parse_String(parseState
, "RC")) {
747 else if (Parse_String(parseState
, "HC")) {
751 RETURN_ERROR1("Invalid write-only register name");
759 * Parse a program local parameter register "p[##]"
762 Parse_ProgramParamReg(struct parse_state
*parseState
, GLint
*regNum
)
766 if (!Parse_String(parseState
, "p["))
767 RETURN_ERROR1("Expected p[");
769 if (!Parse_Token(parseState
, token
))
772 if (IsDigit(token
[0])) {
773 /* a numbered program parameter register */
774 GLint reg
= _mesa_atoi((const char *) token
);
775 if (reg
>= MAX_NV_FRAGMENT_PROGRAM_PARAMS
)
776 RETURN_ERROR1("Invalid constant program number");
783 if (!Parse_String(parseState
, "]"))
784 RETURN_ERROR1("Expected ]");
791 * Parse f[name] - fragment input register
794 Parse_FragReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
800 if (!Parse_String(parseState
, "f["))
801 RETURN_ERROR1("Expected f[");
803 /* get <name> and look for match */
804 if (!Parse_Token(parseState
, token
)) {
807 for (j
= 0; InputRegisters
[j
]; j
++) {
808 if (_mesa_strcmp((const char *) token
, InputRegisters
[j
]) == 0) {
810 parseState
->inputsRead
|= (1 << j
);
814 if (!InputRegisters
[j
]) {
815 /* unknown input register label */
816 RETURN_ERROR2("Invalid register name", token
);
820 if (!Parse_String(parseState
, "]"))
821 RETURN_ERROR1("Expected ]");
828 Parse_OutputReg(struct parse_state
*parseState
, GLint
*outputRegNum
)
834 if (!Parse_String(parseState
, "o["))
835 RETURN_ERROR1("Expected o[");
837 /* Get output reg name */
838 if (!Parse_Token(parseState
, token
))
841 /* try to match an output register name */
842 for (j
= 0; OutputRegisters
[j
]; j
++) {
843 if (_mesa_strcmp((const char *) token
, OutputRegisters
[j
]) == 0) {
844 static GLuint bothColors
= (1 << FRAG_RESULT_COLR
) | (1 << FRAG_RESULT_COLH
);
846 parseState
->outputsWritten
|= (1 << j
);
847 if ((parseState
->outputsWritten
& bothColors
) == bothColors
) {
848 RETURN_ERROR1("Illegal to write to both o[COLR] and o[COLH]");
853 if (!OutputRegisters
[j
])
854 RETURN_ERROR1("Invalid output register name");
857 if (!Parse_String(parseState
, "]"))
858 RETURN_ERROR1("Expected ]");
865 Parse_MaskedDstReg(struct parse_state
*parseState
,
866 struct prog_dst_register
*dstReg
)
871 /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
872 if (!Peek_Token(parseState
, token
))
875 if (_mesa_strcmp((const char *) token
, "RC") == 0 ||
876 _mesa_strcmp((const char *) token
, "HC") == 0) {
877 /* a write-only register */
878 dstReg
->File
= PROGRAM_WRITE_ONLY
;
879 if (!Parse_DummyReg(parseState
, &idx
))
883 else if (token
[0] == 'R' || token
[0] == 'H') {
884 /* a temporary register */
885 dstReg
->File
= PROGRAM_TEMPORARY
;
886 if (!Parse_TempReg(parseState
, &idx
))
890 else if (token
[0] == 'o') {
891 /* an output register */
892 dstReg
->File
= PROGRAM_OUTPUT
;
893 if (!Parse_OutputReg(parseState
, &idx
))
898 RETURN_ERROR1("Invalid destination register name");
901 /* Parse optional write mask */
902 if (Parse_String(parseState
, ".")) {
906 if (!Parse_Token(parseState
, token
)) /* get xyzw writemask */
909 dstReg
->WriteMask
= 0;
911 if (token
[k
] == 'x') {
912 dstReg
->WriteMask
|= WRITEMASK_X
;
915 if (token
[k
] == 'y') {
916 dstReg
->WriteMask
|= WRITEMASK_Y
;
919 if (token
[k
] == 'z') {
920 dstReg
->WriteMask
|= WRITEMASK_Z
;
923 if (token
[k
] == 'w') {
924 dstReg
->WriteMask
|= WRITEMASK_W
;
928 RETURN_ERROR1("Invalid writemask character");
933 dstReg
->WriteMask
= WRITEMASK_XYZW
;
936 /* optional condition code mask */
937 if (Parse_String(parseState
, "(")) {
938 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
939 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
940 if (!Parse_CondCodeMask(parseState
, dstReg
))
943 if (!Parse_String(parseState
, ")")) /* consume ")" */
944 RETURN_ERROR1("Expected )");
949 /* no cond code mask */
950 dstReg
->CondMask
= COND_TR
;
951 dstReg
->CondSwizzle
= SWIZZLE_NOOP
;
958 * Parse a vector source (register, constant, etc):
959 * <vectorSrc> ::= <absVectorSrc>
961 * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
964 Parse_VectorSrc(struct parse_state
*parseState
,
965 struct prog_src_register
*srcReg
)
972 * First, take care of +/- and absolute value stuff.
974 if (Parse_String(parseState
, "-"))
976 else if (Parse_String(parseState
, "+"))
979 if (Parse_String(parseState
, "|")) {
980 srcReg
->Abs
= GL_TRUE
;
981 srcReg
->NegateAbs
= (sign
< 0.0F
) ? GL_TRUE
: GL_FALSE
;
983 if (Parse_String(parseState
, "-"))
984 srcReg
->NegateBase
= NEGATE_XYZW
;
985 else if (Parse_String(parseState
, "+"))
986 srcReg
->NegateBase
= NEGATE_NONE
;
988 srcReg
->NegateBase
= NEGATE_NONE
;
991 srcReg
->Abs
= GL_FALSE
;
992 srcReg
->NegateAbs
= GL_FALSE
;
993 srcReg
->NegateBase
= (sign
< 0.0F
) ? NEGATE_XYZW
: NEGATE_NONE
;
996 /* This should be the real src vector/register name */
997 if (!Peek_Token(parseState
, token
))
1000 /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
1001 * literal or vector literal.
1003 if (token
[0] == 'R' || token
[0] == 'H') {
1004 srcReg
->File
= PROGRAM_TEMPORARY
;
1005 if (!Parse_TempReg(parseState
, &idx
))
1007 srcReg
->Index
= idx
;
1009 else if (token
[0] == 'f') {
1010 /* XXX this might be an identifier! */
1011 srcReg
->File
= PROGRAM_INPUT
;
1012 if (!Parse_FragReg(parseState
, &idx
))
1014 srcReg
->Index
= idx
;
1016 else if (token
[0] == 'p') {
1017 /* XXX this might be an identifier! */
1018 srcReg
->File
= PROGRAM_LOCAL_PARAM
;
1019 if (!Parse_ProgramParamReg(parseState
, &idx
))
1021 srcReg
->Index
= idx
;
1023 else if (IsLetter(token
[0])){
1026 if (!Parse_Identifier(parseState
, ident
))
1028 paramIndex
= _mesa_lookup_parameter_index(parseState
->parameters
,
1029 -1, (const char *) ident
);
1030 if (paramIndex
< 0) {
1031 RETURN_ERROR2("Undefined constant or parameter: ", ident
);
1033 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1034 srcReg
->Index
= paramIndex
;
1036 else if (IsDigit(token
[0]) || token
[0] == '-' || token
[0] == '+' || token
[0] == '.'){
1037 /* literal scalar constant */
1039 GLuint paramIndex
, swizzle
;
1040 if (!Parse_ScalarConstant(parseState
, values
))
1042 paramIndex
= _mesa_add_unnamed_constant(parseState
->parameters
,
1043 values
, 4, &swizzle
);
1044 ASSERT(swizzle
== SWIZZLE_NOOP
);
1045 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1046 srcReg
->Index
= paramIndex
;
1048 else if (token
[0] == '{'){
1049 /* literal vector constant */
1051 GLuint paramIndex
, swizzle
;
1052 (void) Parse_String(parseState
, "{");
1053 if (!Parse_VectorConstant(parseState
, values
))
1055 paramIndex
= _mesa_add_unnamed_constant(parseState
->parameters
,
1056 values
, 4, &swizzle
);
1057 ASSERT(swizzle
== SWIZZLE_NOOP
);
1058 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1059 srcReg
->Index
= paramIndex
;
1062 RETURN_ERROR2("Invalid source register name", token
);
1065 /* init swizzle fields */
1066 srcReg
->Swizzle
= SWIZZLE_NOOP
;
1068 /* Look for optional swizzle suffix */
1069 if (Parse_String(parseState
, ".")) {
1072 if (!Parse_Token(parseState
, token
))
1075 if (!Parse_SwizzleSuffix(token
, swz
))
1076 RETURN_ERROR1("Invalid swizzle suffix");
1078 srcReg
->Swizzle
= MAKE_SWIZZLE4(swz
[0], swz
[1], swz
[2], swz
[3]);
1081 /* Finish absolute value */
1082 if (srcReg
->Abs
&& !Parse_String(parseState
, "|")) {
1083 RETURN_ERROR1("Expected |");
1091 Parse_ScalarSrcReg(struct parse_state
*parseState
,
1092 struct prog_src_register
*srcReg
)
1095 GLfloat sign
= 1.0F
;
1096 GLboolean needSuffix
= GL_TRUE
;
1100 * First, take care of +/- and absolute value stuff.
1102 if (Parse_String(parseState
, "-"))
1104 else if (Parse_String(parseState
, "+"))
1107 if (Parse_String(parseState
, "|")) {
1108 srcReg
->Abs
= GL_TRUE
;
1109 srcReg
->NegateAbs
= (sign
< 0.0F
) ? GL_TRUE
: GL_FALSE
;
1111 if (Parse_String(parseState
, "-"))
1112 srcReg
->NegateBase
= NEGATE_XYZW
;
1113 else if (Parse_String(parseState
, "+"))
1114 srcReg
->NegateBase
= NEGATE_NONE
;
1116 srcReg
->NegateBase
= NEGATE_NONE
;
1119 srcReg
->Abs
= GL_FALSE
;
1120 srcReg
->NegateAbs
= GL_FALSE
;
1121 srcReg
->NegateBase
= (sign
< 0.0F
) ? NEGATE_XYZW
: NEGATE_NONE
;
1124 if (!Peek_Token(parseState
, token
))
1127 /* Src reg can be R<n>, H<n> or a named fragment attrib */
1128 if (token
[0] == 'R' || token
[0] == 'H') {
1129 srcReg
->File
= PROGRAM_TEMPORARY
;
1130 if (!Parse_TempReg(parseState
, &idx
))
1132 srcReg
->Index
= idx
;
1134 else if (token
[0] == 'f') {
1135 srcReg
->File
= PROGRAM_INPUT
;
1136 if (!Parse_FragReg(parseState
, &idx
))
1138 srcReg
->Index
= idx
;
1140 else if (token
[0] == '{') {
1141 /* vector literal */
1143 GLuint paramIndex
, swizzle
;
1144 (void) Parse_String(parseState
, "{");
1145 if (!Parse_VectorConstant(parseState
, values
))
1147 paramIndex
= _mesa_add_unnamed_constant(parseState
->parameters
,
1148 values
, 4, &swizzle
);
1149 ASSERT(swizzle
== SWIZZLE_NOOP
);
1150 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1151 srcReg
->Index
= paramIndex
;
1153 else if (IsLetter(token
[0])){
1154 /* named param/constant */
1157 if (!Parse_Identifier(parseState
, ident
))
1159 paramIndex
= _mesa_lookup_parameter_index(parseState
->parameters
,
1160 -1, (const char *) ident
);
1161 if (paramIndex
< 0) {
1162 RETURN_ERROR2("Undefined constant or parameter: ", ident
);
1164 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1165 srcReg
->Index
= paramIndex
;
1167 else if (IsDigit(token
[0])) {
1168 /* scalar literal */
1170 GLuint paramIndex
, swizzle
;
1171 if (!Parse_ScalarConstant(parseState
, values
))
1173 paramIndex
= _mesa_add_unnamed_constant(parseState
->parameters
,
1174 values
, 4, &swizzle
);
1175 ASSERT(swizzle
== SWIZZLE_NOOP
);
1176 srcReg
->Index
= paramIndex
;
1177 srcReg
->File
= PROGRAM_NAMED_PARAM
;
1178 needSuffix
= GL_FALSE
;
1181 RETURN_ERROR2("Invalid scalar source argument", token
);
1184 srcReg
->Swizzle
= 0;
1186 /* parse .[xyzw] suffix */
1187 if (!Parse_String(parseState
, "."))
1188 RETURN_ERROR1("Expected .");
1190 if (!Parse_Token(parseState
, token
))
1193 if (token
[0] == 'x' && token
[1] == 0) {
1194 srcReg
->Swizzle
= 0;
1196 else if (token
[0] == 'y' && token
[1] == 0) {
1197 srcReg
->Swizzle
= 1;
1199 else if (token
[0] == 'z' && token
[1] == 0) {
1200 srcReg
->Swizzle
= 2;
1202 else if (token
[0] == 'w' && token
[1] == 0) {
1203 srcReg
->Swizzle
= 3;
1206 RETURN_ERROR1("Invalid scalar source suffix");
1210 /* Finish absolute value */
1211 if (srcReg
->Abs
&& !Parse_String(parseState
, "|")) {
1212 RETURN_ERROR1("Expected |");
1220 Parse_PrintInstruction(struct parse_state
*parseState
,
1221 struct prog_instruction
*inst
)
1228 /* The first argument is a literal string 'just like this' */
1229 if (!Parse_String(parseState
, "'"))
1230 RETURN_ERROR1("Expected '");
1232 str
= parseState
->pos
;
1233 for (len
= 0; str
[len
] != '\''; len
++) /* find closing quote */
1235 parseState
->pos
+= len
+ 1;
1236 msg
= (GLubyte
*) _mesa_malloc(len
+ 1);
1238 _mesa_memcpy(msg
, str
, len
);
1242 if (Parse_String(parseState
, ",")) {
1243 /* got an optional register to print */
1245 GetToken(parseState
, token
);
1246 if (token
[0] == 'o') {
1248 if (!Parse_OutputReg(parseState
, &idx
))
1250 inst
->SrcReg
[0].Index
= idx
;
1251 inst
->SrcReg
[0].File
= PROGRAM_OUTPUT
;
1255 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1260 inst
->SrcReg
[0].File
= PROGRAM_UNDEFINED
;
1263 inst
->SrcReg
[0].Swizzle
= SWIZZLE_NOOP
;
1264 inst
->SrcReg
[0].NegateBase
= NEGATE_NONE
;
1265 inst
->SrcReg
[0].Abs
= GL_FALSE
;
1266 inst
->SrcReg
[0].NegateAbs
= GL_FALSE
;
1273 Parse_InstructionSequence(struct parse_state
*parseState
,
1274 struct prog_instruction program
[])
1277 struct prog_instruction
*inst
= program
+ parseState
->numInst
;
1278 struct instruction_pattern instMatch
;
1281 /* Initialize the instruction */
1282 _mesa_init_instructions(inst
, 1);
1284 /* special instructions */
1285 if (Parse_String(parseState
, "DEFINE")) {
1287 GLfloat value
[7]; /* yes, 7 to be safe */
1288 if (!Parse_Identifier(parseState
, id
))
1290 /* XXX make sure id is not a reserved identifer, like R9 */
1291 if (!Parse_String(parseState
, "="))
1292 RETURN_ERROR1("Expected =");
1293 if (!Parse_VectorOrScalarConstant(parseState
, value
))
1295 if (!Parse_String(parseState
, ";"))
1296 RETURN_ERROR1("Expected ;");
1297 if (_mesa_lookup_parameter_index(parseState
->parameters
,
1298 -1, (const char *) id
) >= 0) {
1299 RETURN_ERROR2(id
, "already defined");
1301 _mesa_add_named_parameter(parseState
->parameters
,
1302 (const char *) id
, value
);
1304 else if (Parse_String(parseState
, "DECLARE")) {
1306 GLfloat value
[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, 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 if (!Parse_VectorOrScalarConstant(parseState
, value
))
1314 if (!Parse_String(parseState
, ";"))
1315 RETURN_ERROR1("Expected ;");
1316 if (_mesa_lookup_parameter_index(parseState
->parameters
,
1317 -1, (const char *) id
) >= 0) {
1318 RETURN_ERROR2(id
, "already declared");
1320 _mesa_add_named_parameter(parseState
->parameters
,
1321 (const char *) id
, value
);
1323 else if (Parse_String(parseState
, "END")) {
1324 inst
->Opcode
= OPCODE_END
;
1325 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
1326 assert(inst
->StringPos
>= 0);
1327 parseState
->numInst
++;
1328 if (Parse_Token(parseState
, token
)) {
1329 RETURN_ERROR1("Code after END opcode.");
1334 /* general/arithmetic instruction */
1337 if (!Parse_Token(parseState
, token
)) {
1338 RETURN_ERROR1("Missing END instruction.");
1341 /* try to find matching instuction */
1342 instMatch
= MatchInstruction(token
);
1343 if (instMatch
.opcode
>= MAX_OPCODE
) {
1344 /* bad instruction name */
1345 RETURN_ERROR2("Unexpected token: ", token
);
1348 inst
->Opcode
= instMatch
.opcode
;
1349 inst
->Precision
= instMatch
.suffixes
& (_R
| _H
| _X
);
1350 inst
->SaturateMode
= (instMatch
.suffixes
& (_S
))
1351 ? SATURATE_ZERO_ONE
: SATURATE_OFF
;
1352 inst
->CondUpdate
= (instMatch
.suffixes
& (_C
)) ? GL_TRUE
: GL_FALSE
;
1353 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
1354 assert(inst
->StringPos
>= 0);
1357 * parse the input and output operands
1359 if (instMatch
.outputs
== OUTPUT_S
|| instMatch
.outputs
== OUTPUT_V
) {
1360 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
1362 if (!Parse_String(parseState
, ","))
1363 RETURN_ERROR1("Expected ,");
1365 else if (instMatch
.outputs
== OUTPUT_NONE
) {
1366 if (instMatch
.opcode
== OPCODE_KIL_NV
) {
1367 /* This is a little weird, the cond code info is in
1368 * the dest register.
1370 if (!Parse_CondCodeMask(parseState
, &inst
->DstReg
))
1374 ASSERT(instMatch
.opcode
== OPCODE_PRINT
);
1378 if (instMatch
.inputs
== INPUT_1V
) {
1379 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1382 else if (instMatch
.inputs
== INPUT_2V
) {
1383 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1385 if (!Parse_String(parseState
, ","))
1386 RETURN_ERROR1("Expected ,");
1387 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[1]))
1390 else if (instMatch
.inputs
== INPUT_3V
) {
1391 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1393 if (!Parse_String(parseState
, ","))
1394 RETURN_ERROR1("Expected ,");
1395 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[1]))
1397 if (!Parse_String(parseState
, ","))
1398 RETURN_ERROR1("Expected ,");
1399 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[2]))
1402 else if (instMatch
.inputs
== INPUT_1S
) {
1403 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
1406 else if (instMatch
.inputs
== INPUT_2S
) {
1407 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
1409 if (!Parse_String(parseState
, ","))
1410 RETURN_ERROR1("Expected ,");
1411 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[1]))
1414 else if (instMatch
.inputs
== INPUT_CC
) {
1417 else if (instMatch
.inputs
== INPUT_1V_T
) {
1419 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1421 if (!Parse_String(parseState
, ","))
1422 RETURN_ERROR1("Expected ,");
1423 if (!Parse_TextureImageId(parseState
, &unit
, &idx
))
1425 inst
->TexSrcUnit
= unit
;
1426 inst
->TexSrcTarget
= idx
;
1428 else if (instMatch
.inputs
== INPUT_3V_T
) {
1430 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[0]))
1432 if (!Parse_String(parseState
, ","))
1433 RETURN_ERROR1("Expected ,");
1434 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[1]))
1436 if (!Parse_String(parseState
, ","))
1437 RETURN_ERROR1("Expected ,");
1438 if (!Parse_VectorSrc(parseState
, &inst
->SrcReg
[2]))
1440 if (!Parse_String(parseState
, ","))
1441 RETURN_ERROR1("Expected ,");
1442 if (!Parse_TextureImageId(parseState
, &unit
, &idx
))
1444 inst
->TexSrcUnit
= unit
;
1445 inst
->TexSrcTarget
= idx
;
1447 else if (instMatch
.inputs
== INPUT_1V_S
) {
1448 if (!Parse_PrintInstruction(parseState
, inst
))
1452 /* end of statement semicolon */
1453 if (!Parse_String(parseState
, ";"))
1454 RETURN_ERROR1("Expected ;");
1456 parseState
->numInst
++;
1458 if (parseState
->numInst
>= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
)
1459 RETURN_ERROR1("Program too long");
1468 * Parse/compile the 'str' returning the compiled 'program'.
1469 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1470 * indicates the position of the error in 'str'.
1473 _mesa_parse_nv_fragment_program(GLcontext
*ctx
, GLenum dstTarget
,
1474 const GLubyte
*str
, GLsizei len
,
1475 struct gl_fragment_program
*program
)
1477 struct parse_state parseState
;
1478 struct prog_instruction instBuffer
[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
];
1479 struct prog_instruction
*newInst
;
1481 GLubyte
*programString
;
1483 /* Make a null-terminated copy of the program string */
1484 programString
= (GLubyte
*) MALLOC(len
+ 1);
1485 if (!programString
) {
1486 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1489 MEMCPY(programString
, str
, len
);
1490 programString
[len
] = 0;
1492 /* Get ready to parse */
1493 _mesa_bzero(&parseState
, sizeof(struct parse_state
));
1494 parseState
.ctx
= ctx
;
1495 parseState
.start
= programString
;
1496 parseState
.program
= program
;
1497 parseState
.numInst
= 0;
1498 parseState
.curLine
= programString
;
1499 parseState
.parameters
= _mesa_new_parameter_list();
1501 /* Reset error state */
1502 _mesa_set_program_error(ctx
, -1, NULL
);
1504 /* check the program header */
1505 if (_mesa_strncmp((const char *) programString
, "!!FP1.0", 7) == 0) {
1506 target
= GL_FRAGMENT_PROGRAM_NV
;
1507 parseState
.pos
= programString
+ 7;
1509 else if (_mesa_strncmp((const char *) programString
, "!!FCP1.0", 8) == 0) {
1510 /* fragment / register combiner program - not supported */
1511 _mesa_set_program_error(ctx
, 0, "Invalid fragment program header");
1512 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1516 /* invalid header */
1517 _mesa_set_program_error(ctx
, 0, "Invalid fragment program header");
1518 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1522 /* make sure target and header match */
1523 if (target
!= dstTarget
) {
1524 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1525 "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1530 if (Parse_InstructionSequence(&parseState
, instBuffer
)) {
1532 /* successful parse! */
1534 if (parseState
.outputsWritten
== 0) {
1535 /* must write at least one output! */
1536 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1537 "Invalid fragment program - no outputs written.");
1541 /* copy the compiled instructions */
1542 assert(parseState
.numInst
<= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS
);
1543 newInst
= _mesa_alloc_instructions(parseState
.numInst
);
1545 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1546 return; /* out of memory */
1548 _mesa_memcpy(newInst
, instBuffer
,
1549 parseState
.numInst
* sizeof(struct prog_instruction
));
1551 /* install the program */
1552 program
->Base
.Target
= target
;
1553 if (program
->Base
.String
) {
1554 FREE(program
->Base
.String
);
1556 program
->Base
.String
= programString
;
1557 program
->Base
.Format
= GL_PROGRAM_FORMAT_ASCII_ARB
;
1558 if (program
->Base
.Instructions
) {
1559 _mesa_free(program
->Base
.Instructions
);
1561 program
->Base
.Instructions
= newInst
;
1562 program
->Base
.NumInstructions
= parseState
.numInst
;
1563 program
->Base
.InputsRead
= parseState
.inputsRead
;
1564 program
->Base
.OutputsWritten
= parseState
.outputsWritten
;
1565 for (u
= 0; u
< ctx
->Const
.MaxTextureImageUnits
; u
++)
1566 program
->Base
.TexturesUsed
[u
] = parseState
.texturesUsed
[u
];
1568 /* save program parameters */
1569 program
->Base
.Parameters
= parseState
.parameters
;
1571 /* allocate registers for declared program parameters */
1573 _mesa_assign_program_registers(&(program
->SymbolTable
));
1577 _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program
->Base
.Id
);
1578 _mesa_print_nv_fragment_program(program
);
1579 _mesa_printf("----------------------------------\n");
1584 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1585 /* NOTE: _mesa_set_program_error would have been called already */
1591 PrintSrcReg(const struct gl_fragment_program
*program
,
1592 const struct prog_src_register
*src
)
1594 static const char comps
[5] = "xyzw";
1596 if (src
->NegateAbs
) {
1602 if (src
->NegateBase
) {
1605 if (src
->File
== PROGRAM_NAMED_PARAM
) {
1606 if (program
->Base
.Parameters
->Parameters
[src
->Index
].Type
1607 == PROGRAM_CONSTANT
) {
1609 v
= program
->Base
.Parameters
->ParameterValues
[src
->Index
];
1610 _mesa_printf("{%g, %g, %g, %g}", v
[0], v
[1], v
[2], v
[3]);
1613 ASSERT(program
->Base
.Parameters
->Parameters
[src
->Index
].Type
1614 == PROGRAM_NAMED_PARAM
);
1615 _mesa_printf("%s", program
->Base
.Parameters
->Parameters
[src
->Index
].Name
);
1618 else if (src
->File
== PROGRAM_OUTPUT
) {
1619 _mesa_printf("o[%s]", OutputRegisters
[src
->Index
]);
1621 else if (src
->File
== PROGRAM_INPUT
) {
1622 _mesa_printf("f[%s]", InputRegisters
[src
->Index
]);
1624 else if (src
->File
== PROGRAM_LOCAL_PARAM
) {
1625 _mesa_printf("p[%d]", src
->Index
);
1627 else if (src
->File
== PROGRAM_TEMPORARY
) {
1628 if (src
->Index
>= 32)
1629 _mesa_printf("H%d", src
->Index
);
1631 _mesa_printf("R%d", src
->Index
);
1633 else if (src
->File
== PROGRAM_WRITE_ONLY
) {
1634 _mesa_printf("%cC", "HR"[src
->Index
]);
1637 _mesa_problem(NULL
, "Invalid fragment register %d", src
->Index
);
1640 if (GET_SWZ(src
->Swizzle
, 0) == GET_SWZ(src
->Swizzle
, 1) &&
1641 GET_SWZ(src
->Swizzle
, 0) == GET_SWZ(src
->Swizzle
, 2) &&
1642 GET_SWZ(src
->Swizzle
, 0) == GET_SWZ(src
->Swizzle
, 3)) {
1643 _mesa_printf(".%c", comps
[GET_SWZ(src
->Swizzle
, 0)]);
1645 else if (src
->Swizzle
!= SWIZZLE_NOOP
) {
1646 _mesa_printf(".%c%c%c%c",
1647 comps
[GET_SWZ(src
->Swizzle
, 0)],
1648 comps
[GET_SWZ(src
->Swizzle
, 1)],
1649 comps
[GET_SWZ(src
->Swizzle
, 2)],
1650 comps
[GET_SWZ(src
->Swizzle
, 3)]);
1658 PrintTextureSrc(const struct prog_instruction
*inst
)
1660 _mesa_printf("TEX%d, ", inst
->TexSrcUnit
);
1661 switch (inst
->TexSrcTarget
) {
1662 case TEXTURE_1D_INDEX
:
1665 case TEXTURE_2D_INDEX
:
1668 case TEXTURE_3D_INDEX
:
1671 case TEXTURE_RECT_INDEX
:
1672 _mesa_printf("RECT");
1674 case TEXTURE_CUBE_INDEX
:
1675 _mesa_printf("CUBE");
1678 _mesa_problem(NULL
, "Invalid textue target in PrintTextureSrc");
1683 PrintCondCode(const struct prog_dst_register
*dst
)
1685 static const char *comps
= "xyzw";
1686 static const char *ccString
[] = {
1687 "??", "GT", "EQ", "LT", "UN", "GE", "LE", "NE", "TR", "FL", "??"
1690 _mesa_printf("%s", ccString
[dst
->CondMask
]);
1691 if (GET_SWZ(dst
->CondSwizzle
, 0) == GET_SWZ(dst
->CondSwizzle
, 1) &&
1692 GET_SWZ(dst
->CondSwizzle
, 0) == GET_SWZ(dst
->CondSwizzle
, 2) &&
1693 GET_SWZ(dst
->CondSwizzle
, 0) == GET_SWZ(dst
->CondSwizzle
, 3)) {
1694 _mesa_printf(".%c", comps
[GET_SWZ(dst
->CondSwizzle
, 0)]);
1696 else if (dst
->CondSwizzle
!= SWIZZLE_NOOP
) {
1697 _mesa_printf(".%c%c%c%c",
1698 comps
[GET_SWZ(dst
->CondSwizzle
, 0)],
1699 comps
[GET_SWZ(dst
->CondSwizzle
, 1)],
1700 comps
[GET_SWZ(dst
->CondSwizzle
, 2)],
1701 comps
[GET_SWZ(dst
->CondSwizzle
, 3)]);
1707 PrintDstReg(const struct prog_dst_register
*dst
)
1709 if (dst
->File
== PROGRAM_OUTPUT
) {
1710 _mesa_printf("o[%s]", OutputRegisters
[dst
->Index
]);
1712 else if (dst
->File
== PROGRAM_TEMPORARY
) {
1713 if (dst
->Index
>= 32)
1714 _mesa_printf("H%d", dst
->Index
);
1716 _mesa_printf("R%d", dst
->Index
);
1718 else if (dst
->File
== PROGRAM_LOCAL_PARAM
) {
1719 _mesa_printf("p[%d]", dst
->Index
);
1721 else if (dst
->File
== PROGRAM_WRITE_ONLY
) {
1722 _mesa_printf("%cC", "HR"[dst
->Index
]);
1725 _mesa_printf("???");
1728 if (dst
->WriteMask
!= 0 && dst
->WriteMask
!= WRITEMASK_XYZW
) {
1730 if (dst
->WriteMask
& WRITEMASK_X
)
1732 if (dst
->WriteMask
& WRITEMASK_Y
)
1734 if (dst
->WriteMask
& WRITEMASK_Z
)
1736 if (dst
->WriteMask
& WRITEMASK_W
)
1740 if (dst
->CondMask
!= COND_TR
||
1741 dst
->CondSwizzle
!= SWIZZLE_NOOP
) {
1750 * Print (unparse) the given vertex program. Just for debugging.
1753 _mesa_print_nv_fragment_program(const struct gl_fragment_program
*program
)
1755 const struct prog_instruction
*inst
;
1757 for (inst
= program
->Base
.Instructions
; inst
->Opcode
!= OPCODE_END
; inst
++) {
1759 for (i
= 0; Instructions
[i
].name
; i
++) {
1760 if (inst
->Opcode
== Instructions
[i
].opcode
) {
1761 /* print instruction name */
1762 _mesa_printf("%s", Instructions
[i
].name
);
1763 if (inst
->Precision
== FLOAT16
)
1765 else if (inst
->Precision
== FIXED12
)
1767 if (inst
->CondUpdate
)
1769 if (inst
->SaturateMode
== SATURATE_ZERO_ONE
)
1770 _mesa_printf("_SAT");
1773 if (Instructions
[i
].inputs
== INPUT_CC
) {
1774 PrintCondCode(&inst
->DstReg
);
1776 else if (Instructions
[i
].outputs
== OUTPUT_V
||
1777 Instructions
[i
].outputs
== OUTPUT_S
) {
1778 /* print dest register */
1779 PrintDstReg(&inst
->DstReg
);
1783 /* print source register(s) */
1784 if (Instructions
[i
].inputs
== INPUT_1V
||
1785 Instructions
[i
].inputs
== INPUT_1S
) {
1786 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1788 else if (Instructions
[i
].inputs
== INPUT_2V
||
1789 Instructions
[i
].inputs
== INPUT_2S
) {
1790 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1792 PrintSrcReg(program
, &inst
->SrcReg
[1]);
1794 else if (Instructions
[i
].inputs
== INPUT_3V
) {
1795 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1797 PrintSrcReg(program
, &inst
->SrcReg
[1]);
1799 PrintSrcReg(program
, &inst
->SrcReg
[2]);
1801 else if (Instructions
[i
].inputs
== INPUT_1V_T
) {
1802 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1804 PrintTextureSrc(inst
);
1806 else if (Instructions
[i
].inputs
== INPUT_3V_T
) {
1807 PrintSrcReg(program
, &inst
->SrcReg
[0]);
1809 PrintSrcReg(program
, &inst
->SrcReg
[1]);
1811 PrintSrcReg(program
, &inst
->SrcReg
[2]);
1813 PrintTextureSrc(inst
);
1815 _mesa_printf(";\n");
1819 if (!Instructions
[i
].name
) {
1820 _mesa_printf("Invalid opcode %d\n", inst
->Opcode
);
1823 _mesa_printf("END\n");
1828 _mesa_nv_fragment_input_register_name(GLuint i
)
1830 ASSERT(i
< MAX_NV_FRAGMENT_PROGRAM_INPUTS
);
1831 return InputRegisters
[i
];
1836 _mesa_nv_fragment_output_register_name(GLuint i
)
1838 ASSERT(i
< MAX_NV_FRAGMENT_PROGRAM_OUTPUTS
);
1839 return OutputRegisters
[i
];