2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * NVIDIA vertex program parser.
32 * Regarding GL_NV_vertex_program, GL_NV_vertex_program1_1:
34 * Portions of this software may use or implement intellectual
35 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
36 * any and all warranties with respect to such intellectual property,
37 * including any use thereof or modifications thereto.
46 #include "nvprogram.h"
47 #include "nvvertparse.h"
48 #include "nvvertprog.h"
53 * Current parsing state. This structure is passed among the parsing
54 * functions and keeps track of the current parser position and various
61 const GLubyte
*curLine
;
62 GLboolean isStateProgram
;
63 GLboolean isPositionInvariant
;
64 GLboolean isVersion1_1
;
66 GLuint outputsWritten
;
67 GLboolean anyProgRegsWritten
;
68 GLuint numInst
; /* number of instructions parsed */
73 * Called whenever we find an error during parsing.
76 record_error(struct parse_state
*parseState
, const char *msg
, int lineNo
)
80 const GLubyte
*lineStr
;
81 lineStr
= _mesa_find_line_column(parseState
->start
,
82 parseState
->pos
, &line
, &column
);
83 _mesa_debug(parseState
->ctx
,
84 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
85 lineNo
, line
, column
, (char *) lineStr
, msg
);
86 _mesa_free((void *) lineStr
);
91 /* Check that no error was already recorded. Only record the first one. */
92 if (parseState
->ctx
->Program
.ErrorString
[0] == 0) {
93 _mesa_set_program_error(parseState
->ctx
,
94 parseState
->pos
- parseState
->start
,
100 #define RETURN_ERROR \
102 record_error(parseState, "Unexpected end of input.", __LINE__); \
106 #define RETURN_ERROR1(msg) \
108 record_error(parseState, msg, __LINE__); \
112 #define RETURN_ERROR2(msg1, msg2) \
115 _mesa_sprintf(err, "%s %s", msg1, msg2); \
116 record_error(parseState, err, __LINE__); \
124 static GLboolean
IsLetter(GLubyte b
)
126 return (b
>= 'a' && b
<= 'z') || (b
>= 'A' && b
<= 'Z');
130 static GLboolean
IsDigit(GLubyte b
)
132 return b
>= '0' && b
<= '9';
136 static GLboolean
IsWhitespace(GLubyte b
)
138 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
143 * Starting at 'str' find the next token. A token can be an integer,
144 * an identifier or punctuation symbol.
145 * \return <= 0 we found an error, else, return number of characters parsed.
148 GetToken(struct parse_state
*parseState
, GLubyte
*token
)
150 const GLubyte
*str
= parseState
->pos
;
155 /* skip whitespace and comments */
156 while (str
[i
] && (IsWhitespace(str
[i
]) || str
[i
] == '#')) {
159 while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
162 if (str
[i
] == '\n' || str
[i
] == '\r')
163 parseState
->curLine
= str
+ i
+ 1;
166 /* skip whitespace */
167 if (str
[i
] == '\n' || str
[i
] == '\r')
168 parseState
->curLine
= str
+ i
+ 1;
176 /* try matching an integer */
177 while (str
[i
] && IsDigit(str
[i
])) {
178 token
[j
++] = str
[i
++];
180 if (j
> 0 || !str
[i
]) {
185 /* try matching an identifier */
186 if (IsLetter(str
[i
])) {
187 while (str
[i
] && (IsLetter(str
[i
]) || IsDigit(str
[i
]))) {
188 token
[j
++] = str
[i
++];
194 /* punctuation character */
208 * Get next token from input stream and increment stream pointer past token.
211 Parse_Token(struct parse_state
*parseState
, GLubyte
*token
)
214 i
= GetToken(parseState
, token
);
216 parseState
->pos
+= (-i
);
219 parseState
->pos
+= i
;
225 * Get next token from input stream but don't increment stream pointer.
228 Peek_Token(struct parse_state
*parseState
, GLubyte
*token
)
231 i
= GetToken(parseState
, token
);
233 parseState
->pos
+= (-i
);
236 len
= _mesa_strlen((const char *) token
);
237 parseState
->pos
+= (i
- len
);
243 * Try to match 'pattern' as the next token after any whitespace/comments.
244 * Advance the current parsing position only if we match the pattern.
245 * \return GL_TRUE if pattern is matched, GL_FALSE otherwise.
248 Parse_String(struct parse_state
*parseState
, const char *pattern
)
253 /* skip whitespace and comments */
254 while (IsWhitespace(*parseState
->pos
) || *parseState
->pos
== '#') {
255 if (*parseState
->pos
== '#') {
256 while (*parseState
->pos
&& (*parseState
->pos
!= '\n' && *parseState
->pos
!= '\r')) {
257 parseState
->pos
+= 1;
259 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
260 parseState
->curLine
= parseState
->pos
+ 1;
263 /* skip whitespace */
264 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
265 parseState
->curLine
= parseState
->pos
+ 1;
266 parseState
->pos
+= 1;
270 /* Try to match the pattern */
272 for (i
= 0; pattern
[i
]; i
++) {
273 if (*m
!= (GLubyte
) pattern
[i
])
279 return GL_TRUE
; /* success */
283 /**********************************************************************/
285 static const char *InputRegisters
[MAX_NV_VERTEX_PROGRAM_INPUTS
+ 1] = {
286 "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
287 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
290 static const char *OutputRegisters
[MAX_NV_VERTEX_PROGRAM_OUTPUTS
+ 1] = {
291 "HPOS", "COL0", "COL1", "BFC0", "BFC1", "FOGC", "PSIZ",
292 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
295 /* NOTE: the order here must match opcodes in nvvertprog.h */
296 static const char *Opcodes
[] = {
297 "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
298 "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
300 /* GL_ARB_vertex_program */
301 "FLR", "FRC", "EX2", "LG2", "POW", "XPD", "SWZ",
308 * Parse a temporary register: Rnn
311 Parse_TempReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
315 /* Should be 'R##' */
316 if (!Parse_Token(parseState
, token
))
319 RETURN_ERROR1("Expected R##");
321 if (IsDigit(token
[1])) {
322 GLint reg
= _mesa_atoi((char *) (token
+ 1));
323 if (reg
>= MAX_NV_VERTEX_PROGRAM_TEMPS
)
324 RETURN_ERROR1("Bad temporary register name");
328 RETURN_ERROR1("Bad temporary register name");
336 * Parse address register "A0.x"
339 Parse_AddrReg(struct parse_state
*parseState
)
342 if (!Parse_String(parseState
, "A0"))
346 if (!Parse_String(parseState
, "."))
350 if (!Parse_String(parseState
, "x"))
358 * Parse absolute program parameter register "c[##]"
361 Parse_AbsParamReg(struct parse_state
*parseState
, GLint
*regNum
)
365 if (!Parse_String(parseState
, "c"))
368 if (!Parse_String(parseState
, "["))
371 if (!Parse_Token(parseState
, token
))
374 if (IsDigit(token
[0])) {
375 /* a numbered program parameter register */
376 GLint reg
= _mesa_atoi((char *) token
);
377 if (reg
>= MAX_NV_VERTEX_PROGRAM_PARAMS
)
378 RETURN_ERROR1("Bad program parameter number");
385 if (!Parse_String(parseState
, "]"))
393 Parse_ParamReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
397 if (!Parse_String(parseState
, "c"))
400 if (!Parse_String(parseState
, "["))
403 if (!Peek_Token(parseState
, token
))
406 if (IsDigit(token
[0])) {
407 /* a numbered program parameter register */
409 (void) Parse_Token(parseState
, token
);
410 reg
= _mesa_atoi((char *) token
);
411 if (reg
>= MAX_NV_VERTEX_PROGRAM_PARAMS
)
412 RETURN_ERROR1("Bad program parameter number");
413 srcReg
->File
= PROGRAM_ENV_PARAM
;
416 else if (_mesa_strcmp((const char *) token
, "A0") == 0) {
417 /* address register "A0.x" */
418 if (!Parse_AddrReg(parseState
))
421 srcReg
->RelAddr
= GL_TRUE
;
422 srcReg
->File
= PROGRAM_ENV_PARAM
;
423 /* Look for +/-N offset */
424 if (!Peek_Token(parseState
, token
))
427 if (token
[0] == '-' || token
[0] == '+') {
428 const GLubyte sign
= token
[0];
429 (void) Parse_Token(parseState
, token
); /* consume +/- */
431 /* an integer should be next */
432 if (!Parse_Token(parseState
, token
))
435 if (IsDigit(token
[0])) {
436 const GLint k
= _mesa_atoi((char *) token
);
439 RETURN_ERROR1("Bad address offset");
444 RETURN_ERROR1("Bad address offset");
453 /* probably got a ']', catch it below */
460 /* Match closing ']' */
461 if (!Parse_String(parseState
, "]"))
469 * Parse v[#] or v[<name>]
472 Parse_AttribReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
478 if (!Parse_String(parseState
, "v"))
482 if (!Parse_String(parseState
, "["))
485 /* match number or named register */
486 if (!Parse_Token(parseState
, token
))
489 if (parseState
->isStateProgram
&& token
[0] != '0')
490 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
492 if (IsDigit(token
[0])) {
493 GLint reg
= _mesa_atoi((char *) token
);
494 if (reg
>= MAX_NV_VERTEX_PROGRAM_INPUTS
)
495 RETURN_ERROR1("Bad vertex attribute register name");
499 for (j
= 0; InputRegisters
[j
]; j
++) {
500 if (_mesa_strcmp((const char *) token
, InputRegisters
[j
]) == 0) {
505 if (!InputRegisters
[j
]) {
506 /* unknown input register label */
507 RETURN_ERROR2("Bad register name", token
);
512 if (!Parse_String(parseState
, "]"))
520 Parse_OutputReg(struct parse_state
*parseState
, GLint
*outputRegNum
)
526 if (!Parse_String(parseState
, "o"))
530 if (!Parse_String(parseState
, "["))
533 /* Get output reg name */
534 if (!Parse_Token(parseState
, token
))
537 if (parseState
->isPositionInvariant
)
538 start
= 1; /* skip HPOS register name */
542 /* try to match an output register name */
543 for (j
= start
; OutputRegisters
[j
]; j
++) {
544 if (_mesa_strcmp((const char *) token
, OutputRegisters
[j
]) == 0) {
549 if (!OutputRegisters
[j
])
550 RETURN_ERROR1("Unrecognized output register name");
553 if (!Parse_String(parseState
, "]"))
554 RETURN_ERROR1("Expected ]");
561 Parse_MaskedDstReg(struct parse_state
*parseState
, struct vp_dst_register
*dstReg
)
565 /* Dst reg can be R<n> or o[n] */
566 if (!Peek_Token(parseState
, token
))
569 if (token
[0] == 'R') {
570 /* a temporary register */
571 dstReg
->File
= PROGRAM_TEMPORARY
;
572 if (!Parse_TempReg(parseState
, &dstReg
->Index
))
575 else if (!parseState
->isStateProgram
&& token
[0] == 'o') {
576 /* an output register */
577 dstReg
->File
= PROGRAM_OUTPUT
;
578 if (!Parse_OutputReg(parseState
, &dstReg
->Index
))
581 else if (parseState
->isStateProgram
&& token
[0] == 'c' &&
582 parseState
->isStateProgram
) {
583 /* absolute program parameter register */
584 /* Only valid for vertex state programs */
585 dstReg
->File
= PROGRAM_ENV_PARAM
;
586 if (!Parse_AbsParamReg(parseState
, &dstReg
->Index
))
590 RETURN_ERROR1("Bad destination register name");
593 /* Parse optional write mask */
594 if (!Peek_Token(parseState
, token
))
597 if (token
[0] == '.') {
601 if (!Parse_String(parseState
, "."))
604 if (!Parse_Token(parseState
, token
))
607 dstReg
->WriteMask
[0] = GL_FALSE
;
608 dstReg
->WriteMask
[1] = GL_FALSE
;
609 dstReg
->WriteMask
[2] = GL_FALSE
;
610 dstReg
->WriteMask
[3] = GL_FALSE
;
612 if (token
[k
] == 'x') {
613 dstReg
->WriteMask
[0] = GL_TRUE
;
616 if (token
[k
] == 'y') {
617 dstReg
->WriteMask
[1] = GL_TRUE
;
620 if (token
[k
] == 'z') {
621 dstReg
->WriteMask
[2] = GL_TRUE
;
624 if (token
[k
] == 'w') {
625 dstReg
->WriteMask
[3] = GL_TRUE
;
629 RETURN_ERROR1("Bad writemask character");
634 dstReg
->WriteMask
[0] = GL_TRUE
;
635 dstReg
->WriteMask
[1] = GL_TRUE
;
636 dstReg
->WriteMask
[2] = GL_TRUE
;
637 dstReg
->WriteMask
[3] = GL_TRUE
;
644 Parse_SwizzleSrcReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
648 srcReg
->RelAddr
= GL_FALSE
;
651 if (!Peek_Token(parseState
, token
))
653 if (token
[0] == '-') {
654 (void) Parse_String(parseState
, "-");
655 srcReg
->Negate
= GL_TRUE
;
656 if (!Peek_Token(parseState
, token
))
660 srcReg
->Negate
= GL_FALSE
;
663 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
664 if (token
[0] == 'R') {
665 srcReg
->File
= PROGRAM_TEMPORARY
;
666 if (!Parse_TempReg(parseState
, &srcReg
->Index
))
669 else if (token
[0] == 'c') {
670 if (!Parse_ParamReg(parseState
, srcReg
))
673 else if (token
[0] == 'v') {
674 srcReg
->File
= PROGRAM_INPUT
;
675 if (!Parse_AttribReg(parseState
, &srcReg
->Index
))
679 RETURN_ERROR2("Bad source register name", token
);
682 /* init swizzle fields */
683 srcReg
->Swizzle
[0] = 0;
684 srcReg
->Swizzle
[1] = 1;
685 srcReg
->Swizzle
[2] = 2;
686 srcReg
->Swizzle
[3] = 3;
688 /* Look for optional swizzle suffix */
689 if (!Peek_Token(parseState
, token
))
691 if (token
[0] == '.') {
692 (void) Parse_String(parseState
, "."); /* consume . */
694 if (!Parse_Token(parseState
, token
))
698 /* single letter swizzle */
700 ASSIGN_4V(srcReg
->Swizzle
, 0, 0, 0, 0);
701 else if (token
[0] == 'y')
702 ASSIGN_4V(srcReg
->Swizzle
, 1, 1, 1, 1);
703 else if (token
[0] == 'z')
704 ASSIGN_4V(srcReg
->Swizzle
, 2, 2, 2, 2);
705 else if (token
[0] == 'w')
706 ASSIGN_4V(srcReg
->Swizzle
, 3, 3, 3, 3);
708 RETURN_ERROR1("Expected x, y, z, or w");
711 /* 2, 3 or 4-component swizzle */
713 for (k
= 0; token
[k
] && k
< 5; k
++) {
715 srcReg
->Swizzle
[k
] = 0;
716 else if (token
[k
] == 'y')
717 srcReg
->Swizzle
[k
] = 1;
718 else if (token
[k
] == 'z')
719 srcReg
->Swizzle
[k
] = 2;
720 else if (token
[k
] == 'w')
721 srcReg
->Swizzle
[k
] = 3;
735 Parse_ScalarSrcReg(struct parse_state
*parseState
, struct vp_src_register
*srcReg
)
739 srcReg
->RelAddr
= GL_FALSE
;
742 if (!Peek_Token(parseState
, token
))
744 if (token
[0] == '-') {
745 srcReg
->Negate
= GL_TRUE
;
746 (void) Parse_String(parseState
, "-"); /* consume '-' */
747 if (!Peek_Token(parseState
, token
))
751 srcReg
->Negate
= GL_FALSE
;
754 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
755 if (token
[0] == 'R') {
756 srcReg
->File
= PROGRAM_TEMPORARY
;
757 if (!Parse_TempReg(parseState
, &srcReg
->Index
))
760 else if (token
[0] == 'c') {
761 if (!Parse_ParamReg(parseState
, srcReg
))
764 else if (token
[0] == 'v') {
765 srcReg
->File
= PROGRAM_INPUT
;
766 if (!Parse_AttribReg(parseState
, &srcReg
->Index
))
770 RETURN_ERROR2("Bad source register name", token
);
773 /* Look for .[xyzw] suffix */
774 if (!Parse_String(parseState
, "."))
777 if (!Parse_Token(parseState
, token
))
780 if (token
[0] == 'x' && token
[1] == 0) {
781 srcReg
->Swizzle
[0] = 0;
783 else if (token
[0] == 'y' && token
[1] == 0) {
784 srcReg
->Swizzle
[0] = 1;
786 else if (token
[0] == 'z' && token
[1] == 0) {
787 srcReg
->Swizzle
[0] = 2;
789 else if (token
[0] == 'w' && token
[1] == 0) {
790 srcReg
->Swizzle
[0] = 3;
793 RETURN_ERROR1("Bad scalar source suffix");
795 srcReg
->Swizzle
[1] = srcReg
->Swizzle
[2] = srcReg
->Swizzle
[3] = 0;
802 Parse_UnaryOpInstruction(struct parse_state
*parseState
,
803 struct vp_instruction
*inst
, enum vp_opcode opcode
)
805 if (opcode
== VP_OPCODE_ABS
&& !parseState
->isVersion1_1
)
806 RETURN_ERROR1("ABS illegal for vertex program 1.0");
808 inst
->Opcode
= opcode
;
809 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
812 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
816 if (!Parse_String(parseState
, ","))
820 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
824 if (!Parse_String(parseState
, ";"))
832 Parse_BiOpInstruction(struct parse_state
*parseState
,
833 struct vp_instruction
*inst
, enum vp_opcode opcode
)
835 if (opcode
== VP_OPCODE_DPH
&& !parseState
->isVersion1_1
)
836 RETURN_ERROR1("DPH illegal for vertex program 1.0");
837 if (opcode
== VP_OPCODE_SUB
&& !parseState
->isVersion1_1
)
838 RETURN_ERROR1("SUB illegal for vertex program 1.0");
840 inst
->Opcode
= opcode
;
841 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
844 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
848 if (!Parse_String(parseState
, ","))
852 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
856 if (!Parse_String(parseState
, ","))
860 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
864 if (!Parse_String(parseState
, ";"))
867 /* make sure we don't reference more than one program parameter register */
868 if (inst
->SrcReg
[0].File
== PROGRAM_ENV_PARAM
&&
869 inst
->SrcReg
[1].File
== PROGRAM_ENV_PARAM
&&
870 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
)
871 RETURN_ERROR1("Can't reference two program parameter registers");
873 /* make sure we don't reference more than one vertex attribute register */
874 if (inst
->SrcReg
[0].File
== PROGRAM_INPUT
&&
875 inst
->SrcReg
[1].File
== PROGRAM_INPUT
&&
876 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
)
877 RETURN_ERROR1("Can't reference two vertex attribute registers");
884 Parse_TriOpInstruction(struct parse_state
*parseState
,
885 struct vp_instruction
*inst
, enum vp_opcode opcode
)
887 inst
->Opcode
= opcode
;
888 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
891 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
895 if (!Parse_String(parseState
, ","))
899 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
903 if (!Parse_String(parseState
, ","))
907 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
911 if (!Parse_String(parseState
, ","))
915 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[2]))
919 if (!Parse_String(parseState
, ";"))
922 /* make sure we don't reference more than one program parameter register */
923 if ((inst
->SrcReg
[0].File
== PROGRAM_ENV_PARAM
&&
924 inst
->SrcReg
[1].File
== PROGRAM_ENV_PARAM
&&
925 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
) ||
926 (inst
->SrcReg
[0].File
== PROGRAM_ENV_PARAM
&&
927 inst
->SrcReg
[2].File
== PROGRAM_ENV_PARAM
&&
928 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[2].Index
) ||
929 (inst
->SrcReg
[1].File
== PROGRAM_ENV_PARAM
&&
930 inst
->SrcReg
[2].File
== PROGRAM_ENV_PARAM
&&
931 inst
->SrcReg
[1].Index
!= inst
->SrcReg
[2].Index
))
932 RETURN_ERROR1("Can only reference one program register");
934 /* make sure we don't reference more than one vertex attribute register */
935 if ((inst
->SrcReg
[0].File
== PROGRAM_INPUT
&&
936 inst
->SrcReg
[1].File
== PROGRAM_INPUT
&&
937 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
) ||
938 (inst
->SrcReg
[0].File
== PROGRAM_INPUT
&&
939 inst
->SrcReg
[2].File
== PROGRAM_INPUT
&&
940 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[2].Index
) ||
941 (inst
->SrcReg
[1].File
== PROGRAM_INPUT
&&
942 inst
->SrcReg
[2].File
== PROGRAM_INPUT
&&
943 inst
->SrcReg
[1].Index
!= inst
->SrcReg
[2].Index
))
944 RETURN_ERROR1("Can only reference one input register");
951 Parse_ScalarInstruction(struct parse_state
*parseState
,
952 struct vp_instruction
*inst
, enum vp_opcode opcode
)
954 if (opcode
== VP_OPCODE_RCC
&& !parseState
->isVersion1_1
)
955 RETURN_ERROR1("RCC illegal for vertex program 1.0");
957 inst
->Opcode
= opcode
;
958 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
961 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
965 if (!Parse_String(parseState
, ","))
969 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
973 if (!Parse_String(parseState
, ";"))
981 Parse_AddressInstruction(struct parse_state
*parseState
, struct vp_instruction
*inst
)
983 inst
->Opcode
= VP_OPCODE_ARL
;
984 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
987 if (!Parse_AddrReg(parseState
))
991 if (!Parse_String(parseState
, ","))
995 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
999 if (!Parse_String(parseState
, ";"))
1007 Parse_EndInstruction(struct parse_state
*parseState
, struct vp_instruction
*inst
)
1011 inst
->Opcode
= VP_OPCODE_END
;
1012 inst
->StringPos
= parseState
->curLine
- parseState
->start
;
1014 /* this should fail! */
1015 if (Parse_Token(parseState
, token
))
1016 RETURN_ERROR2("Unexpected token after END:", token
);
1023 Parse_OptionSequence(struct parse_state
*parseState
,
1024 struct vp_instruction program
[])
1028 if (!Parse_String(parseState
, "OPTION"))
1029 return GL_TRUE
; /* ok, not an OPTION statement */
1030 if (Parse_String(parseState
, "NV_position_invariant")) {
1031 parseState
->isPositionInvariant
= GL_TRUE
;
1034 RETURN_ERROR1("unexpected OPTION statement");
1036 if (!Parse_String(parseState
, ";"))
1043 Parse_InstructionSequence(struct parse_state
*parseState
,
1044 struct vp_instruction program
[])
1047 struct vp_instruction
*inst
= program
+ parseState
->numInst
;
1049 /* Initialize the instruction */
1050 inst
->SrcReg
[0].File
= (enum register_file
) -1;
1051 inst
->SrcReg
[1].File
= (enum register_file
) -1;
1052 inst
->SrcReg
[2].File
= (enum register_file
) -1;
1053 inst
->DstReg
.File
= (enum register_file
) -1;
1055 if (Parse_String(parseState
, "MOV")) {
1056 if (!Parse_UnaryOpInstruction(parseState
, inst
, VP_OPCODE_MOV
))
1059 else if (Parse_String(parseState
, "LIT")) {
1060 if (!Parse_UnaryOpInstruction(parseState
, inst
, VP_OPCODE_LIT
))
1063 else if (Parse_String(parseState
, "ABS")) {
1064 if (!Parse_UnaryOpInstruction(parseState
, inst
, VP_OPCODE_ABS
))
1067 else if (Parse_String(parseState
, "MUL")) {
1068 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_MUL
))
1071 else if (Parse_String(parseState
, "ADD")) {
1072 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_ADD
))
1075 else if (Parse_String(parseState
, "DP3")) {
1076 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DP3
))
1079 else if (Parse_String(parseState
, "DP4")) {
1080 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DP4
))
1083 else if (Parse_String(parseState
, "DST")) {
1084 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DST
))
1087 else if (Parse_String(parseState
, "MIN")) {
1088 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_MIN
))
1091 else if (Parse_String(parseState
, "MAX")) {
1092 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_MAX
))
1095 else if (Parse_String(parseState
, "SLT")) {
1096 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_SLT
))
1099 else if (Parse_String(parseState
, "SGE")) {
1100 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_SGE
))
1103 else if (Parse_String(parseState
, "DPH")) {
1104 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_DPH
))
1107 else if (Parse_String(parseState
, "SUB")) {
1108 if (!Parse_BiOpInstruction(parseState
, inst
, VP_OPCODE_SUB
))
1111 else if (Parse_String(parseState
, "MAD")) {
1112 if (!Parse_TriOpInstruction(parseState
, inst
, VP_OPCODE_MAD
))
1115 else if (Parse_String(parseState
, "RCP")) {
1116 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_RCP
))
1119 else if (Parse_String(parseState
, "RSQ")) {
1120 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_RSQ
))
1123 else if (Parse_String(parseState
, "EXP")) {
1124 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_EXP
))
1127 else if (Parse_String(parseState
, "LOG")) {
1128 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_LOG
))
1131 else if (Parse_String(parseState
, "RCC")) {
1132 if (!Parse_ScalarInstruction(parseState
, inst
, VP_OPCODE_RCC
))
1135 else if (Parse_String(parseState
, "ARL")) {
1136 if (!Parse_AddressInstruction(parseState
, inst
))
1139 else if (Parse_String(parseState
, "END")) {
1140 if (!Parse_EndInstruction(parseState
, inst
))
1143 parseState
->numInst
++;
1144 return GL_TRUE
; /* all done */
1148 /* bad instruction name */
1149 RETURN_ERROR1("Unexpected token");
1152 /* examine input/output registers */
1153 if (inst
->DstReg
.File
== PROGRAM_OUTPUT
)
1154 parseState
->outputsWritten
|= (1 << inst
->DstReg
.Index
);
1155 else if (inst
->DstReg
.File
== PROGRAM_ENV_PARAM
)
1156 parseState
->anyProgRegsWritten
= GL_TRUE
;
1158 if (inst
->SrcReg
[0].File
== PROGRAM_INPUT
)
1159 parseState
->inputsRead
|= (1 << inst
->SrcReg
[0].Index
);
1160 if (inst
->SrcReg
[1].File
== PROGRAM_INPUT
)
1161 parseState
->inputsRead
|= (1 << inst
->SrcReg
[1].Index
);
1162 if (inst
->SrcReg
[2].File
== PROGRAM_INPUT
)
1163 parseState
->inputsRead
|= (1 << inst
->SrcReg
[2].Index
);
1165 parseState
->numInst
++;
1167 if (parseState
->numInst
>= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
)
1168 RETURN_ERROR1("Program too long");
1176 Parse_Program(struct parse_state
*parseState
,
1177 struct vp_instruction instBuffer
[])
1179 if (parseState
->isVersion1_1
) {
1180 if (!Parse_OptionSequence(parseState
, instBuffer
)) {
1184 return Parse_InstructionSequence(parseState
, instBuffer
);
1189 * Parse/compile the 'str' returning the compiled 'program'.
1190 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1191 * indicates the position of the error in 'str'.
1194 _mesa_parse_nv_vertex_program(GLcontext
*ctx
, GLenum dstTarget
,
1195 const GLubyte
*str
, GLsizei len
,
1196 struct vertex_program
*program
)
1198 struct parse_state parseState
;
1199 struct vp_instruction instBuffer
[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
];
1200 struct vp_instruction
*newInst
;
1202 GLubyte
*programString
;
1204 /* Make a null-terminated copy of the program string */
1205 programString
= (GLubyte
*) MALLOC(len
+ 1);
1206 if (!programString
) {
1207 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1210 MEMCPY(programString
, str
, len
);
1211 programString
[len
] = 0;
1213 /* Get ready to parse */
1214 parseState
.ctx
= ctx
;
1215 parseState
.start
= programString
;
1216 parseState
.isPositionInvariant
= GL_FALSE
;
1217 parseState
.isVersion1_1
= GL_FALSE
;
1218 parseState
.numInst
= 0;
1219 parseState
.inputsRead
= 0;
1220 parseState
.outputsWritten
= 0;
1221 parseState
.anyProgRegsWritten
= GL_FALSE
;
1223 /* Reset error state */
1224 _mesa_set_program_error(ctx
, -1, NULL
);
1226 /* check the program header */
1227 if (_mesa_strncmp((const char *) programString
, "!!VP1.0", 7) == 0) {
1228 target
= GL_VERTEX_PROGRAM_NV
;
1229 parseState
.pos
= programString
+ 7;
1230 parseState
.isStateProgram
= GL_FALSE
;
1232 else if (_mesa_strncmp((const char *) programString
, "!!VP1.1", 7) == 0) {
1233 target
= GL_VERTEX_PROGRAM_NV
;
1234 parseState
.pos
= programString
+ 7;
1235 parseState
.isStateProgram
= GL_FALSE
;
1236 parseState
.isVersion1_1
= GL_TRUE
;
1238 else if (_mesa_strncmp((const char *) programString
, "!!VSP1.0", 8) == 0) {
1239 target
= GL_VERTEX_STATE_PROGRAM_NV
;
1240 parseState
.pos
= programString
+ 8;
1241 parseState
.isStateProgram
= GL_TRUE
;
1244 /* invalid header */
1245 ctx
->Program
.ErrorPos
= 0;
1246 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1250 /* make sure target and header match */
1251 if (target
!= dstTarget
) {
1252 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1253 "glLoadProgramNV(target mismatch)");
1258 if (Parse_Program(&parseState
, instBuffer
)) {
1259 /* successful parse! */
1261 if (parseState
.isStateProgram
) {
1262 if (!parseState
.anyProgRegsWritten
) {
1263 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1264 "glLoadProgramNV(c[#] not written)");
1269 if (!parseState
.isPositionInvariant
&&
1270 !(parseState
.outputsWritten
& 1)) {
1271 /* bit 1 = HPOS register */
1272 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1273 "glLoadProgramNV(HPOS not written)");
1278 /* copy the compiled instructions */
1279 assert(parseState
.numInst
<= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
);
1280 newInst
= (struct vp_instruction
*)
1281 MALLOC(parseState
.numInst
* sizeof(struct vp_instruction
));
1283 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1284 FREE(programString
);
1285 return; /* out of memory */
1287 MEMCPY(newInst
, instBuffer
,
1288 parseState
.numInst
* sizeof(struct vp_instruction
));
1290 /* install the program */
1291 program
->Base
.Target
= target
;
1292 if (program
->Base
.String
) {
1293 FREE(program
->Base
.String
);
1295 program
->Base
.String
= programString
;
1296 program
->Base
.Format
= GL_PROGRAM_FORMAT_ASCII_ARB
;
1297 if (program
->Instructions
) {
1298 FREE(program
->Instructions
);
1300 program
->Instructions
= newInst
;
1301 program
->InputsRead
= parseState
.inputsRead
;
1302 program
->OutputsWritten
= parseState
.outputsWritten
;
1303 program
->IsPositionInvariant
= parseState
.isPositionInvariant
;
1304 program
->IsNVProgram
= GL_TRUE
;
1307 _mesa_printf("--- glLoadProgramNV result ---\n");
1308 _mesa_print_nv_vertex_program(program
);
1309 _mesa_printf("------------------------------\n");
1314 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1315 /* NOTE: _mesa_set_program_error would have been called already */
1316 /* GL_NV_vertex_program isn't supposed to set the error string
1317 * so we reset it here.
1319 _mesa_set_program_error(ctx
, ctx
->Program
.ErrorPos
, NULL
);
1325 PrintSrcReg(const struct vp_src_register
*src
)
1327 static const char comps
[5] = "xyzw";
1332 _mesa_printf("c[A0.x + %d]", src
->Index
);
1333 else if (src
->Index
< 0)
1334 _mesa_printf("c[A0.x - %d]", -src
->Index
);
1336 _mesa_printf("c[A0.x]");
1338 else if (src
->File
== PROGRAM_OUTPUT
) {
1339 _mesa_printf("o[%s]", OutputRegisters
[src
->Index
]);
1341 else if (src
->File
== PROGRAM_INPUT
) {
1342 _mesa_printf("v[%s]", InputRegisters
[src
->Index
]);
1344 else if (src
->File
== PROGRAM_ENV_PARAM
) {
1345 _mesa_printf("c[%d]", src
->Index
);
1348 ASSERT(src
->File
== PROGRAM_TEMPORARY
);
1349 _mesa_printf("R%d", src
->Index
);
1352 if (src
->Swizzle
[0] == src
->Swizzle
[1] &&
1353 src
->Swizzle
[0] == src
->Swizzle
[2] &&
1354 src
->Swizzle
[0] == src
->Swizzle
[3]) {
1355 _mesa_printf(".%c", comps
[src
->Swizzle
[0]]);
1357 else if (src
->Swizzle
[0] != 0 ||
1358 src
->Swizzle
[1] != 1 ||
1359 src
->Swizzle
[2] != 2 ||
1360 src
->Swizzle
[3] != 3) {
1361 _mesa_printf(".%c%c%c%c",
1362 comps
[src
->Swizzle
[0]],
1363 comps
[src
->Swizzle
[1]],
1364 comps
[src
->Swizzle
[2]],
1365 comps
[src
->Swizzle
[3]]);
1371 PrintDstReg(const struct vp_dst_register
*dst
)
1373 GLint w
= dst
->WriteMask
[0] + dst
->WriteMask
[1]
1374 + dst
->WriteMask
[2] + dst
->WriteMask
[3];
1376 if (dst
->File
== PROGRAM_OUTPUT
) {
1377 _mesa_printf("o[%s]", OutputRegisters
[dst
->Index
]);
1379 else if (dst
->File
== PROGRAM_INPUT
) {
1380 _mesa_printf("v[%s]", InputRegisters
[dst
->Index
]);
1382 else if (dst
->File
== PROGRAM_ENV_PARAM
) {
1383 _mesa_printf("c[%d]", dst
->Index
);
1386 ASSERT(dst
->File
== PROGRAM_TEMPORARY
);
1387 _mesa_printf("R%d", dst
->Index
);
1390 if (w
!= 0 && w
!= 4) {
1392 if (dst
->WriteMask
[0])
1394 if (dst
->WriteMask
[1])
1396 if (dst
->WriteMask
[2])
1398 if (dst
->WriteMask
[3])
1405 * Print a single NVIDIA vertex program instruction.
1408 _mesa_print_nv_vertex_instruction(const struct vp_instruction
*inst
)
1410 switch (inst
->Opcode
) {
1419 _mesa_printf("%s ", Opcodes
[(int) inst
->Opcode
]);
1420 PrintDstReg(&inst
->DstReg
);
1422 PrintSrcReg(&inst
->SrcReg
[0]);
1423 _mesa_printf(";\n");
1436 _mesa_printf("%s ", Opcodes
[(int) inst
->Opcode
]);
1437 PrintDstReg(&inst
->DstReg
);
1439 PrintSrcReg(&inst
->SrcReg
[0]);
1441 PrintSrcReg(&inst
->SrcReg
[1]);
1442 _mesa_printf(";\n");
1445 _mesa_printf("MAD ");
1446 PrintDstReg(&inst
->DstReg
);
1448 PrintSrcReg(&inst
->SrcReg
[0]);
1450 PrintSrcReg(&inst
->SrcReg
[1]);
1452 PrintSrcReg(&inst
->SrcReg
[2]);
1453 _mesa_printf(";\n");
1456 _mesa_printf("ARL A0.x, ");
1457 PrintSrcReg(&inst
->SrcReg
[0]);
1458 _mesa_printf(";\n");
1461 _mesa_printf("END\n");
1464 _mesa_printf("BAD INSTRUCTION\n");
1470 * Print (unparse) the given vertex program. Just for debugging.
1473 _mesa_print_nv_vertex_program(const struct vertex_program
*program
)
1475 const struct vp_instruction
*inst
;
1477 for (inst
= program
->Instructions
; ; inst
++) {
1478 _mesa_print_nv_vertex_instruction(inst
);
1479 if (inst
->Opcode
== VP_OPCODE_END
)
1486 _mesa_nv_vertex_input_register_name(GLuint i
)
1488 ASSERT(i
< MAX_NV_VERTEX_PROGRAM_INPUTS
);
1489 return InputRegisters
[i
];
1494 _mesa_nv_vertex_output_register_name(GLuint i
)
1496 ASSERT(i
< MAX_NV_VERTEX_PROGRAM_OUTPUTS
);
1497 return OutputRegisters
[i
];