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/nvprogram.h"
44 #include "nvvertparse.h"
45 #include "prog_instruction.h"
46 #include "prog_parameter.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 GLboolean indirectRegisterFiles
;
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 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 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
= (GLint
) 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", "FOGC",
292 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7",
293 "PSIZ", "BFC0", "BFC1", NULL
299 * Parse a temporary register: Rnn
302 Parse_TempReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
306 /* Should be 'R##' */
307 if (!Parse_Token(parseState
, token
))
310 RETURN_ERROR1("Expected R##");
312 if (IsDigit(token
[1])) {
313 GLint reg
= atoi((char *) (token
+ 1));
314 if (reg
>= MAX_NV_VERTEX_PROGRAM_TEMPS
)
315 RETURN_ERROR1("Bad temporary register name");
319 RETURN_ERROR1("Bad temporary register name");
327 * Parse address register "A0.x"
330 Parse_AddrReg(struct parse_state
*parseState
)
333 if (!Parse_String(parseState
, "A0"))
337 if (!Parse_String(parseState
, "."))
341 if (!Parse_String(parseState
, "x"))
349 * Parse absolute program parameter register "c[##]"
352 Parse_AbsParamReg(struct parse_state
*parseState
, GLint
*regNum
)
356 if (!Parse_String(parseState
, "c"))
359 if (!Parse_String(parseState
, "["))
362 if (!Parse_Token(parseState
, token
))
365 if (IsDigit(token
[0])) {
366 /* a numbered program parameter register */
367 GLint reg
= atoi((char *) token
);
368 if (reg
>= MAX_NV_VERTEX_PROGRAM_PARAMS
)
369 RETURN_ERROR1("Bad program parameter number");
376 if (!Parse_String(parseState
, "]"))
384 Parse_ParamReg(struct parse_state
*parseState
, struct prog_src_register
*srcReg
)
388 if (!Parse_String(parseState
, "c"))
391 if (!Parse_String(parseState
, "["))
394 if (!Peek_Token(parseState
, token
))
397 if (IsDigit(token
[0])) {
398 /* a numbered program parameter register */
400 (void) Parse_Token(parseState
, token
);
401 reg
= atoi((char *) token
);
402 if (reg
>= MAX_NV_VERTEX_PROGRAM_PARAMS
)
403 RETURN_ERROR1("Bad program parameter number");
404 srcReg
->File
= PROGRAM_ENV_PARAM
;
407 else if (strcmp((const char *) token
, "A0") == 0) {
408 /* address register "A0.x" */
409 if (!Parse_AddrReg(parseState
))
412 srcReg
->RelAddr
= GL_TRUE
;
413 srcReg
->File
= PROGRAM_ENV_PARAM
;
414 parseState
->indirectRegisterFiles
|= (1 << srcReg
->File
);
415 /* Look for +/-N offset */
416 if (!Peek_Token(parseState
, token
))
419 if (token
[0] == '-' || token
[0] == '+') {
420 const GLubyte sign
= token
[0];
421 (void) Parse_Token(parseState
, token
); /* consume +/- */
423 /* an integer should be next */
424 if (!Parse_Token(parseState
, token
))
427 if (IsDigit(token
[0])) {
428 const GLint k
= atoi((char *) token
);
431 RETURN_ERROR1("Bad address offset");
436 RETURN_ERROR1("Bad address offset");
445 /* probably got a ']', catch it below */
452 /* Match closing ']' */
453 if (!Parse_String(parseState
, "]"))
461 * Parse v[#] or v[<name>]
464 Parse_AttribReg(struct parse_state
*parseState
, GLint
*tempRegNum
)
470 if (!Parse_String(parseState
, "v"))
474 if (!Parse_String(parseState
, "["))
477 /* match number or named register */
478 if (!Parse_Token(parseState
, token
))
481 if (parseState
->isStateProgram
&& token
[0] != '0')
482 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
484 if (IsDigit(token
[0])) {
485 GLint reg
= atoi((char *) token
);
486 if (reg
>= MAX_NV_VERTEX_PROGRAM_INPUTS
)
487 RETURN_ERROR1("Bad vertex attribute register name");
491 for (j
= 0; InputRegisters
[j
]; j
++) {
492 if (strcmp((const char *) token
, InputRegisters
[j
]) == 0) {
497 if (!InputRegisters
[j
]) {
498 /* unknown input register label */
499 RETURN_ERROR2("Bad register name", token
);
504 if (!Parse_String(parseState
, "]"))
512 Parse_OutputReg(struct parse_state
*parseState
, GLint
*outputRegNum
)
518 if (!Parse_String(parseState
, "o"))
522 if (!Parse_String(parseState
, "["))
525 /* Get output reg name */
526 if (!Parse_Token(parseState
, token
))
529 if (parseState
->isPositionInvariant
)
530 start
= 1; /* skip HPOS register name */
534 /* try to match an output register name */
535 for (j
= start
; OutputRegisters
[j
]; j
++) {
536 if (strcmp((const char *) token
, OutputRegisters
[j
]) == 0) {
541 if (!OutputRegisters
[j
])
542 RETURN_ERROR1("Unrecognized output register name");
545 if (!Parse_String(parseState
, "]"))
546 RETURN_ERROR1("Expected ]");
553 Parse_MaskedDstReg(struct parse_state
*parseState
, struct prog_dst_register
*dstReg
)
558 /* Dst reg can be R<n> or o[n] */
559 if (!Peek_Token(parseState
, token
))
562 if (token
[0] == 'R') {
563 /* a temporary register */
564 dstReg
->File
= PROGRAM_TEMPORARY
;
565 if (!Parse_TempReg(parseState
, &idx
))
569 else if (!parseState
->isStateProgram
&& token
[0] == 'o') {
570 /* an output register */
571 dstReg
->File
= PROGRAM_OUTPUT
;
572 if (!Parse_OutputReg(parseState
, &idx
))
576 else if (parseState
->isStateProgram
&& token
[0] == 'c' &&
577 parseState
->isStateProgram
) {
578 /* absolute program parameter register */
579 /* Only valid for vertex state programs */
580 dstReg
->File
= PROGRAM_ENV_PARAM
;
581 if (!Parse_AbsParamReg(parseState
, &idx
))
586 RETURN_ERROR1("Bad destination register name");
589 /* Parse optional write mask */
590 if (!Peek_Token(parseState
, token
))
593 if (token
[0] == '.') {
597 if (!Parse_String(parseState
, "."))
600 if (!Parse_Token(parseState
, token
))
603 dstReg
->WriteMask
= 0;
605 if (token
[k
] == 'x') {
606 dstReg
->WriteMask
|= WRITEMASK_X
;
609 if (token
[k
] == 'y') {
610 dstReg
->WriteMask
|= WRITEMASK_Y
;
613 if (token
[k
] == 'z') {
614 dstReg
->WriteMask
|= WRITEMASK_Z
;
617 if (token
[k
] == 'w') {
618 dstReg
->WriteMask
|= WRITEMASK_W
;
622 RETURN_ERROR1("Bad writemask character");
627 dstReg
->WriteMask
= WRITEMASK_XYZW
;
634 Parse_SwizzleSrcReg(struct parse_state
*parseState
, struct prog_src_register
*srcReg
)
639 srcReg
->RelAddr
= GL_FALSE
;
642 if (!Peek_Token(parseState
, token
))
644 if (token
[0] == '-') {
645 (void) Parse_String(parseState
, "-");
646 srcReg
->Negate
= NEGATE_XYZW
;
647 if (!Peek_Token(parseState
, token
))
651 srcReg
->Negate
= NEGATE_NONE
;
654 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
655 if (token
[0] == 'R') {
656 srcReg
->File
= PROGRAM_TEMPORARY
;
657 if (!Parse_TempReg(parseState
, &idx
))
661 else if (token
[0] == 'c') {
662 if (!Parse_ParamReg(parseState
, srcReg
))
665 else if (token
[0] == 'v') {
666 srcReg
->File
= PROGRAM_INPUT
;
667 if (!Parse_AttribReg(parseState
, &idx
))
672 RETURN_ERROR2("Bad source register name", token
);
675 /* init swizzle fields */
676 srcReg
->Swizzle
= SWIZZLE_NOOP
;
678 /* Look for optional swizzle suffix */
679 if (!Peek_Token(parseState
, token
))
681 if (token
[0] == '.') {
682 (void) Parse_String(parseState
, "."); /* consume . */
684 if (!Parse_Token(parseState
, token
))
688 /* single letter swizzle */
690 srcReg
->Swizzle
= SWIZZLE_XXXX
;
691 else if (token
[0] == 'y')
692 srcReg
->Swizzle
= SWIZZLE_YYYY
;
693 else if (token
[0] == 'z')
694 srcReg
->Swizzle
= SWIZZLE_ZZZZ
;
695 else if (token
[0] == 'w')
696 srcReg
->Swizzle
= SWIZZLE_WWWW
;
698 RETURN_ERROR1("Expected x, y, z, or w");
701 /* 2, 3 or 4-component swizzle */
706 for (k
= 0; token
[k
] && k
< 5; k
++) {
708 srcReg
->Swizzle
|= 0 << (k
*3);
709 else if (token
[k
] == 'y')
710 srcReg
->Swizzle
|= 1 << (k
*3);
711 else if (token
[k
] == 'z')
712 srcReg
->Swizzle
|= 2 << (k
*3);
713 else if (token
[k
] == 'w')
714 srcReg
->Swizzle
|= 3 << (k
*3);
728 Parse_ScalarSrcReg(struct parse_state
*parseState
, struct prog_src_register
*srcReg
)
733 srcReg
->RelAddr
= GL_FALSE
;
736 if (!Peek_Token(parseState
, token
))
738 if (token
[0] == '-') {
739 srcReg
->Negate
= NEGATE_XYZW
;
740 (void) Parse_String(parseState
, "-"); /* consume '-' */
741 if (!Peek_Token(parseState
, token
))
745 srcReg
->Negate
= NEGATE_NONE
;
748 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
749 if (token
[0] == 'R') {
750 srcReg
->File
= PROGRAM_TEMPORARY
;
751 if (!Parse_TempReg(parseState
, &idx
))
755 else if (token
[0] == 'c') {
756 if (!Parse_ParamReg(parseState
, srcReg
))
759 else if (token
[0] == 'v') {
760 srcReg
->File
= PROGRAM_INPUT
;
761 if (!Parse_AttribReg(parseState
, &idx
))
766 RETURN_ERROR2("Bad source register name", token
);
769 /* Look for .[xyzw] suffix */
770 if (!Parse_String(parseState
, "."))
773 if (!Parse_Token(parseState
, token
))
776 if (token
[0] == 'x' && token
[1] == 0) {
779 else if (token
[0] == 'y' && token
[1] == 0) {
782 else if (token
[0] == 'z' && token
[1] == 0) {
785 else if (token
[0] == 'w' && token
[1] == 0) {
789 RETURN_ERROR1("Bad scalar source suffix");
797 Parse_UnaryOpInstruction(struct parse_state
*parseState
,
798 struct prog_instruction
*inst
,
799 enum prog_opcode opcode
)
801 if (opcode
== OPCODE_ABS
&& !parseState
->isVersion1_1
)
802 RETURN_ERROR1("ABS illegal for vertex program 1.0");
804 inst
->Opcode
= opcode
;
807 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
811 if (!Parse_String(parseState
, ","))
815 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
819 if (!Parse_String(parseState
, ";"))
827 Parse_BiOpInstruction(struct parse_state
*parseState
,
828 struct prog_instruction
*inst
,
829 enum prog_opcode opcode
)
831 if (opcode
== OPCODE_DPH
&& !parseState
->isVersion1_1
)
832 RETURN_ERROR1("DPH illegal for vertex program 1.0");
833 if (opcode
== OPCODE_SUB
&& !parseState
->isVersion1_1
)
834 RETURN_ERROR1("SUB illegal for vertex program 1.0");
836 inst
->Opcode
= opcode
;
839 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
843 if (!Parse_String(parseState
, ","))
847 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
851 if (!Parse_String(parseState
, ","))
855 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
859 if (!Parse_String(parseState
, ";"))
862 /* make sure we don't reference more than one program parameter register */
863 if (inst
->SrcReg
[0].File
== PROGRAM_ENV_PARAM
&&
864 inst
->SrcReg
[1].File
== PROGRAM_ENV_PARAM
&&
865 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
)
866 RETURN_ERROR1("Can't reference two program parameter registers");
868 /* make sure we don't reference more than one vertex attribute register */
869 if (inst
->SrcReg
[0].File
== PROGRAM_INPUT
&&
870 inst
->SrcReg
[1].File
== PROGRAM_INPUT
&&
871 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
)
872 RETURN_ERROR1("Can't reference two vertex attribute registers");
879 Parse_TriOpInstruction(struct parse_state
*parseState
,
880 struct prog_instruction
*inst
,
881 enum prog_opcode opcode
)
883 inst
->Opcode
= opcode
;
886 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
890 if (!Parse_String(parseState
, ","))
894 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[0]))
898 if (!Parse_String(parseState
, ","))
902 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[1]))
906 if (!Parse_String(parseState
, ","))
910 if (!Parse_SwizzleSrcReg(parseState
, &inst
->SrcReg
[2]))
914 if (!Parse_String(parseState
, ";"))
917 /* make sure we don't reference more than one program parameter register */
918 if ((inst
->SrcReg
[0].File
== PROGRAM_ENV_PARAM
&&
919 inst
->SrcReg
[1].File
== PROGRAM_ENV_PARAM
&&
920 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
) ||
921 (inst
->SrcReg
[0].File
== PROGRAM_ENV_PARAM
&&
922 inst
->SrcReg
[2].File
== PROGRAM_ENV_PARAM
&&
923 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[2].Index
) ||
924 (inst
->SrcReg
[1].File
== PROGRAM_ENV_PARAM
&&
925 inst
->SrcReg
[2].File
== PROGRAM_ENV_PARAM
&&
926 inst
->SrcReg
[1].Index
!= inst
->SrcReg
[2].Index
))
927 RETURN_ERROR1("Can only reference one program register");
929 /* make sure we don't reference more than one vertex attribute register */
930 if ((inst
->SrcReg
[0].File
== PROGRAM_INPUT
&&
931 inst
->SrcReg
[1].File
== PROGRAM_INPUT
&&
932 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[1].Index
) ||
933 (inst
->SrcReg
[0].File
== PROGRAM_INPUT
&&
934 inst
->SrcReg
[2].File
== PROGRAM_INPUT
&&
935 inst
->SrcReg
[0].Index
!= inst
->SrcReg
[2].Index
) ||
936 (inst
->SrcReg
[1].File
== PROGRAM_INPUT
&&
937 inst
->SrcReg
[2].File
== PROGRAM_INPUT
&&
938 inst
->SrcReg
[1].Index
!= inst
->SrcReg
[2].Index
))
939 RETURN_ERROR1("Can only reference one input register");
946 Parse_ScalarInstruction(struct parse_state
*parseState
,
947 struct prog_instruction
*inst
,
948 enum prog_opcode opcode
)
950 if (opcode
== OPCODE_RCC
&& !parseState
->isVersion1_1
)
951 RETURN_ERROR1("RCC illegal for vertex program 1.0");
953 inst
->Opcode
= opcode
;
956 if (!Parse_MaskedDstReg(parseState
, &inst
->DstReg
))
960 if (!Parse_String(parseState
, ","))
964 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
968 if (!Parse_String(parseState
, ";"))
976 Parse_AddressInstruction(struct parse_state
*parseState
, struct prog_instruction
*inst
)
978 inst
->Opcode
= OPCODE_ARL
;
980 /* Make ARB_vp backends happy */
981 inst
->DstReg
.File
= PROGRAM_ADDRESS
;
982 inst
->DstReg
.WriteMask
= WRITEMASK_X
;
983 inst
->DstReg
.Index
= 0;
986 if (!Parse_AddrReg(parseState
))
990 if (!Parse_String(parseState
, ","))
994 if (!Parse_ScalarSrcReg(parseState
, &inst
->SrcReg
[0]))
998 if (!Parse_String(parseState
, ";"))
1006 Parse_EndInstruction(struct parse_state
*parseState
, struct prog_instruction
*inst
)
1010 inst
->Opcode
= OPCODE_END
;
1012 /* this should fail! */
1013 if (Parse_Token(parseState
, token
))
1014 RETURN_ERROR2("Unexpected token after END:", token
);
1021 * The PRINT instruction is Mesa-specific and is meant as a debugging aid for
1022 * the vertex program developer.
1023 * The NV_vertex_program extension grammar is modified as follows:
1025 * <instruction> ::= <ARL-instruction>
1027 * | <PRINT-instruction>
1029 * <PRINT-instruction> ::= "PRINT" <string literal>
1030 * | "PRINT" <string literal> "," <srcReg>
1031 * | "PRINT" <string literal> "," <dstReg>
1034 Parse_PrintInstruction(struct parse_state
*parseState
, struct prog_instruction
*inst
)
1040 struct prog_src_register
*srcReg
= &inst
->SrcReg
[0];
1043 inst
->Opcode
= OPCODE_PRINT
;
1045 /* The first argument is a literal string 'just like this' */
1046 if (!Parse_String(parseState
, "'"))
1049 str
= parseState
->pos
;
1050 for (len
= 0; str
[len
] != '\''; len
++) /* find closing quote */
1052 parseState
->pos
+= len
+ 1;
1053 msg
= (GLubyte
*) malloc(len
+ 1);
1055 memcpy(msg
, str
, len
);
1060 if (Parse_String(parseState
, ",")) {
1062 /* The second argument is a register name */
1063 if (!Peek_Token(parseState
, token
))
1066 srcReg
->RelAddr
= GL_FALSE
;
1067 srcReg
->Negate
= NEGATE_NONE
;
1068 srcReg
->Swizzle
= SWIZZLE_NOOP
;
1070 /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
1071 * or an o[n] output register.
1073 if (token
[0] == 'R') {
1074 srcReg
->File
= PROGRAM_TEMPORARY
;
1075 if (!Parse_TempReg(parseState
, &idx
))
1077 srcReg
->Index
= idx
;
1079 else if (token
[0] == 'c') {
1080 srcReg
->File
= PROGRAM_ENV_PARAM
;
1081 if (!Parse_ParamReg(parseState
, srcReg
))
1084 else if (token
[0] == 'v') {
1085 srcReg
->File
= PROGRAM_INPUT
;
1086 if (!Parse_AttribReg(parseState
, &idx
))
1088 srcReg
->Index
= idx
;
1090 else if (token
[0] == 'o') {
1091 srcReg
->File
= PROGRAM_OUTPUT
;
1092 if (!Parse_OutputReg(parseState
, &idx
))
1094 srcReg
->Index
= idx
;
1097 RETURN_ERROR2("Bad source register name", token
);
1101 srcReg
->File
= PROGRAM_UNDEFINED
;
1105 if (!Parse_String(parseState
, ";"))
1113 Parse_OptionSequence(struct parse_state
*parseState
,
1114 struct prog_instruction program
[])
1118 if (!Parse_String(parseState
, "OPTION"))
1119 return GL_TRUE
; /* ok, not an OPTION statement */
1120 if (Parse_String(parseState
, "NV_position_invariant")) {
1121 parseState
->isPositionInvariant
= GL_TRUE
;
1124 RETURN_ERROR1("unexpected OPTION statement");
1126 if (!Parse_String(parseState
, ";"))
1133 Parse_InstructionSequence(struct parse_state
*parseState
,
1134 struct prog_instruction program
[])
1137 struct prog_instruction
*inst
= program
+ parseState
->numInst
;
1139 /* Initialize the instruction */
1140 _mesa_init_instructions(inst
, 1);
1142 if (Parse_String(parseState
, "MOV")) {
1143 if (!Parse_UnaryOpInstruction(parseState
, inst
, OPCODE_MOV
))
1146 else if (Parse_String(parseState
, "LIT")) {
1147 if (!Parse_UnaryOpInstruction(parseState
, inst
, OPCODE_LIT
))
1150 else if (Parse_String(parseState
, "ABS")) {
1151 if (!Parse_UnaryOpInstruction(parseState
, inst
, OPCODE_ABS
))
1154 else if (Parse_String(parseState
, "MUL")) {
1155 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_MUL
))
1158 else if (Parse_String(parseState
, "ADD")) {
1159 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_ADD
))
1162 else if (Parse_String(parseState
, "DP3")) {
1163 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_DP3
))
1166 else if (Parse_String(parseState
, "DP4")) {
1167 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_DP4
))
1170 else if (Parse_String(parseState
, "DST")) {
1171 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_DST
))
1174 else if (Parse_String(parseState
, "MIN")) {
1175 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_MIN
))
1178 else if (Parse_String(parseState
, "MAX")) {
1179 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_MAX
))
1182 else if (Parse_String(parseState
, "SLT")) {
1183 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_SLT
))
1186 else if (Parse_String(parseState
, "SGE")) {
1187 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_SGE
))
1190 else if (Parse_String(parseState
, "DPH")) {
1191 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_DPH
))
1194 else if (Parse_String(parseState
, "SUB")) {
1195 if (!Parse_BiOpInstruction(parseState
, inst
, OPCODE_SUB
))
1198 else if (Parse_String(parseState
, "MAD")) {
1199 if (!Parse_TriOpInstruction(parseState
, inst
, OPCODE_MAD
))
1202 else if (Parse_String(parseState
, "RCP")) {
1203 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_RCP
))
1206 else if (Parse_String(parseState
, "RSQ")) {
1207 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_RSQ
))
1210 else if (Parse_String(parseState
, "EXP")) {
1211 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_EXP
))
1214 else if (Parse_String(parseState
, "LOG")) {
1215 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_LOG
))
1218 else if (Parse_String(parseState
, "RCC")) {
1219 if (!Parse_ScalarInstruction(parseState
, inst
, OPCODE_RCC
))
1222 else if (Parse_String(parseState
, "ARL")) {
1223 if (!Parse_AddressInstruction(parseState
, inst
))
1226 else if (Parse_String(parseState
, "PRINT")) {
1227 if (!Parse_PrintInstruction(parseState
, inst
))
1230 else if (Parse_String(parseState
, "END")) {
1231 if (!Parse_EndInstruction(parseState
, inst
))
1234 parseState
->numInst
++;
1235 return GL_TRUE
; /* all done */
1239 /* bad instruction name */
1240 RETURN_ERROR1("Unexpected token");
1243 /* examine input/output registers */
1244 if (inst
->DstReg
.File
== PROGRAM_OUTPUT
)
1245 parseState
->outputsWritten
|= (1 << inst
->DstReg
.Index
);
1246 else if (inst
->DstReg
.File
== PROGRAM_ENV_PARAM
)
1247 parseState
->anyProgRegsWritten
= GL_TRUE
;
1249 if (inst
->SrcReg
[0].File
== PROGRAM_INPUT
)
1250 parseState
->inputsRead
|= (1 << inst
->SrcReg
[0].Index
);
1251 if (inst
->SrcReg
[1].File
== PROGRAM_INPUT
)
1252 parseState
->inputsRead
|= (1 << inst
->SrcReg
[1].Index
);
1253 if (inst
->SrcReg
[2].File
== PROGRAM_INPUT
)
1254 parseState
->inputsRead
|= (1 << inst
->SrcReg
[2].Index
);
1256 parseState
->numInst
++;
1258 if (parseState
->numInst
>= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
)
1259 RETURN_ERROR1("Program too long");
1267 Parse_Program(struct parse_state
*parseState
,
1268 struct prog_instruction instBuffer
[])
1270 if (parseState
->isVersion1_1
) {
1271 if (!Parse_OptionSequence(parseState
, instBuffer
)) {
1275 return Parse_InstructionSequence(parseState
, instBuffer
);
1280 * Parse/compile the 'str' returning the compiled 'program'.
1281 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1282 * indicates the position of the error in 'str'.
1285 _mesa_parse_nv_vertex_program(GLcontext
*ctx
, GLenum dstTarget
,
1286 const GLubyte
*str
, GLsizei len
,
1287 struct gl_vertex_program
*program
)
1289 struct parse_state parseState
;
1290 struct prog_instruction instBuffer
[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
];
1291 struct prog_instruction
*newInst
;
1293 GLubyte
*programString
;
1295 /* Make a null-terminated copy of the program string */
1296 programString
= (GLubyte
*) MALLOC(len
+ 1);
1297 if (!programString
) {
1298 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1301 memcpy(programString
, str
, len
);
1302 programString
[len
] = 0;
1304 /* Get ready to parse */
1305 parseState
.ctx
= ctx
;
1306 parseState
.start
= programString
;
1307 parseState
.isPositionInvariant
= GL_FALSE
;
1308 parseState
.isVersion1_1
= GL_FALSE
;
1309 parseState
.numInst
= 0;
1310 parseState
.inputsRead
= 0;
1311 parseState
.outputsWritten
= 0;
1312 parseState
.anyProgRegsWritten
= GL_FALSE
;
1313 parseState
.indirectRegisterFiles
= 0x0;
1315 /* Reset error state */
1316 _mesa_set_program_error(ctx
, -1, NULL
);
1318 /* check the program header */
1319 if (strncmp((const char *) programString
, "!!VP1.0", 7) == 0) {
1320 target
= GL_VERTEX_PROGRAM_NV
;
1321 parseState
.pos
= programString
+ 7;
1322 parseState
.isStateProgram
= GL_FALSE
;
1324 else if (strncmp((const char *) programString
, "!!VP1.1", 7) == 0) {
1325 target
= GL_VERTEX_PROGRAM_NV
;
1326 parseState
.pos
= programString
+ 7;
1327 parseState
.isStateProgram
= GL_FALSE
;
1328 parseState
.isVersion1_1
= GL_TRUE
;
1330 else if (strncmp((const char *) programString
, "!!VSP1.0", 8) == 0) {
1331 target
= GL_VERTEX_STATE_PROGRAM_NV
;
1332 parseState
.pos
= programString
+ 8;
1333 parseState
.isStateProgram
= GL_TRUE
;
1336 /* invalid header */
1337 ctx
->Program
.ErrorPos
= 0;
1338 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV(bad header)");
1342 /* make sure target and header match */
1343 if (target
!= dstTarget
) {
1344 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1345 "glLoadProgramNV(target mismatch)");
1350 if (Parse_Program(&parseState
, instBuffer
)) {
1351 gl_state_index state_tokens
[STATE_LENGTH
] = {0, 0, 0, 0, 0};
1354 /* successful parse! */
1356 if (parseState
.isStateProgram
) {
1357 if (!parseState
.anyProgRegsWritten
) {
1358 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1359 "glLoadProgramNV(c[#] not written)");
1364 if (!parseState
.isPositionInvariant
&&
1365 !(parseState
.outputsWritten
& (1 << VERT_RESULT_HPOS
))) {
1366 /* bit 1 = HPOS register */
1367 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1368 "glLoadProgramNV(HPOS not written)");
1373 /* copy the compiled instructions */
1374 assert(parseState
.numInst
<= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS
);
1375 newInst
= _mesa_alloc_instructions(parseState
.numInst
);
1377 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glLoadProgramNV");
1378 free(programString
);
1379 return; /* out of memory */
1381 _mesa_copy_instructions(newInst
, instBuffer
, parseState
.numInst
);
1383 /* install the program */
1384 program
->Base
.Target
= target
;
1385 if (program
->Base
.String
) {
1386 free(program
->Base
.String
);
1388 program
->Base
.String
= programString
;
1389 program
->Base
.Format
= GL_PROGRAM_FORMAT_ASCII_ARB
;
1390 if (program
->Base
.Instructions
) {
1391 free(program
->Base
.Instructions
);
1393 program
->Base
.Instructions
= newInst
;
1394 program
->Base
.InputsRead
= parseState
.inputsRead
;
1395 if (parseState
.isPositionInvariant
)
1396 program
->Base
.InputsRead
|= VERT_BIT_POS
;
1397 program
->Base
.NumInstructions
= parseState
.numInst
;
1398 program
->Base
.OutputsWritten
= parseState
.outputsWritten
;
1399 program
->IsPositionInvariant
= parseState
.isPositionInvariant
;
1400 program
->IsNVProgram
= GL_TRUE
;
1403 printf("--- glLoadProgramNV result ---\n");
1404 _mesa_fprint_program_opt(stdout
, &program
->Base
, PROG_PRINT_NV
, 0);
1405 printf("------------------------------\n");
1408 if (program
->Base
.Parameters
)
1409 _mesa_free_parameter_list(program
->Base
.Parameters
);
1411 program
->Base
.Parameters
= _mesa_new_parameter_list ();
1412 program
->Base
.NumParameters
= 0;
1414 program
->Base
.IndirectRegisterFiles
= parseState
.indirectRegisterFiles
;
1416 state_tokens
[0] = STATE_VERTEX_PROGRAM
;
1417 state_tokens
[1] = STATE_ENV
;
1418 /* Add refs to all of the potential params, in order. If we want to not
1419 * upload everything, _mesa_layout_parameters is the answer.
1421 for (i
= 0; i
< MAX_NV_VERTEX_PROGRAM_PARAMS
; i
++) {
1423 state_tokens
[2] = i
;
1424 index
= _mesa_add_state_reference(program
->Base
.Parameters
,
1428 program
->Base
.NumParameters
= program
->Base
.Parameters
->NumParameters
;
1430 _mesa_setup_nv_temporary_count(ctx
, &program
->Base
);
1431 _mesa_emit_nv_temp_initialization(ctx
, &program
->Base
);
1435 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glLoadProgramNV");
1436 /* NOTE: _mesa_set_program_error would have been called already */
1437 /* GL_NV_vertex_program isn't supposed to set the error string
1438 * so we reset it here.
1440 _mesa_set_program_error(ctx
, ctx
->Program
.ErrorPos
, NULL
);
1446 _mesa_nv_vertex_input_register_name(GLuint i
)
1448 ASSERT(i
< MAX_NV_VERTEX_PROGRAM_INPUTS
);
1449 return InputRegisters
[i
];
1454 _mesa_nv_vertex_output_register_name(GLuint i
)
1456 ASSERT(i
< MAX_NV_VERTEX_PROGRAM_OUTPUTS
);
1457 return OutputRegisters
[i
];