fix minor warnings with casts
[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 GLboolean anyProgRegsWritten;
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 /* NOTE: the order here must match opcodes in nvvertprog.h */
286 static const char *Opcodes[] = {
287 "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
288 "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
289 "ABS", "END",
290 /* GL_ARB_vertex_program */
291 "FLR", "FRC", "EX2", "LG2", "POW", "XPD", "SWZ",
292 NULL
293 };
294
295
296
297 /**
298 * Parse a temporary register: Rnn
299 */
300 static GLboolean
301 Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
302 {
303 GLubyte token[100];
304
305 /* Should be 'R##' */
306 if (!Parse_Token(parseState, token))
307 RETURN_ERROR;
308 if (token[0] != 'R')
309 RETURN_ERROR1("Expected R##");
310
311 if (IsDigit(token[1])) {
312 GLint reg = _mesa_atoi((char *) (token + 1));
313 if (reg >= MAX_NV_VERTEX_PROGRAM_TEMPS)
314 RETURN_ERROR1("Bad temporary register name");
315 *tempRegNum = reg;
316 }
317 else {
318 RETURN_ERROR1("Bad temporary register name");
319 }
320
321 return GL_TRUE;
322 }
323
324
325 /**
326 * Parse address register "A0.x"
327 */
328 static GLboolean
329 Parse_AddrReg(struct parse_state *parseState)
330 {
331 /* match 'A0' */
332 if (!Parse_String(parseState, "A0"))
333 RETURN_ERROR;
334
335 /* match '.' */
336 if (!Parse_String(parseState, "."))
337 RETURN_ERROR;
338
339 /* match 'x' */
340 if (!Parse_String(parseState, "x"))
341 RETURN_ERROR;
342
343 return GL_TRUE;
344 }
345
346
347 /**
348 * Parse absolute program parameter register "c[##]"
349 */
350 static GLboolean
351 Parse_AbsParamReg(struct parse_state *parseState, GLint *regNum)
352 {
353 GLubyte token[100];
354
355 if (!Parse_String(parseState, "c"))
356 RETURN_ERROR;
357
358 if (!Parse_String(parseState, "["))
359 RETURN_ERROR;
360
361 if (!Parse_Token(parseState, token))
362 RETURN_ERROR;
363
364 if (IsDigit(token[0])) {
365 /* a numbered program parameter register */
366 GLint reg = _mesa_atoi((char *) token);
367 if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
368 RETURN_ERROR1("Bad program parameter number");
369 *regNum = reg;
370 }
371 else {
372 RETURN_ERROR;
373 }
374
375 if (!Parse_String(parseState, "]"))
376 RETURN_ERROR;
377
378 return GL_TRUE;
379 }
380
381
382 static GLboolean
383 Parse_ParamReg(struct parse_state *parseState, struct vp_src_register *srcReg)
384 {
385 GLubyte token[100];
386
387 if (!Parse_String(parseState, "c"))
388 RETURN_ERROR;
389
390 if (!Parse_String(parseState, "["))
391 RETURN_ERROR;
392
393 if (!Peek_Token(parseState, token))
394 RETURN_ERROR;
395
396 if (IsDigit(token[0])) {
397 /* a numbered program parameter register */
398 GLint reg;
399 (void) Parse_Token(parseState, token);
400 reg = _mesa_atoi((char *) token);
401 if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
402 RETURN_ERROR1("Bad program parameter number");
403 srcReg->File = PROGRAM_ENV_PARAM;
404 srcReg->Index = reg;
405 }
406 else if (_mesa_strcmp((const char *) token, "A0") == 0) {
407 /* address register "A0.x" */
408 if (!Parse_AddrReg(parseState))
409 RETURN_ERROR;
410
411 srcReg->RelAddr = GL_TRUE;
412 srcReg->File = PROGRAM_ENV_PARAM;
413 /* Look for +/-N offset */
414 if (!Peek_Token(parseState, token))
415 RETURN_ERROR;
416
417 if (token[0] == '-' || token[0] == '+') {
418 const GLubyte sign = token[0];
419 (void) Parse_Token(parseState, token); /* consume +/- */
420
421 /* an integer should be next */
422 if (!Parse_Token(parseState, token))
423 RETURN_ERROR;
424
425 if (IsDigit(token[0])) {
426 const GLint k = _mesa_atoi((char *) token);
427 if (sign == '-') {
428 if (k > 64)
429 RETURN_ERROR1("Bad address offset");
430 srcReg->Index = -k;
431 }
432 else {
433 if (k > 63)
434 RETURN_ERROR1("Bad address offset");
435 srcReg->Index = k;
436 }
437 }
438 else {
439 RETURN_ERROR;
440 }
441 }
442 else {
443 /* probably got a ']', catch it below */
444 }
445 }
446 else {
447 RETURN_ERROR;
448 }
449
450 /* Match closing ']' */
451 if (!Parse_String(parseState, "]"))
452 RETURN_ERROR;
453
454 return GL_TRUE;
455 }
456
457
458 /**
459 * Parse v[#] or v[<name>]
460 */
461 static GLboolean
462 Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum)
463 {
464 GLubyte token[100];
465 GLint j;
466
467 /* Match 'v' */
468 if (!Parse_String(parseState, "v"))
469 RETURN_ERROR;
470
471 /* Match '[' */
472 if (!Parse_String(parseState, "["))
473 RETURN_ERROR;
474
475 /* match number or named register */
476 if (!Parse_Token(parseState, token))
477 RETURN_ERROR;
478
479 if (parseState->isStateProgram && token[0] != '0')
480 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
481
482 if (IsDigit(token[0])) {
483 GLint reg = _mesa_atoi((char *) token);
484 if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS)
485 RETURN_ERROR1("Bad vertex attribute register name");
486 *tempRegNum = reg;
487 }
488 else {
489 for (j = 0; InputRegisters[j]; j++) {
490 if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
491 *tempRegNum = j;
492 break;
493 }
494 }
495 if (!InputRegisters[j]) {
496 /* unknown input register label */
497 RETURN_ERROR2("Bad register name", token);
498 }
499 }
500
501 /* Match '[' */
502 if (!Parse_String(parseState, "]"))
503 RETURN_ERROR;
504
505 return GL_TRUE;
506 }
507
508
509 static GLboolean
510 Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
511 {
512 GLubyte token[100];
513 GLint start, j;
514
515 /* Match 'o' */
516 if (!Parse_String(parseState, "o"))
517 RETURN_ERROR;
518
519 /* Match '[' */
520 if (!Parse_String(parseState, "["))
521 RETURN_ERROR;
522
523 /* Get output reg name */
524 if (!Parse_Token(parseState, token))
525 RETURN_ERROR;
526
527 if (parseState->isPositionInvariant)
528 start = 1; /* skip HPOS register name */
529 else
530 start = 0;
531
532 /* try to match an output register name */
533 for (j = start; OutputRegisters[j]; j++) {
534 if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) {
535 *outputRegNum = j;
536 break;
537 }
538 }
539 if (!OutputRegisters[j])
540 RETURN_ERROR1("Unrecognized output register name");
541
542 /* Match ']' */
543 if (!Parse_String(parseState, "]"))
544 RETURN_ERROR1("Expected ]");
545
546 return GL_TRUE;
547 }
548
549
550 static GLboolean
551 Parse_MaskedDstReg(struct parse_state *parseState, struct vp_dst_register *dstReg)
552 {
553 GLubyte token[100];
554
555 /* Dst reg can be R<n> or o[n] */
556 if (!Peek_Token(parseState, token))
557 RETURN_ERROR;
558
559 if (token[0] == 'R') {
560 /* a temporary register */
561 dstReg->File = PROGRAM_TEMPORARY;
562 if (!Parse_TempReg(parseState, &dstReg->Index))
563 RETURN_ERROR;
564 }
565 else if (!parseState->isStateProgram && token[0] == 'o') {
566 /* an output register */
567 dstReg->File = PROGRAM_OUTPUT;
568 if (!Parse_OutputReg(parseState, &dstReg->Index))
569 RETURN_ERROR;
570 }
571 else if (parseState->isStateProgram && token[0] == 'c') {
572 /* absolute program parameter register */
573 dstReg->File = PROGRAM_ENV_PARAM;
574 if (!Parse_AbsParamReg(parseState, &dstReg->Index))
575 RETURN_ERROR;
576 }
577 else {
578 RETURN_ERROR1("Bad destination register name");
579 }
580
581 /* Parse optional write mask */
582 if (!Peek_Token(parseState, token))
583 RETURN_ERROR;
584
585 if (token[0] == '.') {
586 /* got a mask */
587 GLint k = 0;
588
589 if (!Parse_String(parseState, "."))
590 RETURN_ERROR;
591
592 if (!Parse_Token(parseState, token))
593 RETURN_ERROR;
594
595 dstReg->WriteMask[0] = GL_FALSE;
596 dstReg->WriteMask[1] = GL_FALSE;
597 dstReg->WriteMask[2] = GL_FALSE;
598 dstReg->WriteMask[3] = GL_FALSE;
599
600 if (token[k] == 'x') {
601 dstReg->WriteMask[0] = GL_TRUE;
602 k++;
603 }
604 if (token[k] == 'y') {
605 dstReg->WriteMask[1] = GL_TRUE;
606 k++;
607 }
608 if (token[k] == 'z') {
609 dstReg->WriteMask[2] = GL_TRUE;
610 k++;
611 }
612 if (token[k] == 'w') {
613 dstReg->WriteMask[3] = GL_TRUE;
614 k++;
615 }
616 if (k == 0) {
617 RETURN_ERROR1("Bad writemask character");
618 }
619 return GL_TRUE;
620 }
621 else {
622 dstReg->WriteMask[0] = GL_TRUE;
623 dstReg->WriteMask[1] = GL_TRUE;
624 dstReg->WriteMask[2] = GL_TRUE;
625 dstReg->WriteMask[3] = GL_TRUE;
626 return GL_TRUE;
627 }
628 }
629
630
631 static GLboolean
632 Parse_SwizzleSrcReg(struct parse_state *parseState, struct vp_src_register *srcReg)
633 {
634 GLubyte token[100];
635
636 srcReg->RelAddr = GL_FALSE;
637
638 /* check for '-' */
639 if (!Peek_Token(parseState, token))
640 RETURN_ERROR;
641 if (token[0] == '-') {
642 (void) Parse_String(parseState, "-");
643 srcReg->Negate = GL_TRUE;
644 if (!Peek_Token(parseState, token))
645 RETURN_ERROR;
646 }
647 else {
648 srcReg->Negate = GL_FALSE;
649 }
650
651 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
652 if (token[0] == 'R') {
653 srcReg->File = PROGRAM_TEMPORARY;
654 if (!Parse_TempReg(parseState, &srcReg->Index))
655 RETURN_ERROR;
656 }
657 else if (token[0] == 'c') {
658 if (!Parse_ParamReg(parseState, srcReg))
659 RETURN_ERROR;
660 }
661 else if (token[0] == 'v') {
662 srcReg->File = PROGRAM_INPUT;
663 if (!Parse_AttribReg(parseState, &srcReg->Index))
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 srcReg->File = PROGRAM_TEMPORARY;
745 if (!Parse_TempReg(parseState, &srcReg->Index))
746 RETURN_ERROR;
747 }
748 else if (token[0] == 'c') {
749 if (!Parse_ParamReg(parseState, srcReg))
750 RETURN_ERROR;
751 }
752 else if (token[0] == 'v') {
753 srcReg->File = PROGRAM_INPUT;
754 if (!Parse_AttribReg(parseState, &srcReg->Index))
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 inst->StringPos = parseState->curLine - parseState->start;
798
799 /* dest reg */
800 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
801 RETURN_ERROR;
802
803 /* comma */
804 if (!Parse_String(parseState, ","))
805 RETURN_ERROR;
806
807 /* src arg */
808 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
809 RETURN_ERROR;
810
811 /* semicolon */
812 if (!Parse_String(parseState, ";"))
813 RETURN_ERROR;
814
815 return GL_TRUE;
816 }
817
818
819 static GLboolean
820 Parse_BiOpInstruction(struct parse_state *parseState,
821 struct vp_instruction *inst, enum vp_opcode opcode)
822 {
823 if (opcode == VP_OPCODE_DPH && !parseState->isVersion1_1)
824 RETURN_ERROR1("DPH illegal for vertex program 1.0");
825 if (opcode == VP_OPCODE_SUB && !parseState->isVersion1_1)
826 RETURN_ERROR1("SUB illegal for vertex program 1.0");
827
828 inst->Opcode = opcode;
829 inst->StringPos = parseState->curLine - parseState->start;
830
831 /* dest reg */
832 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
833 RETURN_ERROR;
834
835 /* comma */
836 if (!Parse_String(parseState, ","))
837 RETURN_ERROR;
838
839 /* first src arg */
840 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
841 RETURN_ERROR;
842
843 /* comma */
844 if (!Parse_String(parseState, ","))
845 RETURN_ERROR;
846
847 /* second src arg */
848 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
849 RETURN_ERROR;
850
851 /* semicolon */
852 if (!Parse_String(parseState, ";"))
853 RETURN_ERROR;
854
855 /* make sure we don't reference more than one program parameter register */
856 if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
857 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
858 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
859 RETURN_ERROR1("Can't reference two program parameter registers");
860
861 /* make sure we don't reference more than one vertex attribute register */
862 if (inst->SrcReg[0].File == PROGRAM_INPUT &&
863 inst->SrcReg[1].File == PROGRAM_INPUT &&
864 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
865 RETURN_ERROR1("Can't reference two vertex attribute registers");
866
867 return GL_TRUE;
868 }
869
870
871 static GLboolean
872 Parse_TriOpInstruction(struct parse_state *parseState,
873 struct vp_instruction *inst, enum vp_opcode opcode)
874 {
875 inst->Opcode = opcode;
876 inst->StringPos = parseState->curLine - parseState->start;
877
878 /* dest reg */
879 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
880 RETURN_ERROR;
881
882 /* comma */
883 if (!Parse_String(parseState, ","))
884 RETURN_ERROR;
885
886 /* first src arg */
887 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
888 RETURN_ERROR;
889
890 /* comma */
891 if (!Parse_String(parseState, ","))
892 RETURN_ERROR;
893
894 /* second src arg */
895 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
896 RETURN_ERROR;
897
898 /* comma */
899 if (!Parse_String(parseState, ","))
900 RETURN_ERROR;
901
902 /* third src arg */
903 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2]))
904 RETURN_ERROR;
905
906 /* semicolon */
907 if (!Parse_String(parseState, ";"))
908 RETURN_ERROR;
909
910 /* make sure we don't reference more than one program parameter register */
911 if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
912 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
913 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
914 (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
915 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
916 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
917 (inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
918 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
919 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
920 RETURN_ERROR1("Can only reference one program register");
921
922 /* make sure we don't reference more than one vertex attribute register */
923 if ((inst->SrcReg[0].File == PROGRAM_INPUT &&
924 inst->SrcReg[1].File == PROGRAM_INPUT &&
925 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
926 (inst->SrcReg[0].File == PROGRAM_INPUT &&
927 inst->SrcReg[2].File == PROGRAM_INPUT &&
928 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
929 (inst->SrcReg[1].File == PROGRAM_INPUT &&
930 inst->SrcReg[2].File == PROGRAM_INPUT &&
931 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
932 RETURN_ERROR1("Can only reference one input register");
933
934 return GL_TRUE;
935 }
936
937
938 static GLboolean
939 Parse_ScalarInstruction(struct parse_state *parseState,
940 struct vp_instruction *inst, enum vp_opcode opcode)
941 {
942 if (opcode == VP_OPCODE_RCC && !parseState->isVersion1_1)
943 RETURN_ERROR1("RCC illegal for vertex program 1.0");
944
945 inst->Opcode = opcode;
946 inst->StringPos = parseState->curLine - parseState->start;
947
948 /* dest reg */
949 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
950 RETURN_ERROR;
951
952 /* comma */
953 if (!Parse_String(parseState, ","))
954 RETURN_ERROR;
955
956 /* first src arg */
957 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
958 RETURN_ERROR;
959
960 /* semicolon */
961 if (!Parse_String(parseState, ";"))
962 RETURN_ERROR;
963
964 return GL_TRUE;
965 }
966
967
968 static GLboolean
969 Parse_AddressInstruction(struct parse_state *parseState, struct vp_instruction *inst)
970 {
971 inst->Opcode = VP_OPCODE_ARL;
972 inst->StringPos = parseState->curLine - parseState->start;
973
974 /* dest A0 reg */
975 if (!Parse_AddrReg(parseState))
976 RETURN_ERROR;
977
978 /* comma */
979 if (!Parse_String(parseState, ","))
980 RETURN_ERROR;
981
982 /* parse src reg */
983 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
984 RETURN_ERROR;
985
986 /* semicolon */
987 if (!Parse_String(parseState, ";"))
988 RETURN_ERROR;
989
990 return GL_TRUE;
991 }
992
993
994 static GLboolean
995 Parse_EndInstruction(struct parse_state *parseState, struct vp_instruction *inst)
996 {
997 GLubyte token[100];
998
999 inst->Opcode = VP_OPCODE_END;
1000 inst->StringPos = parseState->curLine - parseState->start;
1001
1002 /* this should fail! */
1003 if (Parse_Token(parseState, token))
1004 RETURN_ERROR2("Unexpected token after END:", token);
1005 else
1006 return GL_TRUE;
1007 }
1008
1009
1010 static GLboolean
1011 Parse_OptionSequence(struct parse_state *parseState,
1012 struct vp_instruction program[])
1013 {
1014 while (1) {
1015 if (!Parse_String(parseState, "OPTION"))
1016 return GL_TRUE; /* ok, not an OPTION statement */
1017 if (Parse_String(parseState, "NV_position_invariant")) {
1018 parseState->isPositionInvariant = GL_TRUE;
1019 }
1020 else {
1021 RETURN_ERROR1("unexpected OPTION statement");
1022 }
1023 if (!Parse_String(parseState, ";"))
1024 return GL_FALSE;
1025 }
1026 }
1027
1028
1029 static GLboolean
1030 Parse_InstructionSequence(struct parse_state *parseState,
1031 struct vp_instruction program[])
1032 {
1033 while (1) {
1034 struct vp_instruction *inst = program + parseState->numInst;
1035
1036 /* Initialize the instruction */
1037 inst->SrcReg[0].File = (enum register_file) -1;
1038 inst->SrcReg[1].File = (enum register_file) -1;
1039 inst->SrcReg[2].File = (enum register_file) -1;
1040 inst->DstReg.File = (enum register_file) -1;
1041
1042 if (Parse_String(parseState, "MOV")) {
1043 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_MOV))
1044 RETURN_ERROR;
1045 }
1046 else if (Parse_String(parseState, "LIT")) {
1047 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_LIT))
1048 RETURN_ERROR;
1049 }
1050 else if (Parse_String(parseState, "ABS")) {
1051 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_ABS))
1052 RETURN_ERROR;
1053 }
1054 else if (Parse_String(parseState, "MUL")) {
1055 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MUL))
1056 RETURN_ERROR;
1057 }
1058 else if (Parse_String(parseState, "ADD")) {
1059 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_ADD))
1060 RETURN_ERROR;
1061 }
1062 else if (Parse_String(parseState, "DP3")) {
1063 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP3))
1064 RETURN_ERROR;
1065 }
1066 else if (Parse_String(parseState, "DP4")) {
1067 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP4))
1068 RETURN_ERROR;
1069 }
1070 else if (Parse_String(parseState, "DST")) {
1071 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DST))
1072 RETURN_ERROR;
1073 }
1074 else if (Parse_String(parseState, "MIN")) {
1075 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MIN))
1076 RETURN_ERROR;
1077 }
1078 else if (Parse_String(parseState, "MAX")) {
1079 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MAX))
1080 RETURN_ERROR;
1081 }
1082 else if (Parse_String(parseState, "SLT")) {
1083 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SLT))
1084 RETURN_ERROR;
1085 }
1086 else if (Parse_String(parseState, "SGE")) {
1087 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SGE))
1088 RETURN_ERROR;
1089 }
1090 else if (Parse_String(parseState, "DPH")) {
1091 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DPH))
1092 RETURN_ERROR;
1093 }
1094 else if (Parse_String(parseState, "SUB")) {
1095 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SUB))
1096 RETURN_ERROR;
1097 }
1098 else if (Parse_String(parseState, "MAD")) {
1099 if (!Parse_TriOpInstruction(parseState, inst, VP_OPCODE_MAD))
1100 RETURN_ERROR;
1101 }
1102 else if (Parse_String(parseState, "RCP")) {
1103 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCP))
1104 RETURN_ERROR;
1105 }
1106 else if (Parse_String(parseState, "RSQ")) {
1107 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RSQ))
1108 RETURN_ERROR;
1109 }
1110 else if (Parse_String(parseState, "EXP")) {
1111 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_EXP))
1112 RETURN_ERROR;
1113 }
1114 else if (Parse_String(parseState, "LOG")) {
1115 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_LOG))
1116 RETURN_ERROR;
1117 }
1118 else if (Parse_String(parseState, "RCC")) {
1119 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCC))
1120 RETURN_ERROR;
1121 }
1122 else if (Parse_String(parseState, "ARL")) {
1123 if (!Parse_AddressInstruction(parseState, inst))
1124 RETURN_ERROR;
1125 }
1126 else if (Parse_String(parseState, "END")) {
1127 if (!Parse_EndInstruction(parseState, inst))
1128 RETURN_ERROR;
1129 else {
1130 parseState->numInst++;
1131 return GL_TRUE; /* all done */
1132 }
1133 }
1134 else {
1135 /* bad instruction name */
1136 RETURN_ERROR1("Unexpected token");
1137 }
1138
1139 /* examine input/output registers */
1140 if (inst->DstReg.File == PROGRAM_OUTPUT)
1141 parseState->outputsWritten |= (1 << inst->DstReg.Index);
1142 else if (inst->DstReg.File == PROGRAM_ENV_PARAM)
1143 parseState->anyProgRegsWritten = GL_TRUE;
1144
1145 if (inst->SrcReg[0].File == PROGRAM_INPUT)
1146 parseState->inputsRead |= (1 << inst->SrcReg[0].Index);
1147 if (inst->SrcReg[1].File == PROGRAM_INPUT)
1148 parseState->inputsRead |= (1 << inst->SrcReg[1].Index);
1149 if (inst->SrcReg[2].File == PROGRAM_INPUT)
1150 parseState->inputsRead |= (1 << inst->SrcReg[2].Index);
1151
1152 parseState->numInst++;
1153
1154 if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
1155 RETURN_ERROR1("Program too long");
1156 }
1157
1158 RETURN_ERROR;
1159 }
1160
1161
1162 static GLboolean
1163 Parse_Program(struct parse_state *parseState,
1164 struct vp_instruction instBuffer[])
1165 {
1166 if (parseState->isVersion1_1) {
1167 if (!Parse_OptionSequence(parseState, instBuffer)) {
1168 return GL_FALSE;
1169 }
1170 }
1171 return Parse_InstructionSequence(parseState, instBuffer);
1172 }
1173
1174
1175 /**
1176 * Parse/compile the 'str' returning the compiled 'program'.
1177 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1178 * indicates the position of the error in 'str'.
1179 */
1180 void
1181 _mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
1182 const GLubyte *str, GLsizei len,
1183 struct vertex_program *program)
1184 {
1185 struct parse_state parseState;
1186 struct vp_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1187 struct vp_instruction *newInst;
1188 GLenum target;
1189 GLubyte *programString;
1190
1191 /* Make a null-terminated copy of the program string */
1192 programString = (GLubyte *) MALLOC(len + 1);
1193 if (!programString) {
1194 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1195 return;
1196 }
1197 MEMCPY(programString, str, len);
1198 programString[len] = 0;
1199
1200 /* Get ready to parse */
1201 parseState.ctx = ctx;
1202 parseState.start = programString;
1203 parseState.isPositionInvariant = GL_FALSE;
1204 parseState.isVersion1_1 = GL_FALSE;
1205 parseState.numInst = 0;
1206 parseState.inputsRead = 0;
1207 parseState.outputsWritten = 0;
1208 parseState.anyProgRegsWritten = GL_FALSE;
1209
1210 /* Reset error state */
1211 _mesa_set_program_error(ctx, -1, NULL);
1212
1213 /* check the program header */
1214 if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
1215 target = GL_VERTEX_PROGRAM_NV;
1216 parseState.pos = programString + 7;
1217 parseState.isStateProgram = GL_FALSE;
1218 }
1219 else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
1220 target = GL_VERTEX_PROGRAM_NV;
1221 parseState.pos = programString + 7;
1222 parseState.isStateProgram = GL_FALSE;
1223 parseState.isVersion1_1 = GL_TRUE;
1224 }
1225 else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
1226 target = GL_VERTEX_STATE_PROGRAM_NV;
1227 parseState.pos = programString + 8;
1228 parseState.isStateProgram = GL_TRUE;
1229 }
1230 else {
1231 /* invalid header */
1232 ctx->Program.ErrorPos = 0;
1233 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1234 return;
1235 }
1236
1237 /* make sure target and header match */
1238 if (target != dstTarget) {
1239 _mesa_error(ctx, GL_INVALID_OPERATION,
1240 "glLoadProgramNV(target mismatch)");
1241 return;
1242 }
1243
1244
1245 if (Parse_Program(&parseState, instBuffer)) {
1246 /* successful parse! */
1247
1248 if (parseState.isStateProgram) {
1249 if (!parseState.anyProgRegsWritten) {
1250 _mesa_error(ctx, GL_INVALID_OPERATION,
1251 "glLoadProgramNV(c[#] not written)");
1252 return;
1253 }
1254 }
1255 else {
1256 if (!parseState.isPositionInvariant &&
1257 !(parseState.outputsWritten & 1)) {
1258 /* bit 1 = HPOS register */
1259 _mesa_error(ctx, GL_INVALID_OPERATION,
1260 "glLoadProgramNV(HPOS not written)");
1261 return;
1262 }
1263 }
1264
1265 /* copy the compiled instructions */
1266 assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
1267 newInst = (struct vp_instruction *)
1268 MALLOC(parseState.numInst * sizeof(struct vp_instruction));
1269 if (!newInst) {
1270 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1271 FREE(programString);
1272 return; /* out of memory */
1273 }
1274 MEMCPY(newInst, instBuffer,
1275 parseState.numInst * sizeof(struct vp_instruction));
1276
1277 /* install the program */
1278 program->Base.Target = target;
1279 if (program->Base.String) {
1280 FREE(program->Base.String);
1281 }
1282 program->Base.String = programString;
1283 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1284 if (program->Instructions) {
1285 FREE(program->Instructions);
1286 }
1287 program->Instructions = newInst;
1288 program->InputsRead = parseState.inputsRead;
1289 program->OutputsWritten = parseState.outputsWritten;
1290 program->IsPositionInvariant = parseState.isPositionInvariant;
1291
1292 #ifdef DEBUG
1293 _mesa_printf("--- glLoadProgramNV result ---\n");
1294 _mesa_print_nv_vertex_program(program);
1295 _mesa_printf("------------------------------\n");
1296 #endif
1297 }
1298 else {
1299 /* Error! */
1300 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1301 /* NOTE: _mesa_set_program_error would have been called already */
1302 /* GL_NV_vertex_program isn't supposed to set the error string
1303 * so we reset it here.
1304 */
1305 _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
1306 }
1307 }
1308
1309
1310 static void
1311 PrintSrcReg(const struct vp_src_register *src)
1312 {
1313 static const char comps[5] = "xyzw";
1314 if (src->Negate)
1315 _mesa_printf("-");
1316 if (src->RelAddr) {
1317 if (src->Index > 0)
1318 _mesa_printf("c[A0.x + %d]", src->Index);
1319 else if (src->Index < 0)
1320 _mesa_printf("c[A0.x - %d]", -src->Index);
1321 else
1322 _mesa_printf("c[A0.x]");
1323 }
1324 else if (src->File == PROGRAM_OUTPUT) {
1325 _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1326 }
1327 else if (src->File == PROGRAM_INPUT) {
1328 _mesa_printf("v[%s]", InputRegisters[src->Index]);
1329 }
1330 else if (src->File == PROGRAM_ENV_PARAM) {
1331 _mesa_printf("c[%d]", src->Index);
1332 }
1333 else {
1334 ASSERT(src->File == PROGRAM_TEMPORARY);
1335 _mesa_printf("R%d", src->Index);
1336 }
1337
1338 if (src->Swizzle[0] == src->Swizzle[1] &&
1339 src->Swizzle[0] == src->Swizzle[2] &&
1340 src->Swizzle[0] == src->Swizzle[3]) {
1341 _mesa_printf(".%c", comps[src->Swizzle[0]]);
1342 }
1343 else if (src->Swizzle[0] != 0 ||
1344 src->Swizzle[1] != 1 ||
1345 src->Swizzle[2] != 2 ||
1346 src->Swizzle[3] != 3) {
1347 _mesa_printf(".%c%c%c%c",
1348 comps[src->Swizzle[0]],
1349 comps[src->Swizzle[1]],
1350 comps[src->Swizzle[2]],
1351 comps[src->Swizzle[3]]);
1352 }
1353 }
1354
1355
1356 static void
1357 PrintDstReg(const struct vp_dst_register *dst)
1358 {
1359 GLint w = dst->WriteMask[0] + dst->WriteMask[1]
1360 + dst->WriteMask[2] + dst->WriteMask[3];
1361
1362 if (dst->File == PROGRAM_OUTPUT) {
1363 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1364 }
1365 else if (dst->File == PROGRAM_INPUT) {
1366 _mesa_printf("v[%s]", InputRegisters[dst->Index]);
1367 }
1368 else if (dst->File == PROGRAM_ENV_PARAM) {
1369 _mesa_printf("c[%d]", dst->Index);
1370 }
1371 else {
1372 ASSERT(dst->File == PROGRAM_TEMPORARY);
1373 _mesa_printf("R%d", dst->Index);
1374 }
1375
1376 if (w != 0 && w != 4) {
1377 _mesa_printf(".");
1378 if (dst->WriteMask[0])
1379 _mesa_printf("x");
1380 if (dst->WriteMask[1])
1381 _mesa_printf("y");
1382 if (dst->WriteMask[2])
1383 _mesa_printf("z");
1384 if (dst->WriteMask[3])
1385 _mesa_printf("w");
1386 }
1387 }
1388
1389
1390 /**
1391 * Print a single NVIDIA vertex program instruction.
1392 */
1393 void
1394 _mesa_print_nv_vertex_instruction(const struct vp_instruction *inst)
1395 {
1396 switch (inst->Opcode) {
1397 case VP_OPCODE_MOV:
1398 case VP_OPCODE_LIT:
1399 case VP_OPCODE_RCP:
1400 case VP_OPCODE_RSQ:
1401 case VP_OPCODE_EXP:
1402 case VP_OPCODE_LOG:
1403 case VP_OPCODE_RCC:
1404 case VP_OPCODE_ABS:
1405 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1406 PrintDstReg(&inst->DstReg);
1407 _mesa_printf(", ");
1408 PrintSrcReg(&inst->SrcReg[0]);
1409 _mesa_printf(";\n");
1410 break;
1411 case VP_OPCODE_MUL:
1412 case VP_OPCODE_ADD:
1413 case VP_OPCODE_DP3:
1414 case VP_OPCODE_DP4:
1415 case VP_OPCODE_DST:
1416 case VP_OPCODE_MIN:
1417 case VP_OPCODE_MAX:
1418 case VP_OPCODE_SLT:
1419 case VP_OPCODE_SGE:
1420 case VP_OPCODE_DPH:
1421 case VP_OPCODE_SUB:
1422 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1423 PrintDstReg(&inst->DstReg);
1424 _mesa_printf(", ");
1425 PrintSrcReg(&inst->SrcReg[0]);
1426 _mesa_printf(", ");
1427 PrintSrcReg(&inst->SrcReg[1]);
1428 _mesa_printf(";\n");
1429 break;
1430 case VP_OPCODE_MAD:
1431 _mesa_printf("MAD ");
1432 PrintDstReg(&inst->DstReg);
1433 _mesa_printf(", ");
1434 PrintSrcReg(&inst->SrcReg[0]);
1435 _mesa_printf(", ");
1436 PrintSrcReg(&inst->SrcReg[1]);
1437 _mesa_printf(", ");
1438 PrintSrcReg(&inst->SrcReg[2]);
1439 _mesa_printf(";\n");
1440 break;
1441 case VP_OPCODE_ARL:
1442 _mesa_printf("ARL A0.x, ");
1443 PrintSrcReg(&inst->SrcReg[0]);
1444 _mesa_printf(";\n");
1445 break;
1446 case VP_OPCODE_END:
1447 _mesa_printf("END\n");
1448 break;
1449 default:
1450 _mesa_printf("BAD INSTRUCTION\n");
1451 }
1452 }
1453
1454
1455 /**
1456 * Print (unparse) the given vertex program. Just for debugging.
1457 */
1458 void
1459 _mesa_print_nv_vertex_program(const struct vertex_program *program)
1460 {
1461 const struct vp_instruction *inst;
1462
1463 for (inst = program->Instructions; ; inst++) {
1464 _mesa_print_nv_vertex_instruction(inst);
1465 if (inst->Opcode == VP_OPCODE_END)
1466 return;
1467 }
1468 }
1469
1470
1471 const char *
1472 _mesa_nv_vertex_input_register_name(GLuint i)
1473 {
1474 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1475 return InputRegisters[i];
1476 }
1477
1478
1479 const char *
1480 _mesa_nv_vertex_output_register_name(GLuint i)
1481 {
1482 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1483 return OutputRegisters[i];
1484 }