1 /* $Id: nvvertparse.c,v 1.3 2003/02/25 19:27:54 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 * Current parsing state. This structure is passed among the parsing
46 * functions and keeps track of the current parser position and various
51 GLboolean isStateProgram
;
52 GLboolean isPositionInvariant
;
53 GLboolean isVersion1_1
;
55 GLuint outputsWritten
;
56 GLuint progRegsWritten
;
57 GLuint numInst
; /* number of instructions parsed */
61 static GLboolean
IsLetter(GLubyte b
)
63 return (b
>= 'a' && b
<= 'z') || (b
>= 'A' && b
<= 'Z');
67 static GLboolean
IsDigit(GLubyte b
)
69 return b
>= '0' && b
<= '9';
73 static GLboolean
IsWhitespace(GLubyte b
)
75 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
80 * Starting at 'str' find the next token. A token can be an integer,
81 * an identifier or punctuation symbol.
82 * \return <= 0 we found an error, else, return number of characters parsed.
85 GetToken(const GLubyte
*str
, GLubyte
*token
)
91 /* skip whitespace and comments */
92 while (str
[i
] && (IsWhitespace(str
[i
]) || str
[i
] == '#')) {
95 while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
100 /* skip whitespace */
108 /* try matching an integer */
109 while (str
[i
] && IsDigit(str
[i
])) {
110 token
[j
++] = str
[i
++];
112 if (j
> 0 || !str
[i
]) {
117 /* try matching an identifier */
118 if (IsLetter(str
[i
])) {
119 while (str
[i
] && (IsLetter(str
[i
]) || IsDigit(str
[i
]))) {
120 token
[j
++] = str
[i
++];
140 * Get next token from input stream and increment stream pointer past token.
143 Parse_Token(struct parse_state
*parseState
, GLubyte
*token
)
146 i
= GetToken(parseState
->pos
, token
);
148 parseState
->pos
+= (-i
);
151 parseState
->pos
+= i
;
157 * Get next token from input stream but don't increment stream pointer.
160 Peek_Token(struct parse_state
*parseState
, GLubyte
*token
)
163 i
= GetToken(parseState
->pos
, token
);
165 parseState
->pos
+= (-i
);
168 len
= _mesa_strlen((const char *) token
);
169 parseState
->pos
+= (i
- len
);
175 * Try to match 'pattern' as the next token after any whitespace/comments.
176 * Advance the current parsing position only if we match the pattern.
177 * \return GL_TRUE if pattern is matched, GL_FALSE otherwise.
180 Parse_String(struct parse_state
*parseState
, const char *pattern
)
185 /* skip whitespace and comments */
186 while (IsWhitespace(*parseState
->pos
) || *parseState
->pos
== '#') {
187 if (*parseState
->pos
== '#') {
188 while (*parseState
->pos
&& (*parseState
->pos
!= '\n' && *parseState
->pos
!= '\r')) {
189 parseState
->pos
+= 1;
193 /* skip whitespace */
194 parseState
->pos
+= 1;
198 /* Try to match the pattern */
200 for (i
= 0; pattern
[i
]; i
++) {
201 if (*m
!= (GLubyte
) pattern
[i
])
207 return GL_TRUE
; /* success */
211 /**********************************************************************/
213 static const char *InputRegisters
[] = {
214 "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
215 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
218 static const char *OutputRegisters
[] = {
219 "HPOS", "COL0", "COL1", "BFC0", "BFC1", "FOGC", "PSIZ",
220 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
223 static const char *Opcodes
[] = {
224 "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
225 "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
232 #define RETURN_ERROR \
234 _mesa_printf("vert prog error at %d\n", __LINE__); \
238 #define RETURN_ERROR1(msg) \
240 _mesa_printf("vert prog error at %d: %s\n", __LINE__, msg); \
244 #define RETURN_ERROR2(msg1, msg2) \
246 _mesa_printf("vert prog error at %d: %s %s\n", __LINE__, msg1, msg2);\
252 #define RETURN_ERROR return GL_FALSE
253 #define RETURN_ERROR1(msg1) return GL_FALSE
254 #define RETURN_ERROR2(msg1, msg2) return GL_FALSE
260 IsProgRegister(GLuint r
)
262 return (GLuint
) (r
>= VP_PROG_REG_START
&& r
<= VP_PROG_REG_END
);
266 IsInputRegister(GLuint r
)
268 return (GLuint
) (r
>= VP_INPUT_REG_START
&& r
<= VP_INPUT_REG_END
);
272 IsOutputRegister(GLuint r
)
274 return (GLuint
) (r
>= VP_OUTPUT_REG_START
&& r
<= VP_OUTPUT_REG_END
);
279 * Parse a temporary register: Rnn
282 Parse_TempReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
286 /* Should be 'R##' */
287 if (!Parse_Token(parseState
, token
))
290 RETURN_ERROR1("Expected R##");
292 if (IsDigit(token
[1])) {
293 GLint reg
= _mesa_atoi((char *) (token
+ 1));
294 if (reg
>= VP_NUM_TEMP_REGS
)
295 RETURN_ERROR1("Bad temporary register name");
296 *tempRegNum
= VP_TEMP_REG_START
+ reg
;
299 RETURN_ERROR1("Bad temporary register name");
307 * Parse address register "A0.x"
310 Parse_AddrReg(struct parse_state
*parseState
)
313 if (!Parse_String(parseState
, "A0"))
317 if (!Parse_String(parseState
, "."))
321 if (!Parse_String(parseState
, "x"))
329 * Parse absolute program parameter register "c[##]"
332 Parse_AbsParamReg(struct parse_state
*parseState
, GLint
*regNum
)
336 if (!Parse_String(parseState
, "c"))
339 if (!Parse_String(parseState
, "["))
342 if (!Parse_Token(parseState
, token
))
345 if (IsDigit(token
[0])) {
346 /* a numbered program parameter register */
347 GLint reg
= _mesa_atoi((char *) token
);
348 if (reg
>= VP_NUM_PROG_REGS
)
349 RETURN_ERROR1("Bad constant program number");
350 *regNum
= VP_PROG_REG_START
+ reg
;
356 if (!Parse_String(parseState
, "]"))
364 Parse_ParamReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
368 if (!Parse_String(parseState
, "c"))
371 if (!Parse_String(parseState
, "["))
374 if (!Peek_Token(parseState
, token
))
377 if (IsDigit(token
[0])) {
378 /* a numbered program parameter register */
380 (void) Parse_Token(parseState
, token
);
381 reg
= _mesa_atoi((char *) token
);
382 if (reg
>= VP_NUM_PROG_REGS
)
383 RETURN_ERROR1("Bad constant program number");
384 srcReg
->Register
= VP_PROG_REG_START
+ reg
;
386 else if (_mesa_strcmp((const char *) token
, "A0") == 0) {
387 /* address register "A0.x" */
388 if (!Parse_AddrReg(parseState
))
391 srcReg
->RelAddr
= GL_TRUE
;
392 srcReg
->Register
= 0;
394 /* Look for +/-N offset */
395 if (!Peek_Token(parseState
, token
))
398 if (token
[0] == '-' || token
[0] == '+') {
399 const GLubyte sign
= token
[0];
400 (void) Parse_Token(parseState
, token
); /* consume +/- */
402 /* an integer should be next */
403 if (!Parse_Token(parseState
, token
))
406 if (IsDigit(token
[0])) {
407 const GLint k
= _mesa_atoi((char *) token
);
410 RETURN_ERROR1("Bad address offset");
411 srcReg
->Register
= -k
;
415 RETURN_ERROR1("Bad address offset");
416 srcReg
->Register
= k
;
424 /* probably got a ']', catch it below */
431 /* Match closing ']' */
432 if (!Parse_String(parseState
, "]"))
440 * Parse v[#] or v[<name>]
443 Parse_AttribReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
449 if (!Parse_String(parseState
, "v"))
453 if (!Parse_String(parseState
, "["))
456 /* match number or named register */
457 if (!Parse_Token(parseState
, token
))
460 if (parseState
->isStateProgram
&& token
[0] != '0')
461 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
463 if (IsDigit(token
[0])) {
464 GLint reg
= _mesa_atoi((char *) token
);
465 if (reg
>= VP_NUM_INPUT_REGS
)
466 RETURN_ERROR1("Bad vertex attribute register name");
467 *tempRegNum
= VP_INPUT_REG_START
+ reg
;
470 for (j
= 0; InputRegisters
[j
]; j
++) {
471 if (_mesa_strcmp((const char *) token
, InputRegisters
[j
]) == 0) {
472 *tempRegNum
= VP_INPUT_REG_START
+ j
;
476 if (!InputRegisters
[j
]) {
477 /* unknown input register label */
478 RETURN_ERROR2("Bad register name", token
);
483 if (!Parse_String(parseState
, "]"))
491 Parse_OutputReg(struct parse_state
*parseState
, GLint
*outputRegNum
)
497 if (!Parse_String(parseState
, "o"))
501 if (!Parse_String(parseState
, "["))
504 /* Get output reg name */
505 if (!Parse_Token(parseState
, token
))
508 if (parseState
->isPositionInvariant
)
509 start
= 1; /* skip HPOS register name */
513 /* try to match an output register name */
514 for (j
= start
; OutputRegisters
[j
]; j
++) {
515 if (_mesa_strcmp((const char *) token
, OutputRegisters
[j
]) == 0) {
516 *outputRegNum
= VP_OUTPUT_REG_START
+ j
;
520 if (!OutputRegisters
[j
])
521 RETURN_ERROR1("Unrecognized output register name");
524 if (!Parse_String(parseState
, "]"))
525 RETURN_ERROR1("Expected ]");
532 Parse_MaskedDstReg(struct parse_state
*parseState
, struct vp_dst_register
*dstReg
)
536 /* Dst reg can be R<n> or o[n] */
537 if (!Peek_Token(parseState
, token
))
540 if (token
[0] == 'R') {
541 /* a temporary register */
542 if (!Parse_TempReg(parseState
, &dstReg
->Register
))
545 else if (!parseState
->isStateProgram
&& token
[0] == 'o') {
546 /* an output register */
547 if (!Parse_OutputReg(parseState
, &dstReg
->Register
))
550 else if (parseState
->isStateProgram
&& token
[0] == 'c') {
551 /* absolute program parameter register */
552 if (!Parse_AbsParamReg(parseState
, &dstReg
->Register
))
556 RETURN_ERROR1("Bad destination register name");
559 /* Parse optional write mask */
560 if (!Peek_Token(parseState
, token
))
563 if (token
[0] == '.') {
567 if (!Parse_String(parseState
, "."))
570 if (!Parse_Token(parseState
, token
))
573 dstReg
->WriteMask
[0] = GL_FALSE
;
574 dstReg
->WriteMask
[1] = GL_FALSE
;
575 dstReg
->WriteMask
[2] = GL_FALSE
;
576 dstReg
->WriteMask
[3] = GL_FALSE
;
578 if (token
[k
] == 'x') {
579 dstReg
->WriteMask
[0] = GL_TRUE
;
582 if (token
[k
] == 'y') {
583 dstReg
->WriteMask
[1] = GL_TRUE
;
586 if (token
[k
] == 'z') {
587 dstReg
->WriteMask
[2] = GL_TRUE
;
590 if (token
[k
] == 'w') {
591 dstReg
->WriteMask
[3] = GL_TRUE
;
595 RETURN_ERROR1("Bad writemask character");
600 dstReg
->WriteMask
[0] = GL_TRUE
;
601 dstReg
->WriteMask
[1] = GL_TRUE
;
602 dstReg
->WriteMask
[2] = GL_TRUE
;
603 dstReg
->WriteMask
[3] = GL_TRUE
;
610 Parse_SwizzleSrcReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
614 srcReg
->RelAddr
= GL_FALSE
;
617 if (!Peek_Token(parseState
, token
))
619 if (token
[0] == '-') {
620 (void) Parse_String(parseState
, "-");
621 srcReg
->Negate
= GL_TRUE
;
622 if (!Peek_Token(parseState
, token
))
626 srcReg
->Negate
= GL_FALSE
;
629 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
630 if (token
[0] == 'R') {
631 if (!Parse_TempReg(parseState
, &srcReg
->Register
))
634 else if (token
[0] == 'c') {
635 if (!Parse_ParamReg(parseState
, srcReg
))
638 else if (token
[0] == 'v') {
639 if (!Parse_AttribReg(parseState
, &srcReg
->Register
))
643 RETURN_ERROR2("Bad source register name", token
);
646 /* init swizzle fields */
647 srcReg
->Swizzle
[0] = 0;
648 srcReg
->Swizzle
[1] = 1;
649 srcReg
->Swizzle
[2] = 2;
650 srcReg
->Swizzle
[3] = 3;
652 /* Look for optional swizzle suffix */
653 if (!Peek_Token(parseState
, token
))
655 if (token
[0] == '.') {
656 (void) Parse_String(parseState
, "."); /* consume . */
658 if (!Parse_Token(parseState
, token
))
662 /* single letter swizzle */
664 ASSIGN_4V(srcReg
->Swizzle
, 0, 0, 0, 0);
665 else if (token
[0] == 'y')
666 ASSIGN_4V(srcReg
->Swizzle
, 1, 1, 1, 1);
667 else if (token
[0] == 'z')
668 ASSIGN_4V(srcReg
->Swizzle
, 2, 2, 2, 2);
669 else if (token
[0] == 'w')
670 ASSIGN_4V(srcReg
->Swizzle
, 3, 3, 3, 3);
672 RETURN_ERROR1("Expected x, y, z, or w");
675 /* 2, 3 or 4-component swizzle */
677 for (k
= 0; token
[k
] && k
< 5; k
++) {
679 srcReg
->Swizzle
[k
] = 0;
680 else if (token
[k
] == 'y')
681 srcReg
->Swizzle
[k
] = 1;
682 else if (token
[k
] == 'z')
683 srcReg
->Swizzle
[k
] = 2;
684 else if (token
[k
] == 'w')
685 srcReg
->Swizzle
[k
] = 3;
699 Parse_ScalarSrcReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
703 srcReg
->RelAddr
= GL_FALSE
;
706 if (!Peek_Token(parseState
, token
))
708 if (token
[0] == '-') {
709 srcReg
->Negate
= GL_TRUE
;
710 (void) Parse_String(parseState
, "-"); /* consume '-' */
711 if (!Peek_Token(parseState
, token
))
715 srcReg
->Negate
= GL_FALSE
;
718 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
719 if (token
[0] == 'R') {
720 if (!Parse_TempReg(parseState
, &srcReg
->Register
))
723 else if (token
[0] == 'c') {
724 if (!Parse_ParamReg(parseState
, srcReg
))
727 else if (token
[0] == 'v') {
728 if (!Parse_AttribReg(parseState
, &srcReg
->Register
))
732 RETURN_ERROR2("Bad source register name", token
);
735 /* Look for .[xyzw] suffix */
736 if (!Parse_String(parseState
, "."))
739 if (!Parse_Token(parseState
, token
))
742 if (token
[0] == 'x' && token
[1] == 0) {
743 srcReg
->Swizzle
[0] = 0;
745 else if (token
[0] == 'y' && token
[1] == 0) {
746 srcReg
->Swizzle
[0] = 1;
748 else if (token
[0] == 'z' && token
[1] == 0) {
749 srcReg
->Swizzle
[0] = 2;
751 else if (token
[0] == 'w' && token
[1] == 0) {
752 srcReg
->Swizzle
[0] = 3;
755 RETURN_ERROR1("Bad scalar source suffix");
757 srcReg
->Swizzle
[1] = srcReg
->Swizzle
[2] = srcReg
->Swizzle
[3] = 0;
764 Parse_UnaryOpInstruction(struct parse_state
*parseState
,
765 struct vp_instruction
*inst
, enum vp_opcode opcode
)
767 if (opcode
== VP_OPCODE_ABS
&& !parseState
->isVersion1_1
)
768 RETURN_ERROR1("ABS illegal for vertex program 1.0");
770 inst
->Opcode
= opcode
;
773 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
777 if (!Parse_String(parseState
, ","))
781 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
785 if (!Parse_String(parseState
, ";"))
793 Parse_BiOpInstruction(struct parse_state
*parseState
,
794 struct vp_instruction
*inst
, enum vp_opcode opcode
)
796 if (opcode
== VP_OPCODE_DPH
&& !parseState
->isVersion1_1
)
797 RETURN_ERROR1("DPH illegal for vertex program 1.0");
798 if (opcode
== VP_OPCODE_SUB
&& !parseState
->isVersion1_1
)
799 RETURN_ERROR1("SUB illegal for vertex program 1.0");
801 inst
->Opcode
= opcode
;
804 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
808 if (!Parse_String(parseState
, ","))
812 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
816 if (!Parse_String(parseState
, ","))
820 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
824 if (!Parse_String(parseState
, ";"))
827 /* make sure we don't reference more than one program parameter register */
828 if (IsProgRegister(inst
->SrcReg
[0].Register
) &&
829 IsProgRegister(inst
->SrcReg
[1].Register
) &&
830 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
)
831 RETURN_ERROR1("Can't reference two program parameter registers");
833 /* make sure we don't reference more than one vertex attribute register */
834 if (IsInputRegister(inst
->SrcReg
[0].Register
) &&
835 IsInputRegister(inst
->SrcReg
[1].Register
) &&
836 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
)
837 RETURN_ERROR1("Can't reference two vertex attribute registers");
844 Parse_TriOpInstruction(struct parse_state
*parseState
,
845 struct vp_instruction
*inst
, enum vp_opcode opcode
)
847 inst
->Opcode
= opcode
;
850 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
854 if (!Parse_String(parseState
, ","))
858 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
862 if (!Parse_String(parseState
, ","))
866 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
870 if (!Parse_String(parseState
, ","))
874 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[2]))
878 if (!Parse_String(parseState
, ";"))
881 /* make sure we don't reference more than one program parameter register */
882 if ((IsProgRegister(inst
->SrcReg
[0].Register
) &&
883 IsProgRegister(inst
->SrcReg
[1].Register
) &&
884 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
) ||
885 (IsProgRegister(inst
->SrcReg
[0].Register
) &&
886 IsProgRegister(inst
->SrcReg
[2].Register
) &&
887 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[2].Register
) ||
888 (IsProgRegister(inst
->SrcReg
[1].Register
) &&
889 IsProgRegister(inst
->SrcReg
[2].Register
) &&
890 inst
->SrcReg
[1].Register
!= inst
->SrcReg
[2].Register
))
891 RETURN_ERROR1("Can only reference one program register");
893 /* make sure we don't reference more than one vertex attribute register */
894 if ((IsInputRegister(inst
->SrcReg
[0].Register
) &&
895 IsInputRegister(inst
->SrcReg
[1].Register
) &&
896 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
) ||
897 (IsInputRegister(inst
->SrcReg
[0].Register
) &&
898 IsInputRegister(inst
->SrcReg
[2].Register
) &&
899 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[2].Register
) ||
900 (IsInputRegister(inst
->SrcReg
[1].Register
) &&
901 IsInputRegister(inst
->SrcReg
[2].Register
) &&
902 inst
->SrcReg
[1].Register
!= inst
->SrcReg
[2].Register
))
903 RETURN_ERROR1("Can only reference one input register");
910 Parse_ScalarInstruction(struct parse_state
*parseState
,
911 struct vp_instruction
*inst
, enum vp_opcode opcode
)
913 if (opcode
== VP_OPCODE_RCC
&& !parseState
->isVersion1_1
)
914 RETURN_ERROR1("RCC illegal for vertex program 1.0");
916 inst
->Opcode
= opcode
;
919 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
923 if (!Parse_String(parseState
, ","))
927 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
931 if (!Parse_String(parseState
, ";"))
939 Parse_AddressInstruction(struct parse_state
*parseState
, struct vp_instruction
*inst
)
941 inst
->Opcode
= VP_OPCODE_ARL
;
944 if (!Parse_AddrReg(parseState
))
948 if (!Parse_String(parseState
, ","))
952 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
956 if (!Parse_String(parseState
, ";"))
964 Parse_EndInstruction(struct parse_state
*parseState
, struct vp_instruction
*inst
)
968 inst
->Opcode
= VP_OPCODE_END
;
970 /* this should fail! */
971 if (Parse_Token(parseState
, token
))
972 RETURN_ERROR2("Unexpected token after END:", token
);
979 Parse_OptionSequence(struct parse_state
*parseState
,
980 struct vp_instruction program
[])
983 if (!Parse_String(parseState
, "OPTION"))
984 return GL_TRUE
; /* ok, not an OPTION statement */
985 if (Parse_String(parseState
, "NV_position_invariant")) {
986 parseState
->isPositionInvariant
= GL_TRUE
;
989 RETURN_ERROR1("unexpected OPTION statement");
991 if (!Parse_String(parseState
, ";"))
998 Parse_InstructionSequence(struct parse_state
*parseState
,
999 struct vp_instruction program
[])
1002 struct vp_instruction
*inst
= program
+ parseState
->numInst
;
1004 /* Initialize the instruction */
1005 inst
->SrcReg
[0].Register
= -1;
1006 inst
->SrcReg
[1].Register
= -1;
1007 inst
->SrcReg
[2].Register
= -1;
1008 inst
->DstReg
.Register
= -1;
1010 if (Parse_String(parseState
, "MOV")) {
1011 if (!Parse_UnaryOpInstruction(parseState
, inst
, VP_OPCODE_MOV
))
1014 else if (Parse_String(parseState
, "LIT")) {
1015 if (!Parse_UnaryOpInstruction(parseState
, inst
, VP_OPCODE_LIT
))
1018 else if (Parse_String(parseState
, "ABS")) {
1019 if (!Parse_UnaryOpInstruction(parseState
, inst
, VP_OPCODE_ABS
))
1022 else if (Parse_String(parseState
, "MUL")) {
1023 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_MUL
))
1026 else if (Parse_String(parseState
, "ADD")) {
1027 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_ADD
))
1030 else if (Parse_String(parseState
, "DP3")) {
1031 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DP3
))
1034 else if (Parse_String(parseState
, "DP4")) {
1035 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DP4
))
1038 else if (Parse_String(parseState
, "DST")) {
1039 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DST
))
1042 else if (Parse_String(parseState
, "MIN")) {
1043 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_MIN
))
1046 else if (Parse_String(parseState
, "MAX")) {
1047 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_MAX
))
1050 else if (Parse_String(parseState
, "SLT")) {
1051 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_SLT
))
1054 else if (Parse_String(parseState
, "SGE")) {
1055 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_SGE
))
1058 else if (Parse_String(parseState
, "DPH")) {
1059 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DPH
))
1062 else if (Parse_String(parseState
, "SUB")) {
1063 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_SUB
))
1066 else if (Parse_String(parseState
, "MAD")) {
1067 if (!Parse_TriOpInstruction(parseState
, inst
, VP_OPCODE_MAD
))
1070 else if (Parse_String(parseState
, "RCP")) {
1071 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_RCP
))
1074 else if (Parse_String(parseState
, "RSQ")) {
1075 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_RSQ
))
1078 else if (Parse_String(parseState
, "EXP")) {
1079 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_EXP
))
1082 else if (Parse_String(parseState
, "LOG")) {
1083 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_LOG
))
1086 else if (Parse_String(parseState
, "RCC")) {
1087 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_RCC
))
1090 else if (Parse_String(parseState
, "ARL")) {
1091 if (!Parse_AddressInstruction(parseState
, inst
))
1094 else if (Parse_String(parseState
, "END")) {
1095 if (!Parse_EndInstruction(parseState
, inst
))
1098 parseState
->numInst
++;
1099 return GL_TRUE
; /* all done */
1103 /* bad instruction name */
1104 RETURN_ERROR1("Unexpected token");
1107 /* examine input/output registers */
1109 const GLint srcReg0
= inst
->SrcReg
[0].Register
;
1110 const GLint srcReg1
= inst
->SrcReg
[1].Register
;
1111 const GLint srcReg2
= inst
->SrcReg
[2].Register
;
1112 const GLint dstReg
= inst
->DstReg
.Register
;
1114 if (IsOutputRegister(dstReg
))
1115 parseState
->outputsWritten
|= (1 << (dstReg
- VP_OUTPUT_REG_START
));
1116 else if (IsProgRegister(dstReg
))
1117 parseState
->progRegsWritten
|= (1 << (dstReg
- VP_PROG_REG_START
));
1119 if (IsInputRegister(srcReg0
) && !inst
->SrcReg
[0].RelAddr
)
1120 parseState
->inputsRead
|= (1 << (srcReg0
- VP_INPUT_REG_START
));
1122 if (IsInputRegister(srcReg1
) && !inst
->SrcReg
[1].RelAddr
)
1123 parseState
->inputsRead
|= (1 << (srcReg1
- VP_INPUT_REG_START
));
1125 if (IsInputRegister(srcReg2
) && !inst
->SrcReg
[2].RelAddr
)
1126 parseState
->inputsRead
|= (1 << (srcReg2
- VP_INPUT_REG_START
));
1129 parseState
->numInst
++;
1131 if (parseState
->numInst
>= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
)
1132 RETURN_ERROR1("Program too long");
1140 Parse_Program(struct parse_state
*parseState
,
1141 struct vp_instruction instBuffer
[])
1143 if (parseState
->isVersion1_1
) {
1144 if (!Parse_OptionSequence(parseState
, instBuffer
)) {
1148 return Parse_InstructionSequence(parseState
, instBuffer
);
1153 * Parse/compile the 'str' returning the compiled 'program'.
1154 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1155 * indicates the position of the error in 'str'.
1158 _mesa_parse_nv_vertex_program(GLcontext
*ctx
, GLenum dstTarget
,
1159 const GLubyte
*str
, GLsizei len
,
1160 struct vertex_program
*program
)
1162 struct parse_state parseState
;
1163 struct vp_instruction instBuffer
[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
];
1164 struct vp_instruction
*newInst
;
1166 GLubyte
*programString
;
1168 /* Make a null-terminated copy of the program string */
1169 programString
= (GLubyte
*) MALLOC(len
+ 1);
1170 if (!programString
) {
1171 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1174 MEMCPY(programString
, str
, len
);
1175 programString
[len
] = 0;
1177 /* get ready to parse */
1178 parseState
.isPositionInvariant
= GL_FALSE
;
1179 parseState
.isVersion1_1
= GL_FALSE
;
1180 parseState
.numInst
= 0;
1181 parseState
.inputsRead
= 0;
1182 parseState
.outputsWritten
= 0;
1183 parseState
.progRegsWritten
= 0;
1185 /* check the program header */
1186 if (_mesa_strncmp((const char *) programString
, "!!VP1.0", 7) == 0) {
1187 target
= GL_VERTEX_PROGRAM_NV
;
1188 parseState
.pos
= programString
+ 7;
1189 parseState
.isStateProgram
= GL_FALSE
;
1191 else if (_mesa_strncmp((const char *) programString
, "!!VP1.1", 7) == 0) {
1192 target
= GL_VERTEX_PROGRAM_NV
;
1193 parseState
.pos
= programString
+ 7;
1194 parseState
.isStateProgram
= GL_FALSE
;
1195 parseState
.isVersion1_1
= GL_TRUE
;
1197 else if (_mesa_strncmp((const char *) programString
, "!!VSP1.0", 8) == 0) {
1198 target
= GL_VERTEX_STATE_PROGRAM_NV
;
1199 parseState
.pos
= programString
+ 8;
1200 parseState
.isStateProgram
= GL_TRUE
;
1203 /* invalid header */
1204 ctx
->Program
.ErrorPos
= 0;
1205 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1209 /* make sure target and header match */
1210 if (target
!= dstTarget
) {
1211 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1212 "glLoadProgramNV(target mismatch)");
1217 if (Parse_Program(&parseState
, instBuffer
)) {
1218 /* successful parse! */
1220 if (parseState
.isStateProgram
) {
1221 if (parseState
.progRegsWritten
== 0) {
1222 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1223 "glLoadProgramNV(c[#] not written)");
1228 if (!parseState
.isPositionInvariant
&&
1229 !(parseState
.outputsWritten
& 1)) {
1230 /* bit 1 = HPOS register */
1231 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1232 "glLoadProgramNV(HPOS not written)");
1237 /* copy the compiled instructions */
1238 assert(parseState
.numInst
<= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
);
1239 newInst
= (struct vp_instruction
*)
1240 MALLOC(parseState
.numInst
* sizeof(struct vp_instruction
));
1242 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1243 FREE(programString
);
1244 return; /* out of memory */
1246 MEMCPY(newInst
, instBuffer
,
1247 parseState
.numInst
* sizeof(struct vp_instruction
));
1249 /* install the program */
1250 program
->Base
.Target
= target
;
1251 if (program
->Base
.String
) {
1252 FREE(program
->Base
.String
);
1254 program
->Base
.String
= programString
;
1255 if (program
->Instructions
) {
1256 FREE(program
->Instructions
);
1258 program
->Instructions
= newInst
;
1259 program
->InputsRead
= parseState
.inputsRead
;
1260 program
->OutputsWritten
= parseState
.outputsWritten
;
1261 program
->IsPositionInvariant
= parseState
.isPositionInvariant
;
1264 _mesa_printf("--- glLoadProgramNV result ---\n");
1265 _mesa_print_nv_vertex_program(program
);
1266 _mesa_printf("------------------------------\n");
1271 ctx
->Program
.ErrorPos
= parseState
.pos
- str
;
1272 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1276 const GLubyte
*lineStr
;
1277 lineStr
= _mesa_find_line_column(programString
,
1278 parseState
.pos
, &line
, &column
);
1279 _mesa_debug(ctx
, "Parse error on line %d, column %d:%s\n",
1280 line
, column
, (char *) lineStr
);
1281 _mesa_free((void *) lineStr
);
1289 PrintSrcReg(const struct vp_src_register
*src
)
1291 static const char comps
[5] = "xyzw";
1295 if (src
->Register
> 0)
1296 _mesa_printf("c[A0.x + %d]", src
->Register
);
1297 else if (src
->Register
< 0)
1298 _mesa_printf("c[A0.x - %d]", -src
->Register
);
1300 _mesa_printf("c[A0.x]");
1302 else if (src
->Register
>= VP_OUTPUT_REG_START
1303 && src
->Register
<= VP_OUTPUT_REG_END
) {
1304 _mesa_printf("o[%s]", OutputRegisters
[src
->Register
- VP_OUTPUT_REG_START
]);
1306 else if (src
->Register
>= VP_INPUT_REG_START
1307 && src
->Register
<= VP_INPUT_REG_END
) {
1308 _mesa_printf("v[%s]", InputRegisters
[src
->Register
- VP_INPUT_REG_START
]);
1310 else if (src
->Register
>= VP_PROG_REG_START
1311 && src
->Register
<= VP_PROG_REG_END
) {
1312 _mesa_printf("c[%d]", src
->Register
- VP_PROG_REG_START
);
1315 _mesa_printf("R%d", src
->Register
- VP_TEMP_REG_START
);
1318 if (src
->Swizzle
[0] == src
->Swizzle
[1] &&
1319 src
->Swizzle
[0] == src
->Swizzle
[2] &&
1320 src
->Swizzle
[0] == src
->Swizzle
[3]) {
1321 _mesa_printf(".%c", comps
[src
->Swizzle
[0]]);
1323 else if (src
->Swizzle
[0] != 0 ||
1324 src
->Swizzle
[1] != 1 ||
1325 src
->Swizzle
[2] != 2 ||
1326 src
->Swizzle
[3] != 3) {
1327 _mesa_printf(".%c%c%c%c",
1328 comps
[src
->Swizzle
[0]],
1329 comps
[src
->Swizzle
[1]],
1330 comps
[src
->Swizzle
[2]],
1331 comps
[src
->Swizzle
[3]]);
1337 PrintDstReg(const struct vp_dst_register
*dst
)
1339 GLint w
= dst
->WriteMask
[0] + dst
->WriteMask
[1]
1340 + dst
->WriteMask
[2] + dst
->WriteMask
[3];
1342 if (dst
->Register
>= VP_OUTPUT_REG_START
1343 && dst
->Register
<= VP_OUTPUT_REG_END
) {
1344 _mesa_printf("o[%s]", OutputRegisters
[dst
->Register
- VP_OUTPUT_REG_START
]);
1346 else if (dst
->Register
>= VP_INPUT_REG_START
1347 && dst
->Register
<= VP_INPUT_REG_END
) {
1348 _mesa_printf("v[%s]", InputRegisters
[dst
->Register
- VP_INPUT_REG_START
]);
1350 else if (dst
->Register
>= VP_PROG_REG_START
1351 && dst
->Register
<= VP_PROG_REG_END
) {
1352 _mesa_printf("c[%d]", dst
->Register
- VP_PROG_REG_START
);
1355 _mesa_printf("R%d", dst
->Register
- VP_TEMP_REG_START
);
1358 if (w
!= 0 && w
!= 4) {
1360 if (dst
->WriteMask
[0])
1362 if (dst
->WriteMask
[1])
1364 if (dst
->WriteMask
[2])
1366 if (dst
->WriteMask
[3])
1373 * Print (unparse) the given vertex program. Just for debugging.
1376 _mesa_print_nv_vertex_program(const struct vertex_program
*program
)
1378 const struct vp_instruction
*inst
;
1380 for (inst
= program
->Instructions
; ; inst
++) {
1381 switch (inst
->Opcode
) {
1390 _mesa_printf("%s ", Opcodes
[(int) inst
->Opcode
]);
1391 PrintDstReg(&inst
->DstReg
);
1393 PrintSrcReg(&inst
->SrcReg
[0]);
1394 _mesa_printf(";\n");
1407 _mesa_printf("%s ", Opcodes
[(int) inst
->Opcode
]);
1408 PrintDstReg(&inst
->DstReg
);
1410 PrintSrcReg(&inst
->SrcReg
[0]);
1412 PrintSrcReg(&inst
->SrcReg
[1]);
1413 _mesa_printf(";\n");
1416 _mesa_printf("MAD ");
1417 PrintDstReg(&inst
->DstReg
);
1419 PrintSrcReg(&inst
->SrcReg
[0]);
1421 PrintSrcReg(&inst
->SrcReg
[1]);
1423 PrintSrcReg(&inst
->SrcReg
[2]);
1424 _mesa_printf(";\n");
1427 _mesa_printf("ARL A0.x, ");
1428 PrintSrcReg(&inst
->SrcReg
[0]);
1429 _mesa_printf(";\n");
1432 _mesa_printf("END\n");
1435 _mesa_printf("BAD INSTRUCTION\n");