improved solve_plane_chan() (Evgeny Kotsuba)
[mesa.git] / src / mesa / main / nvvertparse.c
1 /* $Id: nvvertparse.c,v 1.1 2003/01/14 04:55:46 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 5.1
6 *
7 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 /**
28 * \file nvvertparse.c
29 * \brief NVIDIA vertex program parser.
30 * \author Brian Paul
31 */
32
33
34 #include "glheader.h"
35 #include "context.h"
36 #include "hash.h"
37 #include "imports.h"
38 #include "macros.h"
39 #include "mtypes.h"
40 #include "nvprogram.h"
41 #include "nvvertparse.h"
42 #include "nvvertprog.h"
43
44
45 /************************ Symbol Table ******************************/
46
47 /* A simple symbol table implementation for ARB_vertex_program
48 * (not used yet)
49 */
50
51 #if 000
52 struct symbol
53 {
54 GLubyte *name;
55 GLint value;
56 struct symbol *next;
57 };
58
59 static struct symbol *SymbolTable = NULL;
60
61 static GLboolean
62 IsSymbol(const GLubyte *symbol)
63 {
64 struct symbol *s;
65 for (s = SymbolTable; s; s = s->next) {
66 if (strcmp((char *) symbol, (char *)s->name) == 0)
67 return GL_TRUE;
68 }
69 return GL_FALSE;
70 }
71
72 static GLint
73 GetSymbolValue(const GLubyte *symbol)
74 {
75 struct symbol *s;
76 for (s = SymbolTable; s; s = s->next) {
77 if (strcmp((char *) symbol, (char *)s->name) == 0)
78 return s->value;
79 }
80 return 0;
81 }
82
83 static void
84 AddSymbol(const GLubyte *symbol, GLint value)
85 {
86 struct symbol *s = MALLOC_STRUCT(symbol);
87 if (s) {
88 s->name = (GLubyte *) strdup((char *) symbol);
89 s->value = value;
90 s->next = SymbolTable;
91 SymbolTable = s;
92 }
93 }
94
95 static void
96 ResetSymbolTable(void)
97 {
98 struct symbol *s, *next;
99 for (s = SymbolTable; s; s = next) {
100 next = s->next;
101 FREE(s->name);
102 FREE(s);
103 s = next;
104 }
105 SymbolTable = NULL;
106 }
107 #endif
108
109 /***************************** Parsing ******************************/
110
111
112 static GLboolean IsLetter(GLubyte b)
113 {
114 return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z');
115 }
116
117
118 static GLboolean IsDigit(GLubyte b)
119 {
120 return b >= '0' && b <= '9';
121 }
122
123
124 static GLboolean IsWhitespace(GLubyte b)
125 {
126 return b == ' ' || b == '\t' || b == '\n' || b == '\r';
127 }
128
129
130 /**
131 * Starting at 'str' find the next token. A token can be an integer,
132 * an identifier or punctuation symbol.
133 * \return <= 0 we found an error, else, return number of characters parsed.
134 */
135 static GLint
136 GetToken(const GLubyte *str, GLubyte *token)
137 {
138 GLint i = 0, j = 0;
139
140 token[0] = 0;
141
142 /* skip whitespace and comments */
143 while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
144 if (str[i] == '#') {
145 /* skip comment */
146 while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
147 i++;
148 }
149 }
150 else {
151 /* skip whitespace */
152 i++;
153 }
154 }
155
156 if (str[i] == 0)
157 return -i;
158
159 /* try matching an integer */
160 while (str[i] && IsDigit(str[i])) {
161 token[j++] = str[i++];
162 }
163 if (j > 0 || !str[i]) {
164 token[j] = 0;
165 return i;
166 }
167
168 /* try matching an identifier */
169 if (IsLetter(str[i])) {
170 while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
171 token[j++] = str[i++];
172 }
173 token[j] = 0;
174 return i;
175 }
176
177 /* punctuation */
178 if (str[i]) {
179 token[0] = str[i++];
180 token[1] = 0;
181 return i;
182 }
183
184 /* end of input */
185 token[0] = 0;
186 return i;
187 }
188
189
190 /**
191 * Get next token from input stream and increment stream pointer past token.
192 */
193 static GLboolean
194 Parse_Token(const GLubyte **s, GLubyte *token)
195 {
196 GLint i;
197 i = GetToken(*s, token);
198 if (i <= 0) {
199 *s += (-i);
200 return GL_FALSE;
201 }
202 *s += i;
203 return GL_TRUE;
204 }
205
206
207 /**
208 * Get next token from input stream but don't increment stream pointer.
209 */
210 static GLboolean
211 Peek_Token(const GLubyte **s, GLubyte *token)
212 {
213 GLint i, len;
214 i = GetToken(*s, token);
215 if (i <= 0) {
216 *s += (-i);
217 return GL_FALSE;
218 }
219 len = _mesa_strlen((char *) token);
220 *s += (i - len);
221 return GL_TRUE;
222 }
223
224
225 /**
226 * String equality test
227 */
228 static GLboolean
229 StrEq(const GLubyte *a, const GLubyte *b)
230 {
231 GLint i;
232 for (i = 0; a[i] && b[i] && a[i] == b[i]; i++)
233 ;
234 if (a[i] == 0 && b[i] == 0)
235 return GL_TRUE;
236 else
237 return GL_FALSE;
238 }
239
240
241 /**********************************************************************/
242
243 static const char *InputRegisters[] = {
244 "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7",
245 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
246 };
247
248 static const char *OutputRegisters[] = {
249 "HPOS", "COL0", "COL1", "BFC0", "BFC1", "FOGC", "PSIZ",
250 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
251 };
252
253 static const char *Opcodes[] = {
254 "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
255 "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
256 "ABS", "END", NULL
257 };
258
259
260 #ifdef DEBUG
261
262 #define PARSE_ERROR \
263 do { \
264 _mesa_printf("vpparse.c error at %d: parse error\n", __LINE__); \
265 return GL_FALSE; \
266 } while(0)
267
268 #define PARSE_ERROR1(msg) \
269 do { \
270 _mesa_printf("vpparse.c error at %d: %s\n", __LINE__, msg); \
271 return GL_FALSE; \
272 } while(0)
273
274 #define PARSE_ERROR2(msg1, msg2) \
275 do { \
276 _mesa_printf("vpparse.c error at %d: %s %s\n", __LINE__, msg1, msg2); \
277 return GL_FALSE; \
278 } while(0)
279
280 #else
281
282 #define PARSE_ERROR return GL_FALSE
283 #define PARSE_ERROR1(msg1) return GL_FALSE
284 #define PARSE_ERROR2(msg1, msg2) return GL_FALSE
285
286 #endif
287
288
289 static GLuint
290 IsProgRegister(GLuint r)
291 {
292 return (GLuint) (r >= VP_PROG_REG_START && r <= VP_PROG_REG_END);
293 }
294
295 static GLuint
296 IsInputRegister(GLuint r)
297 {
298 return (GLuint) (r >= VP_INPUT_REG_START && r <= VP_INPUT_REG_END);
299 }
300
301 static GLuint
302 IsOutputRegister(GLuint r)
303 {
304 return (GLuint) (r >= VP_OUTPUT_REG_START && r <= VP_OUTPUT_REG_END);
305 }
306
307
308
309 /**********************************************************************/
310
311 /* XXX
312 * These shouldn't be globals as that makes the parser non-reentrant.
313 * We should really define a "ParserContext" class which contains these
314 * and the <s> pointer into the program text.
315 */
316 static GLboolean IsStateProgram = GL_FALSE;
317 static GLboolean IsPositionInvariant = GL_FALSE;
318 static GLboolean IsVersion1_1 = GL_FALSE;
319
320 /**
321 * Try to match 'pattern' as the next token after any whitespace/comments.
322 */
323 static GLboolean
324 Parse_String(const GLubyte **s, const char *pattern)
325 {
326 GLint i;
327
328 /* skip whitespace and comments */
329 while (IsWhitespace(**s) || **s == '#') {
330 if (**s == '#') {
331 while (**s && (**s != '\n' && **s != '\r')) {
332 *s += 1;
333 }
334 }
335 else {
336 /* skip whitespace */
337 *s += 1;
338 }
339 }
340
341 /* Try to match the pattern */
342 for (i = 0; pattern[i]; i++) {
343 if (**s != pattern[i])
344 PARSE_ERROR2("failed to match", pattern); /* failure */
345 *s += 1;
346 }
347
348 return GL_TRUE; /* success */
349 }
350
351
352 /**
353 * Parse a temporary register: Rnn
354 */
355 static GLboolean
356 Parse_TempReg(const GLubyte **s, GLint *tempRegNum)
357 {
358 GLubyte token[100];
359
360 /* Should be 'R##' */
361 if (!Parse_Token(s, token))
362 PARSE_ERROR;
363 if (token[0] != 'R')
364 PARSE_ERROR1("Expected R##");
365
366 if (IsDigit(token[1])) {
367 GLint reg = _mesa_atoi((char *) (token + 1));
368 if (reg >= VP_NUM_TEMP_REGS)
369 PARSE_ERROR1("Bad temporary register name");
370 *tempRegNum = VP_TEMP_REG_START + reg;
371 }
372 else {
373 PARSE_ERROR1("Bad temporary register name");
374 }
375
376 return GL_TRUE;
377 }
378
379
380 /**
381 * Parse address register "A0.x"
382 */
383 static GLboolean
384 Parse_AddrReg(const GLubyte **s)
385 {
386 /* match 'A0' */
387 if (!Parse_String(s, "A0"))
388 PARSE_ERROR;
389
390 /* match '.' */
391 if (!Parse_String(s, "."))
392 PARSE_ERROR;
393
394 /* match 'x' */
395 if (!Parse_String(s, "x"))
396 PARSE_ERROR;
397
398 return GL_TRUE;
399 }
400
401
402 /**
403 * Parse absolute program parameter register "c[##]"
404 */
405 static GLboolean
406 Parse_AbsParamReg(const GLubyte **s, GLint *regNum)
407 {
408 GLubyte token[100];
409
410 if (!Parse_String(s, "c"))
411 PARSE_ERROR;
412
413 if (!Parse_String(s, "["))
414 PARSE_ERROR;
415
416 if (!Parse_Token(s, token))
417 PARSE_ERROR;
418
419 if (IsDigit(token[0])) {
420 /* a numbered program parameter register */
421 GLint reg = _mesa_atoi((char *) token);
422 if (reg >= VP_NUM_PROG_REGS)
423 PARSE_ERROR1("Bad constant program number");
424 *regNum = VP_PROG_REG_START + reg;
425 }
426 else {
427 PARSE_ERROR;
428 }
429
430 if (!Parse_String(s, "]"))
431 PARSE_ERROR;
432
433 return GL_TRUE;
434 }
435
436
437 static GLboolean
438 Parse_ParamReg(const GLubyte **s, struct vp_src_register *srcReg)
439 {
440 GLubyte token[100];
441
442 if (!Parse_String(s, "c"))
443 PARSE_ERROR;
444
445 if (!Parse_String(s, "["))
446 PARSE_ERROR;
447
448 if (!Peek_Token(s, token))
449 PARSE_ERROR;
450
451 if (IsDigit(token[0])) {
452 /* a numbered program parameter register */
453 GLint reg;
454 (void) Parse_Token(s, token);
455 reg = _mesa_atoi((char *) token);
456 if (reg >= VP_NUM_PROG_REGS)
457 PARSE_ERROR1("Bad constant program number");
458 srcReg->Register = VP_PROG_REG_START + reg;
459 }
460 else if (StrEq(token, (GLubyte *) "A0")) {
461 /* address register "A0.x" */
462 if (!Parse_AddrReg(s))
463 PARSE_ERROR;
464
465 srcReg->RelAddr = GL_TRUE;
466 srcReg->Register = 0;
467
468 /* Look for +/-N offset */
469 if (!Peek_Token(s, token))
470 PARSE_ERROR;
471
472 if (token[0] == '-' || token[0] == '+') {
473 const GLubyte sign = token[0];
474 (void) Parse_Token(s, token); /* consume +/- */
475
476 /* an integer should be next */
477 if (!Parse_Token(s, token))
478 PARSE_ERROR;
479
480 if (IsDigit(token[0])) {
481 const GLint k = _mesa_atoi((char *) token);
482 if (sign == '-') {
483 if (k > 64)
484 PARSE_ERROR1("Bad address offset");
485 srcReg->Register = -k;
486 }
487 else {
488 if (k > 63)
489 PARSE_ERROR1("Bad address offset");
490 srcReg->Register = k;
491 }
492 }
493 else {
494 PARSE_ERROR;
495 }
496 }
497 else {
498 /* probably got a ']', catch it below */
499 }
500 }
501 else {
502 PARSE_ERROR;
503 }
504
505 /* Match closing ']' */
506 if (!Parse_String(s, "]"))
507 PARSE_ERROR;
508
509 return GL_TRUE;
510 }
511
512
513 /**
514 * Parse v[#] or v[<name>]
515 */
516 static GLboolean
517 Parse_AttribReg(const GLubyte **s, GLint *tempRegNum)
518 {
519 GLubyte token[100];
520 GLint j;
521
522 /* Match 'v' */
523 if (!Parse_String(s, "v"))
524 PARSE_ERROR;
525
526 /* Match '[' */
527 if (!Parse_String(s, "["))
528 PARSE_ERROR;
529
530 /* match number or named register */
531 if (!Parse_Token(s, token))
532 PARSE_ERROR;
533
534 if (IsStateProgram && token[0] != '0')
535 PARSE_ERROR1("Only v[0] accessible in vertex state programs");
536
537 if (IsDigit(token[0])) {
538 GLint reg = _mesa_atoi((char *) token);
539 if (reg >= VP_NUM_INPUT_REGS)
540 PARSE_ERROR1("Bad vertex attribute register name");
541 *tempRegNum = VP_INPUT_REG_START + reg;
542 }
543 else {
544 for (j = 0; InputRegisters[j]; j++) {
545 if (StrEq(token, (const GLubyte *) InputRegisters[j])) {
546 *tempRegNum = VP_INPUT_REG_START + j;
547 break;
548 }
549 }
550 if (!InputRegisters[j]) {
551 /* unknown input register label */
552 PARSE_ERROR2("Bad register name", token);
553 }
554 }
555
556 /* Match '[' */
557 if (!Parse_String(s, "]"))
558 PARSE_ERROR;
559
560 return GL_TRUE;
561 }
562
563
564 static GLboolean
565 Parse_OutputReg(const GLubyte **s, GLint *outputRegNum)
566 {
567 GLubyte token[100];
568 GLint start, j;
569
570 /* Match 'o' */
571 if (!Parse_String(s, "o"))
572 PARSE_ERROR;
573
574 /* Match '[' */
575 if (!Parse_String(s, "["))
576 PARSE_ERROR;
577
578 /* Get output reg name */
579 if (!Parse_Token(s, token))
580 PARSE_ERROR;
581
582 if (IsPositionInvariant)
583 start = 1; /* skip HPOS register name */
584 else
585 start = 0;
586
587 /* try to match an output register name */
588 for (j = start; OutputRegisters[j]; j++) {
589 if (StrEq(token, (const GLubyte *) OutputRegisters[j])) {
590 *outputRegNum = VP_OUTPUT_REG_START + j;
591 break;
592 }
593 }
594 if (!OutputRegisters[j])
595 PARSE_ERROR1("Unrecognized output register name");
596
597 /* Match ']' */
598 if (!Parse_String(s, "]"))
599 PARSE_ERROR1("Expected ]");
600
601 return GL_TRUE;
602 }
603
604
605 static GLboolean
606 Parse_MaskedDstReg(const GLubyte **s, struct vp_dst_register *dstReg)
607 {
608 GLubyte token[100];
609
610 /* Dst reg can be R<n> or o[n] */
611 if (!Peek_Token(s, token))
612 PARSE_ERROR;
613
614 if (token[0] == 'R') {
615 /* a temporary register */
616 if (!Parse_TempReg(s, &dstReg->Register))
617 PARSE_ERROR;
618 }
619 else if (!IsStateProgram && token[0] == 'o') {
620 /* an output register */
621 if (!Parse_OutputReg(s, &dstReg->Register))
622 PARSE_ERROR;
623 }
624 else if (IsStateProgram && token[0] == 'c') {
625 /* absolute program parameter register */
626 if (!Parse_AbsParamReg(s, &dstReg->Register))
627 PARSE_ERROR;
628 }
629 else {
630 PARSE_ERROR1("Bad destination register name");
631 }
632
633 /* Parse optional write mask */
634 if (!Peek_Token(s, token))
635 PARSE_ERROR;
636
637 if (token[0] == '.') {
638 /* got a mask */
639 GLint k = 0;
640
641 if (!Parse_String(s, "."))
642 PARSE_ERROR;
643
644 if (!Parse_Token(s, token))
645 PARSE_ERROR;
646
647 dstReg->WriteMask[0] = GL_FALSE;
648 dstReg->WriteMask[1] = GL_FALSE;
649 dstReg->WriteMask[2] = GL_FALSE;
650 dstReg->WriteMask[3] = GL_FALSE;
651
652 if (token[k] == 'x') {
653 dstReg->WriteMask[0] = GL_TRUE;
654 k++;
655 }
656 if (token[k] == 'y') {
657 dstReg->WriteMask[1] = GL_TRUE;
658 k++;
659 }
660 if (token[k] == 'z') {
661 dstReg->WriteMask[2] = GL_TRUE;
662 k++;
663 }
664 if (token[k] == 'w') {
665 dstReg->WriteMask[3] = GL_TRUE;
666 k++;
667 }
668 if (k == 0) {
669 PARSE_ERROR1("Bad writemask character");
670 }
671 return GL_TRUE;
672 }
673 else {
674 dstReg->WriteMask[0] = GL_TRUE;
675 dstReg->WriteMask[1] = GL_TRUE;
676 dstReg->WriteMask[2] = GL_TRUE;
677 dstReg->WriteMask[3] = GL_TRUE;
678 return GL_TRUE;
679 }
680 }
681
682
683 static GLboolean
684 Parse_SwizzleSrcReg(const GLubyte **s, struct vp_src_register *srcReg)
685 {
686 GLubyte token[100];
687
688 srcReg->RelAddr = GL_FALSE;
689
690 /* check for '-' */
691 if (!Peek_Token(s, token))
692 PARSE_ERROR;
693 if (token[0] == '-') {
694 (void) Parse_String(s, "-");
695 srcReg->Negate = GL_TRUE;
696 if (!Peek_Token(s, token))
697 PARSE_ERROR;
698 }
699 else {
700 srcReg->Negate = GL_FALSE;
701 }
702
703 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
704 if (token[0] == 'R') {
705 if (!Parse_TempReg(s, &srcReg->Register))
706 PARSE_ERROR;
707 }
708 else if (token[0] == 'c') {
709 if (!Parse_ParamReg(s, srcReg))
710 PARSE_ERROR;
711 }
712 else if (token[0] == 'v') {
713 if (!Parse_AttribReg(s, &srcReg->Register))
714 PARSE_ERROR;
715 }
716 else {
717 PARSE_ERROR2("Bad source register name", token);
718 }
719
720 /* init swizzle fields */
721 srcReg->Swizzle[0] = 0;
722 srcReg->Swizzle[1] = 1;
723 srcReg->Swizzle[2] = 2;
724 srcReg->Swizzle[3] = 3;
725
726 /* Look for optional swizzle suffix */
727 if (!Peek_Token(s, token))
728 PARSE_ERROR;
729 if (token[0] == '.') {
730 (void) Parse_String(s, "."); /* consume . */
731
732 if (!Parse_Token(s, token))
733 PARSE_ERROR;
734
735 if (token[1] == 0) {
736 /* single letter swizzle */
737 if (token[0] == 'x')
738 ASSIGN_4V(srcReg->Swizzle, 0, 0, 0, 0);
739 else if (token[0] == 'y')
740 ASSIGN_4V(srcReg->Swizzle, 1, 1, 1, 1);
741 else if (token[0] == 'z')
742 ASSIGN_4V(srcReg->Swizzle, 2, 2, 2, 2);
743 else if (token[0] == 'w')
744 ASSIGN_4V(srcReg->Swizzle, 3, 3, 3, 3);
745 else
746 PARSE_ERROR1("Expected x, y, z, or w");
747 }
748 else {
749 /* 2, 3 or 4-component swizzle */
750 GLint k;
751 for (k = 0; token[k] && k < 5; k++) {
752 if (token[k] == 'x')
753 srcReg->Swizzle[k] = 0;
754 else if (token[k] == 'y')
755 srcReg->Swizzle[k] = 1;
756 else if (token[k] == 'z')
757 srcReg->Swizzle[k] = 2;
758 else if (token[k] == 'w')
759 srcReg->Swizzle[k] = 3;
760 else
761 PARSE_ERROR;
762 }
763 if (k >= 5)
764 PARSE_ERROR;
765 }
766 }
767
768 return GL_TRUE;
769 }
770
771
772 static GLboolean
773 Parse_ScalarSrcReg(const GLubyte **s, struct vp_src_register *srcReg)
774 {
775 GLubyte token[100];
776
777 srcReg->RelAddr = GL_FALSE;
778
779 /* check for '-' */
780 if (!Peek_Token(s, token))
781 PARSE_ERROR;
782 if (token[0] == '-') {
783 srcReg->Negate = GL_TRUE;
784 (void) Parse_String(s, "-"); /* consume '-' */
785 if (!Peek_Token(s, token))
786 PARSE_ERROR;
787 }
788 else {
789 srcReg->Negate = GL_FALSE;
790 }
791
792 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
793 if (token[0] == 'R') {
794 if (!Parse_TempReg(s, &srcReg->Register))
795 PARSE_ERROR;
796 }
797 else if (token[0] == 'c') {
798 if (!Parse_ParamReg(s, srcReg))
799 PARSE_ERROR;
800 }
801 else if (token[0] == 'v') {
802 if (!Parse_AttribReg(s, &srcReg->Register))
803 PARSE_ERROR;
804 }
805 else {
806 PARSE_ERROR2("Bad source register name", token);
807 }
808
809 /* Look for .[xyzw] suffix */
810 if (!Parse_String(s, "."))
811 PARSE_ERROR;
812
813 if (!Parse_Token(s, token))
814 PARSE_ERROR;
815
816 if (token[0] == 'x' && token[1] == 0) {
817 srcReg->Swizzle[0] = 0;
818 }
819 else if (token[0] == 'y' && token[1] == 0) {
820 srcReg->Swizzle[0] = 1;
821 }
822 else if (token[0] == 'z' && token[1] == 0) {
823 srcReg->Swizzle[0] = 2;
824 }
825 else if (token[0] == 'w' && token[1] == 0) {
826 srcReg->Swizzle[0] = 3;
827 }
828 else {
829 PARSE_ERROR1("Bad scalar source suffix");
830 }
831 srcReg->Swizzle[1] = srcReg->Swizzle[2] = srcReg->Swizzle[3] = 0;
832
833 return GL_TRUE;
834 }
835
836
837 static GLint
838 Parse_UnaryOpInstruction(const GLubyte **s, struct vp_instruction *inst)
839 {
840 GLubyte token[100];
841
842 /* opcode */
843 if (!Parse_Token(s, token))
844 PARSE_ERROR;
845
846 if (StrEq(token, (GLubyte *) "MOV")) {
847 inst->Opcode = VP_OPCODE_MOV;
848 }
849 else if (StrEq(token, (GLubyte *) "LIT")) {
850 inst->Opcode = VP_OPCODE_LIT;
851 }
852 else if (StrEq(token, (GLubyte *) "ABS") && IsVersion1_1) {
853 inst->Opcode = VP_OPCODE_ABS;
854 }
855 else {
856 PARSE_ERROR;
857 }
858
859 /* dest reg */
860 if (!Parse_MaskedDstReg(s, &inst->DstReg))
861 PARSE_ERROR;
862
863 /* comma */
864 if (!Parse_String(s, ","))
865 PARSE_ERROR;
866
867 /* src arg */
868 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
869 PARSE_ERROR;
870
871 /* semicolon */
872 if (!Parse_String(s, ";"))
873 PARSE_ERROR;
874
875 return GL_TRUE;
876 }
877
878
879 static GLboolean
880 Parse_BiOpInstruction(const GLubyte **s, struct vp_instruction *inst)
881 {
882 GLubyte token[100];
883
884 /* opcode */
885 if (!Parse_Token(s, token))
886 PARSE_ERROR;
887
888 if (StrEq(token, (GLubyte *) "MUL")) {
889 inst->Opcode = VP_OPCODE_MUL;
890 }
891 else if (StrEq(token, (GLubyte *) "ADD")) {
892 inst->Opcode = VP_OPCODE_ADD;
893 }
894 else if (StrEq(token, (GLubyte *) "DP3")) {
895 inst->Opcode = VP_OPCODE_DP3;
896 }
897 else if (StrEq(token, (GLubyte *) "DP4")) {
898 inst->Opcode = VP_OPCODE_DP4;
899 }
900 else if (StrEq(token, (GLubyte *) "DST")) {
901 inst->Opcode = VP_OPCODE_DST;
902 }
903 else if (StrEq(token, (GLubyte *) "MIN")) {
904 inst->Opcode = VP_OPCODE_ADD;
905 }
906 else if (StrEq(token, (GLubyte *) "MAX")) {
907 inst->Opcode = VP_OPCODE_ADD;
908 }
909 else if (StrEq(token, (GLubyte *) "SLT")) {
910 inst->Opcode = VP_OPCODE_SLT;
911 }
912 else if (StrEq(token, (GLubyte *) "SGE")) {
913 inst->Opcode = VP_OPCODE_SGE;
914 }
915 else if (StrEq(token, (GLubyte *) "DPH") && IsVersion1_1) {
916 inst->Opcode = VP_OPCODE_DPH;
917 }
918 else if (StrEq(token, (GLubyte *) "SUB") && IsVersion1_1) {
919 inst->Opcode = VP_OPCODE_SUB;
920 }
921 else {
922 PARSE_ERROR;
923 }
924
925 /* dest reg */
926 if (!Parse_MaskedDstReg(s, &inst->DstReg))
927 PARSE_ERROR;
928
929 /* comma */
930 if (!Parse_String(s, ","))
931 PARSE_ERROR;
932
933 /* first src arg */
934 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
935 PARSE_ERROR;
936
937 /* comma */
938 if (!Parse_String(s, ","))
939 PARSE_ERROR;
940
941 /* second src arg */
942 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
943 PARSE_ERROR;
944
945 /* semicolon */
946 if (!Parse_String(s, ";"))
947 PARSE_ERROR;
948
949 /* make sure we don't reference more than one program parameter register */
950 if (IsProgRegister(inst->SrcReg[0].Register) &&
951 IsProgRegister(inst->SrcReg[1].Register) &&
952 inst->SrcReg[0].Register != inst->SrcReg[1].Register)
953 PARSE_ERROR1("Can't reference two program parameter registers");
954
955 /* make sure we don't reference more than one vertex attribute register */
956 if (IsInputRegister(inst->SrcReg[0].Register) &&
957 IsInputRegister(inst->SrcReg[1].Register) &&
958 inst->SrcReg[0].Register != inst->SrcReg[1].Register)
959 PARSE_ERROR1("Can't reference two vertex attribute registers");
960
961 return GL_TRUE;
962 }
963
964
965 static GLboolean
966 Parse_TriOpInstruction(const GLubyte **s, struct vp_instruction *inst)
967 {
968 GLubyte token[100];
969
970 /* opcode */
971 if (!Parse_Token(s, token))
972 PARSE_ERROR;
973
974 if (StrEq(token, (GLubyte *) "MAD")) {
975 inst->Opcode = VP_OPCODE_MAD;
976 }
977 else {
978 PARSE_ERROR;
979 }
980
981 /* dest reg */
982 if (!Parse_MaskedDstReg(s, &inst->DstReg))
983 PARSE_ERROR;
984
985 /* comma */
986 if (!Parse_String(s, ","))
987 PARSE_ERROR;
988
989 /* first src arg */
990 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
991 PARSE_ERROR;
992
993 /* comma */
994 if (!Parse_String(s, ","))
995 PARSE_ERROR;
996
997 /* second src arg */
998 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
999 PARSE_ERROR;
1000
1001 /* comma */
1002 if (!Parse_String(s, ","))
1003 PARSE_ERROR;
1004
1005 /* third src arg */
1006 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[2]))
1007 PARSE_ERROR;
1008
1009 /* semicolon */
1010 if (!Parse_String(s, ";"))
1011 PARSE_ERROR;
1012
1013 /* make sure we don't reference more than one program parameter register */
1014 if ((IsProgRegister(inst->SrcReg[0].Register) &&
1015 IsProgRegister(inst->SrcReg[1].Register) &&
1016 inst->SrcReg[0].Register != inst->SrcReg[1].Register) ||
1017 (IsProgRegister(inst->SrcReg[0].Register) &&
1018 IsProgRegister(inst->SrcReg[2].Register) &&
1019 inst->SrcReg[0].Register != inst->SrcReg[2].Register) ||
1020 (IsProgRegister(inst->SrcReg[1].Register) &&
1021 IsProgRegister(inst->SrcReg[2].Register) &&
1022 inst->SrcReg[1].Register != inst->SrcReg[2].Register))
1023 PARSE_ERROR1("Can only reference one program register");
1024
1025 /* make sure we don't reference more than one vertex attribute register */
1026 if ((IsInputRegister(inst->SrcReg[0].Register) &&
1027 IsInputRegister(inst->SrcReg[1].Register) &&
1028 inst->SrcReg[0].Register != inst->SrcReg[1].Register) ||
1029 (IsInputRegister(inst->SrcReg[0].Register) &&
1030 IsInputRegister(inst->SrcReg[2].Register) &&
1031 inst->SrcReg[0].Register != inst->SrcReg[2].Register) ||
1032 (IsInputRegister(inst->SrcReg[1].Register) &&
1033 IsInputRegister(inst->SrcReg[2].Register) &&
1034 inst->SrcReg[1].Register != inst->SrcReg[2].Register))
1035 PARSE_ERROR1("Can only reference one input register");
1036
1037 return GL_TRUE;
1038 }
1039
1040
1041 static GLboolean
1042 Parse_ScalarInstruction(const GLubyte **s, struct vp_instruction *inst)
1043 {
1044 GLubyte token[100];
1045
1046 /* opcode */
1047 if (!Parse_Token(s, token))
1048 PARSE_ERROR;
1049
1050 if (StrEq(token, (GLubyte *) "RCP")) {
1051 inst->Opcode = VP_OPCODE_RCP;
1052 }
1053 else if (StrEq(token, (GLubyte *) "RSQ")) {
1054 inst->Opcode = VP_OPCODE_RSQ;
1055 }
1056 else if (StrEq(token, (GLubyte *) "EXP")) {
1057 inst->Opcode = VP_OPCODE_EXP;
1058 }
1059 else if (StrEq(token, (GLubyte *) "LOG")) {
1060 inst->Opcode = VP_OPCODE_LOG;
1061 }
1062 else if (StrEq(token, (GLubyte *) "RCC") && IsVersion1_1) {
1063 inst->Opcode = VP_OPCODE_RCC;
1064 }
1065 else {
1066 PARSE_ERROR;
1067 }
1068
1069 /* dest reg */
1070 if (!Parse_MaskedDstReg(s, &inst->DstReg))
1071 PARSE_ERROR;
1072
1073 /* comma */
1074 if (!Parse_String(s, ","))
1075 PARSE_ERROR;
1076
1077 /* first src arg */
1078 if (!Parse_ScalarSrcReg(s, &inst->SrcReg[0]))
1079 PARSE_ERROR;
1080
1081 /* semicolon */
1082 if (!Parse_String(s, ";"))
1083 PARSE_ERROR;
1084
1085 return GL_TRUE;
1086 }
1087
1088
1089 static GLboolean
1090 Parse_AddressInstruction(const GLubyte **s, struct vp_instruction *inst)
1091 {
1092 inst->Opcode = VP_OPCODE_ARL;
1093
1094 /* opcode */
1095 if (!Parse_String(s, "ARL"))
1096 PARSE_ERROR;
1097
1098 /* dest A0 reg */
1099 if (!Parse_AddrReg(s))
1100 PARSE_ERROR;
1101
1102 /* comma */
1103 if (!Parse_String(s, ","))
1104 PARSE_ERROR;
1105
1106 /* parse src reg */
1107 if (!Parse_ScalarSrcReg(s, &inst->SrcReg[0]))
1108 PARSE_ERROR;
1109
1110 /* semicolon */
1111 if (!Parse_String(s, ";"))
1112 PARSE_ERROR;
1113
1114 return GL_TRUE;
1115 }
1116
1117
1118 static GLboolean
1119 Parse_EndInstruction(const GLubyte **s, struct vp_instruction *inst)
1120 {
1121 GLubyte token[100];
1122
1123 /* opcode */
1124 if (!Parse_String(s, "END"))
1125 PARSE_ERROR;
1126
1127 inst->Opcode = VP_OPCODE_END;
1128
1129 /* this should fail! */
1130 if (Parse_Token(s, token))
1131 PARSE_ERROR2("Unexpected token after END:", token);
1132 else
1133 return GL_TRUE;
1134 }
1135
1136
1137 static GLboolean
1138 Parse_OptionSequence(const GLubyte **s, struct vp_instruction program[])
1139 {
1140 while (1) {
1141 GLubyte token[100];
1142 if (!Peek_Token(s, token)) {
1143 PARSE_ERROR1("Unexpected end of input");
1144 return GL_FALSE; /* end of input */
1145 }
1146
1147 if (!StrEq(token, (GLubyte *) "OPTION"))
1148 return GL_TRUE; /* probably an instruction */
1149
1150 Parse_Token(s, token);
1151
1152 if (!Parse_String(s, "NV_position_invariant"))
1153 return GL_FALSE;
1154 if (!Parse_String(s, ";"))
1155 return GL_FALSE;
1156 IsPositionInvariant = GL_TRUE;
1157 }
1158 }
1159
1160
1161 static GLboolean
1162 Parse_InstructionSequence(const GLubyte **s, struct vp_instruction program[])
1163 {
1164 GLubyte token[100];
1165 GLint count = 0;
1166
1167 while (1) {
1168 struct vp_instruction *inst = program + count;
1169
1170 /* Initialize the instruction */
1171 inst->SrcReg[0].Register = -1;
1172 inst->SrcReg[1].Register = -1;
1173 inst->SrcReg[2].Register = -1;
1174 inst->DstReg.Register = -1;
1175
1176 if (!Peek_Token(s, token))
1177 PARSE_ERROR;
1178
1179 if (StrEq(token, (GLubyte *) "MOV") ||
1180 StrEq(token, (GLubyte *) "LIT") ||
1181 StrEq(token, (GLubyte *) "ABS")) {
1182 if (!Parse_UnaryOpInstruction(s, inst))
1183 PARSE_ERROR;
1184 }
1185 else if (StrEq(token, (GLubyte *) "MUL") ||
1186 StrEq(token, (GLubyte *) "ADD") ||
1187 StrEq(token, (GLubyte *) "DP3") ||
1188 StrEq(token, (GLubyte *) "DP4") ||
1189 StrEq(token, (GLubyte *) "DST") ||
1190 StrEq(token, (GLubyte *) "MIN") ||
1191 StrEq(token, (GLubyte *) "MAX") ||
1192 StrEq(token, (GLubyte *) "SLT") ||
1193 StrEq(token, (GLubyte *) "SGE") ||
1194 StrEq(token, (GLubyte *) "DPH") ||
1195 StrEq(token, (GLubyte *) "SUB")) {
1196 if (!Parse_BiOpInstruction(s, inst))
1197 PARSE_ERROR;
1198 }
1199 else if (StrEq(token, (GLubyte *) "MAD")) {
1200 if (!Parse_TriOpInstruction(s, inst))
1201 PARSE_ERROR;
1202 }
1203 else if (StrEq(token, (GLubyte *) "RCP") ||
1204 StrEq(token, (GLubyte *) "RSQ") ||
1205 StrEq(token, (GLubyte *) "EXP") ||
1206 StrEq(token, (GLubyte *) "LOG") ||
1207 StrEq(token, (GLubyte *) "RCC")) {
1208 if (!Parse_ScalarInstruction(s, inst))
1209 PARSE_ERROR;
1210 }
1211 else if (StrEq(token, (GLubyte *) "ARL")) {
1212 if (!Parse_AddressInstruction(s, inst))
1213 PARSE_ERROR;
1214 }
1215 else if (StrEq(token, (GLubyte *) "END")) {
1216 if (!Parse_EndInstruction(s, inst))
1217 PARSE_ERROR;
1218 else
1219 return GL_TRUE; /* all done */
1220 }
1221 else {
1222 /* bad instruction name */
1223 PARSE_ERROR2("Unexpected token: ", token);
1224 }
1225
1226 count++;
1227 if (count >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
1228 PARSE_ERROR1("Program too long");
1229 }
1230
1231 PARSE_ERROR;
1232 }
1233
1234
1235 static GLboolean
1236 Parse_Program(const GLubyte **s, struct vp_instruction instBuffer[])
1237 {
1238 if (IsVersion1_1) {
1239 if (!Parse_OptionSequence(s, instBuffer)) {
1240 return GL_FALSE;
1241 }
1242 }
1243 return Parse_InstructionSequence(s, instBuffer);
1244 }
1245
1246
1247 /**
1248 * Parse/compile the 'str' returning the compiled 'program'.
1249 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1250 * indicates the position of the error in 'str'.
1251 */
1252 void
1253 _mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
1254 const GLubyte *str, GLsizei len,
1255 struct vertex_program *program)
1256 {
1257 const GLubyte *s;
1258 struct vp_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1259 struct vp_instruction *newInst;
1260 GLenum target;
1261 GLubyte *programString;
1262
1263 /* Make a null-terminated copy of the program string */
1264 programString = (GLubyte *) MALLOC(len + 1);
1265 if (!programString) {
1266 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1267 return;
1268 }
1269 MEMCPY(programString, str, len);
1270 programString[len] = 0;
1271
1272 IsPositionInvariant = GL_FALSE;
1273 IsVersion1_1 = GL_FALSE;
1274
1275 /* check the program header */
1276 if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
1277 target = GL_VERTEX_PROGRAM_NV;
1278 s = programString + 7;
1279 IsStateProgram = GL_FALSE;
1280 }
1281 else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
1282 target = GL_VERTEX_PROGRAM_NV;
1283 s = programString + 7;
1284 IsStateProgram = GL_FALSE;
1285 IsVersion1_1 = GL_TRUE;
1286 }
1287 else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
1288 target = GL_VERTEX_STATE_PROGRAM_NV;
1289 s = programString + 8;
1290 IsStateProgram = GL_TRUE;
1291 }
1292 else {
1293 /* invalid header */
1294 ctx->Program.ErrorPos = 0;
1295 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1296 return;
1297 }
1298
1299 /* make sure target and header match */
1300 if (target != dstTarget) {
1301 _mesa_error(ctx, GL_INVALID_OPERATION,
1302 "glLoadProgramNV(target mismatch)");
1303 return;
1304 }
1305
1306 if (Parse_Program(&s, instBuffer)) {
1307 GLuint numInst;
1308 GLuint inputsRead = 0;
1309 GLuint outputsWritten = 0;
1310 GLuint progRegsWritten = 0;
1311
1312 /* Find length of the program and compute bitmasks to indicate which
1313 * vertex input registers are read, which vertex result registers are
1314 * written to, and which program registers are written to.
1315 * We could actually do this while we parse the program.
1316 */
1317 for (numInst = 0; instBuffer[numInst].Opcode != VP_OPCODE_END; numInst++) {
1318 const GLint srcReg0 = instBuffer[numInst].SrcReg[0].Register;
1319 const GLint srcReg1 = instBuffer[numInst].SrcReg[1].Register;
1320 const GLint srcReg2 = instBuffer[numInst].SrcReg[2].Register;
1321 const GLint dstReg = instBuffer[numInst].DstReg.Register;
1322
1323 if (IsOutputRegister(dstReg))
1324 outputsWritten |= (1 << (dstReg - VP_OUTPUT_REG_START));
1325 else if (IsProgRegister(dstReg))
1326 progRegsWritten |= (1 << (dstReg - VP_PROG_REG_START));
1327 if (IsInputRegister(srcReg0)
1328 && !instBuffer[numInst].SrcReg[0].RelAddr)
1329 inputsRead |= (1 << (srcReg0 - VP_INPUT_REG_START));
1330 if (IsInputRegister(srcReg1)
1331 && !instBuffer[numInst].SrcReg[1].RelAddr)
1332 inputsRead |= (1 << (srcReg1 - VP_INPUT_REG_START));
1333 if (IsInputRegister(srcReg2)
1334 && !instBuffer[numInst].SrcReg[2].RelAddr)
1335 inputsRead |= (1 << (srcReg2 - VP_INPUT_REG_START));
1336 }
1337 numInst++;
1338
1339 if (IsStateProgram) {
1340 if (progRegsWritten == 0) {
1341 _mesa_error(ctx, GL_INVALID_OPERATION,
1342 "glLoadProgramNV(c[#] not written)");
1343 return;
1344 }
1345 }
1346 else {
1347 if (!IsPositionInvariant && !(outputsWritten & 1)) {
1348 /* bit 1 = HPOS register */
1349 _mesa_error(ctx, GL_INVALID_OPERATION,
1350 "glLoadProgramNV(HPOS not written)");
1351 return;
1352 }
1353 }
1354
1355 program->InputsRead = inputsRead;
1356 program->OutputsWritten = outputsWritten;
1357 program->IsPositionInvariant = IsPositionInvariant;
1358
1359 /* copy the compiled instructions */
1360 assert(numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
1361 newInst = (struct vp_instruction *) MALLOC(numInst * sizeof(struct vp_instruction));
1362 if (!newInst) {
1363 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1364 FREE(programString);
1365 return; /* out of memory */
1366 }
1367 MEMCPY(newInst, instBuffer, numInst * sizeof(struct vp_instruction));
1368
1369 /* install the program */
1370 program->Base.Target = target;
1371 if (program->Base.String) {
1372 FREE(program->Base.String);
1373 }
1374 program->Base.String = programString;
1375 if (program->Instructions) {
1376 FREE(program->Instructions);
1377 }
1378 program->Instructions = newInst;
1379
1380 #ifdef DEBUG_foo
1381 _mesa_printf("--- glLoadProgramNV result ---\n");
1382 _mesa_print_nv_vertex_program(program);
1383 _mesa_printf("------------------------------\n");
1384 #endif
1385 }
1386 else {
1387 /* Error! */
1388 #ifdef DEBUG
1389 /* print a message showing the program line containing the error */
1390 ctx->Program.ErrorPos = s - str;
1391 {
1392 const GLubyte *p = str, *line = str;
1393 int lineNum = 1, statementNum = 1, column = 0;
1394 char errorLine[1000];
1395 int i;
1396 while (*p && p < s) { /* s is the error position */
1397 if (*p == '\n') {
1398 line = p + 1;
1399 lineNum++;
1400 column = 0;
1401 }
1402 else if (*p == ';') {
1403 statementNum++;
1404 }
1405 else
1406 column++;
1407 p++;
1408 }
1409 if (p) {
1410 /* Copy the line with the error into errorLine so we can null-
1411 * terminate it.
1412 */
1413 for (i = 0; line[i] != '\n' && line[i]; i++)
1414 errorLine[i] = (char) line[i];
1415 errorLine[i] = 0;
1416 }
1417 /*
1418 _mesa_debug("Error pos = %d (%c) col %d\n",
1419 ctx->Program.ErrorPos, *s, column);
1420 */
1421 _mesa_debug(ctx, "Vertex program error on line %2d: %s\n", lineNum, errorLine);
1422 _mesa_debug(ctx, " (statement %2d) near column %2d: ", statementNum, column+1);
1423 for (i = 0; i < column; i++)
1424 _mesa_debug(ctx, " ");
1425 _mesa_debug(ctx, "^\n");
1426 }
1427 #endif
1428 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1429 }
1430 }
1431
1432
1433 static void
1434 PrintSrcReg(const struct vp_src_register *src)
1435 {
1436 static const char comps[5] = "xyzw";
1437 if (src->Negate)
1438 _mesa_printf("-");
1439 if (src->RelAddr) {
1440 if (src->Register > 0)
1441 _mesa_printf("c[A0.x + %d]", src->Register);
1442 else if (src->Register < 0)
1443 _mesa_printf("c[A0.x - %d]", -src->Register);
1444 else
1445 _mesa_printf("c[A0.x]");
1446 }
1447 else if (src->Register >= VP_OUTPUT_REG_START
1448 && src->Register <= VP_OUTPUT_REG_END) {
1449 _mesa_printf("o[%s]", OutputRegisters[src->Register - VP_OUTPUT_REG_START]);
1450 }
1451 else if (src->Register >= VP_INPUT_REG_START
1452 && src->Register <= VP_INPUT_REG_END) {
1453 _mesa_printf("v[%s]", InputRegisters[src->Register - VP_INPUT_REG_START]);
1454 }
1455 else if (src->Register >= VP_PROG_REG_START
1456 && src->Register <= VP_PROG_REG_END) {
1457 _mesa_printf("c[%d]", src->Register - VP_PROG_REG_START);
1458 }
1459 else {
1460 _mesa_printf("R%d", src->Register - VP_TEMP_REG_START);
1461 }
1462
1463 if (src->Swizzle[0] == src->Swizzle[1] &&
1464 src->Swizzle[0] == src->Swizzle[2] &&
1465 src->Swizzle[0] == src->Swizzle[3]) {
1466 _mesa_printf(".%c", comps[src->Swizzle[0]]);
1467 }
1468 else if (src->Swizzle[0] != 0 ||
1469 src->Swizzle[1] != 1 ||
1470 src->Swizzle[2] != 2 ||
1471 src->Swizzle[3] != 3) {
1472 _mesa_printf(".%c%c%c%c",
1473 comps[src->Swizzle[0]],
1474 comps[src->Swizzle[1]],
1475 comps[src->Swizzle[2]],
1476 comps[src->Swizzle[3]]);
1477 }
1478 }
1479
1480
1481 static void
1482 PrintDstReg(const struct vp_dst_register *dst)
1483 {
1484 GLint w = dst->WriteMask[0] + dst->WriteMask[1]
1485 + dst->WriteMask[2] + dst->WriteMask[3];
1486
1487 if (dst->Register >= VP_OUTPUT_REG_START
1488 && dst->Register <= VP_OUTPUT_REG_END) {
1489 _mesa_printf("o[%s]", OutputRegisters[dst->Register - VP_OUTPUT_REG_START]);
1490 }
1491 else if (dst->Register >= VP_INPUT_REG_START
1492 && dst->Register <= VP_INPUT_REG_END) {
1493 _mesa_printf("v[%s]", InputRegisters[dst->Register - VP_INPUT_REG_START]);
1494 }
1495 else if (dst->Register >= VP_PROG_REG_START
1496 && dst->Register <= VP_PROG_REG_END) {
1497 _mesa_printf("c[%d]", dst->Register - VP_PROG_REG_START);
1498 }
1499 else {
1500 _mesa_printf("R%d", dst->Register - VP_TEMP_REG_START);
1501 }
1502
1503 if (w != 0 && w != 4) {
1504 _mesa_printf(".");
1505 if (dst->WriteMask[0])
1506 _mesa_printf("x");
1507 if (dst->WriteMask[1])
1508 _mesa_printf("y");
1509 if (dst->WriteMask[2])
1510 _mesa_printf("z");
1511 if (dst->WriteMask[3])
1512 _mesa_printf("w");
1513 }
1514 }
1515
1516
1517 /**
1518 * Print (unparse) the given vertex program. Just for debugging.
1519 */
1520 void
1521 _mesa_print_nv_vertex_program(const struct vertex_program *program)
1522 {
1523 const struct vp_instruction *inst;
1524
1525 for (inst = program->Instructions; ; inst++) {
1526 switch (inst->Opcode) {
1527 case VP_OPCODE_MOV:
1528 case VP_OPCODE_LIT:
1529 case VP_OPCODE_RCP:
1530 case VP_OPCODE_RSQ:
1531 case VP_OPCODE_EXP:
1532 case VP_OPCODE_LOG:
1533 case VP_OPCODE_RCC:
1534 case VP_OPCODE_ABS:
1535 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1536 PrintDstReg(&inst->DstReg);
1537 _mesa_printf(", ");
1538 PrintSrcReg(&inst->SrcReg[0]);
1539 _mesa_printf(";\n");
1540 break;
1541 case VP_OPCODE_MUL:
1542 case VP_OPCODE_ADD:
1543 case VP_OPCODE_DP3:
1544 case VP_OPCODE_DP4:
1545 case VP_OPCODE_DST:
1546 case VP_OPCODE_MIN:
1547 case VP_OPCODE_MAX:
1548 case VP_OPCODE_SLT:
1549 case VP_OPCODE_SGE:
1550 case VP_OPCODE_DPH:
1551 case VP_OPCODE_SUB:
1552 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1553 PrintDstReg(&inst->DstReg);
1554 _mesa_printf(", ");
1555 PrintSrcReg(&inst->SrcReg[0]);
1556 _mesa_printf(", ");
1557 PrintSrcReg(&inst->SrcReg[1]);
1558 _mesa_printf(";\n");
1559 break;
1560 case VP_OPCODE_MAD:
1561 _mesa_printf("MAD ");
1562 PrintDstReg(&inst->DstReg);
1563 _mesa_printf(", ");
1564 PrintSrcReg(&inst->SrcReg[0]);
1565 _mesa_printf(", ");
1566 PrintSrcReg(&inst->SrcReg[1]);
1567 _mesa_printf(", ");
1568 PrintSrcReg(&inst->SrcReg[2]);
1569 _mesa_printf(";\n");
1570 break;
1571 case VP_OPCODE_ARL:
1572 _mesa_printf("ARL A0.x, ");
1573 PrintSrcReg(&inst->SrcReg[0]);
1574 _mesa_printf(";\n");
1575 break;
1576 case VP_OPCODE_END:
1577 _mesa_printf("END\n");
1578 return;
1579 default:
1580 _mesa_printf("BAD INSTRUCTION\n");
1581 }
1582 }
1583 }
1584