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"
47 #include "prog_print.h"
52 * Current parsing state. This structure is passed among the parsing
53 * functions and keeps track of the current parser position and various
60 const GLubyte
*curLine
;
61 GLboolean isStateProgram
;
62 GLboolean isPositionInvariant
;
63 GLboolean isVersion1_1
;
64 GLbitfield inputsRead
;
65 GLbitfield outputsWritten
;
66 GLboolean anyProgRegsWritten
;
67 GLuint numInst
; /* number of instructions parsed */
72 * Called whenever we find an error during parsing.
75 record_error(struct parse_state
*parseState
, const char *msg
, int lineNo
)
79 const GLubyte
*lineStr
;
80 lineStr
= _mesa_find_line_column(parseState
->start
,
81 parseState
->pos
, &line
, &column
);
82 _mesa_debug(parseState
->ctx
,
83 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
84 lineNo
, line
, column
, (char *) lineStr
, msg
);
85 _mesa_free((void *) lineStr
);
90 /* Check that no error was already recorded. Only record the first one. */
91 if (parseState
->ctx
->Program
.ErrorString
[0] == 0) {
92 _mesa_set_program_error(parseState
->ctx
,
93 parseState
->pos
- parseState
->start
,
99 #define RETURN_ERROR \
101 record_error(parseState, "Unexpected end of input.", __LINE__); \
105 #define RETURN_ERROR1(msg) \
107 record_error(parseState, msg, __LINE__); \
111 #define RETURN_ERROR2(msg1, msg2) \
114 _mesa_sprintf(err, "%s %s", msg1, msg2); \
115 record_error(parseState, err, __LINE__); \
123 static GLboolean
IsLetter(GLubyte b
)
125 return (b
>= 'a' && b
<= 'z') || (b
>= 'A' && b
<= 'Z');
129 static GLboolean
IsDigit(GLubyte b
)
131 return b
>= '0' && b
<= '9';
135 static GLboolean
IsWhitespace(GLubyte b
)
137 return b
== ' ' || b
== '\t' || b
== '\n' || b
== '\r';
142 * Starting at 'str' find the next token. A token can be an integer,
143 * an identifier or punctuation symbol.
144 * \return <= 0 we found an error, else, return number of characters parsed.
147 GetToken(struct parse_state
*parseState
, GLubyte
*token
)
149 const GLubyte
*str
= parseState
->pos
;
154 /* skip whitespace and comments */
155 while (str
[i
] && (IsWhitespace(str
[i
]) || str
[i
] == '#')) {
158 while (str
[i
] && (str
[i
] != '\n' && str
[i
] != '\r')) {
161 if (str
[i
] == '\n' || str
[i
] == '\r')
162 parseState
->curLine
= str
+ i
+ 1;
165 /* skip whitespace */
166 if (str
[i
] == '\n' || str
[i
] == '\r')
167 parseState
->curLine
= str
+ i
+ 1;
175 /* try matching an integer */
176 while (str
[i
] && IsDigit(str
[i
])) {
177 token
[j
++] = str
[i
++];
179 if (j
> 0 || !str
[i
]) {
184 /* try matching an identifier */
185 if (IsLetter(str
[i
])) {
186 while (str
[i
] && (IsLetter(str
[i
]) || IsDigit(str
[i
]))) {
187 token
[j
++] = str
[i
++];
193 /* punctuation character */
207 * Get next token from input stream and increment stream pointer past token.
210 Parse_Token(struct parse_state
*parseState
, GLubyte
*token
)
213 i
= GetToken(parseState
, token
);
215 parseState
->pos
+= (-i
);
218 parseState
->pos
+= i
;
224 * Get next token from input stream but don't increment stream pointer.
227 Peek_Token(struct parse_state
*parseState
, GLubyte
*token
)
230 i
= GetToken(parseState
, token
);
232 parseState
->pos
+= (-i
);
235 len
= (GLint
)_mesa_strlen((const char *) token
);
236 parseState
->pos
+= (i
- len
);
242 * Try to match 'pattern' as the next token after any whitespace/comments.
243 * Advance the current parsing position only if we match the pattern.
244 * \return GL_TRUE if pattern is matched, GL_FALSE otherwise.
247 Parse_String(struct parse_state
*parseState
, const char *pattern
)
252 /* skip whitespace and comments */
253 while (IsWhitespace(*parseState
->pos
) || *parseState
->pos
== '#') {
254 if (*parseState
->pos
== '#') {
255 while (*parseState
->pos
&& (*parseState
->pos
!= '\n' && *parseState
->pos
!= '\r')) {
256 parseState
->pos
+= 1;
258 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
259 parseState
->curLine
= parseState
->pos
+ 1;
262 /* skip whitespace */
263 if (*parseState
->pos
== '\n' || *parseState
->pos
== '\r')
264 parseState
->curLine
= parseState
->pos
+ 1;
265 parseState
->pos
+= 1;
269 /* Try to match the pattern */
271 for (i
= 0; pattern
[i
]; i
++) {
272 if (*m
!= (GLubyte
) pattern
[i
])
278 return GL_TRUE
; /* success */
282 /**********************************************************************/
284 static const char *InputRegisters
[MAX_NV_VERTEX_PROGRAM_INPUTS
+ 1] = {
285 "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
286 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
289 static const char *OutputRegisters
[MAX_NV_VERTEX_PROGRAM_OUTPUTS
+ 1] = {
290 "HPOS", "COL0", "COL1", "FOGC",
291 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7",
292 "PSIZ", "BFC0", "BFC1", NULL
298 * Parse a temporary register: Rnn
301 Parse_TempReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
305 /* Should be 'R##' */
306 if (!Parse_Token(parseState
, token
))
309 RETURN_ERROR1("Expected R##");
311 if (IsDigit(token
[1])) {
312 GLint reg
= _mesa_atoi((char *) (token
+ 1));
313 if (reg
>= MAX_NV_VERTEX_PROGRAM_TEMPS
)
314 RETURN_ERROR1("Bad temporary register name");
318 RETURN_ERROR1("Bad temporary register name");
326 * Parse address register "A0.x"
329 Parse_AddrReg(struct parse_state
*parseState
)
332 if (!Parse_String(parseState
, "A0"))
336 if (!Parse_String(parseState
, "."))
340 if (!Parse_String(parseState
, "x"))
348 * Parse absolute program parameter register "c[##]"
351 Parse_AbsParamReg(struct parse_state
*parseState
, GLint
*regNum
)
355 if (!Parse_String(parseState
, "c"))
358 if (!Parse_String(parseState
, "["))
361 if (!Parse_Token(parseState
, token
))
364 if (IsDigit(token
[0])) {
365 /* a numbered program parameter register */
366 GLint reg
= _mesa_atoi((char *) token
);
367 if (reg
>= MAX_NV_VERTEX_PROGRAM_PARAMS
)
368 RETURN_ERROR1("Bad program parameter number");
375 if (!Parse_String(parseState
, "]"))
383 Parse_ParamReg(struct parse_state
*parseState
, struct prog_src_register
*srcReg
)
387 if (!Parse_String(parseState
, "c"))
390 if (!Parse_String(parseState
, "["))
393 if (!Peek_Token(parseState
, token
))
396 if (IsDigit(token
[0])) {
397 /* a numbered program parameter register */
399 (void) Parse_Token(parseState
, token
);
400 reg
= _mesa_atoi((char *) token
);
401 if (reg
>= MAX_NV_VERTEX_PROGRAM_PARAMS
)
402 RETURN_ERROR1("Bad program parameter number");
403 srcReg
->File
= PROGRAM_ENV_PARAM
;
406 else if (_mesa_strcmp((const char *) token
, "A0") == 0) {
407 /* address register "A0.x" */
408 if (!Parse_AddrReg(parseState
))
411 srcReg
->RelAddr
= GL_TRUE
;
412 srcReg
->File
= PROGRAM_ENV_PARAM
;
413 /* Look for +/-N offset */
414 if (!Peek_Token(parseState
, token
))
417 if (token
[0] == '-' || token
[0] == '+') {
418 const GLubyte sign
= token
[0];
419 (void) Parse_Token(parseState
, token
); /* consume +/- */
421 /* an integer should be next */
422 if (!Parse_Token(parseState
, token
))
425 if (IsDigit(token
[0])) {
426 const GLint k
= _mesa_atoi((char *) token
);
429 RETURN_ERROR1("Bad address offset");
434 RETURN_ERROR1("Bad address offset");
443 /* probably got a ']', catch it below */
450 /* Match closing ']' */
451 if (!Parse_String(parseState
, "]"))
459 * Parse v[#] or v[<name>]
462 Parse_AttribReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
468 if (!Parse_String(parseState
, "v"))
472 if (!Parse_String(parseState
, "["))
475 /* match number or named register */
476 if (!Parse_Token(parseState
, token
))
479 if (parseState
->isStateProgram
&& token
[0] != '0')
480 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
482 if (IsDigit(token
[0])) {
483 GLint reg
= _mesa_atoi((char *) token
);
484 if (reg
>= MAX_NV_VERTEX_PROGRAM_INPUTS
)
485 RETURN_ERROR1("Bad vertex attribute register name");
489 for (j
= 0; InputRegisters
[j
]; j
++) {
490 if (_mesa_strcmp((const char *) token
, InputRegisters
[j
]) == 0) {
495 if (!InputRegisters
[j
]) {
496 /* unknown input register label */
497 RETURN_ERROR2("Bad register name", token
);
502 if (!Parse_String(parseState
, "]"))
510 Parse_OutputReg(struct parse_state
*parseState
, GLint
*outputRegNum
)
516 if (!Parse_String(parseState
, "o"))
520 if (!Parse_String(parseState
, "["))
523 /* Get output reg name */
524 if (!Parse_Token(parseState
, token
))
527 if (parseState
->isPositionInvariant
)
528 start
= 1; /* skip HPOS register name */
532 /* try to match an output register name */
533 for (j
= start
; OutputRegisters
[j
]; j
++) {
534 if (_mesa_strcmp((const char *) token
, OutputRegisters
[j
]) == 0) {
539 if (!OutputRegisters
[j
])
540 RETURN_ERROR1("Unrecognized output register name");
543 if (!Parse_String(parseState
, "]"))
544 RETURN_ERROR1("Expected ]");
551 Parse_MaskedDstReg(struct parse_state
*parseState
, struct prog_dst_register
*dstReg
)
556 /* Dst reg can be R<n> or o[n] */
557 if (!Peek_Token(parseState
, token
))
560 if (token
[0] == 'R') {
561 /* a temporary register */
562 dstReg
->File
= PROGRAM_TEMPORARY
;
563 if (!Parse_TempReg(parseState
, &idx
))
567 else if (!parseState
->isStateProgram
&& token
[0] == 'o') {
568 /* an output register */
569 dstReg
->File
= PROGRAM_OUTPUT
;
570 if (!Parse_OutputReg(parseState
, &idx
))
574 else if (parseState
->isStateProgram
&& token
[0] == 'c' &&
575 parseState
->isStateProgram
) {
576 /* absolute program parameter register */
577 /* Only valid for vertex state programs */
578 dstReg
->File
= PROGRAM_ENV_PARAM
;
579 if (!Parse_AbsParamReg(parseState
, &idx
))
584 RETURN_ERROR1("Bad destination register name");
587 /* Parse optional write mask */
588 if (!Peek_Token(parseState
, token
))
591 if (token
[0] == '.') {
595 if (!Parse_String(parseState
, "."))
598 if (!Parse_Token(parseState
, token
))
601 dstReg
->WriteMask
= 0;
603 if (token
[k
] == 'x') {
604 dstReg
->WriteMask
|= WRITEMASK_X
;
607 if (token
[k
] == 'y') {
608 dstReg
->WriteMask
|= WRITEMASK_Y
;
611 if (token
[k
] == 'z') {
612 dstReg
->WriteMask
|= WRITEMASK_Z
;
615 if (token
[k
] == 'w') {
616 dstReg
->WriteMask
|= WRITEMASK_W
;
620 RETURN_ERROR1("Bad writemask character");
625 dstReg
->WriteMask
= WRITEMASK_XYZW
;
632 Parse_SwizzleSrcReg(struct parse_state
*parseState
, struct prog_src_register
*srcReg
)
637 srcReg
->RelAddr
= GL_FALSE
;
640 if (!Peek_Token(parseState
, token
))
642 if (token
[0] == '-') {
643 (void) Parse_String(parseState
, "-");
644 srcReg
->Negate
= NEGATE_XYZW
;
645 if (!Peek_Token(parseState
, token
))
649 srcReg
->Negate
= NEGATE_NONE
;
652 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
653 if (token
[0] == 'R') {
654 srcReg
->File
= PROGRAM_TEMPORARY
;
655 if (!Parse_TempReg(parseState
, &idx
))
659 else if (token
[0] == 'c') {
660 if (!Parse_ParamReg(parseState
, srcReg
))
663 else if (token
[0] == 'v') {
664 srcReg
->File
= PROGRAM_INPUT
;
665 if (!Parse_AttribReg(parseState
, &idx
))
670 RETURN_ERROR2("Bad source register name", token
);
673 /* init swizzle fields */
674 srcReg
->Swizzle
= SWIZZLE_NOOP
;
676 /* Look for optional swizzle suffix */
677 if (!Peek_Token(parseState
, token
))
679 if (token
[0] == '.') {
680 (void) Parse_String(parseState
, "."); /* consume . */
682 if (!Parse_Token(parseState
, token
))
686 /* single letter swizzle */
688 srcReg
->Swizzle
= SWIZZLE_XXXX
;
689 else if (token
[0] == 'y')
690 srcReg
->Swizzle
= SWIZZLE_YYYY
;
691 else if (token
[0] == 'z')
692 srcReg
->Swizzle
= SWIZZLE_ZZZZ
;
693 else if (token
[0] == 'w')
694 srcReg
->Swizzle
= SWIZZLE_WWWW
;
696 RETURN_ERROR1("Expected x, y, z, or w");
699 /* 2, 3 or 4-component swizzle */
704 for (k
= 0; token
[k
] && k
< 5; k
++) {
706 srcReg
->Swizzle
|= 0 << (k
*3);
707 else if (token
[k
] == 'y')
708 srcReg
->Swizzle
|= 1 << (k
*3);
709 else if (token
[k
] == 'z')
710 srcReg
->Swizzle
|= 2 << (k
*3);
711 else if (token
[k
] == 'w')
712 srcReg
->Swizzle
|= 3 << (k
*3);
726 Parse_ScalarSrcReg(struct parse_state
*parseState
, struct prog_src_register
*srcReg
)
731 srcReg
->RelAddr
= GL_FALSE
;
734 if (!Peek_Token(parseState
, token
))
736 if (token
[0] == '-') {
737 srcReg
->Negate
= NEGATE_XYZW
;
738 (void) Parse_String(parseState
, "-"); /* consume '-' */
739 if (!Peek_Token(parseState
, token
))
743 srcReg
->Negate
= NEGATE_NONE
;
746 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
747 if (token
[0] == 'R') {
748 srcReg
->File
= PROGRAM_TEMPORARY
;
749 if (!Parse_TempReg(parseState
, &idx
))
753 else if (token
[0] == 'c') {
754 if (!Parse_ParamReg(parseState
, srcReg
))
757 else if (token
[0] == 'v') {
758 srcReg
->File
= PROGRAM_INPUT
;
759 if (!Parse_AttribReg(parseState
, &idx
))
764 RETURN_ERROR2("Bad source register name", token
);
767 /* Look for .[xyzw] suffix */
768 if (!Parse_String(parseState
, "."))
771 if (!Parse_Token(parseState
, token
))
774 if (token
[0] == 'x' && token
[1] == 0) {
777 else if (token
[0] == 'y' && token
[1] == 0) {
780 else if (token
[0] == 'z' && token
[1] == 0) {
783 else if (token
[0] == 'w' && token
[1] == 0) {
787 RETURN_ERROR1("Bad scalar source suffix");
795 Parse_UnaryOpInstruction(struct parse_state
*parseState
,
796 struct prog_instruction
*inst
,
797 enum prog_opcode opcode
)
799 if (opcode
== OPCODE_ABS
&& !parseState
->isVersion1_1
)
800 RETURN_ERROR1("ABS illegal for vertex program 1.0");
802 inst
->Opcode
= opcode
;
805 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
809 if (!Parse_String(parseState
, ","))
813 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
817 if (!Parse_String(parseState
, ";"))
825 Parse_BiOpInstruction(struct parse_state
*parseState
,
826 struct prog_instruction
*inst
,
827 enum prog_opcode opcode
)
829 if (opcode
== OPCODE_DPH
&& !parseState
->isVersion1_1
)
830 RETURN_ERROR1("DPH illegal for vertex program 1.0");
831 if (opcode
== OPCODE_SUB
&& !parseState
->isVersion1_1
)
832 RETURN_ERROR1("SUB illegal for vertex program 1.0");
834 inst
->Opcode
= opcode
;
837 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
841 if (!Parse_String(parseState
, ","))
845 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
849 if (!Parse_String(parseState
, ","))
853 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
857 if (!Parse_String(parseState
, ";"))
860 /* make sure we don't reference more than one program parameter register */
861 if (inst
->SrcReg
[0].File
== PROGRAM_ENV_PARAM
&&
862 inst
->SrcReg
[1].File
== PROGRAM_ENV_PARAM
&&
863 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
)
864 RETURN_ERROR1("Can't reference two program parameter registers");
866 /* make sure we don't reference more than one vertex attribute register */
867 if (inst
->SrcReg
[0].File
== PROGRAM_INPUT
&&
868 inst
->SrcReg
[1].File
== PROGRAM_INPUT
&&
869 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
)
870 RETURN_ERROR1("Can't reference two vertex attribute registers");
877 Parse_TriOpInstruction(struct parse_state
*parseState
,
878 struct prog_instruction
*inst
,
879 enum prog_opcode opcode
)
881 inst
->Opcode
= opcode
;
884 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
888 if (!Parse_String(parseState
, ","))
892 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
896 if (!Parse_String(parseState
, ","))
900 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
904 if (!Parse_String(parseState
, ","))
908 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[2]))
912 if (!Parse_String(parseState
, ";"))
915 /* make sure we don't reference more than one program parameter register */
916 if ((inst
->SrcReg
[0].File
== PROGRAM_ENV_PARAM
&&
917 inst
->SrcReg
[1].File
== PROGRAM_ENV_PARAM
&&
918 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
) ||
919 (inst
->SrcReg
[0].File
== PROGRAM_ENV_PARAM
&&
920 inst
->SrcReg
[2].File
== PROGRAM_ENV_PARAM
&&
921 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[2].Index
) ||
922 (inst
->SrcReg
[1].File
== PROGRAM_ENV_PARAM
&&
923 inst
->SrcReg
[2].File
== PROGRAM_ENV_PARAM
&&
924 inst
->SrcReg
[1].Index
!= inst
->SrcReg
[2].Index
))
925 RETURN_ERROR1("Can only reference one program register");
927 /* make sure we don't reference more than one vertex attribute register */
928 if ((inst
->SrcReg
[0].File
== PROGRAM_INPUT
&&
929 inst
->SrcReg
[1].File
== PROGRAM_INPUT
&&
930 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
) ||
931 (inst
->SrcReg
[0].File
== PROGRAM_INPUT
&&
932 inst
->SrcReg
[2].File
== PROGRAM_INPUT
&&
933 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[2].Index
) ||
934 (inst
->SrcReg
[1].File
== PROGRAM_INPUT
&&
935 inst
->SrcReg
[2].File
== PROGRAM_INPUT
&&
936 inst
->SrcReg
[1].Index
!= inst
->SrcReg
[2].Index
))
937 RETURN_ERROR1("Can only reference one input register");
944 Parse_ScalarInstruction(struct parse_state
*parseState
,
945 struct prog_instruction
*inst
,
946 enum prog_opcode opcode
)
948 if (opcode
== OPCODE_RCC
&& !parseState
->isVersion1_1
)
949 RETURN_ERROR1("RCC illegal for vertex program 1.0");
951 inst
->Opcode
= opcode
;
954 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
958 if (!Parse_String(parseState
, ","))
962 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
966 if (!Parse_String(parseState
, ";"))
974 Parse_AddressInstruction(struct parse_state
*parseState
, struct prog_instruction
*inst
)
976 inst
->Opcode
= OPCODE_ARL
;
978 /* Make ARB_vp backends happy */
979 inst
->DstReg
.File
= PROGRAM_ADDRESS
;
980 inst
->DstReg
.WriteMask
= WRITEMASK_X
;
981 inst
->DstReg
.Index
= 0;
984 if (!Parse_AddrReg(parseState
))
988 if (!Parse_String(parseState
, ","))
992 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
996 if (!Parse_String(parseState
, ";"))
1004 Parse_EndInstruction(struct parse_state
*parseState
, struct prog_instruction
*inst
)
1008 inst
->Opcode
= OPCODE_END
;
1010 /* this should fail! */
1011 if (Parse_Token(parseState
, token
))
1012 RETURN_ERROR2("Unexpected token after END:", token
);
1019 * The PRINT instruction is Mesa-specific and is meant as a debugging aid for
1020 * the vertex program developer.
1021 * The NV_vertex_program extension grammar is modified as follows:
1023 * <instruction> ::= <ARL-instruction>
1025 * | <PRINT-instruction>
1027 * <PRINT-instruction> ::= "PRINT" <string literal>
1028 * | "PRINT" <string literal> "," <srcReg>
1029 * | "PRINT" <string literal> "," <dstReg>
1032 Parse_PrintInstruction(struct parse_state
*parseState
, struct prog_instruction
*inst
)
1038 struct prog_src_register
*srcReg
= &inst
->SrcReg
[0];
1041 inst
->Opcode
= OPCODE_PRINT
;
1043 /* The first argument is a literal string 'just like this' */
1044 if (!Parse_String(parseState
, "'"))
1047 str
= parseState
->pos
;
1048 for (len
= 0; str
[len
] != '\''; len
++) /* find closing quote */
1050 parseState
->pos
+= len
+ 1;
1051 msg
= (GLubyte
*) _mesa_malloc(len
+ 1);
1053 _mesa_memcpy(msg
, str
, len
);
1058 if (Parse_String(parseState
, ",")) {
1060 /* The second argument is a register name */
1061 if (!Peek_Token(parseState
, token
))
1064 srcReg
->RelAddr
= GL_FALSE
;
1065 srcReg
->Negate
= NEGATE_NONE
;
1066 srcReg
->Swizzle
= SWIZZLE_NOOP
;
1068 /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
1069 * or an o[n] output register.
1071 if (token
[0] == 'R') {
1072 srcReg
->File
= PROGRAM_TEMPORARY
;
1073 if (!Parse_TempReg(parseState
, &idx
))
1075 srcReg
->Index
= idx
;
1077 else if (token
[0] == 'c') {
1078 srcReg
->File
= PROGRAM_ENV_PARAM
;
1079 if (!Parse_ParamReg(parseState
, srcReg
))
1082 else if (token
[0] == 'v') {
1083 srcReg
->File
= PROGRAM_INPUT
;
1084 if (!Parse_AttribReg(parseState
, &idx
))
1086 srcReg
->Index
= idx
;
1088 else if (token
[0] == 'o') {
1089 srcReg
->File
= PROGRAM_OUTPUT
;
1090 if (!Parse_OutputReg(parseState
, &idx
))
1092 srcReg
->Index
= idx
;
1095 RETURN_ERROR2("Bad source register name", token
);
1103 if (!Parse_String(parseState
, ";"))
1111 Parse_OptionSequence(struct parse_state
*parseState
,
1112 struct prog_instruction program
[])
1116 if (!Parse_String(parseState
, "OPTION"))
1117 return GL_TRUE
; /* ok, not an OPTION statement */
1118 if (Parse_String(parseState
, "NV_position_invariant")) {
1119 parseState
->isPositionInvariant
= GL_TRUE
;
1122 RETURN_ERROR1("unexpected OPTION statement");
1124 if (!Parse_String(parseState
, ";"))
1131 Parse_InstructionSequence(struct parse_state
*parseState
,
1132 struct prog_instruction program
[])
1135 struct prog_instruction
*inst
= program
+ parseState
->numInst
;
1137 /* Initialize the instruction */
1138 _mesa_init_instructions(inst
, 1);
1140 if (Parse_String(parseState
, "MOV")) {
1141 if (!Parse_UnaryOpInstruction(parseState
, inst
, OPCODE_MOV
))
1144 else if (Parse_String(parseState
, "LIT")) {
1145 if (!Parse_UnaryOpInstruction(parseState
, inst
, OPCODE_LIT
))
1148 else if (Parse_String(parseState
, "ABS")) {
1149 if (!Parse_UnaryOpInstruction(parseState
, inst
, OPCODE_ABS
))
1152 else if (Parse_String(parseState
, "MUL")) {
1153 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_MUL
))
1156 else if (Parse_String(parseState
, "ADD")) {
1157 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_ADD
))
1160 else if (Parse_String(parseState
, "DP3")) {
1161 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_DP3
))
1164 else if (Parse_String(parseState
, "DP4")) {
1165 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_DP4
))
1168 else if (Parse_String(parseState
, "DST")) {
1169 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_DST
))
1172 else if (Parse_String(parseState
, "MIN")) {
1173 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_MIN
))
1176 else if (Parse_String(parseState
, "MAX")) {
1177 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_MAX
))
1180 else if (Parse_String(parseState
, "SLT")) {
1181 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_SLT
))
1184 else if (Parse_String(parseState
, "SGE")) {
1185 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_SGE
))
1188 else if (Parse_String(parseState
, "DPH")) {
1189 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_DPH
))
1192 else if (Parse_String(parseState
, "SUB")) {
1193 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_SUB
))
1196 else if (Parse_String(parseState
, "MAD")) {
1197 if (!Parse_TriOpInstruction(parseState
, inst
, OPCODE_MAD
))
1200 else if (Parse_String(parseState
, "RCP")) {
1201 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_RCP
))
1204 else if (Parse_String(parseState
, "RSQ")) {
1205 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_RSQ
))
1208 else if (Parse_String(parseState
, "EXP")) {
1209 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_EXP
))
1212 else if (Parse_String(parseState
, "LOG")) {
1213 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_LOG
))
1216 else if (Parse_String(parseState
, "RCC")) {
1217 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_RCC
))
1220 else if (Parse_String(parseState
, "ARL")) {
1221 if (!Parse_AddressInstruction(parseState
, inst
))
1224 else if (Parse_String(parseState
, "PRINT")) {
1225 if (!Parse_PrintInstruction(parseState
, inst
))
1228 else if (Parse_String(parseState
, "END")) {
1229 if (!Parse_EndInstruction(parseState
, inst
))
1232 parseState
->numInst
++;
1233 return GL_TRUE
; /* all done */
1237 /* bad instruction name */
1238 RETURN_ERROR1("Unexpected token");
1241 /* examine input/output registers */
1242 if (inst
->DstReg
.File
== PROGRAM_OUTPUT
)
1243 parseState
->outputsWritten
|= (1 << inst
->DstReg
.Index
);
1244 else if (inst
->DstReg
.File
== PROGRAM_ENV_PARAM
)
1245 parseState
->anyProgRegsWritten
= GL_TRUE
;
1247 if (inst
->SrcReg
[0].File
== PROGRAM_INPUT
)
1248 parseState
->inputsRead
|= (1 << inst
->SrcReg
[0].Index
);
1249 if (inst
->SrcReg
[1].File
== PROGRAM_INPUT
)
1250 parseState
->inputsRead
|= (1 << inst
->SrcReg
[1].Index
);
1251 if (inst
->SrcReg
[2].File
== PROGRAM_INPUT
)
1252 parseState
->inputsRead
|= (1 << inst
->SrcReg
[2].Index
);
1254 parseState
->numInst
++;
1256 if (parseState
->numInst
>= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
)
1257 RETURN_ERROR1("Program too long");
1265 Parse_Program(struct parse_state
*parseState
,
1266 struct prog_instruction instBuffer
[])
1268 if (parseState
->isVersion1_1
) {
1269 if (!Parse_OptionSequence(parseState
, instBuffer
)) {
1273 return Parse_InstructionSequence(parseState
, instBuffer
);
1278 * Parse/compile the 'str' returning the compiled 'program'.
1279 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1280 * indicates the position of the error in 'str'.
1283 _mesa_parse_nv_vertex_program(GLcontext
*ctx
, GLenum dstTarget
,
1284 const GLubyte
*str
, GLsizei len
,
1285 struct gl_vertex_program
*program
)
1287 struct parse_state parseState
;
1288 struct prog_instruction instBuffer
[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
];
1289 struct prog_instruction
*newInst
;
1291 GLubyte
*programString
;
1293 /* Make a null-terminated copy of the program string */
1294 programString
= (GLubyte
*) MALLOC(len
+ 1);
1295 if (!programString
) {
1296 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1299 MEMCPY(programString
, str
, len
);
1300 programString
[len
] = 0;
1302 /* Get ready to parse */
1303 parseState
.ctx
= ctx
;
1304 parseState
.start
= programString
;
1305 parseState
.isPositionInvariant
= GL_FALSE
;
1306 parseState
.isVersion1_1
= GL_FALSE
;
1307 parseState
.numInst
= 0;
1308 parseState
.inputsRead
= 0;
1309 parseState
.outputsWritten
= 0;
1310 parseState
.anyProgRegsWritten
= GL_FALSE
;
1312 /* Reset error state */
1313 _mesa_set_program_error(ctx
, -1, NULL
);
1315 /* check the program header */
1316 if (_mesa_strncmp((const char *) programString
, "!!VP1.0", 7) == 0) {
1317 target
= GL_VERTEX_PROGRAM_NV
;
1318 parseState
.pos
= programString
+ 7;
1319 parseState
.isStateProgram
= GL_FALSE
;
1321 else if (_mesa_strncmp((const char *) programString
, "!!VP1.1", 7) == 0) {
1322 target
= GL_VERTEX_PROGRAM_NV
;
1323 parseState
.pos
= programString
+ 7;
1324 parseState
.isStateProgram
= GL_FALSE
;
1325 parseState
.isVersion1_1
= GL_TRUE
;
1327 else if (_mesa_strncmp((const char *) programString
, "!!VSP1.0", 8) == 0) {
1328 target
= GL_VERTEX_STATE_PROGRAM_NV
;
1329 parseState
.pos
= programString
+ 8;
1330 parseState
.isStateProgram
= GL_TRUE
;
1333 /* invalid header */
1334 ctx
->Program
.ErrorPos
= 0;
1335 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1339 /* make sure target and header match */
1340 if (target
!= dstTarget
) {
1341 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1342 "glLoadProgramNV(target mismatch)");
1347 if (Parse_Program(&parseState
, instBuffer
)) {
1348 /* successful parse! */
1350 if (parseState
.isStateProgram
) {
1351 if (!parseState
.anyProgRegsWritten
) {
1352 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1353 "glLoadProgramNV(c[#] not written)");
1358 if (!parseState
.isPositionInvariant
&&
1359 !(parseState
.outputsWritten
& (1 << VERT_RESULT_HPOS
))) {
1360 /* bit 1 = HPOS register */
1361 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1362 "glLoadProgramNV(HPOS not written)");
1367 /* copy the compiled instructions */
1368 assert(parseState
.numInst
<= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
);
1369 newInst
= _mesa_alloc_instructions(parseState
.numInst
);
1371 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1372 _mesa_free(programString
);
1373 return; /* out of memory */
1375 _mesa_copy_instructions(newInst
, instBuffer
, parseState
.numInst
);
1377 /* install the program */
1378 program
->Base
.Target
= target
;
1379 if (program
->Base
.String
) {
1380 _mesa_free(program
->Base
.String
);
1382 program
->Base
.String
= programString
;
1383 program
->Base
.Format
= GL_PROGRAM_FORMAT_ASCII_ARB
;
1384 if (program
->Base
.Instructions
) {
1385 _mesa_free(program
->Base
.Instructions
);
1387 program
->Base
.Instructions
= newInst
;
1388 program
->Base
.InputsRead
= parseState
.inputsRead
;
1389 if (parseState
.isPositionInvariant
)
1390 program
->Base
.InputsRead
|= VERT_BIT_POS
;
1391 program
->Base
.NumInstructions
= parseState
.numInst
;
1392 program
->Base
.OutputsWritten
= parseState
.outputsWritten
;
1393 program
->IsPositionInvariant
= parseState
.isPositionInvariant
;
1394 program
->IsNVProgram
= GL_TRUE
;
1397 _mesa_printf("--- glLoadProgramNV result ---\n");
1398 _mesa_fprint_program_opt(stdout
, &program
->Base
, PROG_PRINT_NV
, 0);
1399 _mesa_printf("------------------------------\n");
1404 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1405 /* NOTE: _mesa_set_program_error would have been called already */
1406 /* GL_NV_vertex_program isn't supposed to set the error string
1407 * so we reset it here.
1409 _mesa_set_program_error(ctx
, ctx
->Program
.ErrorPos
, NULL
);
1415 _mesa_nv_vertex_input_register_name(GLuint i
)
1417 ASSERT(i
< MAX_NV_VERTEX_PROGRAM_INPUTS
);
1418 return InputRegisters
[i
];
1423 _mesa_nv_vertex_output_register_name(GLuint i
)
1425 ASSERT(i
< MAX_NV_VERTEX_PROGRAM_OUTPUTS
);
1426 return OutputRegisters
[i
];