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