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