Merge master and fix conflicts
[mesa.git] / src / mesa / shader / nvvertparse.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
4 *
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
6 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
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.
23 */
24
25 /**
26 * \file nvvertparse.c
27 * NVIDIA vertex program parser.
28 * \author Brian Paul
29 */
30
31 /*
32 * Regarding GL_NV_vertex_program, GL_NV_vertex_program1_1:
33 *
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.
38 */
39
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"
48 #include "program.h"
49
50
51 /**
52 * Current parsing state. This structure is passed among the parsing
53 * functions and keeps track of the current parser position and various
54 * program attributes.
55 */
56 struct parse_state {
57 GLcontext *ctx;
58 const GLubyte *start;
59 const GLubyte *pos;
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 */
68 };
69
70
71 /*
72 * Called whenever we find an error during parsing.
73 */
74 static void
75 record_error(struct parse_state *parseState, const char *msg, int lineNo)
76 {
77 #ifdef DEBUG
78 GLint line, column;
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);
86 #else
87 (void) lineNo;
88 #endif
89
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,
94 msg);
95 }
96 }
97
98
99 #define RETURN_ERROR \
100 do { \
101 record_error(parseState, "Unexpected end of input.", __LINE__); \
102 return GL_FALSE; \
103 } while(0)
104
105 #define RETURN_ERROR1(msg) \
106 do { \
107 record_error(parseState, msg, __LINE__); \
108 return GL_FALSE; \
109 } while(0)
110
111 #define RETURN_ERROR2(msg1, msg2) \
112 do { \
113 char err[1000]; \
114 _mesa_sprintf(err, "%s %s", msg1, msg2); \
115 record_error(parseState, err, __LINE__); \
116 return GL_FALSE; \
117 } while(0)
118
119
120
121
122
123 static GLboolean IsLetter(GLubyte b)
124 {
125 return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z');
126 }
127
128
129 static GLboolean IsDigit(GLubyte b)
130 {
131 return b >= '0' && b <= '9';
132 }
133
134
135 static GLboolean IsWhitespace(GLubyte b)
136 {
137 return b == ' ' || b == '\t' || b == '\n' || b == '\r';
138 }
139
140
141 /**
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.
145 */
146 static GLint
147 GetToken(struct parse_state *parseState, GLubyte *token)
148 {
149 const GLubyte *str = parseState->pos;
150 GLint i = 0, j = 0;
151
152 token[0] = 0;
153
154 /* skip whitespace and comments */
155 while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
156 if (str[i] == '#') {
157 /* skip comment */
158 while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
159 i++;
160 }
161 if (str[i] == '\n' || str[i] == '\r')
162 parseState->curLine = str + i + 1;
163 }
164 else {
165 /* skip whitespace */
166 if (str[i] == '\n' || str[i] == '\r')
167 parseState->curLine = str + i + 1;
168 i++;
169 }
170 }
171
172 if (str[i] == 0)
173 return -i;
174
175 /* try matching an integer */
176 while (str[i] && IsDigit(str[i])) {
177 token[j++] = str[i++];
178 }
179 if (j > 0 || !str[i]) {
180 token[j] = 0;
181 return i;
182 }
183
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++];
188 }
189 token[j] = 0;
190 return i;
191 }
192
193 /* punctuation character */
194 if (str[i]) {
195 token[0] = str[i++];
196 token[1] = 0;
197 return i;
198 }
199
200 /* end of input */
201 token[0] = 0;
202 return i;
203 }
204
205
206 /**
207 * Get next token from input stream and increment stream pointer past token.
208 */
209 static GLboolean
210 Parse_Token(struct parse_state *parseState, GLubyte *token)
211 {
212 GLint i;
213 i = GetToken(parseState, token);
214 if (i <= 0) {
215 parseState->pos += (-i);
216 return GL_FALSE;
217 }
218 parseState->pos += i;
219 return GL_TRUE;
220 }
221
222
223 /**
224 * Get next token from input stream but don't increment stream pointer.
225 */
226 static GLboolean
227 Peek_Token(struct parse_state *parseState, GLubyte *token)
228 {
229 GLint i, len;
230 i = GetToken(parseState, token);
231 if (i <= 0) {
232 parseState->pos += (-i);
233 return GL_FALSE;
234 }
235 len = (GLint)_mesa_strlen((const char *) token);
236 parseState->pos += (i - len);
237 return GL_TRUE;
238 }
239
240
241 /**
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.
245 */
246 static GLboolean
247 Parse_String(struct parse_state *parseState, const char *pattern)
248 {
249 const GLubyte *m;
250 GLint i;
251
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;
257 }
258 if (*parseState->pos == '\n' || *parseState->pos == '\r')
259 parseState->curLine = parseState->pos + 1;
260 }
261 else {
262 /* skip whitespace */
263 if (*parseState->pos == '\n' || *parseState->pos == '\r')
264 parseState->curLine = parseState->pos + 1;
265 parseState->pos += 1;
266 }
267 }
268
269 /* Try to match the pattern */
270 m = parseState->pos;
271 for (i = 0; pattern[i]; i++) {
272 if (*m != (GLubyte) pattern[i])
273 return GL_FALSE;
274 m += 1;
275 }
276 parseState->pos = m;
277
278 return GL_TRUE; /* success */
279 }
280
281
282 /**********************************************************************/
283
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
287 };
288
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
293 };
294
295
296
297 /**
298 * Parse a temporary register: Rnn
299 */
300 static GLboolean
301 Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
302 {
303 GLubyte token[100];
304
305 /* Should be 'R##' */
306 if (!Parse_Token(parseState, token))
307 RETURN_ERROR;
308 if (token[0] != 'R')
309 RETURN_ERROR1("Expected R##");
310
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");
315 *tempRegNum = reg;
316 }
317 else {
318 RETURN_ERROR1("Bad temporary register name");
319 }
320
321 return GL_TRUE;
322 }
323
324
325 /**
326 * Parse address register "A0.x"
327 */
328 static GLboolean
329 Parse_AddrReg(struct parse_state *parseState)
330 {
331 /* match 'A0' */
332 if (!Parse_String(parseState, "A0"))
333 RETURN_ERROR;
334
335 /* match '.' */
336 if (!Parse_String(parseState, "."))
337 RETURN_ERROR;
338
339 /* match 'x' */
340 if (!Parse_String(parseState, "x"))
341 RETURN_ERROR;
342
343 return GL_TRUE;
344 }
345
346
347 /**
348 * Parse absolute program parameter register "c[##]"
349 */
350 static GLboolean
351 Parse_AbsParamReg(struct parse_state *parseState, GLint *regNum)
352 {
353 GLubyte token[100];
354
355 if (!Parse_String(parseState, "c"))
356 RETURN_ERROR;
357
358 if (!Parse_String(parseState, "["))
359 RETURN_ERROR;
360
361 if (!Parse_Token(parseState, token))
362 RETURN_ERROR;
363
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");
369 *regNum = reg;
370 }
371 else {
372 RETURN_ERROR;
373 }
374
375 if (!Parse_String(parseState, "]"))
376 RETURN_ERROR;
377
378 return GL_TRUE;
379 }
380
381
382 static GLboolean
383 Parse_ParamReg(struct parse_state *parseState, struct prog_src_register *srcReg)
384 {
385 GLubyte token[100];
386
387 if (!Parse_String(parseState, "c"))
388 RETURN_ERROR;
389
390 if (!Parse_String(parseState, "["))
391 RETURN_ERROR;
392
393 if (!Peek_Token(parseState, token))
394 RETURN_ERROR;
395
396 if (IsDigit(token[0])) {
397 /* a numbered program parameter register */
398 GLint reg;
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;
404 srcReg->Index = reg;
405 }
406 else if (_mesa_strcmp((const char *) token, "A0") == 0) {
407 /* address register "A0.x" */
408 if (!Parse_AddrReg(parseState))
409 RETURN_ERROR;
410
411 srcReg->RelAddr = GL_TRUE;
412 srcReg->File = PROGRAM_ENV_PARAM;
413 /* Look for +/-N offset */
414 if (!Peek_Token(parseState, token))
415 RETURN_ERROR;
416
417 if (token[0] == '-' || token[0] == '+') {
418 const GLubyte sign = token[0];
419 (void) Parse_Token(parseState, token); /* consume +/- */
420
421 /* an integer should be next */
422 if (!Parse_Token(parseState, token))
423 RETURN_ERROR;
424
425 if (IsDigit(token[0])) {
426 const GLint k = _mesa_atoi((char *) token);
427 if (sign == '-') {
428 if (k > 64)
429 RETURN_ERROR1("Bad address offset");
430 srcReg->Index = -k;
431 }
432 else {
433 if (k > 63)
434 RETURN_ERROR1("Bad address offset");
435 srcReg->Index = k;
436 }
437 }
438 else {
439 RETURN_ERROR;
440 }
441 }
442 else {
443 /* probably got a ']', catch it below */
444 }
445 }
446 else {
447 RETURN_ERROR;
448 }
449
450 /* Match closing ']' */
451 if (!Parse_String(parseState, "]"))
452 RETURN_ERROR;
453
454 return GL_TRUE;
455 }
456
457
458 /**
459 * Parse v[#] or v[<name>]
460 */
461 static GLboolean
462 Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum)
463 {
464 GLubyte token[100];
465 GLint j;
466
467 /* Match 'v' */
468 if (!Parse_String(parseState, "v"))
469 RETURN_ERROR;
470
471 /* Match '[' */
472 if (!Parse_String(parseState, "["))
473 RETURN_ERROR;
474
475 /* match number or named register */
476 if (!Parse_Token(parseState, token))
477 RETURN_ERROR;
478
479 if (parseState->isStateProgram && token[0] != '0')
480 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
481
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");
486 *tempRegNum = reg;
487 }
488 else {
489 for (j = 0; InputRegisters[j]; j++) {
490 if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
491 *tempRegNum = j;
492 break;
493 }
494 }
495 if (!InputRegisters[j]) {
496 /* unknown input register label */
497 RETURN_ERROR2("Bad register name", token);
498 }
499 }
500
501 /* Match '[' */
502 if (!Parse_String(parseState, "]"))
503 RETURN_ERROR;
504
505 return GL_TRUE;
506 }
507
508
509 static GLboolean
510 Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
511 {
512 GLubyte token[100];
513 GLint start, j;
514
515 /* Match 'o' */
516 if (!Parse_String(parseState, "o"))
517 RETURN_ERROR;
518
519 /* Match '[' */
520 if (!Parse_String(parseState, "["))
521 RETURN_ERROR;
522
523 /* Get output reg name */
524 if (!Parse_Token(parseState, token))
525 RETURN_ERROR;
526
527 if (parseState->isPositionInvariant)
528 start = 1; /* skip HPOS register name */
529 else
530 start = 0;
531
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) {
535 *outputRegNum = j;
536 break;
537 }
538 }
539 if (!OutputRegisters[j])
540 RETURN_ERROR1("Unrecognized output register name");
541
542 /* Match ']' */
543 if (!Parse_String(parseState, "]"))
544 RETURN_ERROR1("Expected ]");
545
546 return GL_TRUE;
547 }
548
549
550 static GLboolean
551 Parse_MaskedDstReg(struct parse_state *parseState, struct prog_dst_register *dstReg)
552 {
553 GLubyte token[100];
554 GLint idx;
555
556 /* Dst reg can be R<n> or o[n] */
557 if (!Peek_Token(parseState, token))
558 RETURN_ERROR;
559
560 if (token[0] == 'R') {
561 /* a temporary register */
562 dstReg->File = PROGRAM_TEMPORARY;
563 if (!Parse_TempReg(parseState, &idx))
564 RETURN_ERROR;
565 dstReg->Index = idx;
566 }
567 else if (!parseState->isStateProgram && token[0] == 'o') {
568 /* an output register */
569 dstReg->File = PROGRAM_OUTPUT;
570 if (!Parse_OutputReg(parseState, &idx))
571 RETURN_ERROR;
572 dstReg->Index = idx;
573 }
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))
580 RETURN_ERROR;
581 dstReg->Index = idx;
582 }
583 else {
584 RETURN_ERROR1("Bad destination register name");
585 }
586
587 /* Parse optional write mask */
588 if (!Peek_Token(parseState, token))
589 RETURN_ERROR;
590
591 if (token[0] == '.') {
592 /* got a mask */
593 GLint k = 0;
594
595 if (!Parse_String(parseState, "."))
596 RETURN_ERROR;
597
598 if (!Parse_Token(parseState, token))
599 RETURN_ERROR;
600
601 dstReg->WriteMask = 0;
602
603 if (token[k] == 'x') {
604 dstReg->WriteMask |= WRITEMASK_X;
605 k++;
606 }
607 if (token[k] == 'y') {
608 dstReg->WriteMask |= WRITEMASK_Y;
609 k++;
610 }
611 if (token[k] == 'z') {
612 dstReg->WriteMask |= WRITEMASK_Z;
613 k++;
614 }
615 if (token[k] == 'w') {
616 dstReg->WriteMask |= WRITEMASK_W;
617 k++;
618 }
619 if (k == 0) {
620 RETURN_ERROR1("Bad writemask character");
621 }
622 return GL_TRUE;
623 }
624 else {
625 dstReg->WriteMask = WRITEMASK_XYZW;
626 return GL_TRUE;
627 }
628 }
629
630
631 static GLboolean
632 Parse_SwizzleSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
633 {
634 GLubyte token[100];
635 GLint idx;
636
637 srcReg->RelAddr = GL_FALSE;
638
639 /* check for '-' */
640 if (!Peek_Token(parseState, token))
641 RETURN_ERROR;
642 if (token[0] == '-') {
643 (void) Parse_String(parseState, "-");
644 srcReg->Negate = NEGATE_XYZW;
645 if (!Peek_Token(parseState, token))
646 RETURN_ERROR;
647 }
648 else {
649 srcReg->Negate = NEGATE_NONE;
650 }
651
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))
656 RETURN_ERROR;
657 srcReg->Index = idx;
658 }
659 else if (token[0] == 'c') {
660 if (!Parse_ParamReg(parseState, srcReg))
661 RETURN_ERROR;
662 }
663 else if (token[0] == 'v') {
664 srcReg->File = PROGRAM_INPUT;
665 if (!Parse_AttribReg(parseState, &idx))
666 RETURN_ERROR;
667 srcReg->Index = idx;
668 }
669 else {
670 RETURN_ERROR2("Bad source register name", token);
671 }
672
673 /* init swizzle fields */
674 srcReg->Swizzle = SWIZZLE_NOOP;
675
676 /* Look for optional swizzle suffix */
677 if (!Peek_Token(parseState, token))
678 RETURN_ERROR;
679 if (token[0] == '.') {
680 (void) Parse_String(parseState, "."); /* consume . */
681
682 if (!Parse_Token(parseState, token))
683 RETURN_ERROR;
684
685 if (token[1] == 0) {
686 /* single letter swizzle */
687 if (token[0] == 'x')
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;
695 else
696 RETURN_ERROR1("Expected x, y, z, or w");
697 }
698 else {
699 /* 2, 3 or 4-component swizzle */
700 GLint k;
701
702 srcReg->Swizzle = 0;
703
704 for (k = 0; token[k] && k < 5; k++) {
705 if (token[k] == 'x')
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);
713 else
714 RETURN_ERROR;
715 }
716 if (k >= 5)
717 RETURN_ERROR;
718 }
719 }
720
721 return GL_TRUE;
722 }
723
724
725 static GLboolean
726 Parse_ScalarSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
727 {
728 GLubyte token[100];
729 GLint idx;
730
731 srcReg->RelAddr = GL_FALSE;
732
733 /* check for '-' */
734 if (!Peek_Token(parseState, token))
735 RETURN_ERROR;
736 if (token[0] == '-') {
737 srcReg->Negate = NEGATE_XYZW;
738 (void) Parse_String(parseState, "-"); /* consume '-' */
739 if (!Peek_Token(parseState, token))
740 RETURN_ERROR;
741 }
742 else {
743 srcReg->Negate = NEGATE_NONE;
744 }
745
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))
750 RETURN_ERROR;
751 srcReg->Index = idx;
752 }
753 else if (token[0] == 'c') {
754 if (!Parse_ParamReg(parseState, srcReg))
755 RETURN_ERROR;
756 }
757 else if (token[0] == 'v') {
758 srcReg->File = PROGRAM_INPUT;
759 if (!Parse_AttribReg(parseState, &idx))
760 RETURN_ERROR;
761 srcReg->Index = idx;
762 }
763 else {
764 RETURN_ERROR2("Bad source register name", token);
765 }
766
767 /* Look for .[xyzw] suffix */
768 if (!Parse_String(parseState, "."))
769 RETURN_ERROR;
770
771 if (!Parse_Token(parseState, token))
772 RETURN_ERROR;
773
774 if (token[0] == 'x' && token[1] == 0) {
775 srcReg->Swizzle = 0;
776 }
777 else if (token[0] == 'y' && token[1] == 0) {
778 srcReg->Swizzle = 1;
779 }
780 else if (token[0] == 'z' && token[1] == 0) {
781 srcReg->Swizzle = 2;
782 }
783 else if (token[0] == 'w' && token[1] == 0) {
784 srcReg->Swizzle = 3;
785 }
786 else {
787 RETURN_ERROR1("Bad scalar source suffix");
788 }
789
790 return GL_TRUE;
791 }
792
793
794 static GLint
795 Parse_UnaryOpInstruction(struct parse_state *parseState,
796 struct prog_instruction *inst,
797 enum prog_opcode opcode)
798 {
799 if (opcode == OPCODE_ABS && !parseState->isVersion1_1)
800 RETURN_ERROR1("ABS illegal for vertex program 1.0");
801
802 inst->Opcode = opcode;
803
804 /* dest reg */
805 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
806 RETURN_ERROR;
807
808 /* comma */
809 if (!Parse_String(parseState, ","))
810 RETURN_ERROR;
811
812 /* src arg */
813 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
814 RETURN_ERROR;
815
816 /* semicolon */
817 if (!Parse_String(parseState, ";"))
818 RETURN_ERROR;
819
820 return GL_TRUE;
821 }
822
823
824 static GLboolean
825 Parse_BiOpInstruction(struct parse_state *parseState,
826 struct prog_instruction *inst,
827 enum prog_opcode opcode)
828 {
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");
833
834 inst->Opcode = opcode;
835
836 /* dest reg */
837 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
838 RETURN_ERROR;
839
840 /* comma */
841 if (!Parse_String(parseState, ","))
842 RETURN_ERROR;
843
844 /* first src arg */
845 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
846 RETURN_ERROR;
847
848 /* comma */
849 if (!Parse_String(parseState, ","))
850 RETURN_ERROR;
851
852 /* second src arg */
853 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
854 RETURN_ERROR;
855
856 /* semicolon */
857 if (!Parse_String(parseState, ";"))
858 RETURN_ERROR;
859
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");
865
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");
871
872 return GL_TRUE;
873 }
874
875
876 static GLboolean
877 Parse_TriOpInstruction(struct parse_state *parseState,
878 struct prog_instruction *inst,
879 enum prog_opcode opcode)
880 {
881 inst->Opcode = opcode;
882
883 /* dest reg */
884 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
885 RETURN_ERROR;
886
887 /* comma */
888 if (!Parse_String(parseState, ","))
889 RETURN_ERROR;
890
891 /* first src arg */
892 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
893 RETURN_ERROR;
894
895 /* comma */
896 if (!Parse_String(parseState, ","))
897 RETURN_ERROR;
898
899 /* second src arg */
900 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
901 RETURN_ERROR;
902
903 /* comma */
904 if (!Parse_String(parseState, ","))
905 RETURN_ERROR;
906
907 /* third src arg */
908 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2]))
909 RETURN_ERROR;
910
911 /* semicolon */
912 if (!Parse_String(parseState, ";"))
913 RETURN_ERROR;
914
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");
926
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");
938
939 return GL_TRUE;
940 }
941
942
943 static GLboolean
944 Parse_ScalarInstruction(struct parse_state *parseState,
945 struct prog_instruction *inst,
946 enum prog_opcode opcode)
947 {
948 if (opcode == OPCODE_RCC && !parseState->isVersion1_1)
949 RETURN_ERROR1("RCC illegal for vertex program 1.0");
950
951 inst->Opcode = opcode;
952
953 /* dest reg */
954 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
955 RETURN_ERROR;
956
957 /* comma */
958 if (!Parse_String(parseState, ","))
959 RETURN_ERROR;
960
961 /* first src arg */
962 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
963 RETURN_ERROR;
964
965 /* semicolon */
966 if (!Parse_String(parseState, ";"))
967 RETURN_ERROR;
968
969 return GL_TRUE;
970 }
971
972
973 static GLboolean
974 Parse_AddressInstruction(struct parse_state *parseState, struct prog_instruction *inst)
975 {
976 inst->Opcode = OPCODE_ARL;
977
978 /* Make ARB_vp backends happy */
979 inst->DstReg.File = PROGRAM_ADDRESS;
980 inst->DstReg.WriteMask = WRITEMASK_X;
981 inst->DstReg.Index = 0;
982
983 /* dest A0 reg */
984 if (!Parse_AddrReg(parseState))
985 RETURN_ERROR;
986
987 /* comma */
988 if (!Parse_String(parseState, ","))
989 RETURN_ERROR;
990
991 /* parse src reg */
992 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
993 RETURN_ERROR;
994
995 /* semicolon */
996 if (!Parse_String(parseState, ";"))
997 RETURN_ERROR;
998
999 return GL_TRUE;
1000 }
1001
1002
1003 static GLboolean
1004 Parse_EndInstruction(struct parse_state *parseState, struct prog_instruction *inst)
1005 {
1006 GLubyte token[100];
1007
1008 inst->Opcode = OPCODE_END;
1009
1010 /* this should fail! */
1011 if (Parse_Token(parseState, token))
1012 RETURN_ERROR2("Unexpected token after END:", token);
1013 else
1014 return GL_TRUE;
1015 }
1016
1017
1018 /**
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:
1022 *
1023 * <instruction> ::= <ARL-instruction>
1024 * | ...
1025 * | <PRINT-instruction>
1026 *
1027 * <PRINT-instruction> ::= "PRINT" <string literal>
1028 * | "PRINT" <string literal> "," <srcReg>
1029 * | "PRINT" <string literal> "," <dstReg>
1030 */
1031 static GLboolean
1032 Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *inst)
1033 {
1034 const GLubyte *str;
1035 GLubyte *msg;
1036 GLuint len;
1037 GLubyte token[100];
1038 struct prog_src_register *srcReg = &inst->SrcReg[0];
1039 GLint idx;
1040
1041 inst->Opcode = OPCODE_PRINT;
1042
1043 /* The first argument is a literal string 'just like this' */
1044 if (!Parse_String(parseState, "'"))
1045 RETURN_ERROR;
1046
1047 str = parseState->pos;
1048 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1049 ;
1050 parseState->pos += len + 1;
1051 msg = (GLubyte*) _mesa_malloc(len + 1);
1052
1053 _mesa_memcpy(msg, str, len);
1054 msg[len] = 0;
1055 inst->Data = msg;
1056
1057 /* comma */
1058 if (Parse_String(parseState, ",")) {
1059
1060 /* The second argument is a register name */
1061 if (!Peek_Token(parseState, token))
1062 RETURN_ERROR;
1063
1064 srcReg->RelAddr = GL_FALSE;
1065 srcReg->Negate = NEGATE_NONE;
1066 srcReg->Swizzle = SWIZZLE_NOOP;
1067
1068 /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
1069 * or an o[n] output register.
1070 */
1071 if (token[0] == 'R') {
1072 srcReg->File = PROGRAM_TEMPORARY;
1073 if (!Parse_TempReg(parseState, &idx))
1074 RETURN_ERROR;
1075 srcReg->Index = idx;
1076 }
1077 else if (token[0] == 'c') {
1078 srcReg->File = PROGRAM_ENV_PARAM;
1079 if (!Parse_ParamReg(parseState, srcReg))
1080 RETURN_ERROR;
1081 }
1082 else if (token[0] == 'v') {
1083 srcReg->File = PROGRAM_INPUT;
1084 if (!Parse_AttribReg(parseState, &idx))
1085 RETURN_ERROR;
1086 srcReg->Index = idx;
1087 }
1088 else if (token[0] == 'o') {
1089 srcReg->File = PROGRAM_OUTPUT;
1090 if (!Parse_OutputReg(parseState, &idx))
1091 RETURN_ERROR;
1092 srcReg->Index = idx;
1093 }
1094 else {
1095 RETURN_ERROR2("Bad source register name", token);
1096 }
1097 }
1098 else {
1099 srcReg->File = 0;
1100 }
1101
1102 /* semicolon */
1103 if (!Parse_String(parseState, ";"))
1104 RETURN_ERROR;
1105
1106 return GL_TRUE;
1107 }
1108
1109
1110 static GLboolean
1111 Parse_OptionSequence(struct parse_state *parseState,
1112 struct prog_instruction program[])
1113 {
1114 (void) program;
1115 while (1) {
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;
1120 }
1121 else {
1122 RETURN_ERROR1("unexpected OPTION statement");
1123 }
1124 if (!Parse_String(parseState, ";"))
1125 return GL_FALSE;
1126 }
1127 }
1128
1129
1130 static GLboolean
1131 Parse_InstructionSequence(struct parse_state *parseState,
1132 struct prog_instruction program[])
1133 {
1134 while (1) {
1135 struct prog_instruction *inst = program + parseState->numInst;
1136
1137 /* Initialize the instruction */
1138 _mesa_init_instructions(inst, 1);
1139
1140 if (Parse_String(parseState, "MOV")) {
1141 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_MOV))
1142 RETURN_ERROR;
1143 }
1144 else if (Parse_String(parseState, "LIT")) {
1145 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_LIT))
1146 RETURN_ERROR;
1147 }
1148 else if (Parse_String(parseState, "ABS")) {
1149 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_ABS))
1150 RETURN_ERROR;
1151 }
1152 else if (Parse_String(parseState, "MUL")) {
1153 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MUL))
1154 RETURN_ERROR;
1155 }
1156 else if (Parse_String(parseState, "ADD")) {
1157 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_ADD))
1158 RETURN_ERROR;
1159 }
1160 else if (Parse_String(parseState, "DP3")) {
1161 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP3))
1162 RETURN_ERROR;
1163 }
1164 else if (Parse_String(parseState, "DP4")) {
1165 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP4))
1166 RETURN_ERROR;
1167 }
1168 else if (Parse_String(parseState, "DST")) {
1169 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DST))
1170 RETURN_ERROR;
1171 }
1172 else if (Parse_String(parseState, "MIN")) {
1173 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MIN))
1174 RETURN_ERROR;
1175 }
1176 else if (Parse_String(parseState, "MAX")) {
1177 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MAX))
1178 RETURN_ERROR;
1179 }
1180 else if (Parse_String(parseState, "SLT")) {
1181 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SLT))
1182 RETURN_ERROR;
1183 }
1184 else if (Parse_String(parseState, "SGE")) {
1185 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SGE))
1186 RETURN_ERROR;
1187 }
1188 else if (Parse_String(parseState, "DPH")) {
1189 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DPH))
1190 RETURN_ERROR;
1191 }
1192 else if (Parse_String(parseState, "SUB")) {
1193 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SUB))
1194 RETURN_ERROR;
1195 }
1196 else if (Parse_String(parseState, "MAD")) {
1197 if (!Parse_TriOpInstruction(parseState, inst, OPCODE_MAD))
1198 RETURN_ERROR;
1199 }
1200 else if (Parse_String(parseState, "RCP")) {
1201 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCP))
1202 RETURN_ERROR;
1203 }
1204 else if (Parse_String(parseState, "RSQ")) {
1205 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RSQ))
1206 RETURN_ERROR;
1207 }
1208 else if (Parse_String(parseState, "EXP")) {
1209 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_EXP))
1210 RETURN_ERROR;
1211 }
1212 else if (Parse_String(parseState, "LOG")) {
1213 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_LOG))
1214 RETURN_ERROR;
1215 }
1216 else if (Parse_String(parseState, "RCC")) {
1217 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCC))
1218 RETURN_ERROR;
1219 }
1220 else if (Parse_String(parseState, "ARL")) {
1221 if (!Parse_AddressInstruction(parseState, inst))
1222 RETURN_ERROR;
1223 }
1224 else if (Parse_String(parseState, "PRINT")) {
1225 if (!Parse_PrintInstruction(parseState, inst))
1226 RETURN_ERROR;
1227 }
1228 else if (Parse_String(parseState, "END")) {
1229 if (!Parse_EndInstruction(parseState, inst))
1230 RETURN_ERROR;
1231 else {
1232 parseState->numInst++;
1233 return GL_TRUE; /* all done */
1234 }
1235 }
1236 else {
1237 /* bad instruction name */
1238 RETURN_ERROR1("Unexpected token");
1239 }
1240
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;
1246
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);
1253
1254 parseState->numInst++;
1255
1256 if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
1257 RETURN_ERROR1("Program too long");
1258 }
1259
1260 RETURN_ERROR;
1261 }
1262
1263
1264 static GLboolean
1265 Parse_Program(struct parse_state *parseState,
1266 struct prog_instruction instBuffer[])
1267 {
1268 if (parseState->isVersion1_1) {
1269 if (!Parse_OptionSequence(parseState, instBuffer)) {
1270 return GL_FALSE;
1271 }
1272 }
1273 return Parse_InstructionSequence(parseState, instBuffer);
1274 }
1275
1276
1277 /**
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'.
1281 */
1282 void
1283 _mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
1284 const GLubyte *str, GLsizei len,
1285 struct gl_vertex_program *program)
1286 {
1287 struct parse_state parseState;
1288 struct prog_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1289 struct prog_instruction *newInst;
1290 GLenum target;
1291 GLubyte *programString;
1292
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");
1297 return;
1298 }
1299 MEMCPY(programString, str, len);
1300 programString[len] = 0;
1301
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;
1311
1312 /* Reset error state */
1313 _mesa_set_program_error(ctx, -1, NULL);
1314
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;
1320 }
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;
1326 }
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;
1331 }
1332 else {
1333 /* invalid header */
1334 ctx->Program.ErrorPos = 0;
1335 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1336 return;
1337 }
1338
1339 /* make sure target and header match */
1340 if (target != dstTarget) {
1341 _mesa_error(ctx, GL_INVALID_OPERATION,
1342 "glLoadProgramNV(target mismatch)");
1343 return;
1344 }
1345
1346
1347 if (Parse_Program(&parseState, instBuffer)) {
1348 /* successful parse! */
1349
1350 if (parseState.isStateProgram) {
1351 if (!parseState.anyProgRegsWritten) {
1352 _mesa_error(ctx, GL_INVALID_OPERATION,
1353 "glLoadProgramNV(c[#] not written)");
1354 return;
1355 }
1356 }
1357 else {
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)");
1363 return;
1364 }
1365 }
1366
1367 /* copy the compiled instructions */
1368 assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
1369 newInst = _mesa_alloc_instructions(parseState.numInst);
1370 if (!newInst) {
1371 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1372 _mesa_free(programString);
1373 return; /* out of memory */
1374 }
1375 _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
1376
1377 /* install the program */
1378 program->Base.Target = target;
1379 if (program->Base.String) {
1380 _mesa_free(program->Base.String);
1381 }
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);
1386 }
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;
1395
1396 #ifdef DEBUG_foo
1397 _mesa_printf("--- glLoadProgramNV result ---\n");
1398 _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
1399 _mesa_printf("------------------------------\n");
1400 #endif
1401 }
1402 else {
1403 /* Error! */
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.
1408 */
1409 _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
1410 }
1411 }
1412
1413
1414 const char *
1415 _mesa_nv_vertex_input_register_name(GLuint i)
1416 {
1417 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1418 return InputRegisters[i];
1419 }
1420
1421
1422 const char *
1423 _mesa_nv_vertex_output_register_name(GLuint i)
1424 {
1425 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1426 return OutputRegisters[i];
1427 }
1428