1 /* $Id: nvvertparse.c,v 1.1 2003/01/14 04:55:46 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 * \brief NVIDIA vertex program parser.
40 #include "nvprogram.h"
41 #include "nvvertparse.h"
42 #include "nvvertprog.h"
45 /************************ Symbol Table ******************************/
47 /* A simple symbol table implementation for ARB_vertex_program
59 static struct symbol
*SymbolTable
= NULL
;
62 IsSymbol(const GLubyte
*symbol
)
65 for (s
= SymbolTable
; s
; s
= s
->next
) {
66 if (strcmp((char *) symbol
, (char *)s
->name
) == 0)
73 GetSymbolValue(const GLubyte
*symbol
)
76 for (s
= SymbolTable
; s
; s
= s
->next
) {
77 if (strcmp((char *) symbol
, (char *)s
->name
) == 0)
84 AddSymbol(const GLubyte
*symbol
, GLint value
)
86 struct symbol
*s
= MALLOC_STRUCT(symbol
);
88 s
->name
= (GLubyte
*) strdup((char *) symbol
);
90 s
->next
= SymbolTable
;
96 ResetSymbolTable(void)
98 struct symbol
*s
, *next
;
99 for (s
= SymbolTable
; s
; s
= next
) {
109 /***************************** Parsing ******************************/
112 static GLboolean
IsLetter(GLubyte b
)
114 return (b
>= 'a' && b
<= 'z') || (b
>= 'A' && b
<= 'Z');
118 static GLboolean
IsDigit(GLubyte b
)
120 return b
>= '0' && b
<= '9';
124 static GLboolean
IsWhitespace(GLubyte b
)
126 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
131 * Starting at 'str' find the next token. A token can be an integer,
132 * an identifier or punctuation symbol.
133 * \return <= 0 we found an error, else, return number of characters parsed.
136 GetToken(const GLubyte
*str
, GLubyte
*token
)
142 /* skip whitespace and comments */
143 while (str
[i
] && (IsWhitespace(str
[i
]) || str
[i
] == '#')) {
146 while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
151 /* skip whitespace */
159 /* try matching an integer */
160 while (str
[i
] && IsDigit(str
[i
])) {
161 token
[j
++] = str
[i
++];
163 if (j
> 0 || !str
[i
]) {
168 /* try matching an identifier */
169 if (IsLetter(str
[i
])) {
170 while (str
[i
] && (IsLetter(str
[i
]) || IsDigit(str
[i
]))) {
171 token
[j
++] = str
[i
++];
191 * Get next token from input stream and increment stream pointer past token.
194 Parse_Token(const GLubyte
**s
, GLubyte
*token
)
197 i
= GetToken(*s
, token
);
208 * Get next token from input stream but don't increment stream pointer.
211 Peek_Token(const GLubyte
**s
, GLubyte
*token
)
214 i
= GetToken(*s
, token
);
219 len
= _mesa_strlen((char *) token
);
226 * String equality test
229 StrEq(const GLubyte
*a
, const GLubyte
*b
)
232 for (i
= 0; a
[i
] && b
[i
] && a
[i
] == b
[i
]; i
++)
234 if (a
[i
] == 0 && b
[i
] == 0)
241 /**********************************************************************/
243 static const char *InputRegisters
[] = {
244 "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
245 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
248 static const char *OutputRegisters
[] = {
249 "HPOS", "COL0", "COL1", "BFC0", "BFC1", "FOGC", "PSIZ",
250 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
253 static const char *Opcodes
[] = {
254 "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
255 "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
262 #define PARSE_ERROR \
264 _mesa_printf("vpparse.c error at %d: parse error\n", __LINE__); \
268 #define PARSE_ERROR1(msg) \
270 _mesa_printf("vpparse.c error at %d: %s\n", __LINE__, msg); \
274 #define PARSE_ERROR2(msg1, msg2) \
276 _mesa_printf("vpparse.c error at %d: %s %s\n", __LINE__, msg1, msg2); \
282 #define PARSE_ERROR return GL_FALSE
283 #define PARSE_ERROR1(msg1) return GL_FALSE
284 #define PARSE_ERROR2(msg1, msg2) return GL_FALSE
290 IsProgRegister(GLuint r
)
292 return (GLuint
) (r
>= VP_PROG_REG_START
&& r
<= VP_PROG_REG_END
);
296 IsInputRegister(GLuint r
)
298 return (GLuint
) (r
>= VP_INPUT_REG_START
&& r
<= VP_INPUT_REG_END
);
302 IsOutputRegister(GLuint r
)
304 return (GLuint
) (r
>= VP_OUTPUT_REG_START
&& r
<= VP_OUTPUT_REG_END
);
309 /**********************************************************************/
312 * These shouldn't be globals as that makes the parser non-reentrant.
313 * We should really define a "ParserContext" class which contains these
314 * and the <s> pointer into the program text.
316 static GLboolean IsStateProgram
= GL_FALSE
;
317 static GLboolean IsPositionInvariant
= GL_FALSE
;
318 static GLboolean IsVersion1_1
= GL_FALSE
;
321 * Try to match 'pattern' as the next token after any whitespace/comments.
324 Parse_String(const GLubyte
**s
, const char *pattern
)
328 /* skip whitespace and comments */
329 while (IsWhitespace(**s
) || **s
== '#') {
331 while (**s
&& (**s
!= '\n' && **s
!= '\r')) {
336 /* skip whitespace */
341 /* Try to match the pattern */
342 for (i
= 0; pattern
[i
]; i
++) {
343 if (**s
!= pattern
[i
])
344 PARSE_ERROR2("failed to match", pattern
); /* failure */
348 return GL_TRUE
; /* success */
353 * Parse a temporary register: Rnn
356 Parse_TempReg(const GLubyte
**s
, GLint
*tempRegNum
)
360 /* Should be 'R##' */
361 if (!Parse_Token(s
, token
))
364 PARSE_ERROR1("Expected R##");
366 if (IsDigit(token
[1])) {
367 GLint reg
= _mesa_atoi((char *) (token
+ 1));
368 if (reg
>= VP_NUM_TEMP_REGS
)
369 PARSE_ERROR1("Bad temporary register name");
370 *tempRegNum
= VP_TEMP_REG_START
+ reg
;
373 PARSE_ERROR1("Bad temporary register name");
381 * Parse address register "A0.x"
384 Parse_AddrReg(const GLubyte
**s
)
387 if (!Parse_String(s
, "A0"))
391 if (!Parse_String(s
, "."))
395 if (!Parse_String(s
, "x"))
403 * Parse absolute program parameter register "c[##]"
406 Parse_AbsParamReg(const GLubyte
**s
, GLint
*regNum
)
410 if (!Parse_String(s
, "c"))
413 if (!Parse_String(s
, "["))
416 if (!Parse_Token(s
, token
))
419 if (IsDigit(token
[0])) {
420 /* a numbered program parameter register */
421 GLint reg
= _mesa_atoi((char *) token
);
422 if (reg
>= VP_NUM_PROG_REGS
)
423 PARSE_ERROR1("Bad constant program number");
424 *regNum
= VP_PROG_REG_START
+ reg
;
430 if (!Parse_String(s
, "]"))
438 Parse_ParamReg(const GLubyte
**s
, struct vp_src_register
*srcReg
)
442 if (!Parse_String(s
, "c"))
445 if (!Parse_String(s
, "["))
448 if (!Peek_Token(s
, token
))
451 if (IsDigit(token
[0])) {
452 /* a numbered program parameter register */
454 (void) Parse_Token(s
, token
);
455 reg
= _mesa_atoi((char *) token
);
456 if (reg
>= VP_NUM_PROG_REGS
)
457 PARSE_ERROR1("Bad constant program number");
458 srcReg
->Register
= VP_PROG_REG_START
+ reg
;
460 else if (StrEq(token
, (GLubyte
*) "A0")) {
461 /* address register "A0.x" */
462 if (!Parse_AddrReg(s
))
465 srcReg
->RelAddr
= GL_TRUE
;
466 srcReg
->Register
= 0;
468 /* Look for +/-N offset */
469 if (!Peek_Token(s
, token
))
472 if (token
[0] == '-' || token
[0] == '+') {
473 const GLubyte sign
= token
[0];
474 (void) Parse_Token(s
, token
); /* consume +/- */
476 /* an integer should be next */
477 if (!Parse_Token(s
, token
))
480 if (IsDigit(token
[0])) {
481 const GLint k
= _mesa_atoi((char *) token
);
484 PARSE_ERROR1("Bad address offset");
485 srcReg
->Register
= -k
;
489 PARSE_ERROR1("Bad address offset");
490 srcReg
->Register
= k
;
498 /* probably got a ']', catch it below */
505 /* Match closing ']' */
506 if (!Parse_String(s
, "]"))
514 * Parse v[#] or v[<name>]
517 Parse_AttribReg(const GLubyte
**s
, GLint
*tempRegNum
)
523 if (!Parse_String(s
, "v"))
527 if (!Parse_String(s
, "["))
530 /* match number or named register */
531 if (!Parse_Token(s
, token
))
534 if (IsStateProgram
&& token
[0] != '0')
535 PARSE_ERROR1("Only v[0] accessible in vertex state programs");
537 if (IsDigit(token
[0])) {
538 GLint reg
= _mesa_atoi((char *) token
);
539 if (reg
>= VP_NUM_INPUT_REGS
)
540 PARSE_ERROR1("Bad vertex attribute register name");
541 *tempRegNum
= VP_INPUT_REG_START
+ reg
;
544 for (j
= 0; InputRegisters
[j
]; j
++) {
545 if (StrEq(token
, (const GLubyte
*) InputRegisters
[j
])) {
546 *tempRegNum
= VP_INPUT_REG_START
+ j
;
550 if (!InputRegisters
[j
]) {
551 /* unknown input register label */
552 PARSE_ERROR2("Bad register name", token
);
557 if (!Parse_String(s
, "]"))
565 Parse_OutputReg(const GLubyte
**s
, GLint
*outputRegNum
)
571 if (!Parse_String(s
, "o"))
575 if (!Parse_String(s
, "["))
578 /* Get output reg name */
579 if (!Parse_Token(s
, token
))
582 if (IsPositionInvariant
)
583 start
= 1; /* skip HPOS register name */
587 /* try to match an output register name */
588 for (j
= start
; OutputRegisters
[j
]; j
++) {
589 if (StrEq(token
, (const GLubyte
*) OutputRegisters
[j
])) {
590 *outputRegNum
= VP_OUTPUT_REG_START
+ j
;
594 if (!OutputRegisters
[j
])
595 PARSE_ERROR1("Unrecognized output register name");
598 if (!Parse_String(s
, "]"))
599 PARSE_ERROR1("Expected ]");
606 Parse_MaskedDstReg(const GLubyte
**s
, struct vp_dst_register
*dstReg
)
610 /* Dst reg can be R<n> or o[n] */
611 if (!Peek_Token(s
, token
))
614 if (token
[0] == 'R') {
615 /* a temporary register */
616 if (!Parse_TempReg(s
, &dstReg
->Register
))
619 else if (!IsStateProgram
&& token
[0] == 'o') {
620 /* an output register */
621 if (!Parse_OutputReg(s
, &dstReg
->Register
))
624 else if (IsStateProgram
&& token
[0] == 'c') {
625 /* absolute program parameter register */
626 if (!Parse_AbsParamReg(s
, &dstReg
->Register
))
630 PARSE_ERROR1("Bad destination register name");
633 /* Parse optional write mask */
634 if (!Peek_Token(s
, token
))
637 if (token
[0] == '.') {
641 if (!Parse_String(s
, "."))
644 if (!Parse_Token(s
, token
))
647 dstReg
->WriteMask
[0] = GL_FALSE
;
648 dstReg
->WriteMask
[1] = GL_FALSE
;
649 dstReg
->WriteMask
[2] = GL_FALSE
;
650 dstReg
->WriteMask
[3] = GL_FALSE
;
652 if (token
[k
] == 'x') {
653 dstReg
->WriteMask
[0] = GL_TRUE
;
656 if (token
[k
] == 'y') {
657 dstReg
->WriteMask
[1] = GL_TRUE
;
660 if (token
[k
] == 'z') {
661 dstReg
->WriteMask
[2] = GL_TRUE
;
664 if (token
[k
] == 'w') {
665 dstReg
->WriteMask
[3] = GL_TRUE
;
669 PARSE_ERROR1("Bad writemask character");
674 dstReg
->WriteMask
[0] = GL_TRUE
;
675 dstReg
->WriteMask
[1] = GL_TRUE
;
676 dstReg
->WriteMask
[2] = GL_TRUE
;
677 dstReg
->WriteMask
[3] = GL_TRUE
;
684 Parse_SwizzleSrcReg(const GLubyte
**s
, struct vp_src_register
*srcReg
)
688 srcReg
->RelAddr
= GL_FALSE
;
691 if (!Peek_Token(s
, token
))
693 if (token
[0] == '-') {
694 (void) Parse_String(s
, "-");
695 srcReg
->Negate
= GL_TRUE
;
696 if (!Peek_Token(s
, token
))
700 srcReg
->Negate
= GL_FALSE
;
703 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
704 if (token
[0] == 'R') {
705 if (!Parse_TempReg(s
, &srcReg
->Register
))
708 else if (token
[0] == 'c') {
709 if (!Parse_ParamReg(s
, srcReg
))
712 else if (token
[0] == 'v') {
713 if (!Parse_AttribReg(s
, &srcReg
->Register
))
717 PARSE_ERROR2("Bad source register name", token
);
720 /* init swizzle fields */
721 srcReg
->Swizzle
[0] = 0;
722 srcReg
->Swizzle
[1] = 1;
723 srcReg
->Swizzle
[2] = 2;
724 srcReg
->Swizzle
[3] = 3;
726 /* Look for optional swizzle suffix */
727 if (!Peek_Token(s
, token
))
729 if (token
[0] == '.') {
730 (void) Parse_String(s
, "."); /* consume . */
732 if (!Parse_Token(s
, token
))
736 /* single letter swizzle */
738 ASSIGN_4V(srcReg
->Swizzle
, 0, 0, 0, 0);
739 else if (token
[0] == 'y')
740 ASSIGN_4V(srcReg
->Swizzle
, 1, 1, 1, 1);
741 else if (token
[0] == 'z')
742 ASSIGN_4V(srcReg
->Swizzle
, 2, 2, 2, 2);
743 else if (token
[0] == 'w')
744 ASSIGN_4V(srcReg
->Swizzle
, 3, 3, 3, 3);
746 PARSE_ERROR1("Expected x, y, z, or w");
749 /* 2, 3 or 4-component swizzle */
751 for (k
= 0; token
[k
] && k
< 5; k
++) {
753 srcReg
->Swizzle
[k
] = 0;
754 else if (token
[k
] == 'y')
755 srcReg
->Swizzle
[k
] = 1;
756 else if (token
[k
] == 'z')
757 srcReg
->Swizzle
[k
] = 2;
758 else if (token
[k
] == 'w')
759 srcReg
->Swizzle
[k
] = 3;
773 Parse_ScalarSrcReg(const GLubyte
**s
, struct vp_src_register
*srcReg
)
777 srcReg
->RelAddr
= GL_FALSE
;
780 if (!Peek_Token(s
, token
))
782 if (token
[0] == '-') {
783 srcReg
->Negate
= GL_TRUE
;
784 (void) Parse_String(s
, "-"); /* consume '-' */
785 if (!Peek_Token(s
, token
))
789 srcReg
->Negate
= GL_FALSE
;
792 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
793 if (token
[0] == 'R') {
794 if (!Parse_TempReg(s
, &srcReg
->Register
))
797 else if (token
[0] == 'c') {
798 if (!Parse_ParamReg(s
, srcReg
))
801 else if (token
[0] == 'v') {
802 if (!Parse_AttribReg(s
, &srcReg
->Register
))
806 PARSE_ERROR2("Bad source register name", token
);
809 /* Look for .[xyzw] suffix */
810 if (!Parse_String(s
, "."))
813 if (!Parse_Token(s
, token
))
816 if (token
[0] == 'x' && token
[1] == 0) {
817 srcReg
->Swizzle
[0] = 0;
819 else if (token
[0] == 'y' && token
[1] == 0) {
820 srcReg
->Swizzle
[0] = 1;
822 else if (token
[0] == 'z' && token
[1] == 0) {
823 srcReg
->Swizzle
[0] = 2;
825 else if (token
[0] == 'w' && token
[1] == 0) {
826 srcReg
->Swizzle
[0] = 3;
829 PARSE_ERROR1("Bad scalar source suffix");
831 srcReg
->Swizzle
[1] = srcReg
->Swizzle
[2] = srcReg
->Swizzle
[3] = 0;
838 Parse_UnaryOpInstruction(const GLubyte
**s
, struct vp_instruction
*inst
)
843 if (!Parse_Token(s
, token
))
846 if (StrEq(token
, (GLubyte
*) "MOV")) {
847 inst
->Opcode
= VP_OPCODE_MOV
;
849 else if (StrEq(token
, (GLubyte
*) "LIT")) {
850 inst
->Opcode
= VP_OPCODE_LIT
;
852 else if (StrEq(token
, (GLubyte
*) "ABS") && IsVersion1_1
) {
853 inst
->Opcode
= VP_OPCODE_ABS
;
860 if (!Parse_MaskedDstReg(s
, &inst
->DstReg
))
864 if (!Parse_String(s
, ","))
868 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[0]))
872 if (!Parse_String(s
, ";"))
880 Parse_BiOpInstruction(const GLubyte
**s
, struct vp_instruction
*inst
)
885 if (!Parse_Token(s
, token
))
888 if (StrEq(token
, (GLubyte
*) "MUL")) {
889 inst
->Opcode
= VP_OPCODE_MUL
;
891 else if (StrEq(token
, (GLubyte
*) "ADD")) {
892 inst
->Opcode
= VP_OPCODE_ADD
;
894 else if (StrEq(token
, (GLubyte
*) "DP3")) {
895 inst
->Opcode
= VP_OPCODE_DP3
;
897 else if (StrEq(token
, (GLubyte
*) "DP4")) {
898 inst
->Opcode
= VP_OPCODE_DP4
;
900 else if (StrEq(token
, (GLubyte
*) "DST")) {
901 inst
->Opcode
= VP_OPCODE_DST
;
903 else if (StrEq(token
, (GLubyte
*) "MIN")) {
904 inst
->Opcode
= VP_OPCODE_ADD
;
906 else if (StrEq(token
, (GLubyte
*) "MAX")) {
907 inst
->Opcode
= VP_OPCODE_ADD
;
909 else if (StrEq(token
, (GLubyte
*) "SLT")) {
910 inst
->Opcode
= VP_OPCODE_SLT
;
912 else if (StrEq(token
, (GLubyte
*) "SGE")) {
913 inst
->Opcode
= VP_OPCODE_SGE
;
915 else if (StrEq(token
, (GLubyte
*) "DPH") && IsVersion1_1
) {
916 inst
->Opcode
= VP_OPCODE_DPH
;
918 else if (StrEq(token
, (GLubyte
*) "SUB") && IsVersion1_1
) {
919 inst
->Opcode
= VP_OPCODE_SUB
;
926 if (!Parse_MaskedDstReg(s
, &inst
->DstReg
))
930 if (!Parse_String(s
, ","))
934 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[0]))
938 if (!Parse_String(s
, ","))
942 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[1]))
946 if (!Parse_String(s
, ";"))
949 /* make sure we don't reference more than one program parameter register */
950 if (IsProgRegister(inst
->SrcReg
[0].Register
) &&
951 IsProgRegister(inst
->SrcReg
[1].Register
) &&
952 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
)
953 PARSE_ERROR1("Can't reference two program parameter registers");
955 /* make sure we don't reference more than one vertex attribute register */
956 if (IsInputRegister(inst
->SrcReg
[0].Register
) &&
957 IsInputRegister(inst
->SrcReg
[1].Register
) &&
958 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
)
959 PARSE_ERROR1("Can't reference two vertex attribute registers");
966 Parse_TriOpInstruction(const GLubyte
**s
, struct vp_instruction
*inst
)
971 if (!Parse_Token(s
, token
))
974 if (StrEq(token
, (GLubyte
*) "MAD")) {
975 inst
->Opcode
= VP_OPCODE_MAD
;
982 if (!Parse_MaskedDstReg(s
, &inst
->DstReg
))
986 if (!Parse_String(s
, ","))
990 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[0]))
994 if (!Parse_String(s
, ","))
998 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[1]))
1002 if (!Parse_String(s
, ","))
1006 if (!Parse_SwizzleSrcReg(s
, &inst
->SrcReg
[2]))
1010 if (!Parse_String(s
, ";"))
1013 /* make sure we don't reference more than one program parameter register */
1014 if ((IsProgRegister(inst
->SrcReg
[0].Register
) &&
1015 IsProgRegister(inst
->SrcReg
[1].Register
) &&
1016 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
) ||
1017 (IsProgRegister(inst
->SrcReg
[0].Register
) &&
1018 IsProgRegister(inst
->SrcReg
[2].Register
) &&
1019 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[2].Register
) ||
1020 (IsProgRegister(inst
->SrcReg
[1].Register
) &&
1021 IsProgRegister(inst
->SrcReg
[2].Register
) &&
1022 inst
->SrcReg
[1].Register
!= inst
->SrcReg
[2].Register
))
1023 PARSE_ERROR1("Can only reference one program register");
1025 /* make sure we don't reference more than one vertex attribute register */
1026 if ((IsInputRegister(inst
->SrcReg
[0].Register
) &&
1027 IsInputRegister(inst
->SrcReg
[1].Register
) &&
1028 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
) ||
1029 (IsInputRegister(inst
->SrcReg
[0].Register
) &&
1030 IsInputRegister(inst
->SrcReg
[2].Register
) &&
1031 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[2].Register
) ||
1032 (IsInputRegister(inst
->SrcReg
[1].Register
) &&
1033 IsInputRegister(inst
->SrcReg
[2].Register
) &&
1034 inst
->SrcReg
[1].Register
!= inst
->SrcReg
[2].Register
))
1035 PARSE_ERROR1("Can only reference one input register");
1042 Parse_ScalarInstruction(const GLubyte
**s
, struct vp_instruction
*inst
)
1047 if (!Parse_Token(s
, token
))
1050 if (StrEq(token
, (GLubyte
*) "RCP")) {
1051 inst
->Opcode
= VP_OPCODE_RCP
;
1053 else if (StrEq(token
, (GLubyte
*) "RSQ")) {
1054 inst
->Opcode
= VP_OPCODE_RSQ
;
1056 else if (StrEq(token
, (GLubyte
*) "EXP")) {
1057 inst
->Opcode
= VP_OPCODE_EXP
;
1059 else if (StrEq(token
, (GLubyte
*) "LOG")) {
1060 inst
->Opcode
= VP_OPCODE_LOG
;
1062 else if (StrEq(token
, (GLubyte
*) "RCC") && IsVersion1_1
) {
1063 inst
->Opcode
= VP_OPCODE_RCC
;
1070 if (!Parse_MaskedDstReg(s
, &inst
->DstReg
))
1074 if (!Parse_String(s
, ","))
1078 if (!Parse_ScalarSrcReg(s
, &inst
->SrcReg
[0]))
1082 if (!Parse_String(s
, ";"))
1090 Parse_AddressInstruction(const GLubyte
**s
, struct vp_instruction
*inst
)
1092 inst
->Opcode
= VP_OPCODE_ARL
;
1095 if (!Parse_String(s
, "ARL"))
1099 if (!Parse_AddrReg(s
))
1103 if (!Parse_String(s
, ","))
1107 if (!Parse_ScalarSrcReg(s
, &inst
->SrcReg
[0]))
1111 if (!Parse_String(s
, ";"))
1119 Parse_EndInstruction(const GLubyte
**s
, struct vp_instruction
*inst
)
1124 if (!Parse_String(s
, "END"))
1127 inst
->Opcode
= VP_OPCODE_END
;
1129 /* this should fail! */
1130 if (Parse_Token(s
, token
))
1131 PARSE_ERROR2("Unexpected token after END:", token
);
1138 Parse_OptionSequence(const GLubyte
**s
, struct vp_instruction program
[])
1142 if (!Peek_Token(s
, token
)) {
1143 PARSE_ERROR1("Unexpected end of input");
1144 return GL_FALSE
; /* end of input */
1147 if (!StrEq(token
, (GLubyte
*) "OPTION"))
1148 return GL_TRUE
; /* probably an instruction */
1150 Parse_Token(s
, token
);
1152 if (!Parse_String(s
, "NV_position_invariant"))
1154 if (!Parse_String(s
, ";"))
1156 IsPositionInvariant
= GL_TRUE
;
1162 Parse_InstructionSequence(const GLubyte
**s
, struct vp_instruction program
[])
1168 struct vp_instruction
*inst
= program
+ count
;
1170 /* Initialize the instruction */
1171 inst
->SrcReg
[0].Register
= -1;
1172 inst
->SrcReg
[1].Register
= -1;
1173 inst
->SrcReg
[2].Register
= -1;
1174 inst
->DstReg
.Register
= -1;
1176 if (!Peek_Token(s
, token
))
1179 if (StrEq(token
, (GLubyte
*) "MOV") ||
1180 StrEq(token
, (GLubyte
*) "LIT") ||
1181 StrEq(token
, (GLubyte
*) "ABS")) {
1182 if (!Parse_UnaryOpInstruction(s
, inst
))
1185 else if (StrEq(token
, (GLubyte
*) "MUL") ||
1186 StrEq(token
, (GLubyte
*) "ADD") ||
1187 StrEq(token
, (GLubyte
*) "DP3") ||
1188 StrEq(token
, (GLubyte
*) "DP4") ||
1189 StrEq(token
, (GLubyte
*) "DST") ||
1190 StrEq(token
, (GLubyte
*) "MIN") ||
1191 StrEq(token
, (GLubyte
*) "MAX") ||
1192 StrEq(token
, (GLubyte
*) "SLT") ||
1193 StrEq(token
, (GLubyte
*) "SGE") ||
1194 StrEq(token
, (GLubyte
*) "DPH") ||
1195 StrEq(token
, (GLubyte
*) "SUB")) {
1196 if (!Parse_BiOpInstruction(s
, inst
))
1199 else if (StrEq(token
, (GLubyte
*) "MAD")) {
1200 if (!Parse_TriOpInstruction(s
, inst
))
1203 else if (StrEq(token
, (GLubyte
*) "RCP") ||
1204 StrEq(token
, (GLubyte
*) "RSQ") ||
1205 StrEq(token
, (GLubyte
*) "EXP") ||
1206 StrEq(token
, (GLubyte
*) "LOG") ||
1207 StrEq(token
, (GLubyte
*) "RCC")) {
1208 if (!Parse_ScalarInstruction(s
, inst
))
1211 else if (StrEq(token
, (GLubyte
*) "ARL")) {
1212 if (!Parse_AddressInstruction(s
, inst
))
1215 else if (StrEq(token
, (GLubyte
*) "END")) {
1216 if (!Parse_EndInstruction(s
, inst
))
1219 return GL_TRUE
; /* all done */
1222 /* bad instruction name */
1223 PARSE_ERROR2("Unexpected token: ", token
);
1227 if (count
>= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
)
1228 PARSE_ERROR1("Program too long");
1236 Parse_Program(const GLubyte
**s
, struct vp_instruction instBuffer
[])
1239 if (!Parse_OptionSequence(s
, instBuffer
)) {
1243 return Parse_InstructionSequence(s
, instBuffer
);
1248 * Parse/compile the 'str' returning the compiled 'program'.
1249 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1250 * indicates the position of the error in 'str'.
1253 _mesa_parse_nv_vertex_program(GLcontext
*ctx
, GLenum dstTarget
,
1254 const GLubyte
*str
, GLsizei len
,
1255 struct vertex_program
*program
)
1258 struct vp_instruction instBuffer
[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
];
1259 struct vp_instruction
*newInst
;
1261 GLubyte
*programString
;
1263 /* Make a null-terminated copy of the program string */
1264 programString
= (GLubyte
*) MALLOC(len
+ 1);
1265 if (!programString
) {
1266 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1269 MEMCPY(programString
, str
, len
);
1270 programString
[len
] = 0;
1272 IsPositionInvariant
= GL_FALSE
;
1273 IsVersion1_1
= GL_FALSE
;
1275 /* check the program header */
1276 if (_mesa_strncmp((const char *) programString
, "!!VP1.0", 7) == 0) {
1277 target
= GL_VERTEX_PROGRAM_NV
;
1278 s
= programString
+ 7;
1279 IsStateProgram
= GL_FALSE
;
1281 else if (_mesa_strncmp((const char *) programString
, "!!VP1.1", 7) == 0) {
1282 target
= GL_VERTEX_PROGRAM_NV
;
1283 s
= programString
+ 7;
1284 IsStateProgram
= GL_FALSE
;
1285 IsVersion1_1
= GL_TRUE
;
1287 else if (_mesa_strncmp((const char *) programString
, "!!VSP1.0", 8) == 0) {
1288 target
= GL_VERTEX_STATE_PROGRAM_NV
;
1289 s
= programString
+ 8;
1290 IsStateProgram
= GL_TRUE
;
1293 /* invalid header */
1294 ctx
->Program
.ErrorPos
= 0;
1295 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1299 /* make sure target and header match */
1300 if (target
!= dstTarget
) {
1301 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1302 "glLoadProgramNV(target mismatch)");
1306 if (Parse_Program(&s
, instBuffer
)) {
1308 GLuint inputsRead
= 0;
1309 GLuint outputsWritten
= 0;
1310 GLuint progRegsWritten
= 0;
1312 /* Find length of the program and compute bitmasks to indicate which
1313 * vertex input registers are read, which vertex result registers are
1314 * written to, and which program registers are written to.
1315 * We could actually do this while we parse the program.
1317 for (numInst
= 0; instBuffer
[numInst
].Opcode
!= VP_OPCODE_END
; numInst
++) {
1318 const GLint srcReg0
= instBuffer
[numInst
].SrcReg
[0].Register
;
1319 const GLint srcReg1
= instBuffer
[numInst
].SrcReg
[1].Register
;
1320 const GLint srcReg2
= instBuffer
[numInst
].SrcReg
[2].Register
;
1321 const GLint dstReg
= instBuffer
[numInst
].DstReg
.Register
;
1323 if (IsOutputRegister(dstReg
))
1324 outputsWritten
|= (1 << (dstReg
- VP_OUTPUT_REG_START
));
1325 else if (IsProgRegister(dstReg
))
1326 progRegsWritten
|= (1 << (dstReg
- VP_PROG_REG_START
));
1327 if (IsInputRegister(srcReg0
)
1328 && !instBuffer
[numInst
].SrcReg
[0].RelAddr
)
1329 inputsRead
|= (1 << (srcReg0
- VP_INPUT_REG_START
));
1330 if (IsInputRegister(srcReg1
)
1331 && !instBuffer
[numInst
].SrcReg
[1].RelAddr
)
1332 inputsRead
|= (1 << (srcReg1
- VP_INPUT_REG_START
));
1333 if (IsInputRegister(srcReg2
)
1334 && !instBuffer
[numInst
].SrcReg
[2].RelAddr
)
1335 inputsRead
|= (1 << (srcReg2
- VP_INPUT_REG_START
));
1339 if (IsStateProgram
) {
1340 if (progRegsWritten
== 0) {
1341 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1342 "glLoadProgramNV(c[#] not written)");
1347 if (!IsPositionInvariant
&& !(outputsWritten
& 1)) {
1348 /* bit 1 = HPOS register */
1349 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1350 "glLoadProgramNV(HPOS not written)");
1355 program
->InputsRead
= inputsRead
;
1356 program
->OutputsWritten
= outputsWritten
;
1357 program
->IsPositionInvariant
= IsPositionInvariant
;
1359 /* copy the compiled instructions */
1360 assert(numInst
<= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
);
1361 newInst
= (struct vp_instruction
*) MALLOC(numInst
* sizeof(struct vp_instruction
));
1363 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1364 FREE(programString
);
1365 return; /* out of memory */
1367 MEMCPY(newInst
, instBuffer
, numInst
* sizeof(struct vp_instruction
));
1369 /* install the program */
1370 program
->Base
.Target
= target
;
1371 if (program
->Base
.String
) {
1372 FREE(program
->Base
.String
);
1374 program
->Base
.String
= programString
;
1375 if (program
->Instructions
) {
1376 FREE(program
->Instructions
);
1378 program
->Instructions
= newInst
;
1381 _mesa_printf("--- glLoadProgramNV result ---\n");
1382 _mesa_print_nv_vertex_program(program
);
1383 _mesa_printf("------------------------------\n");
1389 /* print a message showing the program line containing the error */
1390 ctx
->Program
.ErrorPos
= s
- str
;
1392 const GLubyte
*p
= str
, *line
= str
;
1393 int lineNum
= 1, statementNum
= 1, column
= 0;
1394 char errorLine
[1000];
1396 while (*p
&& p
< s
) { /* s is the error position */
1402 else if (*p
== ';') {
1410 /* Copy the line with the error into errorLine so we can null-
1413 for (i
= 0; line
[i
] != '\n' && line
[i
]; i
++)
1414 errorLine
[i
] = (char) line
[i
];
1418 _mesa_debug("Error pos = %d (%c) col %d\n",
1419 ctx->Program.ErrorPos, *s, column);
1421 _mesa_debug(ctx
, "Vertex program error on line %2d: %s\n", lineNum
, errorLine
);
1422 _mesa_debug(ctx
, " (statement %2d) near column %2d: ", statementNum
, column
+1);
1423 for (i
= 0; i
< column
; i
++)
1424 _mesa_debug(ctx
, " ");
1425 _mesa_debug(ctx
, "^\n");
1428 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1434 PrintSrcReg(const struct vp_src_register
*src
)
1436 static const char comps
[5] = "xyzw";
1440 if (src
->Register
> 0)
1441 _mesa_printf("c[A0.x + %d]", src
->Register
);
1442 else if (src
->Register
< 0)
1443 _mesa_printf("c[A0.x - %d]", -src
->Register
);
1445 _mesa_printf("c[A0.x]");
1447 else if (src
->Register
>= VP_OUTPUT_REG_START
1448 && src
->Register
<= VP_OUTPUT_REG_END
) {
1449 _mesa_printf("o[%s]", OutputRegisters
[src
->Register
- VP_OUTPUT_REG_START
]);
1451 else if (src
->Register
>= VP_INPUT_REG_START
1452 && src
->Register
<= VP_INPUT_REG_END
) {
1453 _mesa_printf("v[%s]", InputRegisters
[src
->Register
- VP_INPUT_REG_START
]);
1455 else if (src
->Register
>= VP_PROG_REG_START
1456 && src
->Register
<= VP_PROG_REG_END
) {
1457 _mesa_printf("c[%d]", src
->Register
- VP_PROG_REG_START
);
1460 _mesa_printf("R%d", src
->Register
- VP_TEMP_REG_START
);
1463 if (src
->Swizzle
[0] == src
->Swizzle
[1] &&
1464 src
->Swizzle
[0] == src
->Swizzle
[2] &&
1465 src
->Swizzle
[0] == src
->Swizzle
[3]) {
1466 _mesa_printf(".%c", comps
[src
->Swizzle
[0]]);
1468 else if (src
->Swizzle
[0] != 0 ||
1469 src
->Swizzle
[1] != 1 ||
1470 src
->Swizzle
[2] != 2 ||
1471 src
->Swizzle
[3] != 3) {
1472 _mesa_printf(".%c%c%c%c",
1473 comps
[src
->Swizzle
[0]],
1474 comps
[src
->Swizzle
[1]],
1475 comps
[src
->Swizzle
[2]],
1476 comps
[src
->Swizzle
[3]]);
1482 PrintDstReg(const struct vp_dst_register
*dst
)
1484 GLint w
= dst
->WriteMask
[0] + dst
->WriteMask
[1]
1485 + dst
->WriteMask
[2] + dst
->WriteMask
[3];
1487 if (dst
->Register
>= VP_OUTPUT_REG_START
1488 && dst
->Register
<= VP_OUTPUT_REG_END
) {
1489 _mesa_printf("o[%s]", OutputRegisters
[dst
->Register
- VP_OUTPUT_REG_START
]);
1491 else if (dst
->Register
>= VP_INPUT_REG_START
1492 && dst
->Register
<= VP_INPUT_REG_END
) {
1493 _mesa_printf("v[%s]", InputRegisters
[dst
->Register
- VP_INPUT_REG_START
]);
1495 else if (dst
->Register
>= VP_PROG_REG_START
1496 && dst
->Register
<= VP_PROG_REG_END
) {
1497 _mesa_printf("c[%d]", dst
->Register
- VP_PROG_REG_START
);
1500 _mesa_printf("R%d", dst
->Register
- VP_TEMP_REG_START
);
1503 if (w
!= 0 && w
!= 4) {
1505 if (dst
->WriteMask
[0])
1507 if (dst
->WriteMask
[1])
1509 if (dst
->WriteMask
[2])
1511 if (dst
->WriteMask
[3])
1518 * Print (unparse) the given vertex program. Just for debugging.
1521 _mesa_print_nv_vertex_program(const struct vertex_program
*program
)
1523 const struct vp_instruction
*inst
;
1525 for (inst
= program
->Instructions
; ; inst
++) {
1526 switch (inst
->Opcode
) {
1535 _mesa_printf("%s ", Opcodes
[(int) inst
->Opcode
]);
1536 PrintDstReg(&inst
->DstReg
);
1538 PrintSrcReg(&inst
->SrcReg
[0]);
1539 _mesa_printf(";\n");
1552 _mesa_printf("%s ", Opcodes
[(int) inst
->Opcode
]);
1553 PrintDstReg(&inst
->DstReg
);
1555 PrintSrcReg(&inst
->SrcReg
[0]);
1557 PrintSrcReg(&inst
->SrcReg
[1]);
1558 _mesa_printf(";\n");
1561 _mesa_printf("MAD ");
1562 PrintDstReg(&inst
->DstReg
);
1564 PrintSrcReg(&inst
->SrcReg
[0]);
1566 PrintSrcReg(&inst
->SrcReg
[1]);
1568 PrintSrcReg(&inst
->SrcReg
[2]);
1569 _mesa_printf(";\n");
1572 _mesa_printf("ARL A0.x, ");
1573 PrintSrcReg(&inst
->SrcReg
[0]);
1574 _mesa_printf(";\n");
1577 _mesa_printf("END\n");
1580 _mesa_printf("BAD INSTRUCTION\n");