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