1 /* $Id: nvvertparse.c,v 1.4 2003/03/14 15:40:59 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
53 GLboolean isStateProgram
;
54 GLboolean isPositionInvariant
;
55 GLboolean isVersion1_1
;
57 GLuint outputsWritten
;
58 GLuint progRegsWritten
;
59 GLuint numInst
; /* number of instructions parsed */
64 * Called whenever we find an error during parsing.
67 record_error(struct parse_state
*parseState
, const char *msg
, int lineNo
)
71 const GLubyte
*lineStr
;
72 lineStr
= _mesa_find_line_column(parseState
->start
,
73 parseState
->pos
, &line
, &column
);
74 _mesa_debug(parseState
->ctx
,
75 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
76 lineNo
, line
, column
, (char *) lineStr
, msg
);
77 _mesa_free((void *) lineStr
);
82 /* Check that no error was already recorded. Only record the first one. */
83 if (parseState
->ctx
->Program
.ErrorString
[0] == 0) {
84 _mesa_set_program_error(parseState
->ctx
,
85 parseState
->pos
- parseState
->start
,
91 #define RETURN_ERROR \
93 record_error(parseState, "Unexpected end of input.", __LINE__); \
97 #define RETURN_ERROR1(msg) \
99 record_error(parseState, msg, __LINE__); \
103 #define RETURN_ERROR2(msg1, msg2) \
106 _mesa_sprintf(err, "%s %s", msg1, msg2); \
107 record_error(parseState, err, __LINE__); \
115 static GLboolean
IsLetter(GLubyte b
)
117 return (b
>= 'a' && b
<= 'z') || (b
>= 'A' && b
<= 'Z');
121 static GLboolean
IsDigit(GLubyte b
)
123 return b
>= '0' && b
<= '9';
127 static GLboolean
IsWhitespace(GLubyte b
)
129 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
134 * Starting at 'str' find the next token. A token can be an integer,
135 * an identifier or punctuation symbol.
136 * \return <= 0 we found an error, else, return number of characters parsed.
139 GetToken(const GLubyte
*str
, GLubyte
*token
)
145 /* skip whitespace and comments */
146 while (str
[i
] && (IsWhitespace(str
[i
]) || str
[i
] == '#')) {
149 while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
154 /* skip whitespace */
162 /* try matching an integer */
163 while (str
[i
] && IsDigit(str
[i
])) {
164 token
[j
++] = str
[i
++];
166 if (j
> 0 || !str
[i
]) {
171 /* try matching an identifier */
172 if (IsLetter(str
[i
])) {
173 while (str
[i
] && (IsLetter(str
[i
]) || IsDigit(str
[i
]))) {
174 token
[j
++] = str
[i
++];
194 * Get next token from input stream and increment stream pointer past token.
197 Parse_Token(struct parse_state
*parseState
, GLubyte
*token
)
200 i
= GetToken(parseState
->pos
, token
);
202 parseState
->pos
+= (-i
);
205 parseState
->pos
+= i
;
211 * Get next token from input stream but don't increment stream pointer.
214 Peek_Token(struct parse_state
*parseState
, GLubyte
*token
)
217 i
= GetToken(parseState
->pos
, token
);
219 parseState
->pos
+= (-i
);
222 len
= _mesa_strlen((const char *) token
);
223 parseState
->pos
+= (i
- len
);
229 * Try to match 'pattern' as the next token after any whitespace/comments.
230 * Advance the current parsing position only if we match the pattern.
231 * \return GL_TRUE if pattern is matched, GL_FALSE otherwise.
234 Parse_String(struct parse_state
*parseState
, const char *pattern
)
239 /* skip whitespace and comments */
240 while (IsWhitespace(*parseState
->pos
) || *parseState
->pos
== '#') {
241 if (*parseState
->pos
== '#') {
242 while (*parseState
->pos
&& (*parseState
->pos
!= '\n' && *parseState
->pos
!= '\r')) {
243 parseState
->pos
+= 1;
247 /* skip whitespace */
248 parseState
->pos
+= 1;
252 /* Try to match the pattern */
254 for (i
= 0; pattern
[i
]; i
++) {
255 if (*m
!= (GLubyte
) pattern
[i
])
261 return GL_TRUE
; /* success */
265 /**********************************************************************/
267 static const char *InputRegisters
[] = {
268 "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
269 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
272 static const char *OutputRegisters
[] = {
273 "HPOS", "COL0", "COL1", "BFC0", "BFC1", "FOGC", "PSIZ",
274 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
277 static const char *Opcodes
[] = {
278 "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
279 "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
286 IsProgRegister(GLuint r
)
288 return (GLuint
) (r
>= VP_PROG_REG_START
&& r
<= VP_PROG_REG_END
);
292 IsInputRegister(GLuint r
)
294 return (GLuint
) (r
>= VP_INPUT_REG_START
&& r
<= VP_INPUT_REG_END
);
298 IsOutputRegister(GLuint r
)
300 return (GLuint
) (r
>= VP_OUTPUT_REG_START
&& r
<= VP_OUTPUT_REG_END
);
305 * Parse a temporary register: Rnn
308 Parse_TempReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
312 /* Should be 'R##' */
313 if (!Parse_Token(parseState
, token
))
316 RETURN_ERROR1("Expected R##");
318 if (IsDigit(token
[1])) {
319 GLint reg
= _mesa_atoi((char *) (token
+ 1));
320 if (reg
>= VP_NUM_TEMP_REGS
)
321 RETURN_ERROR1("Bad temporary register name");
322 *tempRegNum
= VP_TEMP_REG_START
+ reg
;
325 RETURN_ERROR1("Bad temporary register name");
333 * Parse address register "A0.x"
336 Parse_AddrReg(struct parse_state
*parseState
)
339 if (!Parse_String(parseState
, "A0"))
343 if (!Parse_String(parseState
, "."))
347 if (!Parse_String(parseState
, "x"))
355 * Parse absolute program parameter register "c[##]"
358 Parse_AbsParamReg(struct parse_state
*parseState
, GLint
*regNum
)
362 if (!Parse_String(parseState
, "c"))
365 if (!Parse_String(parseState
, "["))
368 if (!Parse_Token(parseState
, token
))
371 if (IsDigit(token
[0])) {
372 /* a numbered program parameter register */
373 GLint reg
= _mesa_atoi((char *) token
);
374 if (reg
>= VP_NUM_PROG_REGS
)
375 RETURN_ERROR1("Bad constant program number");
376 *regNum
= VP_PROG_REG_START
+ reg
;
382 if (!Parse_String(parseState
, "]"))
390 Parse_ParamReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
394 if (!Parse_String(parseState
, "c"))
397 if (!Parse_String(parseState
, "["))
400 if (!Peek_Token(parseState
, token
))
403 if (IsDigit(token
[0])) {
404 /* a numbered program parameter register */
406 (void) Parse_Token(parseState
, token
);
407 reg
= _mesa_atoi((char *) token
);
408 if (reg
>= VP_NUM_PROG_REGS
)
409 RETURN_ERROR1("Bad constant program number");
410 srcReg
->Register
= VP_PROG_REG_START
+ reg
;
412 else if (_mesa_strcmp((const char *) token
, "A0") == 0) {
413 /* address register "A0.x" */
414 if (!Parse_AddrReg(parseState
))
417 srcReg
->RelAddr
= GL_TRUE
;
418 srcReg
->Register
= 0;
420 /* Look for +/-N offset */
421 if (!Peek_Token(parseState
, token
))
424 if (token
[0] == '-' || token
[0] == '+') {
425 const GLubyte sign
= token
[0];
426 (void) Parse_Token(parseState
, token
); /* consume +/- */
428 /* an integer should be next */
429 if (!Parse_Token(parseState
, token
))
432 if (IsDigit(token
[0])) {
433 const GLint k
= _mesa_atoi((char *) token
);
436 RETURN_ERROR1("Bad address offset");
437 srcReg
->Register
= -k
;
441 RETURN_ERROR1("Bad address offset");
442 srcReg
->Register
= k
;
450 /* probably got a ']', catch it below */
457 /* Match closing ']' */
458 if (!Parse_String(parseState
, "]"))
466 * Parse v[#] or v[<name>]
469 Parse_AttribReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
475 if (!Parse_String(parseState
, "v"))
479 if (!Parse_String(parseState
, "["))
482 /* match number or named register */
483 if (!Parse_Token(parseState
, token
))
486 if (parseState
->isStateProgram
&& token
[0] != '0')
487 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
489 if (IsDigit(token
[0])) {
490 GLint reg
= _mesa_atoi((char *) token
);
491 if (reg
>= VP_NUM_INPUT_REGS
)
492 RETURN_ERROR1("Bad vertex attribute register name");
493 *tempRegNum
= VP_INPUT_REG_START
+ reg
;
496 for (j
= 0; InputRegisters
[j
]; j
++) {
497 if (_mesa_strcmp((const char *) token
, InputRegisters
[j
]) == 0) {
498 *tempRegNum
= VP_INPUT_REG_START
+ j
;
502 if (!InputRegisters
[j
]) {
503 /* unknown input register label */
504 RETURN_ERROR2("Bad register name", token
);
509 if (!Parse_String(parseState
, "]"))
517 Parse_OutputReg(struct parse_state
*parseState
, GLint
*outputRegNum
)
523 if (!Parse_String(parseState
, "o"))
527 if (!Parse_String(parseState
, "["))
530 /* Get output reg name */
531 if (!Parse_Token(parseState
, token
))
534 if (parseState
->isPositionInvariant
)
535 start
= 1; /* skip HPOS register name */
539 /* try to match an output register name */
540 for (j
= start
; OutputRegisters
[j
]; j
++) {
541 if (_mesa_strcmp((const char *) token
, OutputRegisters
[j
]) == 0) {
542 *outputRegNum
= VP_OUTPUT_REG_START
+ j
;
546 if (!OutputRegisters
[j
])
547 RETURN_ERROR1("Unrecognized output register name");
550 if (!Parse_String(parseState
, "]"))
551 RETURN_ERROR1("Expected ]");
558 Parse_MaskedDstReg(struct parse_state
*parseState
, struct vp_dst_register
*dstReg
)
562 /* Dst reg can be R<n> or o[n] */
563 if (!Peek_Token(parseState
, token
))
566 if (token
[0] == 'R') {
567 /* a temporary register */
568 if (!Parse_TempReg(parseState
, &dstReg
->Register
))
571 else if (!parseState
->isStateProgram
&& token
[0] == 'o') {
572 /* an output register */
573 if (!Parse_OutputReg(parseState
, &dstReg
->Register
))
576 else if (parseState
->isStateProgram
&& token
[0] == 'c') {
577 /* absolute program parameter register */
578 if (!Parse_AbsParamReg(parseState
, &dstReg
->Register
))
582 RETURN_ERROR1("Bad destination register name");
585 /* Parse optional write mask */
586 if (!Peek_Token(parseState
, token
))
589 if (token
[0] == '.') {
593 if (!Parse_String(parseState
, "."))
596 if (!Parse_Token(parseState
, token
))
599 dstReg
->WriteMask
[0] = GL_FALSE
;
600 dstReg
->WriteMask
[1] = GL_FALSE
;
601 dstReg
->WriteMask
[2] = GL_FALSE
;
602 dstReg
->WriteMask
[3] = GL_FALSE
;
604 if (token
[k
] == 'x') {
605 dstReg
->WriteMask
[0] = GL_TRUE
;
608 if (token
[k
] == 'y') {
609 dstReg
->WriteMask
[1] = GL_TRUE
;
612 if (token
[k
] == 'z') {
613 dstReg
->WriteMask
[2] = GL_TRUE
;
616 if (token
[k
] == 'w') {
617 dstReg
->WriteMask
[3] = GL_TRUE
;
621 RETURN_ERROR1("Bad writemask character");
626 dstReg
->WriteMask
[0] = GL_TRUE
;
627 dstReg
->WriteMask
[1] = GL_TRUE
;
628 dstReg
->WriteMask
[2] = GL_TRUE
;
629 dstReg
->WriteMask
[3] = GL_TRUE
;
636 Parse_SwizzleSrcReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
640 srcReg
->RelAddr
= GL_FALSE
;
643 if (!Peek_Token(parseState
, token
))
645 if (token
[0] == '-') {
646 (void) Parse_String(parseState
, "-");
647 srcReg
->Negate
= GL_TRUE
;
648 if (!Peek_Token(parseState
, token
))
652 srcReg
->Negate
= GL_FALSE
;
655 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
656 if (token
[0] == 'R') {
657 if (!Parse_TempReg(parseState
, &srcReg
->Register
))
660 else if (token
[0] == 'c') {
661 if (!Parse_ParamReg(parseState
, srcReg
))
664 else if (token
[0] == 'v') {
665 if (!Parse_AttribReg(parseState
, &srcReg
->Register
))
669 RETURN_ERROR2("Bad source register name", token
);
672 /* init swizzle fields */
673 srcReg
->Swizzle
[0] = 0;
674 srcReg
->Swizzle
[1] = 1;
675 srcReg
->Swizzle
[2] = 2;
676 srcReg
->Swizzle
[3] = 3;
678 /* Look for optional swizzle suffix */
679 if (!Peek_Token(parseState
, token
))
681 if (token
[0] == '.') {
682 (void) Parse_String(parseState
, "."); /* consume . */
684 if (!Parse_Token(parseState
, token
))
688 /* single letter swizzle */
690 ASSIGN_4V(srcReg
->Swizzle
, 0, 0, 0, 0);
691 else if (token
[0] == 'y')
692 ASSIGN_4V(srcReg
->Swizzle
, 1, 1, 1, 1);
693 else if (token
[0] == 'z')
694 ASSIGN_4V(srcReg
->Swizzle
, 2, 2, 2, 2);
695 else if (token
[0] == 'w')
696 ASSIGN_4V(srcReg
->Swizzle
, 3, 3, 3, 3);
698 RETURN_ERROR1("Expected x, y, z, or w");
701 /* 2, 3 or 4-component swizzle */
703 for (k
= 0; token
[k
] && k
< 5; k
++) {
705 srcReg
->Swizzle
[k
] = 0;
706 else if (token
[k
] == 'y')
707 srcReg
->Swizzle
[k
] = 1;
708 else if (token
[k
] == 'z')
709 srcReg
->Swizzle
[k
] = 2;
710 else if (token
[k
] == 'w')
711 srcReg
->Swizzle
[k
] = 3;
725 Parse_ScalarSrcReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
729 srcReg
->RelAddr
= GL_FALSE
;
732 if (!Peek_Token(parseState
, token
))
734 if (token
[0] == '-') {
735 srcReg
->Negate
= GL_TRUE
;
736 (void) Parse_String(parseState
, "-"); /* consume '-' */
737 if (!Peek_Token(parseState
, token
))
741 srcReg
->Negate
= GL_FALSE
;
744 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
745 if (token
[0] == 'R') {
746 if (!Parse_TempReg(parseState
, &srcReg
->Register
))
749 else if (token
[0] == 'c') {
750 if (!Parse_ParamReg(parseState
, srcReg
))
753 else if (token
[0] == 'v') {
754 if (!Parse_AttribReg(parseState
, &srcReg
->Register
))
758 RETURN_ERROR2("Bad source register name", token
);
761 /* Look for .[xyzw] suffix */
762 if (!Parse_String(parseState
, "."))
765 if (!Parse_Token(parseState
, token
))
768 if (token
[0] == 'x' && token
[1] == 0) {
769 srcReg
->Swizzle
[0] = 0;
771 else if (token
[0] == 'y' && token
[1] == 0) {
772 srcReg
->Swizzle
[0] = 1;
774 else if (token
[0] == 'z' && token
[1] == 0) {
775 srcReg
->Swizzle
[0] = 2;
777 else if (token
[0] == 'w' && token
[1] == 0) {
778 srcReg
->Swizzle
[0] = 3;
781 RETURN_ERROR1("Bad scalar source suffix");
783 srcReg
->Swizzle
[1] = srcReg
->Swizzle
[2] = srcReg
->Swizzle
[3] = 0;
790 Parse_UnaryOpInstruction(struct parse_state
*parseState
,
791 struct vp_instruction
*inst
, enum vp_opcode opcode
)
793 if (opcode
== VP_OPCODE_ABS
&& !parseState
->isVersion1_1
)
794 RETURN_ERROR1("ABS illegal for vertex program 1.0");
796 inst
->Opcode
= opcode
;
799 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
803 if (!Parse_String(parseState
, ","))
807 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
811 if (!Parse_String(parseState
, ";"))
819 Parse_BiOpInstruction(struct parse_state
*parseState
,
820 struct vp_instruction
*inst
, enum vp_opcode opcode
)
822 if (opcode
== VP_OPCODE_DPH
&& !parseState
->isVersion1_1
)
823 RETURN_ERROR1("DPH illegal for vertex program 1.0");
824 if (opcode
== VP_OPCODE_SUB
&& !parseState
->isVersion1_1
)
825 RETURN_ERROR1("SUB illegal for vertex program 1.0");
827 inst
->Opcode
= opcode
;
830 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
834 if (!Parse_String(parseState
, ","))
838 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
842 if (!Parse_String(parseState
, ","))
846 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
850 if (!Parse_String(parseState
, ";"))
853 /* make sure we don't reference more than one program parameter register */
854 if (IsProgRegister(inst
->SrcReg
[0].Register
) &&
855 IsProgRegister(inst
->SrcReg
[1].Register
) &&
856 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
)
857 RETURN_ERROR1("Can't reference two program parameter registers");
859 /* make sure we don't reference more than one vertex attribute register */
860 if (IsInputRegister(inst
->SrcReg
[0].Register
) &&
861 IsInputRegister(inst
->SrcReg
[1].Register
) &&
862 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
)
863 RETURN_ERROR1("Can't reference two vertex attribute registers");
870 Parse_TriOpInstruction(struct parse_state
*parseState
,
871 struct vp_instruction
*inst
, enum vp_opcode opcode
)
873 inst
->Opcode
= opcode
;
876 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
880 if (!Parse_String(parseState
, ","))
884 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
888 if (!Parse_String(parseState
, ","))
892 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
896 if (!Parse_String(parseState
, ","))
900 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[2]))
904 if (!Parse_String(parseState
, ";"))
907 /* make sure we don't reference more than one program parameter register */
908 if ((IsProgRegister(inst
->SrcReg
[0].Register
) &&
909 IsProgRegister(inst
->SrcReg
[1].Register
) &&
910 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
) ||
911 (IsProgRegister(inst
->SrcReg
[0].Register
) &&
912 IsProgRegister(inst
->SrcReg
[2].Register
) &&
913 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[2].Register
) ||
914 (IsProgRegister(inst
->SrcReg
[1].Register
) &&
915 IsProgRegister(inst
->SrcReg
[2].Register
) &&
916 inst
->SrcReg
[1].Register
!= inst
->SrcReg
[2].Register
))
917 RETURN_ERROR1("Can only reference one program register");
919 /* make sure we don't reference more than one vertex attribute register */
920 if ((IsInputRegister(inst
->SrcReg
[0].Register
) &&
921 IsInputRegister(inst
->SrcReg
[1].Register
) &&
922 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[1].Register
) ||
923 (IsInputRegister(inst
->SrcReg
[0].Register
) &&
924 IsInputRegister(inst
->SrcReg
[2].Register
) &&
925 inst
->SrcReg
[0].Register
!= inst
->SrcReg
[2].Register
) ||
926 (IsInputRegister(inst
->SrcReg
[1].Register
) &&
927 IsInputRegister(inst
->SrcReg
[2].Register
) &&
928 inst
->SrcReg
[1].Register
!= inst
->SrcReg
[2].Register
))
929 RETURN_ERROR1("Can only reference one input register");
936 Parse_ScalarInstruction(struct parse_state
*parseState
,
937 struct vp_instruction
*inst
, enum vp_opcode opcode
)
939 if (opcode
== VP_OPCODE_RCC
&& !parseState
->isVersion1_1
)
940 RETURN_ERROR1("RCC illegal for vertex program 1.0");
942 inst
->Opcode
= opcode
;
945 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
949 if (!Parse_String(parseState
, ","))
953 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
957 if (!Parse_String(parseState
, ";"))
965 Parse_AddressInstruction(struct parse_state
*parseState
, struct vp_instruction
*inst
)
967 inst
->Opcode
= VP_OPCODE_ARL
;
970 if (!Parse_AddrReg(parseState
))
974 if (!Parse_String(parseState
, ","))
978 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
982 if (!Parse_String(parseState
, ";"))
990 Parse_EndInstruction(struct parse_state
*parseState
, struct vp_instruction
*inst
)
994 inst
->Opcode
= VP_OPCODE_END
;
996 /* this should fail! */
997 if (Parse_Token(parseState
, token
))
998 RETURN_ERROR2("Unexpected token after END:", token
);
1005 Parse_OptionSequence(struct parse_state
*parseState
,
1006 struct vp_instruction program
[])
1009 if (!Parse_String(parseState
, "OPTION"))
1010 return GL_TRUE
; /* ok, not an OPTION statement */
1011 if (Parse_String(parseState
, "NV_position_invariant")) {
1012 parseState
->isPositionInvariant
= GL_TRUE
;
1015 RETURN_ERROR1("unexpected OPTION statement");
1017 if (!Parse_String(parseState
, ";"))
1024 Parse_InstructionSequence(struct parse_state
*parseState
,
1025 struct vp_instruction program
[])
1028 struct vp_instruction
*inst
= program
+ parseState
->numInst
;
1030 /* Initialize the instruction */
1031 inst
->SrcReg
[0].Register
= -1;
1032 inst
->SrcReg
[1].Register
= -1;
1033 inst
->SrcReg
[2].Register
= -1;
1034 inst
->DstReg
.Register
= -1;
1036 if (Parse_String(parseState
, "MOV")) {
1037 if (!Parse_UnaryOpInstruction(parseState
, inst
, VP_OPCODE_MOV
))
1040 else if (Parse_String(parseState
, "LIT")) {
1041 if (!Parse_UnaryOpInstruction(parseState
, inst
, VP_OPCODE_LIT
))
1044 else if (Parse_String(parseState
, "ABS")) {
1045 if (!Parse_UnaryOpInstruction(parseState
, inst
, VP_OPCODE_ABS
))
1048 else if (Parse_String(parseState
, "MUL")) {
1049 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_MUL
))
1052 else if (Parse_String(parseState
, "ADD")) {
1053 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_ADD
))
1056 else if (Parse_String(parseState
, "DP3")) {
1057 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DP3
))
1060 else if (Parse_String(parseState
, "DP4")) {
1061 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DP4
))
1064 else if (Parse_String(parseState
, "DST")) {
1065 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DST
))
1068 else if (Parse_String(parseState
, "MIN")) {
1069 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_MIN
))
1072 else if (Parse_String(parseState
, "MAX")) {
1073 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_MAX
))
1076 else if (Parse_String(parseState
, "SLT")) {
1077 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_SLT
))
1080 else if (Parse_String(parseState
, "SGE")) {
1081 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_SGE
))
1084 else if (Parse_String(parseState
, "DPH")) {
1085 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DPH
))
1088 else if (Parse_String(parseState
, "SUB")) {
1089 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_SUB
))
1092 else if (Parse_String(parseState
, "MAD")) {
1093 if (!Parse_TriOpInstruction(parseState
, inst
, VP_OPCODE_MAD
))
1096 else if (Parse_String(parseState
, "RCP")) {
1097 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_RCP
))
1100 else if (Parse_String(parseState
, "RSQ")) {
1101 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_RSQ
))
1104 else if (Parse_String(parseState
, "EXP")) {
1105 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_EXP
))
1108 else if (Parse_String(parseState
, "LOG")) {
1109 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_LOG
))
1112 else if (Parse_String(parseState
, "RCC")) {
1113 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_RCC
))
1116 else if (Parse_String(parseState
, "ARL")) {
1117 if (!Parse_AddressInstruction(parseState
, inst
))
1120 else if (Parse_String(parseState
, "END")) {
1121 if (!Parse_EndInstruction(parseState
, inst
))
1124 parseState
->numInst
++;
1125 return GL_TRUE
; /* all done */
1129 /* bad instruction name */
1130 RETURN_ERROR1("Unexpected token");
1133 /* examine input/output registers */
1135 const GLint srcReg0
= inst
->SrcReg
[0].Register
;
1136 const GLint srcReg1
= inst
->SrcReg
[1].Register
;
1137 const GLint srcReg2
= inst
->SrcReg
[2].Register
;
1138 const GLint dstReg
= inst
->DstReg
.Register
;
1140 if (IsOutputRegister(dstReg
))
1141 parseState
->outputsWritten
|= (1 << (dstReg
- VP_OUTPUT_REG_START
));
1142 else if (IsProgRegister(dstReg
))
1143 parseState
->progRegsWritten
|= (1 << (dstReg
- VP_PROG_REG_START
));
1145 if (IsInputRegister(srcReg0
) && !inst
->SrcReg
[0].RelAddr
)
1146 parseState
->inputsRead
|= (1 << (srcReg0
- VP_INPUT_REG_START
));
1148 if (IsInputRegister(srcReg1
) && !inst
->SrcReg
[1].RelAddr
)
1149 parseState
->inputsRead
|= (1 << (srcReg1
- VP_INPUT_REG_START
));
1151 if (IsInputRegister(srcReg2
) && !inst
->SrcReg
[2].RelAddr
)
1152 parseState
->inputsRead
|= (1 << (srcReg2
- VP_INPUT_REG_START
));
1155 parseState
->numInst
++;
1157 if (parseState
->numInst
>= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
)
1158 RETURN_ERROR1("Program too long");
1166 Parse_Program(struct parse_state
*parseState
,
1167 struct vp_instruction instBuffer
[])
1169 if (parseState
->isVersion1_1
) {
1170 if (!Parse_OptionSequence(parseState
, instBuffer
)) {
1174 return Parse_InstructionSequence(parseState
, instBuffer
);
1179 * Parse/compile the 'str' returning the compiled 'program'.
1180 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1181 * indicates the position of the error in 'str'.
1184 _mesa_parse_nv_vertex_program(GLcontext
*ctx
, GLenum dstTarget
,
1185 const GLubyte
*str
, GLsizei len
,
1186 struct vertex_program
*program
)
1188 struct parse_state parseState
;
1189 struct vp_instruction instBuffer
[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
];
1190 struct vp_instruction
*newInst
;
1192 GLubyte
*programString
;
1194 /* Make a null-terminated copy of the program string */
1195 programString
= (GLubyte
*) MALLOC(len
+ 1);
1196 if (!programString
) {
1197 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1200 MEMCPY(programString
, str
, len
);
1201 programString
[len
] = 0;
1203 /* Get ready to parse */
1204 parseState
.ctx
= ctx
;
1205 parseState
.start
= programString
;
1206 parseState
.isPositionInvariant
= GL_FALSE
;
1207 parseState
.isVersion1_1
= GL_FALSE
;
1208 parseState
.numInst
= 0;
1209 parseState
.inputsRead
= 0;
1210 parseState
.outputsWritten
= 0;
1211 parseState
.progRegsWritten
= 0;
1213 /* Reset error state */
1214 _mesa_set_program_error(ctx
, -1, NULL
);
1216 /* check the program header */
1217 if (_mesa_strncmp((const char *) programString
, "!!VP1.0", 7) == 0) {
1218 target
= GL_VERTEX_PROGRAM_NV
;
1219 parseState
.pos
= programString
+ 7;
1220 parseState
.isStateProgram
= GL_FALSE
;
1222 else if (_mesa_strncmp((const char *) programString
, "!!VP1.1", 7) == 0) {
1223 target
= GL_VERTEX_PROGRAM_NV
;
1224 parseState
.pos
= programString
+ 7;
1225 parseState
.isStateProgram
= GL_FALSE
;
1226 parseState
.isVersion1_1
= GL_TRUE
;
1228 else if (_mesa_strncmp((const char *) programString
, "!!VSP1.0", 8) == 0) {
1229 target
= GL_VERTEX_STATE_PROGRAM_NV
;
1230 parseState
.pos
= programString
+ 8;
1231 parseState
.isStateProgram
= GL_TRUE
;
1234 /* invalid header */
1235 ctx
->Program
.ErrorPos
= 0;
1236 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1240 /* make sure target and header match */
1241 if (target
!= dstTarget
) {
1242 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1243 "glLoadProgramNV(target mismatch)");
1248 if (Parse_Program(&parseState
, instBuffer
)) {
1249 /* successful parse! */
1251 if (parseState
.isStateProgram
) {
1252 if (parseState
.progRegsWritten
== 0) {
1253 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1254 "glLoadProgramNV(c[#] not written)");
1259 if (!parseState
.isPositionInvariant
&&
1260 !(parseState
.outputsWritten
& 1)) {
1261 /* bit 1 = HPOS register */
1262 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1263 "glLoadProgramNV(HPOS not written)");
1268 /* copy the compiled instructions */
1269 assert(parseState
.numInst
<= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
);
1270 newInst
= (struct vp_instruction
*)
1271 MALLOC(parseState
.numInst
* sizeof(struct vp_instruction
));
1273 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1274 FREE(programString
);
1275 return; /* out of memory */
1277 MEMCPY(newInst
, instBuffer
,
1278 parseState
.numInst
* sizeof(struct vp_instruction
));
1280 /* install the program */
1281 program
->Base
.Target
= target
;
1282 if (program
->Base
.String
) {
1283 FREE(program
->Base
.String
);
1285 program
->Base
.String
= programString
;
1286 if (program
->Instructions
) {
1287 FREE(program
->Instructions
);
1289 program
->Instructions
= newInst
;
1290 program
->InputsRead
= parseState
.inputsRead
;
1291 program
->OutputsWritten
= parseState
.outputsWritten
;
1292 program
->IsPositionInvariant
= parseState
.isPositionInvariant
;
1295 _mesa_printf("--- glLoadProgramNV result ---\n");
1296 _mesa_print_nv_vertex_program(program
);
1297 _mesa_printf("------------------------------\n");
1302 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1303 /* NOTE: _mesa_set_program_error would have been called already */
1304 /* GL_NV_vertex_program isn't supposed to set the error string
1305 * so we reset it here.
1307 _mesa_set_program_error(ctx
, ctx
->Program
.ErrorPos
, NULL
);
1313 PrintSrcReg(const struct vp_src_register
*src
)
1315 static const char comps
[5] = "xyzw";
1319 if (src
->Register
> 0)
1320 _mesa_printf("c[A0.x + %d]", src
->Register
);
1321 else if (src
->Register
< 0)
1322 _mesa_printf("c[A0.x - %d]", -src
->Register
);
1324 _mesa_printf("c[A0.x]");
1326 else if (src
->Register
>= VP_OUTPUT_REG_START
1327 && src
->Register
<= VP_OUTPUT_REG_END
) {
1328 _mesa_printf("o[%s]", OutputRegisters
[src
->Register
- VP_OUTPUT_REG_START
]);
1330 else if (src
->Register
>= VP_INPUT_REG_START
1331 && src
->Register
<= VP_INPUT_REG_END
) {
1332 _mesa_printf("v[%s]", InputRegisters
[src
->Register
- VP_INPUT_REG_START
]);
1334 else if (src
->Register
>= VP_PROG_REG_START
1335 && src
->Register
<= VP_PROG_REG_END
) {
1336 _mesa_printf("c[%d]", src
->Register
- VP_PROG_REG_START
);
1339 _mesa_printf("R%d", src
->Register
- VP_TEMP_REG_START
);
1342 if (src
->Swizzle
[0] == src
->Swizzle
[1] &&
1343 src
->Swizzle
[0] == src
->Swizzle
[2] &&
1344 src
->Swizzle
[0] == src
->Swizzle
[3]) {
1345 _mesa_printf(".%c", comps
[src
->Swizzle
[0]]);
1347 else if (src
->Swizzle
[0] != 0 ||
1348 src
->Swizzle
[1] != 1 ||
1349 src
->Swizzle
[2] != 2 ||
1350 src
->Swizzle
[3] != 3) {
1351 _mesa_printf(".%c%c%c%c",
1352 comps
[src
->Swizzle
[0]],
1353 comps
[src
->Swizzle
[1]],
1354 comps
[src
->Swizzle
[2]],
1355 comps
[src
->Swizzle
[3]]);
1361 PrintDstReg(const struct vp_dst_register
*dst
)
1363 GLint w
= dst
->WriteMask
[0] + dst
->WriteMask
[1]
1364 + dst
->WriteMask
[2] + dst
->WriteMask
[3];
1366 if (dst
->Register
>= VP_OUTPUT_REG_START
1367 && dst
->Register
<= VP_OUTPUT_REG_END
) {
1368 _mesa_printf("o[%s]", OutputRegisters
[dst
->Register
- VP_OUTPUT_REG_START
]);
1370 else if (dst
->Register
>= VP_INPUT_REG_START
1371 && dst
->Register
<= VP_INPUT_REG_END
) {
1372 _mesa_printf("v[%s]", InputRegisters
[dst
->Register
- VP_INPUT_REG_START
]);
1374 else if (dst
->Register
>= VP_PROG_REG_START
1375 && dst
->Register
<= VP_PROG_REG_END
) {
1376 _mesa_printf("c[%d]", dst
->Register
- VP_PROG_REG_START
);
1379 _mesa_printf("R%d", dst
->Register
- VP_TEMP_REG_START
);
1382 if (w
!= 0 && w
!= 4) {
1384 if (dst
->WriteMask
[0])
1386 if (dst
->WriteMask
[1])
1388 if (dst
->WriteMask
[2])
1390 if (dst
->WriteMask
[3])
1397 * Print (unparse) the given vertex program. Just for debugging.
1400 _mesa_print_nv_vertex_program(const struct vertex_program
*program
)
1402 const struct vp_instruction
*inst
;
1404 for (inst
= program
->Instructions
; ; inst
++) {
1405 switch (inst
->Opcode
) {
1414 _mesa_printf("%s ", Opcodes
[(int) inst
->Opcode
]);
1415 PrintDstReg(&inst
->DstReg
);
1417 PrintSrcReg(&inst
->SrcReg
[0]);
1418 _mesa_printf(";\n");
1431 _mesa_printf("%s ", Opcodes
[(int) inst
->Opcode
]);
1432 PrintDstReg(&inst
->DstReg
);
1434 PrintSrcReg(&inst
->SrcReg
[0]);
1436 PrintSrcReg(&inst
->SrcReg
[1]);
1437 _mesa_printf(";\n");
1440 _mesa_printf("MAD ");
1441 PrintDstReg(&inst
->DstReg
);
1443 PrintSrcReg(&inst
->SrcReg
[0]);
1445 PrintSrcReg(&inst
->SrcReg
[1]);
1447 PrintSrcReg(&inst
->SrcReg
[2]);
1448 _mesa_printf(";\n");
1451 _mesa_printf("ARL A0.x, ");
1452 PrintSrcReg(&inst
->SrcReg
[0]);
1453 _mesa_printf(";\n");
1456 _mesa_printf("END\n");
1459 _mesa_printf("BAD INSTRUCTION\n");