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