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 vertex program parser.
38 #include "nvprogram.h"
39 #include "nvvertparse.h"
40 #include "nvvertprog.h"
43 * Current parsing state. This structure is passed among the parsing
44 * functions and keeps track of the current parser position and various
51 const GLubyte
*curLine
;
52 GLboolean isStateProgram
;
53 GLboolean isPositionInvariant
;
54 GLboolean isVersion1_1
;
56 GLuint outputsWritten
;
57 GLuint progRegsWritten
;
58 GLuint numInst
; /* number of instructions parsed */
63 * Called whenever we find an error during parsing.
66 record_error(struct parse_state
*parseState
, const char *msg
, int lineNo
)
70 const GLubyte
*lineStr
;
71 lineStr
= _mesa_find_line_column(parseState
->start
,
72 parseState
->pos
, &line
, &column
);
73 _mesa_debug(parseState
->ctx
,
74 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
75 lineNo
, line
, column
, (char *) lineStr
, msg
);
76 _mesa_free((void *) lineStr
);
81 /* Check that no error was already recorded. Only record the first one. */
82 if (parseState
->ctx
->Program
.ErrorString
[0] == 0) {
83 _mesa_set_program_error(parseState
->ctx
,
84 parseState
->pos
- parseState
->start
,
90 #define RETURN_ERROR \
92 record_error(parseState, "Unexpected end of input.", __LINE__); \
96 #define RETURN_ERROR1(msg) \
98 record_error(parseState, msg, __LINE__); \
102 #define RETURN_ERROR2(msg1, msg2) \
105 _mesa_sprintf(err, "%s %s", msg1, msg2); \
106 record_error(parseState, err, __LINE__); \
114 static GLboolean
IsLetter(GLubyte b
)
116 return (b
>= 'a' && b
<= 'z') || (b
>= 'A' && b
<= 'Z');
120 static GLboolean
IsDigit(GLubyte b
)
122 return b
>= '0' && b
<= '9';
126 static GLboolean
IsWhitespace(GLubyte b
)
128 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
133 * Starting at 'str' find the next token. A token can be an integer,
134 * an identifier or punctuation symbol.
135 * \return <= 0 we found an error, else, return number of characters parsed.
138 GetToken(struct parse_state
*parseState
, GLubyte
*token
)
140 const GLubyte
*str
= parseState
->pos
;
145 /* skip whitespace and comments */
146 while (str
[i
] && (IsWhitespace(str
[i
]) || str
[i
] == '#')) {
149 while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
152 if (str
[i
] == '\n' || str
[i
] == '\r')
153 parseState
->curLine
= str
+ i
+ 1;
156 /* skip whitespace */
157 if (str
[i
] == '\n' || str
[i
] == '\r')
158 parseState
->curLine
= str
+ i
+ 1;
166 /* try matching an integer */
167 while (str
[i
] && IsDigit(str
[i
])) {
168 token
[j
++] = str
[i
++];
170 if (j
> 0 || !str
[i
]) {
175 /* try matching an identifier */
176 if (IsLetter(str
[i
])) {
177 while (str
[i
] && (IsLetter(str
[i
]) || IsDigit(str
[i
]))) {
178 token
[j
++] = str
[i
++];
184 /* punctuation character */
198 * Get next token from input stream and increment stream pointer past token.
201 Parse_Token(struct parse_state
*parseState
, GLubyte
*token
)
204 i
= GetToken(parseState
, token
);
206 parseState
->pos
+= (-i
);
209 parseState
->pos
+= i
;
215 * Get next token from input stream but don't increment stream pointer.
218 Peek_Token(struct parse_state
*parseState
, GLubyte
*token
)
221 i
= GetToken(parseState
, token
);
223 parseState
->pos
+= (-i
);
226 len
= _mesa_strlen((const char *) token
);
227 parseState
->pos
+= (i
- len
);
233 * Try to match 'pattern' as the next token after any whitespace/comments.
234 * Advance the current parsing position only if we match the pattern.
235 * \return GL_TRUE if pattern is matched, GL_FALSE otherwise.
238 Parse_String(struct parse_state
*parseState
, const char *pattern
)
243 /* skip whitespace and comments */
244 while (IsWhitespace(*parseState
->pos
) || *parseState
->pos
== '#') {
245 if (*parseState
->pos
== '#') {
246 while (*parseState
->pos
&& (*parseState
->pos
!= '\n' && *parseState
->pos
!= '\r')) {
247 parseState
->pos
+= 1;
249 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
250 parseState
->curLine
= parseState
->pos
+ 1;
253 /* skip whitespace */
254 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
255 parseState
->curLine
= parseState
->pos
+ 1;
256 parseState
->pos
+= 1;
260 /* Try to match the pattern */
262 for (i
= 0; pattern
[i
]; i
++) {
263 if (*m
!= (GLubyte
) pattern
[i
])
269 return GL_TRUE
; /* success */
273 /**********************************************************************/
275 static const char *InputRegisters
[MAX_NV_VERTEX_PROGRAM_INPUTS
+ 1] = {
276 "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
277 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
280 static const char *OutputRegisters
[MAX_NV_VERTEX_PROGRAM_OUTPUTS
+ 1] = {
281 "HPOS", "COL0", "COL1", "BFC0", "BFC1", "FOGC", "PSIZ",
282 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
285 static const char *Opcodes
[] = {
286 "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
287 "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
294 IsProgRegister(GLuint r
)
296 return (GLuint
) (r
>= VP_PROG_REG_START
&& r
<= VP_PROG_REG_END
);
300 IsInputRegister(GLuint r
)
302 return (GLuint
) (r
>= VP_INPUT_REG_START
&& r
<= VP_INPUT_REG_END
);
306 IsOutputRegister(GLuint r
)
308 return (GLuint
) (r
>= VP_OUTPUT_REG_START
&& r
<= VP_OUTPUT_REG_END
);
313 * Parse a temporary register: Rnn
316 Parse_TempReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
320 /* Should be 'R##' */
321 if (!Parse_Token(parseState
, token
))
324 RETURN_ERROR1("Expected R##");
326 if (IsDigit(token
[1])) {
327 GLint reg
= _mesa_atoi((char *) (token
+ 1));
328 if (reg
>= VP_NUM_TEMP_REGS
)
329 RETURN_ERROR1("Bad temporary register name");
330 *tempRegNum
= VP_TEMP_REG_START
+ reg
;
333 RETURN_ERROR1("Bad temporary register name");
341 * Parse address register "A0.x"
344 Parse_AddrReg(struct parse_state
*parseState
)
347 if (!Parse_String(parseState
, "A0"))
351 if (!Parse_String(parseState
, "."))
355 if (!Parse_String(parseState
, "x"))
363 * Parse absolute program parameter register "c[##]"
366 Parse_AbsParamReg(struct parse_state
*parseState
, GLint
*regNum
)
370 if (!Parse_String(parseState
, "c"))
373 if (!Parse_String(parseState
, "["))
376 if (!Parse_Token(parseState
, token
))
379 if (IsDigit(token
[0])) {
380 /* a numbered program parameter register */
381 GLint reg
= _mesa_atoi((char *) token
);
382 if (reg
>= VP_NUM_PROG_REGS
)
383 RETURN_ERROR1("Bad constant program number");
384 *regNum
= VP_PROG_REG_START
+ reg
;
390 if (!Parse_String(parseState
, "]"))
398 Parse_ParamReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
402 if (!Parse_String(parseState
, "c"))
405 if (!Parse_String(parseState
, "["))
408 if (!Peek_Token(parseState
, token
))
411 if (IsDigit(token
[0])) {
412 /* a numbered program parameter register */
414 (void) Parse_Token(parseState
, token
);
415 reg
= _mesa_atoi((char *) token
);
416 if (reg
>= VP_NUM_PROG_REGS
)
417 RETURN_ERROR1("Bad constant program number");
418 srcReg
->Register
= VP_PROG_REG_START
+ reg
;
420 else if (_mesa_strcmp((const char *) token
, "A0") == 0) {
421 /* address register "A0.x" */
422 if (!Parse_AddrReg(parseState
))
425 srcReg
->RelAddr
= GL_TRUE
;
426 srcReg
->Register
= 0;
428 /* Look for +/-N offset */
429 if (!Peek_Token(parseState
, token
))
432 if (token
[0] == '-' || token
[0] == '+') {
433 const GLubyte sign
= token
[0];
434 (void) Parse_Token(parseState
, token
); /* consume +/- */
436 /* an integer should be next */
437 if (!Parse_Token(parseState
, token
))
440 if (IsDigit(token
[0])) {
441 const GLint k
= _mesa_atoi((char *) token
);
444 RETURN_ERROR1("Bad address offset");
445 srcReg
->Register
= -k
;
449 RETURN_ERROR1("Bad address offset");
450 srcReg
->Register
= k
;
458 /* probably got a ']', catch it below */
465 /* Match closing ']' */
466 if (!Parse_String(parseState
, "]"))
474 * Parse v[#] or v[<name>]
477 Parse_AttribReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
483 if (!Parse_String(parseState
, "v"))
487 if (!Parse_String(parseState
, "["))
490 /* match number or named register */
491 if (!Parse_Token(parseState
, token
))
494 if (parseState
->isStateProgram
&& token
[0] != '0')
495 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
497 if (IsDigit(token
[0])) {
498 GLint reg
= _mesa_atoi((char *) token
);
499 if (reg
>= VP_NUM_INPUT_REGS
)
500 RETURN_ERROR1("Bad vertex attribute register name");
501 *tempRegNum
= VP_INPUT_REG_START
+ reg
;
504 for (j
= 0; InputRegisters
[j
]; j
++) {
505 if (_mesa_strcmp((const char *) token
, InputRegisters
[j
]) == 0) {
506 *tempRegNum
= VP_INPUT_REG_START
+ j
;
510 if (!InputRegisters
[j
]) {
511 /* unknown input register label */
512 RETURN_ERROR2("Bad register name", token
);
517 if (!Parse_String(parseState
, "]"))
525 Parse_OutputReg(struct parse_state
*parseState
, GLint
*outputRegNum
)
531 if (!Parse_String(parseState
, "o"))
535 if (!Parse_String(parseState
, "["))
538 /* Get output reg name */
539 if (!Parse_Token(parseState
, token
))
542 if (parseState
->isPositionInvariant
)
543 start
= 1; /* skip HPOS register name */
547 /* try to match an output register name */
548 for (j
= start
; OutputRegisters
[j
]; j
++) {
549 if (_mesa_strcmp((const char *) token
, OutputRegisters
[j
]) == 0) {
550 *outputRegNum
= VP_OUTPUT_REG_START
+ j
;
554 if (!OutputRegisters
[j
])
555 RETURN_ERROR1("Unrecognized output register name");
558 if (!Parse_String(parseState
, "]"))
559 RETURN_ERROR1("Expected ]");
566 Parse_MaskedDstReg(struct parse_state
*parseState
, struct vp_dst_register
*dstReg
)
570 /* Dst reg can be R<n> or o[n] */
571 if (!Peek_Token(parseState
, token
))
574 if (token
[0] == 'R') {
575 /* a temporary register */
576 if (!Parse_TempReg(parseState
, &dstReg
->Register
))
579 else if (!parseState
->isStateProgram
&& token
[0] == 'o') {
580 /* an output register */
581 if (!Parse_OutputReg(parseState
, &dstReg
->Register
))
584 else if (parseState
->isStateProgram
&& token
[0] == 'c') {
585 /* absolute program parameter register */
586 if (!Parse_AbsParamReg(parseState
, &dstReg
->Register
))
590 RETURN_ERROR1("Bad destination register name");
593 /* Parse optional write mask */
594 if (!Peek_Token(parseState
, token
))
597 if (token
[0] == '.') {
601 if (!Parse_String(parseState
, "."))
604 if (!Parse_Token(parseState
, token
))
607 dstReg
->WriteMask
[0] = GL_FALSE
;
608 dstReg
->WriteMask
[1] = GL_FALSE
;
609 dstReg
->WriteMask
[2] = GL_FALSE
;
610 dstReg
->WriteMask
[3] = GL_FALSE
;
612 if (token
[k
] == 'x') {
613 dstReg
->WriteMask
[0] = GL_TRUE
;
616 if (token
[k
] == 'y') {
617 dstReg
->WriteMask
[1] = GL_TRUE
;
620 if (token
[k
] == 'z') {
621 dstReg
->WriteMask
[2] = GL_TRUE
;
624 if (token
[k
] == 'w') {
625 dstReg
->WriteMask
[3] = GL_TRUE
;
629 RETURN_ERROR1("Bad writemask character");
634 dstReg
->WriteMask
[0] = GL_TRUE
;
635 dstReg
->WriteMask
[1] = GL_TRUE
;
636 dstReg
->WriteMask
[2] = GL_TRUE
;
637 dstReg
->WriteMask
[3] = GL_TRUE
;
644 Parse_SwizzleSrcReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
648 srcReg
->RelAddr
= GL_FALSE
;
651 if (!Peek_Token(parseState
, token
))
653 if (token
[0] == '-') {
654 (void) Parse_String(parseState
, "-");
655 srcReg
->Negate
= GL_TRUE
;
656 if (!Peek_Token(parseState
, token
))
660 srcReg
->Negate
= GL_FALSE
;
663 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
664 if (token
[0] == 'R') {
665 if (!Parse_TempReg(parseState
, &srcReg
->Register
))
668 else if (token
[0] == 'c') {
669 if (!Parse_ParamReg(parseState
, srcReg
))
672 else if (token
[0] == 'v') {
673 if (!Parse_AttribReg(parseState
, &srcReg
->Register
))
677 RETURN_ERROR2("Bad source register name", token
);
680 /* init swizzle fields */
681 srcReg
->Swizzle
[0] = 0;
682 srcReg
->Swizzle
[1] = 1;
683 srcReg
->Swizzle
[2] = 2;
684 srcReg
->Swizzle
[3] = 3;
686 /* Look for optional swizzle suffix */
687 if (!Peek_Token(parseState
, token
))
689 if (token
[0] == '.') {
690 (void) Parse_String(parseState
, "."); /* consume . */
692 if (!Parse_Token(parseState
, token
))
696 /* single letter swizzle */
698 ASSIGN_4V(srcReg
->Swizzle
, 0, 0, 0, 0);
699 else if (token
[0] == 'y')
700 ASSIGN_4V(srcReg
->Swizzle
, 1, 1, 1, 1);
701 else if (token
[0] == 'z')
702 ASSIGN_4V(srcReg
->Swizzle
, 2, 2, 2, 2);
703 else if (token
[0] == 'w')
704 ASSIGN_4V(srcReg
->Swizzle
, 3, 3, 3, 3);
706 RETURN_ERROR1("Expected x, y, z, or w");
709 /* 2, 3 or 4-component swizzle */
711 for (k
= 0; token
[k
] && k
< 5; k
++) {
713 srcReg
->Swizzle
[k
] = 0;
714 else if (token
[k
] == 'y')
715 srcReg
->Swizzle
[k
] = 1;
716 else if (token
[k
] == 'z')
717 srcReg
->Swizzle
[k
] = 2;
718 else if (token
[k
] == 'w')
719 srcReg
->Swizzle
[k
] = 3;
733 Parse_ScalarSrcReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
737 srcReg
->RelAddr
= GL_FALSE
;
740 if (!Peek_Token(parseState
, token
))
742 if (token
[0] == '-') {
743 srcReg
->Negate
= GL_TRUE
;
744 (void) Parse_String(parseState
, "-"); /* consume '-' */
745 if (!Peek_Token(parseState
, token
))
749 srcReg
->Negate
= GL_FALSE
;
752 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
753 if (token
[0] == 'R') {
754 if (!Parse_TempReg(parseState
, &srcReg
->Register
))
757 else if (token
[0] == 'c') {
758 if (!Parse_ParamReg(parseState
, srcReg
))
761 else if (token
[0] == 'v') {
762 if (!Parse_AttribReg(parseState
, &srcReg
->Register
))
766 RETURN_ERROR2("Bad source register name", token
);
769 /* Look for .[xyzw] suffix */
770 if (!Parse_String(parseState
, "."))
773 if (!Parse_Token(parseState
, token
))
776 if (token
[0] == 'x' && token
[1] == 0) {
777 srcReg
->Swizzle
[0] = 0;
779 else if (token
[0] == 'y' && token
[1] == 0) {
780 srcReg
->Swizzle
[0] = 1;
782 else if (token
[0] == 'z' && token
[1] == 0) {
783 srcReg
->Swizzle
[0] = 2;
785 else if (token
[0] == 'w' && token
[1] == 0) {
786 srcReg
->Swizzle
[0] = 3;
789 RETURN_ERROR1("Bad scalar source suffix");
791 srcReg
->Swizzle
[1] = srcReg
->Swizzle
[2] = srcReg
->Swizzle
[3] = 0;
798 Parse_UnaryOpInstruction(struct parse_state
*parseState
,
799 struct vp_instruction
*inst
, enum vp_opcode opcode
)
801 if (opcode
== VP_OPCODE_ABS
&& !parseState
->isVersion1_1
)
802 RETURN_ERROR1("ABS illegal for vertex program 1.0");
804 inst
->Opcode
= opcode
;
805 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
808 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
812 if (!Parse_String(parseState
, ","))
816 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
820 if (!Parse_String(parseState
, ";"))
828 Parse_BiOpInstruction(struct parse_state
*parseState
,
829 struct vp_instruction
*inst
, enum vp_opcode opcode
)
831 if (opcode
== VP_OPCODE_DPH
&& !parseState
->isVersion1_1
)
832 RETURN_ERROR1("DPH illegal for vertex program 1.0");
833 if (opcode
== VP_OPCODE_SUB
&& !parseState
->isVersion1_1
)
834 RETURN_ERROR1("SUB illegal for vertex program 1.0");
836 inst
->Opcode
= opcode
;
837 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
840 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
844 if (!Parse_String(parseState
, ","))
848 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
852 if (!Parse_String(parseState
, ","))
856 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
860 if (!Parse_String(parseState
, ";"))
863 /* make sure we don't reference more than one program parameter register */
864 if (IsProgRegister(inst
->SrcReg
[0].Register
) &&
865 IsProgRegister(inst
->SrcReg
[1].Register
) &&
866 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
)
867 RETURN_ERROR1("Can't reference two program parameter registers");
869 /* make sure we don't reference more than one vertex attribute register */
870 if (IsInputRegister(inst
->SrcReg
[0].Register
) &&
871 IsInputRegister(inst
->SrcReg
[1].Register
) &&
872 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
)
873 RETURN_ERROR1("Can't reference two vertex attribute registers");
880 Parse_TriOpInstruction(struct parse_state
*parseState
,
881 struct vp_instruction
*inst
, enum vp_opcode opcode
)
883 inst
->Opcode
= opcode
;
884 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
887 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
891 if (!Parse_String(parseState
, ","))
895 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
899 if (!Parse_String(parseState
, ","))
903 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
907 if (!Parse_String(parseState
, ","))
911 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[2]))
915 if (!Parse_String(parseState
, ";"))
918 /* make sure we don't reference more than one program parameter register */
919 if ((IsProgRegister(inst
->SrcReg
[0].Register
) &&
920 IsProgRegister(inst
->SrcReg
[1].Register
) &&
921 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
) ||
922 (IsProgRegister(inst
->SrcReg
[0].Register
) &&
923 IsProgRegister(inst
->SrcReg
[2].Register
) &&
924 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[2].Register
) ||
925 (IsProgRegister(inst
->SrcReg
[1].Register
) &&
926 IsProgRegister(inst
->SrcReg
[2].Register
) &&
927 inst
->SrcReg
[1].Register
!= inst
->SrcReg
[2].Register
))
928 RETURN_ERROR1("Can only reference one program register");
930 /* make sure we don't reference more than one vertex attribute register */
931 if ((IsInputRegister(inst
->SrcReg
[0].Register
) &&
932 IsInputRegister(inst
->SrcReg
[1].Register
) &&
933 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
) ||
934 (IsInputRegister(inst
->SrcReg
[0].Register
) &&
935 IsInputRegister(inst
->SrcReg
[2].Register
) &&
936 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[2].Register
) ||
937 (IsInputRegister(inst
->SrcReg
[1].Register
) &&
938 IsInputRegister(inst
->SrcReg
[2].Register
) &&
939 inst
->SrcReg
[1].Register
!= inst
->SrcReg
[2].Register
))
940 RETURN_ERROR1("Can only reference one input register");
947 Parse_ScalarInstruction(struct parse_state
*parseState
,
948 struct vp_instruction
*inst
, enum vp_opcode opcode
)
950 if (opcode
== VP_OPCODE_RCC
&& !parseState
->isVersion1_1
)
951 RETURN_ERROR1("RCC illegal for vertex program 1.0");
953 inst
->Opcode
= opcode
;
954 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
957 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
961 if (!Parse_String(parseState
, ","))
965 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
969 if (!Parse_String(parseState
, ";"))
977 Parse_AddressInstruction(struct parse_state
*parseState
, struct vp_instruction
*inst
)
979 inst
->Opcode
= VP_OPCODE_ARL
;
980 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
983 if (!Parse_AddrReg(parseState
))
987 if (!Parse_String(parseState
, ","))
991 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
995 if (!Parse_String(parseState
, ";"))
1003 Parse_EndInstruction(struct parse_state
*parseState
, struct vp_instruction
*inst
)
1007 inst
->Opcode
= VP_OPCODE_END
;
1008 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
1010 /* this should fail! */
1011 if (Parse_Token(parseState
, token
))
1012 RETURN_ERROR2("Unexpected token after END:", token
);
1019 Parse_OptionSequence(struct parse_state
*parseState
,
1020 struct vp_instruction program
[])
1023 if (!Parse_String(parseState
, "OPTION"))
1024 return GL_TRUE
; /* ok, not an OPTION statement */
1025 if (Parse_String(parseState
, "NV_position_invariant")) {
1026 parseState
->isPositionInvariant
= GL_TRUE
;
1029 RETURN_ERROR1("unexpected OPTION statement");
1031 if (!Parse_String(parseState
, ";"))
1038 Parse_InstructionSequence(struct parse_state
*parseState
,
1039 struct vp_instruction program
[])
1042 struct vp_instruction
*inst
= program
+ parseState
->numInst
;
1044 /* Initialize the instruction */
1045 inst
->SrcReg
[0].Register
= -1;
1046 inst
->SrcReg
[1].Register
= -1;
1047 inst
->SrcReg
[2].Register
= -1;
1048 inst
->DstReg
.Register
= -1;
1050 if (Parse_String(parseState
, "MOV")) {
1051 if (!Parse_UnaryOpInstruction(parseState
, inst
, VP_OPCODE_MOV
))
1054 else if (Parse_String(parseState
, "LIT")) {
1055 if (!Parse_UnaryOpInstruction(parseState
, inst
, VP_OPCODE_LIT
))
1058 else if (Parse_String(parseState
, "ABS")) {
1059 if (!Parse_UnaryOpInstruction(parseState
, inst
, VP_OPCODE_ABS
))
1062 else if (Parse_String(parseState
, "MUL")) {
1063 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_MUL
))
1066 else if (Parse_String(parseState
, "ADD")) {
1067 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_ADD
))
1070 else if (Parse_String(parseState
, "DP3")) {
1071 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DP3
))
1074 else if (Parse_String(parseState
, "DP4")) {
1075 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DP4
))
1078 else if (Parse_String(parseState
, "DST")) {
1079 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DST
))
1082 else if (Parse_String(parseState
, "MIN")) {
1083 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_MIN
))
1086 else if (Parse_String(parseState
, "MAX")) {
1087 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_MAX
))
1090 else if (Parse_String(parseState
, "SLT")) {
1091 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_SLT
))
1094 else if (Parse_String(parseState
, "SGE")) {
1095 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_SGE
))
1098 else if (Parse_String(parseState
, "DPH")) {
1099 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DPH
))
1102 else if (Parse_String(parseState
, "SUB")) {
1103 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_SUB
))
1106 else if (Parse_String(parseState
, "MAD")) {
1107 if (!Parse_TriOpInstruction(parseState
, inst
, VP_OPCODE_MAD
))
1110 else if (Parse_String(parseState
, "RCP")) {
1111 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_RCP
))
1114 else if (Parse_String(parseState
, "RSQ")) {
1115 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_RSQ
))
1118 else if (Parse_String(parseState
, "EXP")) {
1119 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_EXP
))
1122 else if (Parse_String(parseState
, "LOG")) {
1123 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_LOG
))
1126 else if (Parse_String(parseState
, "RCC")) {
1127 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_RCC
))
1130 else if (Parse_String(parseState
, "ARL")) {
1131 if (!Parse_AddressInstruction(parseState
, inst
))
1134 else if (Parse_String(parseState
, "END")) {
1135 if (!Parse_EndInstruction(parseState
, inst
))
1138 parseState
->numInst
++;
1139 return GL_TRUE
; /* all done */
1143 /* bad instruction name */
1144 RETURN_ERROR1("Unexpected token");
1147 /* examine input/output registers */
1149 const GLint srcReg0
= inst
->SrcReg
[0].Register
;
1150 const GLint srcReg1
= inst
->SrcReg
[1].Register
;
1151 const GLint srcReg2
= inst
->SrcReg
[2].Register
;
1152 const GLint dstReg
= inst
->DstReg
.Register
;
1154 if (IsOutputRegister(dstReg
))
1155 parseState
->outputsWritten
|= (1 << (dstReg
- VP_OUTPUT_REG_START
));
1156 else if (IsProgRegister(dstReg
))
1157 parseState
->progRegsWritten
|= (1 << (dstReg
- VP_PROG_REG_START
));
1159 if (IsInputRegister(srcReg0
) && !inst
->SrcReg
[0].RelAddr
)
1160 parseState
->inputsRead
|= (1 << (srcReg0
- VP_INPUT_REG_START
));
1162 if (IsInputRegister(srcReg1
) && !inst
->SrcReg
[1].RelAddr
)
1163 parseState
->inputsRead
|= (1 << (srcReg1
- VP_INPUT_REG_START
));
1165 if (IsInputRegister(srcReg2
) && !inst
->SrcReg
[2].RelAddr
)
1166 parseState
->inputsRead
|= (1 << (srcReg2
- VP_INPUT_REG_START
));
1169 parseState
->numInst
++;
1171 if (parseState
->numInst
>= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
)
1172 RETURN_ERROR1("Program too long");
1180 Parse_Program(struct parse_state
*parseState
,
1181 struct vp_instruction instBuffer
[])
1183 if (parseState
->isVersion1_1
) {
1184 if (!Parse_OptionSequence(parseState
, instBuffer
)) {
1188 return Parse_InstructionSequence(parseState
, instBuffer
);
1193 * Parse/compile the 'str' returning the compiled 'program'.
1194 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1195 * indicates the position of the error in 'str'.
1198 _mesa_parse_nv_vertex_program(GLcontext
*ctx
, GLenum dstTarget
,
1199 const GLubyte
*str
, GLsizei len
,
1200 struct vertex_program
*program
)
1202 struct parse_state parseState
;
1203 struct vp_instruction instBuffer
[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
];
1204 struct vp_instruction
*newInst
;
1206 GLubyte
*programString
;
1208 /* Make a null-terminated copy of the program string */
1209 programString
= (GLubyte
*) MALLOC(len
+ 1);
1210 if (!programString
) {
1211 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1214 MEMCPY(programString
, str
, len
);
1215 programString
[len
] = 0;
1217 /* Get ready to parse */
1218 parseState
.ctx
= ctx
;
1219 parseState
.start
= programString
;
1220 parseState
.isPositionInvariant
= GL_FALSE
;
1221 parseState
.isVersion1_1
= GL_FALSE
;
1222 parseState
.numInst
= 0;
1223 parseState
.inputsRead
= 0;
1224 parseState
.outputsWritten
= 0;
1225 parseState
.progRegsWritten
= 0;
1227 /* Reset error state */
1228 _mesa_set_program_error(ctx
, -1, NULL
);
1230 /* check the program header */
1231 if (_mesa_strncmp((const char *) programString
, "!!VP1.0", 7) == 0) {
1232 target
= GL_VERTEX_PROGRAM_NV
;
1233 parseState
.pos
= programString
+ 7;
1234 parseState
.isStateProgram
= GL_FALSE
;
1236 else if (_mesa_strncmp((const char *) programString
, "!!VP1.1", 7) == 0) {
1237 target
= GL_VERTEX_PROGRAM_NV
;
1238 parseState
.pos
= programString
+ 7;
1239 parseState
.isStateProgram
= GL_FALSE
;
1240 parseState
.isVersion1_1
= GL_TRUE
;
1242 else if (_mesa_strncmp((const char *) programString
, "!!VSP1.0", 8) == 0) {
1243 target
= GL_VERTEX_STATE_PROGRAM_NV
;
1244 parseState
.pos
= programString
+ 8;
1245 parseState
.isStateProgram
= GL_TRUE
;
1248 /* invalid header */
1249 ctx
->Program
.ErrorPos
= 0;
1250 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1254 /* make sure target and header match */
1255 if (target
!= dstTarget
) {
1256 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1257 "glLoadProgramNV(target mismatch)");
1262 if (Parse_Program(&parseState
, instBuffer
)) {
1263 /* successful parse! */
1265 if (parseState
.isStateProgram
) {
1266 if (parseState
.progRegsWritten
== 0) {
1267 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1268 "glLoadProgramNV(c[#] not written)");
1273 if (!parseState
.isPositionInvariant
&&
1274 !(parseState
.outputsWritten
& 1)) {
1275 /* bit 1 = HPOS register */
1276 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1277 "glLoadProgramNV(HPOS not written)");
1282 /* copy the compiled instructions */
1283 assert(parseState
.numInst
<= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
);
1284 newInst
= (struct vp_instruction
*)
1285 MALLOC(parseState
.numInst
* sizeof(struct vp_instruction
));
1287 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1288 FREE(programString
);
1289 return; /* out of memory */
1291 MEMCPY(newInst
, instBuffer
,
1292 parseState
.numInst
* sizeof(struct vp_instruction
));
1294 /* install the program */
1295 program
->Base
.Target
= target
;
1296 if (program
->Base
.String
) {
1297 FREE(program
->Base
.String
);
1299 program
->Base
.String
= programString
;
1300 program
->Base
.Format
= GL_PROGRAM_FORMAT_ASCII_ARB
;
1301 if (program
->Instructions
) {
1302 FREE(program
->Instructions
);
1304 program
->Instructions
= newInst
;
1305 program
->InputsRead
= parseState
.inputsRead
;
1306 program
->OutputsWritten
= parseState
.outputsWritten
;
1307 program
->IsPositionInvariant
= parseState
.isPositionInvariant
;
1310 _mesa_printf("--- glLoadProgramNV result ---\n");
1311 _mesa_print_nv_vertex_program(program
);
1312 _mesa_printf("------------------------------\n");
1317 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1318 /* NOTE: _mesa_set_program_error would have been called already */
1319 /* GL_NV_vertex_program isn't supposed to set the error string
1320 * so we reset it here.
1322 _mesa_set_program_error(ctx
, ctx
->Program
.ErrorPos
, NULL
);
1328 PrintSrcReg(const struct vp_src_register
*src
)
1330 static const char comps
[5] = "xyzw";
1334 if (src
->Register
> 0)
1335 _mesa_printf("c[A0.x + %d]", src
->Register
);
1336 else if (src
->Register
< 0)
1337 _mesa_printf("c[A0.x - %d]", -src
->Register
);
1339 _mesa_printf("c[A0.x]");
1341 else if (src
->Register
>= VP_OUTPUT_REG_START
1342 && src
->Register
<= VP_OUTPUT_REG_END
) {
1343 _mesa_printf("o[%s]", OutputRegisters
[src
->Register
- VP_OUTPUT_REG_START
]);
1345 else if (src
->Register
>= VP_INPUT_REG_START
1346 && src
->Register
<= VP_INPUT_REG_END
) {
1347 _mesa_printf("v[%s]", InputRegisters
[src
->Register
- VP_INPUT_REG_START
]);
1349 else if (src
->Register
>= VP_PROG_REG_START
1350 && src
->Register
<= VP_PROG_REG_END
) {
1351 _mesa_printf("c[%d]", src
->Register
- VP_PROG_REG_START
);
1354 _mesa_printf("R%d", src
->Register
- VP_TEMP_REG_START
);
1357 if (src
->Swizzle
[0] == src
->Swizzle
[1] &&
1358 src
->Swizzle
[0] == src
->Swizzle
[2] &&
1359 src
->Swizzle
[0] == src
->Swizzle
[3]) {
1360 _mesa_printf(".%c", comps
[src
->Swizzle
[0]]);
1362 else if (src
->Swizzle
[0] != 0 ||
1363 src
->Swizzle
[1] != 1 ||
1364 src
->Swizzle
[2] != 2 ||
1365 src
->Swizzle
[3] != 3) {
1366 _mesa_printf(".%c%c%c%c",
1367 comps
[src
->Swizzle
[0]],
1368 comps
[src
->Swizzle
[1]],
1369 comps
[src
->Swizzle
[2]],
1370 comps
[src
->Swizzle
[3]]);
1376 PrintDstReg(const struct vp_dst_register
*dst
)
1378 GLint w
= dst
->WriteMask
[0] + dst
->WriteMask
[1]
1379 + dst
->WriteMask
[2] + dst
->WriteMask
[3];
1381 if (dst
->Register
>= VP_OUTPUT_REG_START
1382 && dst
->Register
<= VP_OUTPUT_REG_END
) {
1383 _mesa_printf("o[%s]", OutputRegisters
[dst
->Register
- VP_OUTPUT_REG_START
]);
1385 else if (dst
->Register
>= VP_INPUT_REG_START
1386 && dst
->Register
<= VP_INPUT_REG_END
) {
1387 _mesa_printf("v[%s]", InputRegisters
[dst
->Register
- VP_INPUT_REG_START
]);
1389 else if (dst
->Register
>= VP_PROG_REG_START
1390 && dst
->Register
<= VP_PROG_REG_END
) {
1391 _mesa_printf("c[%d]", dst
->Register
- VP_PROG_REG_START
);
1394 _mesa_printf("R%d", dst
->Register
- VP_TEMP_REG_START
);
1397 if (w
!= 0 && w
!= 4) {
1399 if (dst
->WriteMask
[0])
1401 if (dst
->WriteMask
[1])
1403 if (dst
->WriteMask
[2])
1405 if (dst
->WriteMask
[3])
1412 * Print a single NVIDIA vertex program instruction.
1415 _mesa_print_nv_vertex_instruction(const struct vp_instruction
*inst
)
1417 switch (inst
->Opcode
) {
1426 _mesa_printf("%s ", Opcodes
[(int) inst
->Opcode
]);
1427 PrintDstReg(&inst
->DstReg
);
1429 PrintSrcReg(&inst
->SrcReg
[0]);
1430 _mesa_printf(";\n");
1443 _mesa_printf("%s ", Opcodes
[(int) inst
->Opcode
]);
1444 PrintDstReg(&inst
->DstReg
);
1446 PrintSrcReg(&inst
->SrcReg
[0]);
1448 PrintSrcReg(&inst
->SrcReg
[1]);
1449 _mesa_printf(";\n");
1452 _mesa_printf("MAD ");
1453 PrintDstReg(&inst
->DstReg
);
1455 PrintSrcReg(&inst
->SrcReg
[0]);
1457 PrintSrcReg(&inst
->SrcReg
[1]);
1459 PrintSrcReg(&inst
->SrcReg
[2]);
1460 _mesa_printf(";\n");
1463 _mesa_printf("ARL A0.x, ");
1464 PrintSrcReg(&inst
->SrcReg
[0]);
1465 _mesa_printf(";\n");
1468 _mesa_printf("END\n");
1471 _mesa_printf("BAD INSTRUCTION\n");
1477 * Print (unparse) the given vertex program. Just for debugging.
1480 _mesa_print_nv_vertex_program(const struct vertex_program
*program
)
1482 const struct vp_instruction
*inst
;
1484 for (inst
= program
->Instructions
; ; inst
++) {
1485 _mesa_print_nv_vertex_instruction(inst
);
1486 if (inst
->Opcode
== VP_OPCODE_END
)
1493 _mesa_nv_vertex_input_register_name(GLuint i
)
1495 ASSERT(i
< MAX_NV_VERTEX_PROGRAM_INPUTS
);
1496 return InputRegisters
[i
];
1501 _mesa_nv_vertex_output_register_name(GLuint i
)
1503 ASSERT(i
< MAX_NV_VERTEX_PROGRAM_OUTPUTS
);
1504 return OutputRegisters
[i
];