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