Minor tweaks to help out at a driver level.
[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 * 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 /* absolute program parameter register */
583 dstReg->File = PROGRAM_ENV_PARAM;
584 if (!Parse_AbsParamReg(parseState, &dstReg->Index))
585 RETURN_ERROR;
586 }
587 else {
588 RETURN_ERROR1("Bad destination register name");
589 }
590
591 /* Parse optional write mask */
592 if (!Peek_Token(parseState, token))
593 RETURN_ERROR;
594
595 if (token[0] == '.') {
596 /* got a mask */
597 GLint k = 0;
598
599 if (!Parse_String(parseState, "."))
600 RETURN_ERROR;
601
602 if (!Parse_Token(parseState, token))
603 RETURN_ERROR;
604
605 dstReg->WriteMask[0] = GL_FALSE;
606 dstReg->WriteMask[1] = GL_FALSE;
607 dstReg->WriteMask[2] = GL_FALSE;
608 dstReg->WriteMask[3] = GL_FALSE;
609
610 if (token[k] == 'x') {
611 dstReg->WriteMask[0] = GL_TRUE;
612 k++;
613 }
614 if (token[k] == 'y') {
615 dstReg->WriteMask[1] = GL_TRUE;
616 k++;
617 }
618 if (token[k] == 'z') {
619 dstReg->WriteMask[2] = GL_TRUE;
620 k++;
621 }
622 if (token[k] == 'w') {
623 dstReg->WriteMask[3] = GL_TRUE;
624 k++;
625 }
626 if (k == 0) {
627 RETURN_ERROR1("Bad writemask character");
628 }
629 return GL_TRUE;
630 }
631 else {
632 dstReg->WriteMask[0] = GL_TRUE;
633 dstReg->WriteMask[1] = GL_TRUE;
634 dstReg->WriteMask[2] = GL_TRUE;
635 dstReg->WriteMask[3] = GL_TRUE;
636 return GL_TRUE;
637 }
638 }
639
640
641 static GLboolean
642 Parse_SwizzleSrcReg(struct parse_state *parseState, struct vp_src_register *srcReg)
643 {
644 GLubyte token[100];
645
646 srcReg->RelAddr = GL_FALSE;
647
648 /* check for '-' */
649 if (!Peek_Token(parseState, token))
650 RETURN_ERROR;
651 if (token[0] == '-') {
652 (void) Parse_String(parseState, "-");
653 srcReg->Negate = GL_TRUE;
654 if (!Peek_Token(parseState, token))
655 RETURN_ERROR;
656 }
657 else {
658 srcReg->Negate = GL_FALSE;
659 }
660
661 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
662 if (token[0] == 'R') {
663 srcReg->File = PROGRAM_TEMPORARY;
664 if (!Parse_TempReg(parseState, &srcReg->Index))
665 RETURN_ERROR;
666 }
667 else if (token[0] == 'c') {
668 if (!Parse_ParamReg(parseState, srcReg))
669 RETURN_ERROR;
670 }
671 else if (token[0] == 'v') {
672 srcReg->File = PROGRAM_INPUT;
673 if (!Parse_AttribReg(parseState, &srcReg->Index))
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 srcReg->File = PROGRAM_TEMPORARY;
755 if (!Parse_TempReg(parseState, &srcReg->Index))
756 RETURN_ERROR;
757 }
758 else if (token[0] == 'c') {
759 if (!Parse_ParamReg(parseState, srcReg))
760 RETURN_ERROR;
761 }
762 else if (token[0] == 'v') {
763 srcReg->File = PROGRAM_INPUT;
764 if (!Parse_AttribReg(parseState, &srcReg->Index))
765 RETURN_ERROR;
766 }
767 else {
768 RETURN_ERROR2("Bad source register name", token);
769 }
770
771 /* Look for .[xyzw] suffix */
772 if (!Parse_String(parseState, "."))
773 RETURN_ERROR;
774
775 if (!Parse_Token(parseState, token))
776 RETURN_ERROR;
777
778 if (token[0] == 'x' && token[1] == 0) {
779 srcReg->Swizzle[0] = 0;
780 }
781 else if (token[0] == 'y' && token[1] == 0) {
782 srcReg->Swizzle[0] = 1;
783 }
784 else if (token[0] == 'z' && token[1] == 0) {
785 srcReg->Swizzle[0] = 2;
786 }
787 else if (token[0] == 'w' && token[1] == 0) {
788 srcReg->Swizzle[0] = 3;
789 }
790 else {
791 RETURN_ERROR1("Bad scalar source suffix");
792 }
793 srcReg->Swizzle[1] = srcReg->Swizzle[2] = srcReg->Swizzle[3] = 0;
794
795 return GL_TRUE;
796 }
797
798
799 static GLint
800 Parse_UnaryOpInstruction(struct parse_state *parseState,
801 struct vp_instruction *inst, enum vp_opcode opcode)
802 {
803 if (opcode == VP_OPCODE_ABS && !parseState->isVersion1_1)
804 RETURN_ERROR1("ABS illegal for vertex program 1.0");
805
806 inst->Opcode = opcode;
807 inst->StringPos = parseState->curLine - parseState->start;
808
809 /* dest reg */
810 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
811 RETURN_ERROR;
812
813 /* comma */
814 if (!Parse_String(parseState, ","))
815 RETURN_ERROR;
816
817 /* src arg */
818 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
819 RETURN_ERROR;
820
821 /* semicolon */
822 if (!Parse_String(parseState, ";"))
823 RETURN_ERROR;
824
825 return GL_TRUE;
826 }
827
828
829 static GLboolean
830 Parse_BiOpInstruction(struct parse_state *parseState,
831 struct vp_instruction *inst, enum vp_opcode opcode)
832 {
833 if (opcode == VP_OPCODE_DPH && !parseState->isVersion1_1)
834 RETURN_ERROR1("DPH illegal for vertex program 1.0");
835 if (opcode == VP_OPCODE_SUB && !parseState->isVersion1_1)
836 RETURN_ERROR1("SUB illegal for vertex program 1.0");
837
838 inst->Opcode = opcode;
839 inst->StringPos = parseState->curLine - parseState->start;
840
841 /* dest reg */
842 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
843 RETURN_ERROR;
844
845 /* comma */
846 if (!Parse_String(parseState, ","))
847 RETURN_ERROR;
848
849 /* first src arg */
850 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
851 RETURN_ERROR;
852
853 /* comma */
854 if (!Parse_String(parseState, ","))
855 RETURN_ERROR;
856
857 /* second src arg */
858 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
859 RETURN_ERROR;
860
861 /* semicolon */
862 if (!Parse_String(parseState, ";"))
863 RETURN_ERROR;
864
865 /* make sure we don't reference more than one program parameter register */
866 if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
867 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
868 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
869 RETURN_ERROR1("Can't reference two program parameter registers");
870
871 /* make sure we don't reference more than one vertex attribute register */
872 if (inst->SrcReg[0].File == PROGRAM_INPUT &&
873 inst->SrcReg[1].File == PROGRAM_INPUT &&
874 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
875 RETURN_ERROR1("Can't reference two vertex attribute registers");
876
877 return GL_TRUE;
878 }
879
880
881 static GLboolean
882 Parse_TriOpInstruction(struct parse_state *parseState,
883 struct vp_instruction *inst, enum vp_opcode opcode)
884 {
885 inst->Opcode = opcode;
886 inst->StringPos = parseState->curLine - parseState->start;
887
888 /* dest reg */
889 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
890 RETURN_ERROR;
891
892 /* comma */
893 if (!Parse_String(parseState, ","))
894 RETURN_ERROR;
895
896 /* first src arg */
897 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
898 RETURN_ERROR;
899
900 /* comma */
901 if (!Parse_String(parseState, ","))
902 RETURN_ERROR;
903
904 /* second src arg */
905 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
906 RETURN_ERROR;
907
908 /* comma */
909 if (!Parse_String(parseState, ","))
910 RETURN_ERROR;
911
912 /* third src arg */
913 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2]))
914 RETURN_ERROR;
915
916 /* semicolon */
917 if (!Parse_String(parseState, ";"))
918 RETURN_ERROR;
919
920 /* make sure we don't reference more than one program parameter register */
921 if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
922 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
923 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
924 (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
925 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
926 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
927 (inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
928 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
929 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
930 RETURN_ERROR1("Can only reference one program register");
931
932 /* make sure we don't reference more than one vertex attribute register */
933 if ((inst->SrcReg[0].File == PROGRAM_INPUT &&
934 inst->SrcReg[1].File == PROGRAM_INPUT &&
935 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
936 (inst->SrcReg[0].File == PROGRAM_INPUT &&
937 inst->SrcReg[2].File == PROGRAM_INPUT &&
938 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
939 (inst->SrcReg[1].File == PROGRAM_INPUT &&
940 inst->SrcReg[2].File == PROGRAM_INPUT &&
941 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
942 RETURN_ERROR1("Can only reference one input register");
943
944 return GL_TRUE;
945 }
946
947
948 static GLboolean
949 Parse_ScalarInstruction(struct parse_state *parseState,
950 struct vp_instruction *inst, enum vp_opcode opcode)
951 {
952 if (opcode == VP_OPCODE_RCC && !parseState->isVersion1_1)
953 RETURN_ERROR1("RCC illegal for vertex program 1.0");
954
955 inst->Opcode = opcode;
956 inst->StringPos = parseState->curLine - parseState->start;
957
958 /* dest reg */
959 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
960 RETURN_ERROR;
961
962 /* comma */
963 if (!Parse_String(parseState, ","))
964 RETURN_ERROR;
965
966 /* first src arg */
967 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
968 RETURN_ERROR;
969
970 /* semicolon */
971 if (!Parse_String(parseState, ";"))
972 RETURN_ERROR;
973
974 return GL_TRUE;
975 }
976
977
978 static GLboolean
979 Parse_AddressInstruction(struct parse_state *parseState, struct vp_instruction *inst)
980 {
981 inst->Opcode = VP_OPCODE_ARL;
982 inst->StringPos = parseState->curLine - parseState->start;
983
984 /* dest A0 reg */
985 if (!Parse_AddrReg(parseState))
986 RETURN_ERROR;
987
988 /* comma */
989 if (!Parse_String(parseState, ","))
990 RETURN_ERROR;
991
992 /* parse src reg */
993 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
994 RETURN_ERROR;
995
996 /* semicolon */
997 if (!Parse_String(parseState, ";"))
998 RETURN_ERROR;
999
1000 return GL_TRUE;
1001 }
1002
1003
1004 static GLboolean
1005 Parse_EndInstruction(struct parse_state *parseState, struct vp_instruction *inst)
1006 {
1007 GLubyte token[100];
1008
1009 inst->Opcode = VP_OPCODE_END;
1010 inst->StringPos = parseState->curLine - parseState->start;
1011
1012 /* this should fail! */
1013 if (Parse_Token(parseState, token))
1014 RETURN_ERROR2("Unexpected token after END:", token);
1015 else
1016 return GL_TRUE;
1017 }
1018
1019
1020 static GLboolean
1021 Parse_OptionSequence(struct parse_state *parseState,
1022 struct vp_instruction program[])
1023 {
1024 while (1) {
1025 if (!Parse_String(parseState, "OPTION"))
1026 return GL_TRUE; /* ok, not an OPTION statement */
1027 if (Parse_String(parseState, "NV_position_invariant")) {
1028 parseState->isPositionInvariant = GL_TRUE;
1029 }
1030 else {
1031 RETURN_ERROR1("unexpected OPTION statement");
1032 }
1033 if (!Parse_String(parseState, ";"))
1034 return GL_FALSE;
1035 }
1036 }
1037
1038
1039 static GLboolean
1040 Parse_InstructionSequence(struct parse_state *parseState,
1041 struct vp_instruction program[])
1042 {
1043 while (1) {
1044 struct vp_instruction *inst = program + parseState->numInst;
1045
1046 /* Initialize the instruction */
1047 inst->SrcReg[0].File = (enum register_file) -1;
1048 inst->SrcReg[1].File = (enum register_file) -1;
1049 inst->SrcReg[2].File = (enum register_file) -1;
1050 inst->DstReg.File = (enum register_file) -1;
1051
1052 if (Parse_String(parseState, "MOV")) {
1053 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_MOV))
1054 RETURN_ERROR;
1055 }
1056 else if (Parse_String(parseState, "LIT")) {
1057 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_LIT))
1058 RETURN_ERROR;
1059 }
1060 else if (Parse_String(parseState, "ABS")) {
1061 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_ABS))
1062 RETURN_ERROR;
1063 }
1064 else if (Parse_String(parseState, "MUL")) {
1065 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MUL))
1066 RETURN_ERROR;
1067 }
1068 else if (Parse_String(parseState, "ADD")) {
1069 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_ADD))
1070 RETURN_ERROR;
1071 }
1072 else if (Parse_String(parseState, "DP3")) {
1073 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP3))
1074 RETURN_ERROR;
1075 }
1076 else if (Parse_String(parseState, "DP4")) {
1077 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP4))
1078 RETURN_ERROR;
1079 }
1080 else if (Parse_String(parseState, "DST")) {
1081 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DST))
1082 RETURN_ERROR;
1083 }
1084 else if (Parse_String(parseState, "MIN")) {
1085 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MIN))
1086 RETURN_ERROR;
1087 }
1088 else if (Parse_String(parseState, "MAX")) {
1089 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MAX))
1090 RETURN_ERROR;
1091 }
1092 else if (Parse_String(parseState, "SLT")) {
1093 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SLT))
1094 RETURN_ERROR;
1095 }
1096 else if (Parse_String(parseState, "SGE")) {
1097 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SGE))
1098 RETURN_ERROR;
1099 }
1100 else if (Parse_String(parseState, "DPH")) {
1101 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DPH))
1102 RETURN_ERROR;
1103 }
1104 else if (Parse_String(parseState, "SUB")) {
1105 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SUB))
1106 RETURN_ERROR;
1107 }
1108 else if (Parse_String(parseState, "MAD")) {
1109 if (!Parse_TriOpInstruction(parseState, inst, VP_OPCODE_MAD))
1110 RETURN_ERROR;
1111 }
1112 else if (Parse_String(parseState, "RCP")) {
1113 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCP))
1114 RETURN_ERROR;
1115 }
1116 else if (Parse_String(parseState, "RSQ")) {
1117 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RSQ))
1118 RETURN_ERROR;
1119 }
1120 else if (Parse_String(parseState, "EXP")) {
1121 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_EXP))
1122 RETURN_ERROR;
1123 }
1124 else if (Parse_String(parseState, "LOG")) {
1125 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_LOG))
1126 RETURN_ERROR;
1127 }
1128 else if (Parse_String(parseState, "RCC")) {
1129 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCC))
1130 RETURN_ERROR;
1131 }
1132 else if (Parse_String(parseState, "ARL")) {
1133 if (!Parse_AddressInstruction(parseState, inst))
1134 RETURN_ERROR;
1135 }
1136 else if (Parse_String(parseState, "END")) {
1137 if (!Parse_EndInstruction(parseState, inst))
1138 RETURN_ERROR;
1139 else {
1140 parseState->numInst++;
1141 return GL_TRUE; /* all done */
1142 }
1143 }
1144 else {
1145 /* bad instruction name */
1146 RETURN_ERROR1("Unexpected token");
1147 }
1148
1149 /* examine input/output registers */
1150 if (inst->DstReg.File == PROGRAM_OUTPUT)
1151 parseState->outputsWritten |= (1 << inst->DstReg.Index);
1152 else if (inst->DstReg.File == PROGRAM_ENV_PARAM)
1153 parseState->anyProgRegsWritten = GL_TRUE;
1154
1155 if (inst->SrcReg[0].File == PROGRAM_INPUT)
1156 parseState->inputsRead |= (1 << inst->SrcReg[0].Index);
1157 if (inst->SrcReg[1].File == PROGRAM_INPUT)
1158 parseState->inputsRead |= (1 << inst->SrcReg[1].Index);
1159 if (inst->SrcReg[2].File == PROGRAM_INPUT)
1160 parseState->inputsRead |= (1 << inst->SrcReg[2].Index);
1161
1162 parseState->numInst++;
1163
1164 if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
1165 RETURN_ERROR1("Program too long");
1166 }
1167
1168 RETURN_ERROR;
1169 }
1170
1171
1172 static GLboolean
1173 Parse_Program(struct parse_state *parseState,
1174 struct vp_instruction instBuffer[])
1175 {
1176 if (parseState->isVersion1_1) {
1177 if (!Parse_OptionSequence(parseState, instBuffer)) {
1178 return GL_FALSE;
1179 }
1180 }
1181 return Parse_InstructionSequence(parseState, instBuffer);
1182 }
1183
1184
1185 /**
1186 * Parse/compile the 'str' returning the compiled 'program'.
1187 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1188 * indicates the position of the error in 'str'.
1189 */
1190 void
1191 _mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
1192 const GLubyte *str, GLsizei len,
1193 struct vertex_program *program)
1194 {
1195 struct parse_state parseState;
1196 struct vp_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1197 struct vp_instruction *newInst;
1198 GLenum target;
1199 GLubyte *programString;
1200
1201 /* Make a null-terminated copy of the program string */
1202 programString = (GLubyte *) MALLOC(len + 1);
1203 if (!programString) {
1204 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1205 return;
1206 }
1207 MEMCPY(programString, str, len);
1208 programString[len] = 0;
1209
1210 /* Get ready to parse */
1211 parseState.ctx = ctx;
1212 parseState.start = programString;
1213 parseState.isPositionInvariant = GL_FALSE;
1214 parseState.isVersion1_1 = GL_FALSE;
1215 parseState.numInst = 0;
1216 parseState.inputsRead = 0;
1217 parseState.outputsWritten = 0;
1218 parseState.anyProgRegsWritten = GL_FALSE;
1219
1220 /* Reset error state */
1221 _mesa_set_program_error(ctx, -1, NULL);
1222
1223 /* check the program header */
1224 if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
1225 target = GL_VERTEX_PROGRAM_NV;
1226 parseState.pos = programString + 7;
1227 parseState.isStateProgram = GL_FALSE;
1228 }
1229 else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
1230 target = GL_VERTEX_PROGRAM_NV;
1231 parseState.pos = programString + 7;
1232 parseState.isStateProgram = GL_FALSE;
1233 parseState.isVersion1_1 = GL_TRUE;
1234 }
1235 else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
1236 target = GL_VERTEX_STATE_PROGRAM_NV;
1237 parseState.pos = programString + 8;
1238 parseState.isStateProgram = GL_TRUE;
1239 }
1240 else {
1241 /* invalid header */
1242 ctx->Program.ErrorPos = 0;
1243 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1244 return;
1245 }
1246
1247 /* make sure target and header match */
1248 if (target != dstTarget) {
1249 _mesa_error(ctx, GL_INVALID_OPERATION,
1250 "glLoadProgramNV(target mismatch)");
1251 return;
1252 }
1253
1254
1255 if (Parse_Program(&parseState, instBuffer)) {
1256 /* successful parse! */
1257
1258 if (parseState.isStateProgram) {
1259 if (!parseState.anyProgRegsWritten) {
1260 _mesa_error(ctx, GL_INVALID_OPERATION,
1261 "glLoadProgramNV(c[#] not written)");
1262 return;
1263 }
1264 }
1265 else {
1266 if (!parseState.isPositionInvariant &&
1267 !(parseState.outputsWritten & 1)) {
1268 /* bit 1 = HPOS register */
1269 _mesa_error(ctx, GL_INVALID_OPERATION,
1270 "glLoadProgramNV(HPOS not written)");
1271 return;
1272 }
1273 }
1274
1275 /* copy the compiled instructions */
1276 assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
1277 newInst = (struct vp_instruction *)
1278 MALLOC(parseState.numInst * sizeof(struct vp_instruction));
1279 if (!newInst) {
1280 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1281 FREE(programString);
1282 return; /* out of memory */
1283 }
1284 MEMCPY(newInst, instBuffer,
1285 parseState.numInst * sizeof(struct vp_instruction));
1286
1287 /* install the program */
1288 program->Base.Target = target;
1289 if (program->Base.String) {
1290 FREE(program->Base.String);
1291 }
1292 program->Base.String = programString;
1293 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1294 if (program->Instructions) {
1295 FREE(program->Instructions);
1296 }
1297 program->Instructions = newInst;
1298 program->InputsRead = parseState.inputsRead;
1299 program->OutputsWritten = parseState.outputsWritten;
1300 program->IsPositionInvariant = parseState.isPositionInvariant;
1301
1302 #ifdef DEBUG
1303 _mesa_printf("--- glLoadProgramNV result ---\n");
1304 _mesa_print_nv_vertex_program(program);
1305 _mesa_printf("------------------------------\n");
1306 #endif
1307 }
1308 else {
1309 /* Error! */
1310 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1311 /* NOTE: _mesa_set_program_error would have been called already */
1312 /* GL_NV_vertex_program isn't supposed to set the error string
1313 * so we reset it here.
1314 */
1315 _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
1316 }
1317 }
1318
1319
1320 static void
1321 PrintSrcReg(const struct vp_src_register *src)
1322 {
1323 static const char comps[5] = "xyzw";
1324 if (src->Negate)
1325 _mesa_printf("-");
1326 if (src->RelAddr) {
1327 if (src->Index > 0)
1328 _mesa_printf("c[A0.x + %d]", src->Index);
1329 else if (src->Index < 0)
1330 _mesa_printf("c[A0.x - %d]", -src->Index);
1331 else
1332 _mesa_printf("c[A0.x]");
1333 }
1334 else if (src->File == PROGRAM_OUTPUT) {
1335 _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1336 }
1337 else if (src->File == PROGRAM_INPUT) {
1338 _mesa_printf("v[%s]", InputRegisters[src->Index]);
1339 }
1340 else if (src->File == PROGRAM_ENV_PARAM) {
1341 _mesa_printf("c[%d]", src->Index);
1342 }
1343 else {
1344 ASSERT(src->File == PROGRAM_TEMPORARY);
1345 _mesa_printf("R%d", src->Index);
1346 }
1347
1348 if (src->Swizzle[0] == src->Swizzle[1] &&
1349 src->Swizzle[0] == src->Swizzle[2] &&
1350 src->Swizzle[0] == src->Swizzle[3]) {
1351 _mesa_printf(".%c", comps[src->Swizzle[0]]);
1352 }
1353 else if (src->Swizzle[0] != 0 ||
1354 src->Swizzle[1] != 1 ||
1355 src->Swizzle[2] != 2 ||
1356 src->Swizzle[3] != 3) {
1357 _mesa_printf(".%c%c%c%c",
1358 comps[src->Swizzle[0]],
1359 comps[src->Swizzle[1]],
1360 comps[src->Swizzle[2]],
1361 comps[src->Swizzle[3]]);
1362 }
1363 }
1364
1365
1366 static void
1367 PrintDstReg(const struct vp_dst_register *dst)
1368 {
1369 GLint w = dst->WriteMask[0] + dst->WriteMask[1]
1370 + dst->WriteMask[2] + dst->WriteMask[3];
1371
1372 if (dst->File == PROGRAM_OUTPUT) {
1373 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1374 }
1375 else if (dst->File == PROGRAM_INPUT) {
1376 _mesa_printf("v[%s]", InputRegisters[dst->Index]);
1377 }
1378 else if (dst->File == PROGRAM_ENV_PARAM) {
1379 _mesa_printf("c[%d]", dst->Index);
1380 }
1381 else {
1382 ASSERT(dst->File == PROGRAM_TEMPORARY);
1383 _mesa_printf("R%d", dst->Index);
1384 }
1385
1386 if (w != 0 && w != 4) {
1387 _mesa_printf(".");
1388 if (dst->WriteMask[0])
1389 _mesa_printf("x");
1390 if (dst->WriteMask[1])
1391 _mesa_printf("y");
1392 if (dst->WriteMask[2])
1393 _mesa_printf("z");
1394 if (dst->WriteMask[3])
1395 _mesa_printf("w");
1396 }
1397 }
1398
1399
1400 /**
1401 * Print a single NVIDIA vertex program instruction.
1402 */
1403 void
1404 _mesa_print_nv_vertex_instruction(const struct vp_instruction *inst)
1405 {
1406 switch (inst->Opcode) {
1407 case VP_OPCODE_MOV:
1408 case VP_OPCODE_LIT:
1409 case VP_OPCODE_RCP:
1410 case VP_OPCODE_RSQ:
1411 case VP_OPCODE_EXP:
1412 case VP_OPCODE_LOG:
1413 case VP_OPCODE_RCC:
1414 case VP_OPCODE_ABS:
1415 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1416 PrintDstReg(&inst->DstReg);
1417 _mesa_printf(", ");
1418 PrintSrcReg(&inst->SrcReg[0]);
1419 _mesa_printf(";\n");
1420 break;
1421 case VP_OPCODE_MUL:
1422 case VP_OPCODE_ADD:
1423 case VP_OPCODE_DP3:
1424 case VP_OPCODE_DP4:
1425 case VP_OPCODE_DST:
1426 case VP_OPCODE_MIN:
1427 case VP_OPCODE_MAX:
1428 case VP_OPCODE_SLT:
1429 case VP_OPCODE_SGE:
1430 case VP_OPCODE_DPH:
1431 case VP_OPCODE_SUB:
1432 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1433 PrintDstReg(&inst->DstReg);
1434 _mesa_printf(", ");
1435 PrintSrcReg(&inst->SrcReg[0]);
1436 _mesa_printf(", ");
1437 PrintSrcReg(&inst->SrcReg[1]);
1438 _mesa_printf(";\n");
1439 break;
1440 case VP_OPCODE_MAD:
1441 _mesa_printf("MAD ");
1442 PrintDstReg(&inst->DstReg);
1443 _mesa_printf(", ");
1444 PrintSrcReg(&inst->SrcReg[0]);
1445 _mesa_printf(", ");
1446 PrintSrcReg(&inst->SrcReg[1]);
1447 _mesa_printf(", ");
1448 PrintSrcReg(&inst->SrcReg[2]);
1449 _mesa_printf(";\n");
1450 break;
1451 case VP_OPCODE_ARL:
1452 _mesa_printf("ARL A0.x, ");
1453 PrintSrcReg(&inst->SrcReg[0]);
1454 _mesa_printf(";\n");
1455 break;
1456 case VP_OPCODE_END:
1457 _mesa_printf("END\n");
1458 break;
1459 default:
1460 _mesa_printf("BAD INSTRUCTION\n");
1461 }
1462 }
1463
1464
1465 /**
1466 * Print (unparse) the given vertex program. Just for debugging.
1467 */
1468 void
1469 _mesa_print_nv_vertex_program(const struct vertex_program *program)
1470 {
1471 const struct vp_instruction *inst;
1472
1473 for (inst = program->Instructions; ; inst++) {
1474 _mesa_print_nv_vertex_instruction(inst);
1475 if (inst->Opcode == VP_OPCODE_END)
1476 return;
1477 }
1478 }
1479
1480
1481 const char *
1482 _mesa_nv_vertex_input_register_name(GLuint i)
1483 {
1484 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1485 return InputRegisters[i];
1486 }
1487
1488
1489 const char *
1490 _mesa_nv_vertex_output_register_name(GLuint i)
1491 {
1492 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1493 return OutputRegisters[i];
1494 }