2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2006 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.
40 #include "main/glheader.h"
41 #include "main/context.h"
42 #include "main/imports.h"
43 #include "main/macros.h"
44 #include "nvprogram.h"
45 #include "nvvertparse.h"
46 #include "prog_instruction.h"
51 * Current parsing state. This structure is passed among the parsing
52 * functions and keeps track of the current parser position and various
59 const GLubyte
*curLine
;
60 GLboolean isStateProgram
;
61 GLboolean isPositionInvariant
;
62 GLboolean isVersion1_1
;
63 GLbitfield inputsRead
;
64 GLbitfield outputsWritten
;
65 GLboolean anyProgRegsWritten
;
66 GLuint numInst
; /* number of instructions parsed */
71 * Called whenever we find an error during parsing.
74 record_error(struct parse_state
*parseState
, const char *msg
, int lineNo
)
78 const GLubyte
*lineStr
;
79 lineStr
= _mesa_find_line_column(parseState
->start
,
80 parseState
->pos
, &line
, &column
);
81 _mesa_debug(parseState
->ctx
,
82 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
83 lineNo
, line
, column
, (char *) lineStr
, msg
);
84 _mesa_free((void *) lineStr
);
89 /* Check that no error was already recorded. Only record the first one. */
90 if (parseState
->ctx
->Program
.ErrorString
[0] == 0) {
91 _mesa_set_program_error(parseState
->ctx
,
92 parseState
->pos
- parseState
->start
,
98 #define RETURN_ERROR \
100 record_error(parseState, "Unexpected end of input.", __LINE__); \
104 #define RETURN_ERROR1(msg) \
106 record_error(parseState, msg, __LINE__); \
110 #define RETURN_ERROR2(msg1, msg2) \
113 _mesa_sprintf(err, "%s %s", msg1, msg2); \
114 record_error(parseState, err, __LINE__); \
122 static GLboolean
IsLetter(GLubyte b
)
124 return (b
>= 'a' && b
<= 'z') || (b
>= 'A' && b
<= 'Z');
128 static GLboolean
IsDigit(GLubyte b
)
130 return b
>= '0' && b
<= '9';
134 static GLboolean
IsWhitespace(GLubyte b
)
136 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
141 * Starting at 'str' find the next token. A token can be an integer,
142 * an identifier or punctuation symbol.
143 * \return <= 0 we found an error, else, return number of characters parsed.
146 GetToken(struct parse_state
*parseState
, GLubyte
*token
)
148 const GLubyte
*str
= parseState
->pos
;
153 /* skip whitespace and comments */
154 while (str
[i
] && (IsWhitespace(str
[i
]) || str
[i
] == '#')) {
157 while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
160 if (str
[i
] == '\n' || str
[i
] == '\r')
161 parseState
->curLine
= str
+ i
+ 1;
164 /* skip whitespace */
165 if (str
[i
] == '\n' || str
[i
] == '\r')
166 parseState
->curLine
= str
+ i
+ 1;
174 /* try matching an integer */
175 while (str
[i
] && IsDigit(str
[i
])) {
176 token
[j
++] = str
[i
++];
178 if (j
> 0 || !str
[i
]) {
183 /* try matching an identifier */
184 if (IsLetter(str
[i
])) {
185 while (str
[i
] && (IsLetter(str
[i
]) || IsDigit(str
[i
]))) {
186 token
[j
++] = str
[i
++];
192 /* punctuation character */
206 * Get next token from input stream and increment stream pointer past token.
209 Parse_Token(struct parse_state
*parseState
, GLubyte
*token
)
212 i
= GetToken(parseState
, token
);
214 parseState
->pos
+= (-i
);
217 parseState
->pos
+= i
;
223 * Get next token from input stream but don't increment stream pointer.
226 Peek_Token(struct parse_state
*parseState
, GLubyte
*token
)
229 i
= GetToken(parseState
, token
);
231 parseState
->pos
+= (-i
);
234 len
= (GLint
)_mesa_strlen((const char *) token
);
235 parseState
->pos
+= (i
- len
);
241 * Try to match 'pattern' as the next token after any whitespace/comments.
242 * Advance the current parsing position only if we match the pattern.
243 * \return GL_TRUE if pattern is matched, GL_FALSE otherwise.
246 Parse_String(struct parse_state
*parseState
, const char *pattern
)
251 /* skip whitespace and comments */
252 while (IsWhitespace(*parseState
->pos
) || *parseState
->pos
== '#') {
253 if (*parseState
->pos
== '#') {
254 while (*parseState
->pos
&& (*parseState
->pos
!= '\n' && *parseState
->pos
!= '\r')) {
255 parseState
->pos
+= 1;
257 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
258 parseState
->curLine
= parseState
->pos
+ 1;
261 /* skip whitespace */
262 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
263 parseState
->curLine
= parseState
->pos
+ 1;
264 parseState
->pos
+= 1;
268 /* Try to match the pattern */
270 for (i
= 0; pattern
[i
]; i
++) {
271 if (*m
!= (GLubyte
) pattern
[i
])
277 return GL_TRUE
; /* success */
281 /**********************************************************************/
283 static const char *InputRegisters
[MAX_NV_VERTEX_PROGRAM_INPUTS
+ 1] = {
284 "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
285 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
288 static const char *OutputRegisters
[MAX_NV_VERTEX_PROGRAM_OUTPUTS
+ 1] = {
289 "HPOS", "COL0", "COL1", "FOGC",
290 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7",
291 "PSIZ", "BFC0", "BFC1", NULL
297 * Parse a temporary register: Rnn
300 Parse_TempReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
304 /* Should be 'R##' */
305 if (!Parse_Token(parseState
, token
))
308 RETURN_ERROR1("Expected R##");
310 if (IsDigit(token
[1])) {
311 GLint reg
= _mesa_atoi((char *) (token
+ 1));
312 if (reg
>= MAX_NV_VERTEX_PROGRAM_TEMPS
)
313 RETURN_ERROR1("Bad temporary register name");
317 RETURN_ERROR1("Bad temporary register name");
325 * Parse address register "A0.x"
328 Parse_AddrReg(struct parse_state
*parseState
)
331 if (!Parse_String(parseState
, "A0"))
335 if (!Parse_String(parseState
, "."))
339 if (!Parse_String(parseState
, "x"))
347 * Parse absolute program parameter register "c[##]"
350 Parse_AbsParamReg(struct parse_state
*parseState
, GLint
*regNum
)
354 if (!Parse_String(parseState
, "c"))
357 if (!Parse_String(parseState
, "["))
360 if (!Parse_Token(parseState
, token
))
363 if (IsDigit(token
[0])) {
364 /* a numbered program parameter register */
365 GLint reg
= _mesa_atoi((char *) token
);
366 if (reg
>= MAX_NV_VERTEX_PROGRAM_PARAMS
)
367 RETURN_ERROR1("Bad program parameter number");
374 if (!Parse_String(parseState
, "]"))
382 Parse_ParamReg(struct parse_state
*parseState
, struct prog_src_register
*srcReg
)
386 if (!Parse_String(parseState
, "c"))
389 if (!Parse_String(parseState
, "["))
392 if (!Peek_Token(parseState
, token
))
395 if (IsDigit(token
[0])) {
396 /* a numbered program parameter register */
398 (void) Parse_Token(parseState
, token
);
399 reg
= _mesa_atoi((char *) token
);
400 if (reg
>= MAX_NV_VERTEX_PROGRAM_PARAMS
)
401 RETURN_ERROR1("Bad program parameter number");
402 srcReg
->File
= PROGRAM_ENV_PARAM
;
405 else if (_mesa_strcmp((const char *) token
, "A0") == 0) {
406 /* address register "A0.x" */
407 if (!Parse_AddrReg(parseState
))
410 srcReg
->RelAddr
= GL_TRUE
;
411 srcReg
->File
= PROGRAM_ENV_PARAM
;
412 /* Look for +/-N offset */
413 if (!Peek_Token(parseState
, token
))
416 if (token
[0] == '-' || token
[0] == '+') {
417 const GLubyte sign
= token
[0];
418 (void) Parse_Token(parseState
, token
); /* consume +/- */
420 /* an integer should be next */
421 if (!Parse_Token(parseState
, token
))
424 if (IsDigit(token
[0])) {
425 const GLint k
= _mesa_atoi((char *) token
);
428 RETURN_ERROR1("Bad address offset");
433 RETURN_ERROR1("Bad address offset");
442 /* probably got a ']', catch it below */
449 /* Match closing ']' */
450 if (!Parse_String(parseState
, "]"))
458 * Parse v[#] or v[<name>]
461 Parse_AttribReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
467 if (!Parse_String(parseState
, "v"))
471 if (!Parse_String(parseState
, "["))
474 /* match number or named register */
475 if (!Parse_Token(parseState
, token
))
478 if (parseState
->isStateProgram
&& token
[0] != '0')
479 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
481 if (IsDigit(token
[0])) {
482 GLint reg
= _mesa_atoi((char *) token
);
483 if (reg
>= MAX_NV_VERTEX_PROGRAM_INPUTS
)
484 RETURN_ERROR1("Bad vertex attribute register name");
488 for (j
= 0; InputRegisters
[j
]; j
++) {
489 if (_mesa_strcmp((const char *) token
, InputRegisters
[j
]) == 0) {
494 if (!InputRegisters
[j
]) {
495 /* unknown input register label */
496 RETURN_ERROR2("Bad register name", token
);
501 if (!Parse_String(parseState
, "]"))
509 Parse_OutputReg(struct parse_state
*parseState
, GLint
*outputRegNum
)
515 if (!Parse_String(parseState
, "o"))
519 if (!Parse_String(parseState
, "["))
522 /* Get output reg name */
523 if (!Parse_Token(parseState
, token
))
526 if (parseState
->isPositionInvariant
)
527 start
= 1; /* skip HPOS register name */
531 /* try to match an output register name */
532 for (j
= start
; OutputRegisters
[j
]; j
++) {
533 if (_mesa_strcmp((const char *) token
, OutputRegisters
[j
]) == 0) {
538 if (!OutputRegisters
[j
])
539 RETURN_ERROR1("Unrecognized output register name");
542 if (!Parse_String(parseState
, "]"))
543 RETURN_ERROR1("Expected ]");
550 Parse_MaskedDstReg(struct parse_state
*parseState
, struct prog_dst_register
*dstReg
)
555 /* Dst reg can be R<n> or o[n] */
556 if (!Peek_Token(parseState
, token
))
559 if (token
[0] == 'R') {
560 /* a temporary register */
561 dstReg
->File
= PROGRAM_TEMPORARY
;
562 if (!Parse_TempReg(parseState
, &idx
))
566 else if (!parseState
->isStateProgram
&& token
[0] == 'o') {
567 /* an output register */
568 dstReg
->File
= PROGRAM_OUTPUT
;
569 if (!Parse_OutputReg(parseState
, &idx
))
573 else if (parseState
->isStateProgram
&& token
[0] == 'c' &&
574 parseState
->isStateProgram
) {
575 /* absolute program parameter register */
576 /* Only valid for vertex state programs */
577 dstReg
->File
= PROGRAM_ENV_PARAM
;
578 if (!Parse_AbsParamReg(parseState
, &idx
))
583 RETURN_ERROR1("Bad destination register name");
586 /* Parse optional write mask */
587 if (!Peek_Token(parseState
, token
))
590 if (token
[0] == '.') {
594 if (!Parse_String(parseState
, "."))
597 if (!Parse_Token(parseState
, token
))
600 dstReg
->WriteMask
= 0;
602 if (token
[k
] == 'x') {
603 dstReg
->WriteMask
|= WRITEMASK_X
;
606 if (token
[k
] == 'y') {
607 dstReg
->WriteMask
|= WRITEMASK_Y
;
610 if (token
[k
] == 'z') {
611 dstReg
->WriteMask
|= WRITEMASK_Z
;
614 if (token
[k
] == 'w') {
615 dstReg
->WriteMask
|= WRITEMASK_W
;
619 RETURN_ERROR1("Bad writemask character");
624 dstReg
->WriteMask
= WRITEMASK_XYZW
;
631 Parse_SwizzleSrcReg(struct parse_state
*parseState
, struct prog_src_register
*srcReg
)
636 srcReg
->RelAddr
= GL_FALSE
;
639 if (!Peek_Token(parseState
, token
))
641 if (token
[0] == '-') {
642 (void) Parse_String(parseState
, "-");
643 srcReg
->NegateBase
= NEGATE_XYZW
;
644 if (!Peek_Token(parseState
, token
))
648 srcReg
->NegateBase
= NEGATE_NONE
;
651 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
652 if (token
[0] == 'R') {
653 srcReg
->File
= PROGRAM_TEMPORARY
;
654 if (!Parse_TempReg(parseState
, &idx
))
658 else if (token
[0] == 'c') {
659 if (!Parse_ParamReg(parseState
, srcReg
))
662 else if (token
[0] == 'v') {
663 srcReg
->File
= PROGRAM_INPUT
;
664 if (!Parse_AttribReg(parseState
, &idx
))
669 RETURN_ERROR2("Bad source register name", token
);
672 /* init swizzle fields */
673 srcReg
->Swizzle
= SWIZZLE_NOOP
;
675 /* Look for optional swizzle suffix */
676 if (!Peek_Token(parseState
, token
))
678 if (token
[0] == '.') {
679 (void) Parse_String(parseState
, "."); /* consume . */
681 if (!Parse_Token(parseState
, token
))
685 /* single letter swizzle */
687 srcReg
->Swizzle
= SWIZZLE_XXXX
;
688 else if (token
[0] == 'y')
689 srcReg
->Swizzle
= SWIZZLE_YYYY
;
690 else if (token
[0] == 'z')
691 srcReg
->Swizzle
= SWIZZLE_ZZZZ
;
692 else if (token
[0] == 'w')
693 srcReg
->Swizzle
= SWIZZLE_WWWW
;
695 RETURN_ERROR1("Expected x, y, z, or w");
698 /* 2, 3 or 4-component swizzle */
703 for (k
= 0; token
[k
] && k
< 5; k
++) {
705 srcReg
->Swizzle
|= 0 << (k
*3);
706 else if (token
[k
] == 'y')
707 srcReg
->Swizzle
|= 1 << (k
*3);
708 else if (token
[k
] == 'z')
709 srcReg
->Swizzle
|= 2 << (k
*3);
710 else if (token
[k
] == 'w')
711 srcReg
->Swizzle
|= 3 << (k
*3);
725 Parse_ScalarSrcReg(struct parse_state
*parseState
, struct prog_src_register
*srcReg
)
730 srcReg
->RelAddr
= GL_FALSE
;
733 if (!Peek_Token(parseState
, token
))
735 if (token
[0] == '-') {
736 srcReg
->NegateBase
= NEGATE_XYZW
;
737 (void) Parse_String(parseState
, "-"); /* consume '-' */
738 if (!Peek_Token(parseState
, token
))
742 srcReg
->NegateBase
= NEGATE_NONE
;
745 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
746 if (token
[0] == 'R') {
747 srcReg
->File
= PROGRAM_TEMPORARY
;
748 if (!Parse_TempReg(parseState
, &idx
))
752 else if (token
[0] == 'c') {
753 if (!Parse_ParamReg(parseState
, srcReg
))
756 else if (token
[0] == 'v') {
757 srcReg
->File
= PROGRAM_INPUT
;
758 if (!Parse_AttribReg(parseState
, &idx
))
763 RETURN_ERROR2("Bad source register name", token
);
766 /* Look for .[xyzw] suffix */
767 if (!Parse_String(parseState
, "."))
770 if (!Parse_Token(parseState
, token
))
773 if (token
[0] == 'x' && token
[1] == 0) {
776 else if (token
[0] == 'y' && token
[1] == 0) {
779 else if (token
[0] == 'z' && token
[1] == 0) {
782 else if (token
[0] == 'w' && token
[1] == 0) {
786 RETURN_ERROR1("Bad scalar source suffix");
794 Parse_UnaryOpInstruction(struct parse_state
*parseState
,
795 struct prog_instruction
*inst
,
796 enum prog_opcode opcode
)
798 if (opcode
== OPCODE_ABS
&& !parseState
->isVersion1_1
)
799 RETURN_ERROR1("ABS 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
, ";"))
824 Parse_BiOpInstruction(struct parse_state
*parseState
,
825 struct prog_instruction
*inst
,
826 enum prog_opcode opcode
)
828 if (opcode
== OPCODE_DPH
&& !parseState
->isVersion1_1
)
829 RETURN_ERROR1("DPH illegal for vertex program 1.0");
830 if (opcode
== OPCODE_SUB
&& !parseState
->isVersion1_1
)
831 RETURN_ERROR1("SUB illegal for vertex program 1.0");
833 inst
->Opcode
= opcode
;
836 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
840 if (!Parse_String(parseState
, ","))
844 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
848 if (!Parse_String(parseState
, ","))
852 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
856 if (!Parse_String(parseState
, ";"))
859 /* make sure we don't reference more than one program parameter register */
860 if (inst
->SrcReg
[0].File
== PROGRAM_ENV_PARAM
&&
861 inst
->SrcReg
[1].File
== PROGRAM_ENV_PARAM
&&
862 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
)
863 RETURN_ERROR1("Can't reference two program parameter registers");
865 /* make sure we don't reference more than one vertex attribute register */
866 if (inst
->SrcReg
[0].File
== PROGRAM_INPUT
&&
867 inst
->SrcReg
[1].File
== PROGRAM_INPUT
&&
868 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
)
869 RETURN_ERROR1("Can't reference two vertex attribute registers");
876 Parse_TriOpInstruction(struct parse_state
*parseState
,
877 struct prog_instruction
*inst
,
878 enum prog_opcode opcode
)
880 inst
->Opcode
= opcode
;
883 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
887 if (!Parse_String(parseState
, ","))
891 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
895 if (!Parse_String(parseState
, ","))
899 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
903 if (!Parse_String(parseState
, ","))
907 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[2]))
911 if (!Parse_String(parseState
, ";"))
914 /* make sure we don't reference more than one program parameter register */
915 if ((inst
->SrcReg
[0].File
== PROGRAM_ENV_PARAM
&&
916 inst
->SrcReg
[1].File
== PROGRAM_ENV_PARAM
&&
917 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
) ||
918 (inst
->SrcReg
[0].File
== PROGRAM_ENV_PARAM
&&
919 inst
->SrcReg
[2].File
== PROGRAM_ENV_PARAM
&&
920 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[2].Index
) ||
921 (inst
->SrcReg
[1].File
== PROGRAM_ENV_PARAM
&&
922 inst
->SrcReg
[2].File
== PROGRAM_ENV_PARAM
&&
923 inst
->SrcReg
[1].Index
!= inst
->SrcReg
[2].Index
))
924 RETURN_ERROR1("Can only reference one program register");
926 /* make sure we don't reference more than one vertex attribute register */
927 if ((inst
->SrcReg
[0].File
== PROGRAM_INPUT
&&
928 inst
->SrcReg
[1].File
== PROGRAM_INPUT
&&
929 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
) ||
930 (inst
->SrcReg
[0].File
== PROGRAM_INPUT
&&
931 inst
->SrcReg
[2].File
== PROGRAM_INPUT
&&
932 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[2].Index
) ||
933 (inst
->SrcReg
[1].File
== PROGRAM_INPUT
&&
934 inst
->SrcReg
[2].File
== PROGRAM_INPUT
&&
935 inst
->SrcReg
[1].Index
!= inst
->SrcReg
[2].Index
))
936 RETURN_ERROR1("Can only reference one input register");
943 Parse_ScalarInstruction(struct parse_state
*parseState
,
944 struct prog_instruction
*inst
,
945 enum prog_opcode opcode
)
947 if (opcode
== OPCODE_RCC
&& !parseState
->isVersion1_1
)
948 RETURN_ERROR1("RCC illegal for vertex program 1.0");
950 inst
->Opcode
= opcode
;
953 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
957 if (!Parse_String(parseState
, ","))
961 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
965 if (!Parse_String(parseState
, ";"))
973 Parse_AddressInstruction(struct parse_state
*parseState
, struct prog_instruction
*inst
)
975 inst
->Opcode
= OPCODE_ARL
;
977 /* Make ARB_vp backends happy */
978 inst
->DstReg
.File
= PROGRAM_ADDRESS
;
979 inst
->DstReg
.WriteMask
= WRITEMASK_X
;
980 inst
->DstReg
.Index
= 0;
983 if (!Parse_AddrReg(parseState
))
987 if (!Parse_String(parseState
, ","))
991 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
995 if (!Parse_String(parseState
, ";"))
1003 Parse_EndInstruction(struct parse_state
*parseState
, struct prog_instruction
*inst
)
1007 inst
->Opcode
= OPCODE_END
;
1009 /* this should fail! */
1010 if (Parse_Token(parseState
, token
))
1011 RETURN_ERROR2("Unexpected token after END:", token
);
1018 * The PRINT instruction is Mesa-specific and is meant as a debugging aid for
1019 * the vertex program developer.
1020 * The NV_vertex_program extension grammar is modified as follows:
1022 * <instruction> ::= <ARL-instruction>
1024 * | <PRINT-instruction>
1026 * <PRINT-instruction> ::= "PRINT" <string literal>
1027 * | "PRINT" <string literal> "," <srcReg>
1028 * | "PRINT" <string literal> "," <dstReg>
1031 Parse_PrintInstruction(struct parse_state
*parseState
, struct prog_instruction
*inst
)
1037 struct prog_src_register
*srcReg
= &inst
->SrcReg
[0];
1040 inst
->Opcode
= OPCODE_PRINT
;
1042 /* The first argument is a literal string 'just like this' */
1043 if (!Parse_String(parseState
, "'"))
1046 str
= parseState
->pos
;
1047 for (len
= 0; str
[len
] != '\''; len
++) /* find closing quote */
1049 parseState
->pos
+= len
+ 1;
1050 msg
= (GLubyte
*) _mesa_malloc(len
+ 1);
1052 _mesa_memcpy(msg
, str
, len
);
1057 if (Parse_String(parseState
, ",")) {
1059 /* The second argument is a register name */
1060 if (!Peek_Token(parseState
, token
))
1063 srcReg
->RelAddr
= GL_FALSE
;
1064 srcReg
->NegateBase
= NEGATE_NONE
;
1065 srcReg
->Swizzle
= SWIZZLE_NOOP
;
1067 /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
1068 * or an o[n] output register.
1070 if (token
[0] == 'R') {
1071 srcReg
->File
= PROGRAM_TEMPORARY
;
1072 if (!Parse_TempReg(parseState
, &idx
))
1074 srcReg
->Index
= idx
;
1076 else if (token
[0] == 'c') {
1077 srcReg
->File
= PROGRAM_ENV_PARAM
;
1078 if (!Parse_ParamReg(parseState
, srcReg
))
1081 else if (token
[0] == 'v') {
1082 srcReg
->File
= PROGRAM_INPUT
;
1083 if (!Parse_AttribReg(parseState
, &idx
))
1085 srcReg
->Index
= idx
;
1087 else if (token
[0] == 'o') {
1088 srcReg
->File
= PROGRAM_OUTPUT
;
1089 if (!Parse_OutputReg(parseState
, &idx
))
1091 srcReg
->Index
= idx
;
1094 RETURN_ERROR2("Bad source register name", token
);
1102 if (!Parse_String(parseState
, ";"))
1110 Parse_OptionSequence(struct parse_state
*parseState
,
1111 struct prog_instruction program
[])
1115 if (!Parse_String(parseState
, "OPTION"))
1116 return GL_TRUE
; /* ok, not an OPTION statement */
1117 if (Parse_String(parseState
, "NV_position_invariant")) {
1118 parseState
->isPositionInvariant
= GL_TRUE
;
1121 RETURN_ERROR1("unexpected OPTION statement");
1123 if (!Parse_String(parseState
, ";"))
1130 Parse_InstructionSequence(struct parse_state
*parseState
,
1131 struct prog_instruction program
[])
1134 struct prog_instruction
*inst
= program
+ parseState
->numInst
;
1136 /* Initialize the instruction */
1137 _mesa_init_instructions(inst
, 1);
1139 if (Parse_String(parseState
, "MOV")) {
1140 if (!Parse_UnaryOpInstruction(parseState
, inst
, OPCODE_MOV
))
1143 else if (Parse_String(parseState
, "LIT")) {
1144 if (!Parse_UnaryOpInstruction(parseState
, inst
, OPCODE_LIT
))
1147 else if (Parse_String(parseState
, "ABS")) {
1148 if (!Parse_UnaryOpInstruction(parseState
, inst
, OPCODE_ABS
))
1151 else if (Parse_String(parseState
, "MUL")) {
1152 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_MUL
))
1155 else if (Parse_String(parseState
, "ADD")) {
1156 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_ADD
))
1159 else if (Parse_String(parseState
, "DP3")) {
1160 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_DP3
))
1163 else if (Parse_String(parseState
, "DP4")) {
1164 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_DP4
))
1167 else if (Parse_String(parseState
, "DST")) {
1168 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_DST
))
1171 else if (Parse_String(parseState
, "MIN")) {
1172 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_MIN
))
1175 else if (Parse_String(parseState
, "MAX")) {
1176 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_MAX
))
1179 else if (Parse_String(parseState
, "SLT")) {
1180 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_SLT
))
1183 else if (Parse_String(parseState
, "SGE")) {
1184 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_SGE
))
1187 else if (Parse_String(parseState
, "DPH")) {
1188 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_DPH
))
1191 else if (Parse_String(parseState
, "SUB")) {
1192 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_SUB
))
1195 else if (Parse_String(parseState
, "MAD")) {
1196 if (!Parse_TriOpInstruction(parseState
, inst
, OPCODE_MAD
))
1199 else if (Parse_String(parseState
, "RCP")) {
1200 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_RCP
))
1203 else if (Parse_String(parseState
, "RSQ")) {
1204 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_RSQ
))
1207 else if (Parse_String(parseState
, "EXP")) {
1208 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_EXP
))
1211 else if (Parse_String(parseState
, "LOG")) {
1212 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_LOG
))
1215 else if (Parse_String(parseState
, "RCC")) {
1216 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_RCC
))
1219 else if (Parse_String(parseState
, "ARL")) {
1220 if (!Parse_AddressInstruction(parseState
, inst
))
1223 else if (Parse_String(parseState
, "PRINT")) {
1224 if (!Parse_PrintInstruction(parseState
, inst
))
1227 else if (Parse_String(parseState
, "END")) {
1228 if (!Parse_EndInstruction(parseState
, inst
))
1231 parseState
->numInst
++;
1232 return GL_TRUE
; /* all done */
1236 /* bad instruction name */
1237 RETURN_ERROR1("Unexpected token");
1240 /* examine input/output registers */
1241 if (inst
->DstReg
.File
== PROGRAM_OUTPUT
)
1242 parseState
->outputsWritten
|= (1 << inst
->DstReg
.Index
);
1243 else if (inst
->DstReg
.File
== PROGRAM_ENV_PARAM
)
1244 parseState
->anyProgRegsWritten
= GL_TRUE
;
1246 if (inst
->SrcReg
[0].File
== PROGRAM_INPUT
)
1247 parseState
->inputsRead
|= (1 << inst
->SrcReg
[0].Index
);
1248 if (inst
->SrcReg
[1].File
== PROGRAM_INPUT
)
1249 parseState
->inputsRead
|= (1 << inst
->SrcReg
[1].Index
);
1250 if (inst
->SrcReg
[2].File
== PROGRAM_INPUT
)
1251 parseState
->inputsRead
|= (1 << inst
->SrcReg
[2].Index
);
1253 parseState
->numInst
++;
1255 if (parseState
->numInst
>= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
)
1256 RETURN_ERROR1("Program too long");
1264 Parse_Program(struct parse_state
*parseState
,
1265 struct prog_instruction instBuffer
[])
1267 if (parseState
->isVersion1_1
) {
1268 if (!Parse_OptionSequence(parseState
, instBuffer
)) {
1272 return Parse_InstructionSequence(parseState
, instBuffer
);
1277 * Parse/compile the 'str' returning the compiled 'program'.
1278 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1279 * indicates the position of the error in 'str'.
1282 _mesa_parse_nv_vertex_program(GLcontext
*ctx
, GLenum dstTarget
,
1283 const GLubyte
*str
, GLsizei len
,
1284 struct gl_vertex_program
*program
)
1286 struct parse_state parseState
;
1287 struct prog_instruction instBuffer
[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
];
1288 struct prog_instruction
*newInst
;
1290 GLubyte
*programString
;
1292 /* Make a null-terminated copy of the program string */
1293 programString
= (GLubyte
*) MALLOC(len
+ 1);
1294 if (!programString
) {
1295 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1298 MEMCPY(programString
, str
, len
);
1299 programString
[len
] = 0;
1301 /* Get ready to parse */
1302 parseState
.ctx
= ctx
;
1303 parseState
.start
= programString
;
1304 parseState
.isPositionInvariant
= GL_FALSE
;
1305 parseState
.isVersion1_1
= GL_FALSE
;
1306 parseState
.numInst
= 0;
1307 parseState
.inputsRead
= 0;
1308 parseState
.outputsWritten
= 0;
1309 parseState
.anyProgRegsWritten
= GL_FALSE
;
1311 /* Reset error state */
1312 _mesa_set_program_error(ctx
, -1, NULL
);
1314 /* check the program header */
1315 if (_mesa_strncmp((const char *) programString
, "!!VP1.0", 7) == 0) {
1316 target
= GL_VERTEX_PROGRAM_NV
;
1317 parseState
.pos
= programString
+ 7;
1318 parseState
.isStateProgram
= GL_FALSE
;
1320 else if (_mesa_strncmp((const char *) programString
, "!!VP1.1", 7) == 0) {
1321 target
= GL_VERTEX_PROGRAM_NV
;
1322 parseState
.pos
= programString
+ 7;
1323 parseState
.isStateProgram
= GL_FALSE
;
1324 parseState
.isVersion1_1
= GL_TRUE
;
1326 else if (_mesa_strncmp((const char *) programString
, "!!VSP1.0", 8) == 0) {
1327 target
= GL_VERTEX_STATE_PROGRAM_NV
;
1328 parseState
.pos
= programString
+ 8;
1329 parseState
.isStateProgram
= GL_TRUE
;
1332 /* invalid header */
1333 ctx
->Program
.ErrorPos
= 0;
1334 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1338 /* make sure target and header match */
1339 if (target
!= dstTarget
) {
1340 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1341 "glLoadProgramNV(target mismatch)");
1346 if (Parse_Program(&parseState
, instBuffer
)) {
1347 /* successful parse! */
1349 if (parseState
.isStateProgram
) {
1350 if (!parseState
.anyProgRegsWritten
) {
1351 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1352 "glLoadProgramNV(c[#] not written)");
1357 if (!parseState
.isPositionInvariant
&&
1358 !(parseState
.outputsWritten
& (1 << VERT_RESULT_HPOS
))) {
1359 /* bit 1 = HPOS register */
1360 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1361 "glLoadProgramNV(HPOS not written)");
1366 /* copy the compiled instructions */
1367 assert(parseState
.numInst
<= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
);
1368 newInst
= _mesa_alloc_instructions(parseState
.numInst
);
1370 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1371 _mesa_free(programString
);
1372 return; /* out of memory */
1374 _mesa_copy_instructions(newInst
, instBuffer
, parseState
.numInst
);
1376 /* install the program */
1377 program
->Base
.Target
= target
;
1378 if (program
->Base
.String
) {
1379 _mesa_free(program
->Base
.String
);
1381 program
->Base
.String
= programString
;
1382 program
->Base
.Format
= GL_PROGRAM_FORMAT_ASCII_ARB
;
1383 if (program
->Base
.Instructions
) {
1384 _mesa_free(program
->Base
.Instructions
);
1386 program
->Base
.Instructions
= newInst
;
1387 program
->Base
.InputsRead
= parseState
.inputsRead
;
1388 if (parseState
.isPositionInvariant
)
1389 program
->Base
.InputsRead
|= VERT_BIT_POS
;
1390 program
->Base
.NumInstructions
= parseState
.numInst
;
1391 program
->Base
.OutputsWritten
= parseState
.outputsWritten
;
1392 program
->IsPositionInvariant
= parseState
.isPositionInvariant
;
1393 program
->IsNVProgram
= GL_TRUE
;
1396 _mesa_printf("--- glLoadProgramNV result ---\n");
1397 _mesa_print_nv_vertex_program(program
);
1398 _mesa_printf("------------------------------\n");
1403 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1404 /* NOTE: _mesa_set_program_error would have been called already */
1405 /* GL_NV_vertex_program isn't supposed to set the error string
1406 * so we reset it here.
1408 _mesa_set_program_error(ctx
, ctx
->Program
.ErrorPos
, NULL
);
1414 PrintSrcReg(const struct prog_src_register
*src
)
1416 static const char comps
[5] = "xyzw";
1417 if (src
->NegateBase
)
1421 _mesa_printf("c[A0.x + %d]", src
->Index
);
1422 else if (src
->Index
< 0)
1423 _mesa_printf("c[A0.x - %d]", -src
->Index
);
1425 _mesa_printf("c[A0.x]");
1427 else if (src
->File
== PROGRAM_OUTPUT
) {
1428 _mesa_printf("o[%s]", OutputRegisters
[src
->Index
]);
1430 else if (src
->File
== PROGRAM_INPUT
) {
1431 _mesa_printf("v[%s]", InputRegisters
[src
->Index
]);
1433 else if (src
->File
== PROGRAM_ENV_PARAM
) {
1434 _mesa_printf("c[%d]", src
->Index
);
1437 ASSERT(src
->File
== PROGRAM_TEMPORARY
);
1438 _mesa_printf("R%d", src
->Index
);
1441 if (GET_SWZ(src
->Swizzle
, 0) == GET_SWZ(src
->Swizzle
, 1) &&
1442 GET_SWZ(src
->Swizzle
, 0) == GET_SWZ(src
->Swizzle
, 2) &&
1443 GET_SWZ(src
->Swizzle
, 0) == GET_SWZ(src
->Swizzle
, 3)) {
1444 _mesa_printf(".%c", comps
[GET_SWZ(src
->Swizzle
, 0)]);
1446 else if (src
->Swizzle
!= SWIZZLE_NOOP
) {
1447 _mesa_printf(".%c%c%c%c",
1448 comps
[GET_SWZ(src
->Swizzle
, 0)],
1449 comps
[GET_SWZ(src
->Swizzle
, 1)],
1450 comps
[GET_SWZ(src
->Swizzle
, 2)],
1451 comps
[GET_SWZ(src
->Swizzle
, 3)]);
1457 PrintDstReg(const struct prog_dst_register
*dst
)
1459 if (dst
->File
== PROGRAM_OUTPUT
) {
1460 _mesa_printf("o[%s]", OutputRegisters
[dst
->Index
]);
1462 else if (dst
->File
== PROGRAM_INPUT
) {
1463 _mesa_printf("v[%s]", InputRegisters
[dst
->Index
]);
1465 else if (dst
->File
== PROGRAM_ENV_PARAM
) {
1466 _mesa_printf("c[%d]", dst
->Index
);
1469 ASSERT(dst
->File
== PROGRAM_TEMPORARY
);
1470 _mesa_printf("R%d", dst
->Index
);
1473 if (dst
->WriteMask
!= 0 && dst
->WriteMask
!= WRITEMASK_XYZW
) {
1475 if (dst
->WriteMask
& WRITEMASK_X
)
1477 if (dst
->WriteMask
& WRITEMASK_Y
)
1479 if (dst
->WriteMask
& WRITEMASK_Z
)
1481 if (dst
->WriteMask
& WRITEMASK_W
)
1488 * Print a single NVIDIA vertex program instruction.
1491 _mesa_print_nv_vertex_instruction(const struct prog_instruction
*inst
)
1495 switch (inst
->Opcode
) {
1516 _mesa_printf("%s ", _mesa_opcode_string(inst
->Opcode
));
1517 PrintDstReg(&inst
->DstReg
);
1519 n
= _mesa_num_inst_src_regs(inst
->Opcode
);
1520 for (i
= 0; i
< n
; i
++) {
1521 PrintSrcReg(&inst
->SrcReg
[i
]);
1525 _mesa_printf(";\n");
1528 _mesa_printf("ARL A0.x, ");
1529 PrintSrcReg(&inst
->SrcReg
[0]);
1530 _mesa_printf(";\n");
1533 _mesa_printf("PRINT '%s'", inst
->Data
);
1534 if (inst
->SrcReg
[0].File
!= PROGRAM_UNDEFINED
) {
1536 PrintSrcReg(&inst
->SrcReg
[0]);
1537 _mesa_printf(";\n");
1544 _mesa_printf("END\n");
1547 _mesa_printf("BAD INSTRUCTION\n");
1553 * Print (unparse) the given vertex program. Just for debugging.
1556 _mesa_print_nv_vertex_program(const struct gl_vertex_program
*program
)
1558 const struct prog_instruction
*inst
;
1560 for (inst
= program
->Base
.Instructions
; ; inst
++) {
1561 _mesa_print_nv_vertex_instruction(inst
);
1562 if (inst
->Opcode
== OPCODE_END
)
1569 _mesa_nv_vertex_input_register_name(GLuint i
)
1571 ASSERT(i
< MAX_NV_VERTEX_PROGRAM_INPUTS
);
1572 return InputRegisters
[i
];
1577 _mesa_nv_vertex_output_register_name(GLuint i
)
1579 ASSERT(i
< MAX_NV_VERTEX_PROGRAM_OUTPUTS
);
1580 return OutputRegisters
[i
];