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