Remove empty r128_vb.h.
[mesa.git] / src / mesa / shader / nvvertparse.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.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 (void) program;
1027 while (1) {
1028 if (!Parse_String(parseState, "OPTION"))
1029 return GL_TRUE; /* ok, not an OPTION statement */
1030 if (Parse_String(parseState, "NV_position_invariant")) {
1031 parseState->isPositionInvariant = GL_TRUE;
1032 }
1033 else {
1034 RETURN_ERROR1("unexpected OPTION statement");
1035 }
1036 if (!Parse_String(parseState, ";"))
1037 return GL_FALSE;
1038 }
1039 }
1040
1041
1042 static GLboolean
1043 Parse_InstructionSequence(struct parse_state *parseState,
1044 struct vp_instruction program[])
1045 {
1046 while (1) {
1047 struct vp_instruction *inst = program + parseState->numInst;
1048
1049 /* Initialize the instruction */
1050 inst->SrcReg[0].File = (enum register_file) -1;
1051 inst->SrcReg[1].File = (enum register_file) -1;
1052 inst->SrcReg[2].File = (enum register_file) -1;
1053 inst->DstReg.File = (enum register_file) -1;
1054
1055 if (Parse_String(parseState, "MOV")) {
1056 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_MOV))
1057 RETURN_ERROR;
1058 }
1059 else if (Parse_String(parseState, "LIT")) {
1060 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_LIT))
1061 RETURN_ERROR;
1062 }
1063 else if (Parse_String(parseState, "ABS")) {
1064 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_ABS))
1065 RETURN_ERROR;
1066 }
1067 else if (Parse_String(parseState, "MUL")) {
1068 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MUL))
1069 RETURN_ERROR;
1070 }
1071 else if (Parse_String(parseState, "ADD")) {
1072 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_ADD))
1073 RETURN_ERROR;
1074 }
1075 else if (Parse_String(parseState, "DP3")) {
1076 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP3))
1077 RETURN_ERROR;
1078 }
1079 else if (Parse_String(parseState, "DP4")) {
1080 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP4))
1081 RETURN_ERROR;
1082 }
1083 else if (Parse_String(parseState, "DST")) {
1084 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DST))
1085 RETURN_ERROR;
1086 }
1087 else if (Parse_String(parseState, "MIN")) {
1088 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MIN))
1089 RETURN_ERROR;
1090 }
1091 else if (Parse_String(parseState, "MAX")) {
1092 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MAX))
1093 RETURN_ERROR;
1094 }
1095 else if (Parse_String(parseState, "SLT")) {
1096 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SLT))
1097 RETURN_ERROR;
1098 }
1099 else if (Parse_String(parseState, "SGE")) {
1100 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SGE))
1101 RETURN_ERROR;
1102 }
1103 else if (Parse_String(parseState, "DPH")) {
1104 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DPH))
1105 RETURN_ERROR;
1106 }
1107 else if (Parse_String(parseState, "SUB")) {
1108 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SUB))
1109 RETURN_ERROR;
1110 }
1111 else if (Parse_String(parseState, "MAD")) {
1112 if (!Parse_TriOpInstruction(parseState, inst, VP_OPCODE_MAD))
1113 RETURN_ERROR;
1114 }
1115 else if (Parse_String(parseState, "RCP")) {
1116 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCP))
1117 RETURN_ERROR;
1118 }
1119 else if (Parse_String(parseState, "RSQ")) {
1120 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RSQ))
1121 RETURN_ERROR;
1122 }
1123 else if (Parse_String(parseState, "EXP")) {
1124 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_EXP))
1125 RETURN_ERROR;
1126 }
1127 else if (Parse_String(parseState, "LOG")) {
1128 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_LOG))
1129 RETURN_ERROR;
1130 }
1131 else if (Parse_String(parseState, "RCC")) {
1132 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCC))
1133 RETURN_ERROR;
1134 }
1135 else if (Parse_String(parseState, "ARL")) {
1136 if (!Parse_AddressInstruction(parseState, inst))
1137 RETURN_ERROR;
1138 }
1139 else if (Parse_String(parseState, "END")) {
1140 if (!Parse_EndInstruction(parseState, inst))
1141 RETURN_ERROR;
1142 else {
1143 parseState->numInst++;
1144 return GL_TRUE; /* all done */
1145 }
1146 }
1147 else {
1148 /* bad instruction name */
1149 RETURN_ERROR1("Unexpected token");
1150 }
1151
1152 /* examine input/output registers */
1153 if (inst->DstReg.File == PROGRAM_OUTPUT)
1154 parseState->outputsWritten |= (1 << inst->DstReg.Index);
1155 else if (inst->DstReg.File == PROGRAM_ENV_PARAM)
1156 parseState->anyProgRegsWritten = GL_TRUE;
1157
1158 if (inst->SrcReg[0].File == PROGRAM_INPUT)
1159 parseState->inputsRead |= (1 << inst->SrcReg[0].Index);
1160 if (inst->SrcReg[1].File == PROGRAM_INPUT)
1161 parseState->inputsRead |= (1 << inst->SrcReg[1].Index);
1162 if (inst->SrcReg[2].File == PROGRAM_INPUT)
1163 parseState->inputsRead |= (1 << inst->SrcReg[2].Index);
1164
1165 parseState->numInst++;
1166
1167 if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
1168 RETURN_ERROR1("Program too long");
1169 }
1170
1171 RETURN_ERROR;
1172 }
1173
1174
1175 static GLboolean
1176 Parse_Program(struct parse_state *parseState,
1177 struct vp_instruction instBuffer[])
1178 {
1179 if (parseState->isVersion1_1) {
1180 if (!Parse_OptionSequence(parseState, instBuffer)) {
1181 return GL_FALSE;
1182 }
1183 }
1184 return Parse_InstructionSequence(parseState, instBuffer);
1185 }
1186
1187
1188 /**
1189 * Parse/compile the 'str' returning the compiled 'program'.
1190 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1191 * indicates the position of the error in 'str'.
1192 */
1193 void
1194 _mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
1195 const GLubyte *str, GLsizei len,
1196 struct vertex_program *program)
1197 {
1198 struct parse_state parseState;
1199 struct vp_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1200 struct vp_instruction *newInst;
1201 GLenum target;
1202 GLubyte *programString;
1203
1204 /* Make a null-terminated copy of the program string */
1205 programString = (GLubyte *) MALLOC(len + 1);
1206 if (!programString) {
1207 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1208 return;
1209 }
1210 MEMCPY(programString, str, len);
1211 programString[len] = 0;
1212
1213 /* Get ready to parse */
1214 parseState.ctx = ctx;
1215 parseState.start = programString;
1216 parseState.isPositionInvariant = GL_FALSE;
1217 parseState.isVersion1_1 = GL_FALSE;
1218 parseState.numInst = 0;
1219 parseState.inputsRead = 0;
1220 parseState.outputsWritten = 0;
1221 parseState.anyProgRegsWritten = GL_FALSE;
1222
1223 /* Reset error state */
1224 _mesa_set_program_error(ctx, -1, NULL);
1225
1226 /* check the program header */
1227 if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
1228 target = GL_VERTEX_PROGRAM_NV;
1229 parseState.pos = programString + 7;
1230 parseState.isStateProgram = GL_FALSE;
1231 }
1232 else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
1233 target = GL_VERTEX_PROGRAM_NV;
1234 parseState.pos = programString + 7;
1235 parseState.isStateProgram = GL_FALSE;
1236 parseState.isVersion1_1 = GL_TRUE;
1237 }
1238 else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
1239 target = GL_VERTEX_STATE_PROGRAM_NV;
1240 parseState.pos = programString + 8;
1241 parseState.isStateProgram = GL_TRUE;
1242 }
1243 else {
1244 /* invalid header */
1245 ctx->Program.ErrorPos = 0;
1246 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1247 return;
1248 }
1249
1250 /* make sure target and header match */
1251 if (target != dstTarget) {
1252 _mesa_error(ctx, GL_INVALID_OPERATION,
1253 "glLoadProgramNV(target mismatch)");
1254 return;
1255 }
1256
1257
1258 if (Parse_Program(&parseState, instBuffer)) {
1259 /* successful parse! */
1260
1261 if (parseState.isStateProgram) {
1262 if (!parseState.anyProgRegsWritten) {
1263 _mesa_error(ctx, GL_INVALID_OPERATION,
1264 "glLoadProgramNV(c[#] not written)");
1265 return;
1266 }
1267 }
1268 else {
1269 if (!parseState.isPositionInvariant &&
1270 !(parseState.outputsWritten & 1)) {
1271 /* bit 1 = HPOS register */
1272 _mesa_error(ctx, GL_INVALID_OPERATION,
1273 "glLoadProgramNV(HPOS not written)");
1274 return;
1275 }
1276 }
1277
1278 /* copy the compiled instructions */
1279 assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
1280 newInst = (struct vp_instruction *)
1281 MALLOC(parseState.numInst * sizeof(struct vp_instruction));
1282 if (!newInst) {
1283 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1284 FREE(programString);
1285 return; /* out of memory */
1286 }
1287 MEMCPY(newInst, instBuffer,
1288 parseState.numInst * sizeof(struct vp_instruction));
1289
1290 /* install the program */
1291 program->Base.Target = target;
1292 if (program->Base.String) {
1293 FREE(program->Base.String);
1294 }
1295 program->Base.String = programString;
1296 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1297 if (program->Instructions) {
1298 FREE(program->Instructions);
1299 }
1300 program->Instructions = newInst;
1301 program->InputsRead = parseState.inputsRead;
1302 program->OutputsWritten = parseState.outputsWritten;
1303 program->IsPositionInvariant = parseState.isPositionInvariant;
1304 program->IsNVProgram = GL_TRUE;
1305
1306 #ifdef DEBUG_foo
1307 _mesa_printf("--- glLoadProgramNV result ---\n");
1308 _mesa_print_nv_vertex_program(program);
1309 _mesa_printf("------------------------------\n");
1310 #endif
1311 }
1312 else {
1313 /* Error! */
1314 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1315 /* NOTE: _mesa_set_program_error would have been called already */
1316 /* GL_NV_vertex_program isn't supposed to set the error string
1317 * so we reset it here.
1318 */
1319 _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
1320 }
1321 }
1322
1323
1324 static void
1325 PrintSrcReg(const struct vp_src_register *src)
1326 {
1327 static const char comps[5] = "xyzw";
1328 if (src->Negate)
1329 _mesa_printf("-");
1330 if (src->RelAddr) {
1331 if (src->Index > 0)
1332 _mesa_printf("c[A0.x + %d]", src->Index);
1333 else if (src->Index < 0)
1334 _mesa_printf("c[A0.x - %d]", -src->Index);
1335 else
1336 _mesa_printf("c[A0.x]");
1337 }
1338 else if (src->File == PROGRAM_OUTPUT) {
1339 _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1340 }
1341 else if (src->File == PROGRAM_INPUT) {
1342 _mesa_printf("v[%s]", InputRegisters[src->Index]);
1343 }
1344 else if (src->File == PROGRAM_ENV_PARAM) {
1345 _mesa_printf("c[%d]", src->Index);
1346 }
1347 else {
1348 ASSERT(src->File == PROGRAM_TEMPORARY);
1349 _mesa_printf("R%d", src->Index);
1350 }
1351
1352 if (src->Swizzle[0] == src->Swizzle[1] &&
1353 src->Swizzle[0] == src->Swizzle[2] &&
1354 src->Swizzle[0] == src->Swizzle[3]) {
1355 _mesa_printf(".%c", comps[src->Swizzle[0]]);
1356 }
1357 else if (src->Swizzle[0] != 0 ||
1358 src->Swizzle[1] != 1 ||
1359 src->Swizzle[2] != 2 ||
1360 src->Swizzle[3] != 3) {
1361 _mesa_printf(".%c%c%c%c",
1362 comps[src->Swizzle[0]],
1363 comps[src->Swizzle[1]],
1364 comps[src->Swizzle[2]],
1365 comps[src->Swizzle[3]]);
1366 }
1367 }
1368
1369
1370 static void
1371 PrintDstReg(const struct vp_dst_register *dst)
1372 {
1373 GLint w = dst->WriteMask[0] + dst->WriteMask[1]
1374 + dst->WriteMask[2] + dst->WriteMask[3];
1375
1376 if (dst->File == PROGRAM_OUTPUT) {
1377 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1378 }
1379 else if (dst->File == PROGRAM_INPUT) {
1380 _mesa_printf("v[%s]", InputRegisters[dst->Index]);
1381 }
1382 else if (dst->File == PROGRAM_ENV_PARAM) {
1383 _mesa_printf("c[%d]", dst->Index);
1384 }
1385 else {
1386 ASSERT(dst->File == PROGRAM_TEMPORARY);
1387 _mesa_printf("R%d", dst->Index);
1388 }
1389
1390 if (w != 0 && w != 4) {
1391 _mesa_printf(".");
1392 if (dst->WriteMask[0])
1393 _mesa_printf("x");
1394 if (dst->WriteMask[1])
1395 _mesa_printf("y");
1396 if (dst->WriteMask[2])
1397 _mesa_printf("z");
1398 if (dst->WriteMask[3])
1399 _mesa_printf("w");
1400 }
1401 }
1402
1403
1404 /**
1405 * Print a single NVIDIA vertex program instruction.
1406 */
1407 void
1408 _mesa_print_nv_vertex_instruction(const struct vp_instruction *inst)
1409 {
1410 switch (inst->Opcode) {
1411 case VP_OPCODE_MOV:
1412 case VP_OPCODE_LIT:
1413 case VP_OPCODE_RCP:
1414 case VP_OPCODE_RSQ:
1415 case VP_OPCODE_EXP:
1416 case VP_OPCODE_LOG:
1417 case VP_OPCODE_RCC:
1418 case VP_OPCODE_ABS:
1419 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1420 PrintDstReg(&inst->DstReg);
1421 _mesa_printf(", ");
1422 PrintSrcReg(&inst->SrcReg[0]);
1423 _mesa_printf(";\n");
1424 break;
1425 case VP_OPCODE_MUL:
1426 case VP_OPCODE_ADD:
1427 case VP_OPCODE_DP3:
1428 case VP_OPCODE_DP4:
1429 case VP_OPCODE_DST:
1430 case VP_OPCODE_MIN:
1431 case VP_OPCODE_MAX:
1432 case VP_OPCODE_SLT:
1433 case VP_OPCODE_SGE:
1434 case VP_OPCODE_DPH:
1435 case VP_OPCODE_SUB:
1436 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1437 PrintDstReg(&inst->DstReg);
1438 _mesa_printf(", ");
1439 PrintSrcReg(&inst->SrcReg[0]);
1440 _mesa_printf(", ");
1441 PrintSrcReg(&inst->SrcReg[1]);
1442 _mesa_printf(";\n");
1443 break;
1444 case VP_OPCODE_MAD:
1445 _mesa_printf("MAD ");
1446 PrintDstReg(&inst->DstReg);
1447 _mesa_printf(", ");
1448 PrintSrcReg(&inst->SrcReg[0]);
1449 _mesa_printf(", ");
1450 PrintSrcReg(&inst->SrcReg[1]);
1451 _mesa_printf(", ");
1452 PrintSrcReg(&inst->SrcReg[2]);
1453 _mesa_printf(";\n");
1454 break;
1455 case VP_OPCODE_ARL:
1456 _mesa_printf("ARL A0.x, ");
1457 PrintSrcReg(&inst->SrcReg[0]);
1458 _mesa_printf(";\n");
1459 break;
1460 case VP_OPCODE_END:
1461 _mesa_printf("END\n");
1462 break;
1463 default:
1464 _mesa_printf("BAD INSTRUCTION\n");
1465 }
1466 }
1467
1468
1469 /**
1470 * Print (unparse) the given vertex program. Just for debugging.
1471 */
1472 void
1473 _mesa_print_nv_vertex_program(const struct vertex_program *program)
1474 {
1475 const struct vp_instruction *inst;
1476
1477 for (inst = program->Instructions; ; inst++) {
1478 _mesa_print_nv_vertex_instruction(inst);
1479 if (inst->Opcode == VP_OPCODE_END)
1480 return;
1481 }
1482 }
1483
1484
1485 const char *
1486 _mesa_nv_vertex_input_register_name(GLuint i)
1487 {
1488 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1489 return InputRegisters[i];
1490 }
1491
1492
1493 const char *
1494 _mesa_nv_vertex_output_register_name(GLuint i)
1495 {
1496 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1497 return OutputRegisters[i];
1498 }