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