1 /* $Id: nvvertparse.c,v 1.2 2003/02/23 05:24:39 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"
47 GLboolean isStateProgram
;
48 GLboolean isPositionInvariant
;
49 GLboolean isVersion1_1
;
51 GLuint outputsWritten
;
52 GLuint progRegsWritten
;
53 GLuint numInst
; /* number of instructions parsed */
57 static GLboolean
IsLetter(GLubyte b
)
59 return (b
>= 'a' && b
<= 'z') || (b
>= 'A' && b
<= 'Z');
63 static GLboolean
IsDigit(GLubyte b
)
65 return b
>= '0' && b
<= '9';
69 static GLboolean
IsWhitespace(GLubyte b
)
71 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
76 * Starting at 'str' find the next token. A token can be an integer,
77 * an identifier or punctuation symbol.
78 * \return <= 0 we found an error, else, return number of characters parsed.
81 GetToken(const GLubyte
*str
, GLubyte
*token
)
87 /* skip whitespace and comments */
88 while (str
[i
] && (IsWhitespace(str
[i
]) || str
[i
] == '#')) {
91 while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
104 /* try matching an integer */
105 while (str
[i
] && IsDigit(str
[i
])) {
106 token
[j
++] = str
[i
++];
108 if (j
> 0 || !str
[i
]) {
113 /* try matching an identifier */
114 if (IsLetter(str
[i
])) {
115 while (str
[i
] && (IsLetter(str
[i
]) || IsDigit(str
[i
]))) {
116 token
[j
++] = str
[i
++];
136 * Get next token from input stream and increment stream pointer past token.
139 Parse_Token(struct parse_state
*parseState
, GLubyte
*token
)
142 i
= GetToken(parseState
->pos
, token
);
144 parseState
->pos
+= (-i
);
147 parseState
->pos
+= i
;
153 * Get next token from input stream but don't increment stream pointer.
156 Peek_Token(struct parse_state
*parseState
, GLubyte
*token
)
159 i
= GetToken(parseState
->pos
, token
);
161 parseState
->pos
+= (-i
);
164 len
= _mesa_strlen((char *) token
);
165 parseState
->pos
+= (i
- len
);
171 * String equality test
174 StrEq(const GLubyte
*a
, const GLubyte
*b
)
177 for (i
= 0; a
[i
] && b
[i
] && a
[i
] == b
[i
]; i
++)
179 if (a
[i
] == 0 && b
[i
] == 0)
186 /**********************************************************************/
188 static const char *InputRegisters
[] = {
189 "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
190 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
193 static const char *OutputRegisters
[] = {
194 "HPOS", "COL0", "COL1", "BFC0", "BFC1", "FOGC", "PSIZ",
195 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
198 static const char *Opcodes
[] = {
199 "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
200 "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
207 #define RETURN_ERROR \
209 _mesa_printf("vpparse.c error at %d: parse error\n", __LINE__); \
213 #define RETURN_ERROR1(msg) \
215 _mesa_printf("vpparse.c error at %d: %s\n", __LINE__, msg); \
219 #define RETURN_ERROR2(msg1, msg2) \
221 _mesa_printf("vpparse.c error at %d: %s %s\n", __LINE__, msg1, msg2); \
227 #define RETURN_ERROR return GL_FALSE
228 #define RETURN_ERROR1(msg1) return GL_FALSE
229 #define RETURN_ERROR2(msg1, msg2) return GL_FALSE
235 IsProgRegister(GLuint r
)
237 return (GLuint
) (r
>= VP_PROG_REG_START
&& r
<= VP_PROG_REG_END
);
241 IsInputRegister(GLuint r
)
243 return (GLuint
) (r
>= VP_INPUT_REG_START
&& r
<= VP_INPUT_REG_END
);
247 IsOutputRegister(GLuint r
)
249 return (GLuint
) (r
>= VP_OUTPUT_REG_START
&& r
<= VP_OUTPUT_REG_END
);
255 * Try to match 'pattern' as the next token after any whitespace/comments.
258 Parse_String(struct parse_state
*parseState
, const char *pattern
)
262 /* skip whitespace and comments */
263 while (IsWhitespace(*parseState
->pos
) || *parseState
->pos
== '#') {
264 if (*parseState
->pos
== '#') {
265 while (*parseState
->pos
&& (*parseState
->pos
!= '\n' && *parseState
->pos
!= '\r')) {
266 parseState
->pos
+= 1;
270 /* skip whitespace */
271 parseState
->pos
+= 1;
275 /* Try to match the pattern */
276 for (i
= 0; pattern
[i
]; i
++) {
277 if (*parseState
->pos
!= pattern
[i
])
278 RETURN_ERROR2("failed to match", pattern
); /* failure */
279 parseState
->pos
+= 1;
282 return GL_TRUE
; /* success */
287 * Parse a temporary register: Rnn
290 Parse_TempReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
294 /* Should be 'R##' */
295 if (!Parse_Token(parseState
, token
))
298 RETURN_ERROR1("Expected R##");
300 if (IsDigit(token
[1])) {
301 GLint reg
= _mesa_atoi((char *) (token
+ 1));
302 if (reg
>= VP_NUM_TEMP_REGS
)
303 RETURN_ERROR1("Bad temporary register name");
304 *tempRegNum
= VP_TEMP_REG_START
+ reg
;
307 RETURN_ERROR1("Bad temporary register name");
315 * Parse address register "A0.x"
318 Parse_AddrReg(struct parse_state
*parseState
)
321 if (!Parse_String(parseState
, "A0"))
325 if (!Parse_String(parseState
, "."))
329 if (!Parse_String(parseState
, "x"))
337 * Parse absolute program parameter register "c[##]"
340 Parse_AbsParamReg(struct parse_state
*parseState
, GLint
*regNum
)
344 if (!Parse_String(parseState
, "c"))
347 if (!Parse_String(parseState
, "["))
350 if (!Parse_Token(parseState
, token
))
353 if (IsDigit(token
[0])) {
354 /* a numbered program parameter register */
355 GLint reg
= _mesa_atoi((char *) token
);
356 if (reg
>= VP_NUM_PROG_REGS
)
357 RETURN_ERROR1("Bad constant program number");
358 *regNum
= VP_PROG_REG_START
+ reg
;
364 if (!Parse_String(parseState
, "]"))
372 Parse_ParamReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
376 if (!Parse_String(parseState
, "c"))
379 if (!Parse_String(parseState
, "["))
382 if (!Peek_Token(parseState
, token
))
385 if (IsDigit(token
[0])) {
386 /* a numbered program parameter register */
388 (void) Parse_Token(parseState
, token
);
389 reg
= _mesa_atoi((char *) token
);
390 if (reg
>= VP_NUM_PROG_REGS
)
391 RETURN_ERROR1("Bad constant program number");
392 srcReg
->Register
= VP_PROG_REG_START
+ reg
;
394 else if (StrEq(token
, (GLubyte
*) "A0")) {
395 /* address register "A0.x" */
396 if (!Parse_AddrReg(parseState
))
399 srcReg
->RelAddr
= GL_TRUE
;
400 srcReg
->Register
= 0;
402 /* Look for +/-N offset */
403 if (!Peek_Token(parseState
, token
))
406 if (token
[0] == '-' || token
[0] == '+') {
407 const GLubyte sign
= token
[0];
408 (void) Parse_Token(parseState
, token
); /* consume +/- */
410 /* an integer should be next */
411 if (!Parse_Token(parseState
, token
))
414 if (IsDigit(token
[0])) {
415 const GLint k
= _mesa_atoi((char *) token
);
418 RETURN_ERROR1("Bad address offset");
419 srcReg
->Register
= -k
;
423 RETURN_ERROR1("Bad address offset");
424 srcReg
->Register
= k
;
432 /* probably got a ']', catch it below */
439 /* Match closing ']' */
440 if (!Parse_String(parseState
, "]"))
448 * Parse v[#] or v[<name>]
451 Parse_AttribReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
457 if (!Parse_String(parseState
, "v"))
461 if (!Parse_String(parseState
, "["))
464 /* match number or named register */
465 if (!Parse_Token(parseState
, token
))
468 if (parseState
->isStateProgram
&& token
[0] != '0')
469 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
471 if (IsDigit(token
[0])) {
472 GLint reg
= _mesa_atoi((char *) token
);
473 if (reg
>= VP_NUM_INPUT_REGS
)
474 RETURN_ERROR1("Bad vertex attribute register name");
475 *tempRegNum
= VP_INPUT_REG_START
+ reg
;
478 for (j
= 0; InputRegisters
[j
]; j
++) {
479 if (StrEq(token
, (const GLubyte
*) InputRegisters
[j
])) {
480 *tempRegNum
= VP_INPUT_REG_START
+ j
;
484 if (!InputRegisters
[j
]) {
485 /* unknown input register label */
486 RETURN_ERROR2("Bad register name", token
);
491 if (!Parse_String(parseState
, "]"))
499 Parse_OutputReg(struct parse_state
*parseState
, GLint
*outputRegNum
)
505 if (!Parse_String(parseState
, "o"))
509 if (!Parse_String(parseState
, "["))
512 /* Get output reg name */
513 if (!Parse_Token(parseState
, token
))
516 if (parseState
->isPositionInvariant
)
517 start
= 1; /* skip HPOS register name */
521 /* try to match an output register name */
522 for (j
= start
; OutputRegisters
[j
]; j
++) {
523 if (StrEq(token
, (const GLubyte
*) OutputRegisters
[j
])) {
524 *outputRegNum
= VP_OUTPUT_REG_START
+ j
;
528 if (!OutputRegisters
[j
])
529 RETURN_ERROR1("Unrecognized output register name");
532 if (!Parse_String(parseState
, "]"))
533 RETURN_ERROR1("Expected ]");
540 Parse_MaskedDstReg(struct parse_state
*parseState
, struct vp_dst_register
*dstReg
)
544 /* Dst reg can be R<n> or o[n] */
545 if (!Peek_Token(parseState
, token
))
548 if (token
[0] == 'R') {
549 /* a temporary register */
550 if (!Parse_TempReg(parseState
, &dstReg
->Register
))
553 else if (!parseState
->isStateProgram
&& token
[0] == 'o') {
554 /* an output register */
555 if (!Parse_OutputReg(parseState
, &dstReg
->Register
))
558 else if (parseState
->isStateProgram
&& token
[0] == 'c') {
559 /* absolute program parameter register */
560 if (!Parse_AbsParamReg(parseState
, &dstReg
->Register
))
564 RETURN_ERROR1("Bad destination register name");
567 /* Parse optional write mask */
568 if (!Peek_Token(parseState
, token
))
571 if (token
[0] == '.') {
575 if (!Parse_String(parseState
, "."))
578 if (!Parse_Token(parseState
, token
))
581 dstReg
->WriteMask
[0] = GL_FALSE
;
582 dstReg
->WriteMask
[1] = GL_FALSE
;
583 dstReg
->WriteMask
[2] = GL_FALSE
;
584 dstReg
->WriteMask
[3] = GL_FALSE
;
586 if (token
[k
] == 'x') {
587 dstReg
->WriteMask
[0] = GL_TRUE
;
590 if (token
[k
] == 'y') {
591 dstReg
->WriteMask
[1] = GL_TRUE
;
594 if (token
[k
] == 'z') {
595 dstReg
->WriteMask
[2] = GL_TRUE
;
598 if (token
[k
] == 'w') {
599 dstReg
->WriteMask
[3] = GL_TRUE
;
603 RETURN_ERROR1("Bad writemask character");
608 dstReg
->WriteMask
[0] = GL_TRUE
;
609 dstReg
->WriteMask
[1] = GL_TRUE
;
610 dstReg
->WriteMask
[2] = GL_TRUE
;
611 dstReg
->WriteMask
[3] = GL_TRUE
;
618 Parse_SwizzleSrcReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
622 srcReg
->RelAddr
= GL_FALSE
;
625 if (!Peek_Token(parseState
, token
))
627 if (token
[0] == '-') {
628 (void) Parse_String(parseState
, "-");
629 srcReg
->Negate
= GL_TRUE
;
630 if (!Peek_Token(parseState
, token
))
634 srcReg
->Negate
= GL_FALSE
;
637 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
638 if (token
[0] == 'R') {
639 if (!Parse_TempReg(parseState
, &srcReg
->Register
))
642 else if (token
[0] == 'c') {
643 if (!Parse_ParamReg(parseState
, srcReg
))
646 else if (token
[0] == 'v') {
647 if (!Parse_AttribReg(parseState
, &srcReg
->Register
))
651 RETURN_ERROR2("Bad source register name", token
);
654 /* init swizzle fields */
655 srcReg
->Swizzle
[0] = 0;
656 srcReg
->Swizzle
[1] = 1;
657 srcReg
->Swizzle
[2] = 2;
658 srcReg
->Swizzle
[3] = 3;
660 /* Look for optional swizzle suffix */
661 if (!Peek_Token(parseState
, token
))
663 if (token
[0] == '.') {
664 (void) Parse_String(parseState
, "."); /* consume . */
666 if (!Parse_Token(parseState
, token
))
670 /* single letter swizzle */
672 ASSIGN_4V(srcReg
->Swizzle
, 0, 0, 0, 0);
673 else if (token
[0] == 'y')
674 ASSIGN_4V(srcReg
->Swizzle
, 1, 1, 1, 1);
675 else if (token
[0] == 'z')
676 ASSIGN_4V(srcReg
->Swizzle
, 2, 2, 2, 2);
677 else if (token
[0] == 'w')
678 ASSIGN_4V(srcReg
->Swizzle
, 3, 3, 3, 3);
680 RETURN_ERROR1("Expected x, y, z, or w");
683 /* 2, 3 or 4-component swizzle */
685 for (k
= 0; token
[k
] && k
< 5; k
++) {
687 srcReg
->Swizzle
[k
] = 0;
688 else if (token
[k
] == 'y')
689 srcReg
->Swizzle
[k
] = 1;
690 else if (token
[k
] == 'z')
691 srcReg
->Swizzle
[k
] = 2;
692 else if (token
[k
] == 'w')
693 srcReg
->Swizzle
[k
] = 3;
707 Parse_ScalarSrcReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
711 srcReg
->RelAddr
= GL_FALSE
;
714 if (!Peek_Token(parseState
, token
))
716 if (token
[0] == '-') {
717 srcReg
->Negate
= GL_TRUE
;
718 (void) Parse_String(parseState
, "-"); /* consume '-' */
719 if (!Peek_Token(parseState
, token
))
723 srcReg
->Negate
= GL_FALSE
;
726 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
727 if (token
[0] == 'R') {
728 if (!Parse_TempReg(parseState
, &srcReg
->Register
))
731 else if (token
[0] == 'c') {
732 if (!Parse_ParamReg(parseState
, srcReg
))
735 else if (token
[0] == 'v') {
736 if (!Parse_AttribReg(parseState
, &srcReg
->Register
))
740 RETURN_ERROR2("Bad source register name", token
);
743 /* Look for .[xyzw] suffix */
744 if (!Parse_String(parseState
, "."))
747 if (!Parse_Token(parseState
, token
))
750 if (token
[0] == 'x' && token
[1] == 0) {
751 srcReg
->Swizzle
[0] = 0;
753 else if (token
[0] == 'y' && token
[1] == 0) {
754 srcReg
->Swizzle
[0] = 1;
756 else if (token
[0] == 'z' && token
[1] == 0) {
757 srcReg
->Swizzle
[0] = 2;
759 else if (token
[0] == 'w' && token
[1] == 0) {
760 srcReg
->Swizzle
[0] = 3;
763 RETURN_ERROR1("Bad scalar source suffix");
765 srcReg
->Swizzle
[1] = srcReg
->Swizzle
[2] = srcReg
->Swizzle
[3] = 0;
772 Parse_UnaryOpInstruction(struct parse_state
*parseState
, struct vp_instruction
*inst
)
777 if (!Parse_Token(parseState
, token
))
780 if (StrEq(token
, (GLubyte
*) "MOV")) {
781 inst
->Opcode
= VP_OPCODE_MOV
;
783 else if (StrEq(token
, (GLubyte
*) "LIT")) {
784 inst
->Opcode
= VP_OPCODE_LIT
;
786 else if (StrEq(token
, (GLubyte
*) "ABS") && parseState
->isVersion1_1
) {
787 inst
->Opcode
= VP_OPCODE_ABS
;
794 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
798 if (!Parse_String(parseState
, ","))
802 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
806 if (!Parse_String(parseState
, ";"))
814 Parse_BiOpInstruction(struct parse_state
*parseState
, struct vp_instruction
*inst
)
819 if (!Parse_Token(parseState
, token
))
822 if (StrEq(token
, (GLubyte
*) "MUL")) {
823 inst
->Opcode
= VP_OPCODE_MUL
;
825 else if (StrEq(token
, (GLubyte
*) "ADD")) {
826 inst
->Opcode
= VP_OPCODE_ADD
;
828 else if (StrEq(token
, (GLubyte
*) "DP3")) {
829 inst
->Opcode
= VP_OPCODE_DP3
;
831 else if (StrEq(token
, (GLubyte
*) "DP4")) {
832 inst
->Opcode
= VP_OPCODE_DP4
;
834 else if (StrEq(token
, (GLubyte
*) "DST")) {
835 inst
->Opcode
= VP_OPCODE_DST
;
837 else if (StrEq(token
, (GLubyte
*) "MIN")) {
838 inst
->Opcode
= VP_OPCODE_ADD
;
840 else if (StrEq(token
, (GLubyte
*) "MAX")) {
841 inst
->Opcode
= VP_OPCODE_ADD
;
843 else if (StrEq(token
, (GLubyte
*) "SLT")) {
844 inst
->Opcode
= VP_OPCODE_SLT
;
846 else if (StrEq(token
, (GLubyte
*) "SGE")) {
847 inst
->Opcode
= VP_OPCODE_SGE
;
849 else if (StrEq(token
, (GLubyte
*) "DPH") && parseState
->isVersion1_1
) {
850 inst
->Opcode
= VP_OPCODE_DPH
;
852 else if (StrEq(token
, (GLubyte
*) "SUB") && parseState
->isVersion1_1
) {
853 inst
->Opcode
= VP_OPCODE_SUB
;
860 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
864 if (!Parse_String(parseState
, ","))
868 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
872 if (!Parse_String(parseState
, ","))
876 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
880 if (!Parse_String(parseState
, ";"))
883 /* make sure we don't reference more than one program parameter register */
884 if (IsProgRegister(inst
->SrcReg
[0].Register
) &&
885 IsProgRegister(inst
->SrcReg
[1].Register
) &&
886 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
)
887 RETURN_ERROR1("Can't reference two program parameter registers");
889 /* make sure we don't reference more than one vertex attribute register */
890 if (IsInputRegister(inst
->SrcReg
[0].Register
) &&
891 IsInputRegister(inst
->SrcReg
[1].Register
) &&
892 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
)
893 RETURN_ERROR1("Can't reference two vertex attribute registers");
900 Parse_TriOpInstruction(struct parse_state
*parseState
, struct vp_instruction
*inst
)
905 if (!Parse_Token(parseState
, token
))
908 if (StrEq(token
, (GLubyte
*) "MAD")) {
909 inst
->Opcode
= VP_OPCODE_MAD
;
916 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
920 if (!Parse_String(parseState
, ","))
924 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
928 if (!Parse_String(parseState
, ","))
932 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
936 if (!Parse_String(parseState
, ","))
940 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[2]))
944 if (!Parse_String(parseState
, ";"))
947 /* make sure we don't reference more than one program parameter register */
948 if ((IsProgRegister(inst
->SrcReg
[0].Register
) &&
949 IsProgRegister(inst
->SrcReg
[1].Register
) &&
950 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
) ||
951 (IsProgRegister(inst
->SrcReg
[0].Register
) &&
952 IsProgRegister(inst
->SrcReg
[2].Register
) &&
953 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[2].Register
) ||
954 (IsProgRegister(inst
->SrcReg
[1].Register
) &&
955 IsProgRegister(inst
->SrcReg
[2].Register
) &&
956 inst
->SrcReg
[1].Register
!= inst
->SrcReg
[2].Register
))
957 RETURN_ERROR1("Can only reference one program register");
959 /* make sure we don't reference more than one vertex attribute register */
960 if ((IsInputRegister(inst
->SrcReg
[0].Register
) &&
961 IsInputRegister(inst
->SrcReg
[1].Register
) &&
962 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
) ||
963 (IsInputRegister(inst
->SrcReg
[0].Register
) &&
964 IsInputRegister(inst
->SrcReg
[2].Register
) &&
965 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[2].Register
) ||
966 (IsInputRegister(inst
->SrcReg
[1].Register
) &&
967 IsInputRegister(inst
->SrcReg
[2].Register
) &&
968 inst
->SrcReg
[1].Register
!= inst
->SrcReg
[2].Register
))
969 RETURN_ERROR1("Can only reference one input register");
976 Parse_ScalarInstruction(struct parse_state
*parseState
, struct vp_instruction
*inst
)
981 if (!Parse_Token(parseState
, token
))
984 if (StrEq(token
, (GLubyte
*) "RCP")) {
985 inst
->Opcode
= VP_OPCODE_RCP
;
987 else if (StrEq(token
, (GLubyte
*) "RSQ")) {
988 inst
->Opcode
= VP_OPCODE_RSQ
;
990 else if (StrEq(token
, (GLubyte
*) "EXP")) {
991 inst
->Opcode
= VP_OPCODE_EXP
;
993 else if (StrEq(token
, (GLubyte
*) "LOG")) {
994 inst
->Opcode
= VP_OPCODE_LOG
;
996 else if (StrEq(token
, (GLubyte
*) "RCC") && parseState
->isVersion1_1
) {
997 inst
->Opcode
= VP_OPCODE_RCC
;
1004 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
1008 if (!Parse_String(parseState
, ","))
1012 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
1016 if (!Parse_String(parseState
, ";"))
1024 Parse_AddressInstruction(struct parse_state
*parseState
, struct vp_instruction
*inst
)
1026 inst
->Opcode
= VP_OPCODE_ARL
;
1029 if (!Parse_String(parseState
, "ARL"))
1033 if (!Parse_AddrReg(parseState
))
1037 if (!Parse_String(parseState
, ","))
1041 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
1045 if (!Parse_String(parseState
, ";"))
1053 Parse_EndInstruction(struct parse_state
*parseState
, struct vp_instruction
*inst
)
1058 if (!Parse_String(parseState
, "END"))
1061 inst
->Opcode
= VP_OPCODE_END
;
1063 /* this should fail! */
1064 if (Parse_Token(parseState
, token
))
1065 RETURN_ERROR2("Unexpected token after END:", token
);
1072 Parse_OptionSequence(struct parse_state
*parseState
,
1073 struct vp_instruction program
[])
1077 if (!Peek_Token(parseState
, token
)) {
1078 RETURN_ERROR1("Unexpected end of input");
1079 return GL_FALSE
; /* end of input */
1082 if (!StrEq(token
, (GLubyte
*) "OPTION"))
1083 return GL_TRUE
; /* probably an instruction */
1085 Parse_Token(parseState
, token
);
1087 if (!Parse_String(parseState
, "NV_position_invariant"))
1089 if (!Parse_String(parseState
, ";"))
1091 parseState
->isPositionInvariant
= GL_TRUE
;
1097 Parse_InstructionSequence(struct parse_state
*parseState
,
1098 struct vp_instruction program
[])
1103 struct vp_instruction
*inst
= program
+ parseState
->numInst
;
1105 /* Initialize the instruction */
1106 inst
->SrcReg
[0].Register
= -1;
1107 inst
->SrcReg
[1].Register
= -1;
1108 inst
->SrcReg
[2].Register
= -1;
1109 inst
->DstReg
.Register
= -1;
1111 if (!Peek_Token(parseState
, token
))
1114 if (StrEq(token
, (GLubyte
*) "MOV") ||
1115 StrEq(token
, (GLubyte
*) "LIT") ||
1116 StrEq(token
, (GLubyte
*) "ABS")) {
1117 if (!Parse_UnaryOpInstruction(parseState
, inst
))
1120 else if (StrEq(token
, (GLubyte
*) "MUL") ||
1121 StrEq(token
, (GLubyte
*) "ADD") ||
1122 StrEq(token
, (GLubyte
*) "DP3") ||
1123 StrEq(token
, (GLubyte
*) "DP4") ||
1124 StrEq(token
, (GLubyte
*) "DST") ||
1125 StrEq(token
, (GLubyte
*) "MIN") ||
1126 StrEq(token
, (GLubyte
*) "MAX") ||
1127 StrEq(token
, (GLubyte
*) "SLT") ||
1128 StrEq(token
, (GLubyte
*) "SGE") ||
1129 StrEq(token
, (GLubyte
*) "DPH") ||
1130 StrEq(token
, (GLubyte
*) "SUB")) {
1131 if (!Parse_BiOpInstruction(parseState
, inst
))
1134 else if (StrEq(token
, (GLubyte
*) "MAD")) {
1135 if (!Parse_TriOpInstruction(parseState
, inst
))
1138 else if (StrEq(token
, (GLubyte
*) "RCP") ||
1139 StrEq(token
, (GLubyte
*) "RSQ") ||
1140 StrEq(token
, (GLubyte
*) "EXP") ||
1141 StrEq(token
, (GLubyte
*) "LOG") ||
1142 StrEq(token
, (GLubyte
*) "RCC")) {
1143 if (!Parse_ScalarInstruction(parseState
, inst
))
1146 else if (StrEq(token
, (GLubyte
*) "ARL")) {
1147 if (!Parse_AddressInstruction(parseState
, inst
))
1150 else if (StrEq(token
, (GLubyte
*) "END")) {
1151 if (!Parse_EndInstruction(parseState
, inst
))
1154 parseState
->numInst
++;
1155 return GL_TRUE
; /* all done */
1159 /* bad instruction name */
1160 RETURN_ERROR2("Unexpected token: ", token
);
1163 /* examine input/output registers */
1165 const GLint srcReg0
= inst
->SrcReg
[0].Register
;
1166 const GLint srcReg1
= inst
->SrcReg
[1].Register
;
1167 const GLint srcReg2
= inst
->SrcReg
[2].Register
;
1168 const GLint dstReg
= inst
->DstReg
.Register
;
1170 if (IsOutputRegister(dstReg
))
1171 parseState
->outputsWritten
|= (1 << (dstReg
- VP_OUTPUT_REG_START
));
1172 else if (IsProgRegister(dstReg
))
1173 parseState
->progRegsWritten
|= (1 << (dstReg
- VP_PROG_REG_START
));
1175 if (IsInputRegister(srcReg0
) && !inst
->SrcReg
[0].RelAddr
)
1176 parseState
->inputsRead
|= (1 << (srcReg0
- VP_INPUT_REG_START
));
1178 if (IsInputRegister(srcReg1
) && !inst
->SrcReg
[1].RelAddr
)
1179 parseState
->inputsRead
|= (1 << (srcReg1
- VP_INPUT_REG_START
));
1181 if (IsInputRegister(srcReg2
) && !inst
->SrcReg
[2].RelAddr
)
1182 parseState
->inputsRead
|= (1 << (srcReg2
- VP_INPUT_REG_START
));
1185 parseState
->numInst
++;
1187 if (parseState
->numInst
>= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
)
1188 RETURN_ERROR1("Program too long");
1196 Parse_Program(struct parse_state
*parseState
,
1197 struct vp_instruction instBuffer
[])
1199 if (parseState
->isVersion1_1
) {
1200 if (!Parse_OptionSequence(parseState
, instBuffer
)) {
1204 return Parse_InstructionSequence(parseState
, instBuffer
);
1209 * Parse/compile the 'str' returning the compiled 'program'.
1210 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1211 * indicates the position of the error in 'str'.
1214 _mesa_parse_nv_vertex_program(GLcontext
*ctx
, GLenum dstTarget
,
1215 const GLubyte
*str
, GLsizei len
,
1216 struct vertex_program
*program
)
1218 struct parse_state parseState
;
1219 struct vp_instruction instBuffer
[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
];
1220 struct vp_instruction
*newInst
;
1222 GLubyte
*programString
;
1224 /* Make a null-terminated copy of the program string */
1225 programString
= (GLubyte
*) MALLOC(len
+ 1);
1226 if (!programString
) {
1227 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1230 MEMCPY(programString
, str
, len
);
1231 programString
[len
] = 0;
1233 /* get ready to parse */
1234 parseState
.isPositionInvariant
= GL_FALSE
;
1235 parseState
.isVersion1_1
= GL_FALSE
;
1236 parseState
.numInst
= 0;
1237 parseState
.inputsRead
= 0;
1238 parseState
.outputsWritten
= 0;
1239 parseState
.progRegsWritten
= 0;
1241 /* check the program header */
1242 if (_mesa_strncmp((const char *) programString
, "!!VP1.0", 7) == 0) {
1243 target
= GL_VERTEX_PROGRAM_NV
;
1244 parseState
.pos
= programString
+ 7;
1245 parseState
.isStateProgram
= GL_FALSE
;
1247 else if (_mesa_strncmp((const char *) programString
, "!!VP1.1", 7) == 0) {
1248 target
= GL_VERTEX_PROGRAM_NV
;
1249 parseState
.pos
= programString
+ 7;
1250 parseState
.isStateProgram
= GL_FALSE
;
1251 parseState
.isVersion1_1
= GL_TRUE
;
1253 else if (_mesa_strncmp((const char *) programString
, "!!VSP1.0", 8) == 0) {
1254 target
= GL_VERTEX_STATE_PROGRAM_NV
;
1255 parseState
.pos
= programString
+ 8;
1256 parseState
.isStateProgram
= GL_TRUE
;
1259 /* invalid header */
1260 ctx
->Program
.ErrorPos
= 0;
1261 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1265 /* make sure target and header match */
1266 if (target
!= dstTarget
) {
1267 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1268 "glLoadProgramNV(target mismatch)");
1273 if (Parse_Program(&parseState
, instBuffer
)) {
1274 /* successful parse! */
1276 if (parseState
.isStateProgram
) {
1277 if (parseState
.progRegsWritten
== 0) {
1278 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1279 "glLoadProgramNV(c[#] not written)");
1284 if (!parseState
.isPositionInvariant
&&
1285 !(parseState
.outputsWritten
& 1)) {
1286 /* bit 1 = HPOS register */
1287 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1288 "glLoadProgramNV(HPOS not written)");
1293 /* save bitmasks of registers read/written */
1294 program
->InputsRead
= parseState
.inputsRead
;
1295 program
->OutputsWritten
= parseState
.outputsWritten
;
1296 program
->IsPositionInvariant
= parseState
.isPositionInvariant
;
1298 /* copy the compiled instructions */
1299 assert(parseState
.numInst
<= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
);
1300 newInst
= (struct vp_instruction
*)
1301 MALLOC(parseState
.numInst
* sizeof(struct vp_instruction
));
1303 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1304 FREE(programString
);
1305 return; /* out of memory */
1307 MEMCPY(newInst
, instBuffer
,
1308 parseState
.numInst
* sizeof(struct vp_instruction
));
1310 /* install the program */
1311 program
->Base
.Target
= target
;
1312 if (program
->Base
.String
) {
1313 FREE(program
->Base
.String
);
1315 program
->Base
.String
= programString
;
1316 if (program
->Instructions
) {
1317 FREE(program
->Instructions
);
1319 program
->Instructions
= newInst
;
1322 _mesa_printf("--- glLoadProgramNV result ---\n");
1323 _mesa_print_nv_vertex_program(program
);
1324 _mesa_printf("------------------------------\n");
1329 ctx
->Program
.ErrorPos
= parseState
.pos
- str
;
1330 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1334 const char *lineStr
;
1335 lineStr
= _mesa_find_line_column((const char *) programString
,
1336 (const char *) parseState
.pos
, &line
, &column
);
1337 _mesa_debug(ctx
, "Parse error on line %d, column %d:%s\n",
1338 line
, column
, lineStr
);
1339 _mesa_free((void *) lineStr
);
1347 PrintSrcReg(const struct vp_src_register
*src
)
1349 static const char comps
[5] = "xyzw";
1353 if (src
->Register
> 0)
1354 _mesa_printf("c[A0.x + %d]", src
->Register
);
1355 else if (src
->Register
< 0)
1356 _mesa_printf("c[A0.x - %d]", -src
->Register
);
1358 _mesa_printf("c[A0.x]");
1360 else if (src
->Register
>= VP_OUTPUT_REG_START
1361 && src
->Register
<= VP_OUTPUT_REG_END
) {
1362 _mesa_printf("o[%s]", OutputRegisters
[src
->Register
- VP_OUTPUT_REG_START
]);
1364 else if (src
->Register
>= VP_INPUT_REG_START
1365 && src
->Register
<= VP_INPUT_REG_END
) {
1366 _mesa_printf("v[%s]", InputRegisters
[src
->Register
- VP_INPUT_REG_START
]);
1368 else if (src
->Register
>= VP_PROG_REG_START
1369 && src
->Register
<= VP_PROG_REG_END
) {
1370 _mesa_printf("c[%d]", src
->Register
- VP_PROG_REG_START
);
1373 _mesa_printf("R%d", src
->Register
- VP_TEMP_REG_START
);
1376 if (src
->Swizzle
[0] == src
->Swizzle
[1] &&
1377 src
->Swizzle
[0] == src
->Swizzle
[2] &&
1378 src
->Swizzle
[0] == src
->Swizzle
[3]) {
1379 _mesa_printf(".%c", comps
[src
->Swizzle
[0]]);
1381 else if (src
->Swizzle
[0] != 0 ||
1382 src
->Swizzle
[1] != 1 ||
1383 src
->Swizzle
[2] != 2 ||
1384 src
->Swizzle
[3] != 3) {
1385 _mesa_printf(".%c%c%c%c",
1386 comps
[src
->Swizzle
[0]],
1387 comps
[src
->Swizzle
[1]],
1388 comps
[src
->Swizzle
[2]],
1389 comps
[src
->Swizzle
[3]]);
1395 PrintDstReg(const struct vp_dst_register
*dst
)
1397 GLint w
= dst
->WriteMask
[0] + dst
->WriteMask
[1]
1398 + dst
->WriteMask
[2] + dst
->WriteMask
[3];
1400 if (dst
->Register
>= VP_OUTPUT_REG_START
1401 && dst
->Register
<= VP_OUTPUT_REG_END
) {
1402 _mesa_printf("o[%s]", OutputRegisters
[dst
->Register
- VP_OUTPUT_REG_START
]);
1404 else if (dst
->Register
>= VP_INPUT_REG_START
1405 && dst
->Register
<= VP_INPUT_REG_END
) {
1406 _mesa_printf("v[%s]", InputRegisters
[dst
->Register
- VP_INPUT_REG_START
]);
1408 else if (dst
->Register
>= VP_PROG_REG_START
1409 && dst
->Register
<= VP_PROG_REG_END
) {
1410 _mesa_printf("c[%d]", dst
->Register
- VP_PROG_REG_START
);
1413 _mesa_printf("R%d", dst
->Register
- VP_TEMP_REG_START
);
1416 if (w
!= 0 && w
!= 4) {
1418 if (dst
->WriteMask
[0])
1420 if (dst
->WriteMask
[1])
1422 if (dst
->WriteMask
[2])
1424 if (dst
->WriteMask
[3])
1431 * Print (unparse) the given vertex program. Just for debugging.
1434 _mesa_print_nv_vertex_program(const struct vertex_program
*program
)
1436 const struct vp_instruction
*inst
;
1438 for (inst
= program
->Instructions
; ; inst
++) {
1439 switch (inst
->Opcode
) {
1448 _mesa_printf("%s ", Opcodes
[(int) inst
->Opcode
]);
1449 PrintDstReg(&inst
->DstReg
);
1451 PrintSrcReg(&inst
->SrcReg
[0]);
1452 _mesa_printf(";\n");
1465 _mesa_printf("%s ", Opcodes
[(int) inst
->Opcode
]);
1466 PrintDstReg(&inst
->DstReg
);
1468 PrintSrcReg(&inst
->SrcReg
[0]);
1470 PrintSrcReg(&inst
->SrcReg
[1]);
1471 _mesa_printf(";\n");
1474 _mesa_printf("MAD ");
1475 PrintDstReg(&inst
->DstReg
);
1477 PrintSrcReg(&inst
->SrcReg
[0]);
1479 PrintSrcReg(&inst
->SrcReg
[1]);
1481 PrintSrcReg(&inst
->SrcReg
[2]);
1482 _mesa_printf(";\n");
1485 _mesa_printf("ARL A0.x, ");
1486 PrintSrcReg(&inst
->SrcReg
[0]);
1487 _mesa_printf(";\n");
1490 _mesa_printf("END\n");
1493 _mesa_printf("BAD INSTRUCTION\n");