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