mesa: remove unneeded swizzle init code in glsl compiler
[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 inst->StringPos = parseState->curLine - parseState->start;
803
804 /* dest reg */
805 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
806 RETURN_ERROR;
807
808 /* comma */
809 if (!Parse_String(parseState, ","))
810 RETURN_ERROR;
811
812 /* src arg */
813 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
814 RETURN_ERROR;
815
816 /* semicolon */
817 if (!Parse_String(parseState, ";"))
818 RETURN_ERROR;
819
820 return GL_TRUE;
821 }
822
823
824 static GLboolean
825 Parse_BiOpInstruction(struct parse_state *parseState,
826 struct prog_instruction *inst,
827 enum prog_opcode opcode)
828 {
829 if (opcode == OPCODE_DPH && !parseState->isVersion1_1)
830 RETURN_ERROR1("DPH illegal for vertex program 1.0");
831 if (opcode == OPCODE_SUB && !parseState->isVersion1_1)
832 RETURN_ERROR1("SUB illegal for vertex program 1.0");
833
834 inst->Opcode = opcode;
835 inst->StringPos = parseState->curLine - parseState->start;
836
837 /* dest reg */
838 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
839 RETURN_ERROR;
840
841 /* comma */
842 if (!Parse_String(parseState, ","))
843 RETURN_ERROR;
844
845 /* first src arg */
846 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
847 RETURN_ERROR;
848
849 /* comma */
850 if (!Parse_String(parseState, ","))
851 RETURN_ERROR;
852
853 /* second src arg */
854 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
855 RETURN_ERROR;
856
857 /* semicolon */
858 if (!Parse_String(parseState, ";"))
859 RETURN_ERROR;
860
861 /* make sure we don't reference more than one program parameter register */
862 if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
863 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
864 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
865 RETURN_ERROR1("Can't reference two program parameter registers");
866
867 /* make sure we don't reference more than one vertex attribute register */
868 if (inst->SrcReg[0].File == PROGRAM_INPUT &&
869 inst->SrcReg[1].File == PROGRAM_INPUT &&
870 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
871 RETURN_ERROR1("Can't reference two vertex attribute registers");
872
873 return GL_TRUE;
874 }
875
876
877 static GLboolean
878 Parse_TriOpInstruction(struct parse_state *parseState,
879 struct prog_instruction *inst,
880 enum prog_opcode opcode)
881 {
882 inst->Opcode = opcode;
883 inst->StringPos = parseState->curLine - parseState->start;
884
885 /* dest reg */
886 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
887 RETURN_ERROR;
888
889 /* comma */
890 if (!Parse_String(parseState, ","))
891 RETURN_ERROR;
892
893 /* first src arg */
894 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
895 RETURN_ERROR;
896
897 /* comma */
898 if (!Parse_String(parseState, ","))
899 RETURN_ERROR;
900
901 /* second src arg */
902 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
903 RETURN_ERROR;
904
905 /* comma */
906 if (!Parse_String(parseState, ","))
907 RETURN_ERROR;
908
909 /* third src arg */
910 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2]))
911 RETURN_ERROR;
912
913 /* semicolon */
914 if (!Parse_String(parseState, ";"))
915 RETURN_ERROR;
916
917 /* make sure we don't reference more than one program parameter register */
918 if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
919 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
920 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
921 (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
922 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
923 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
924 (inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
925 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
926 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
927 RETURN_ERROR1("Can only reference one program register");
928
929 /* make sure we don't reference more than one vertex attribute register */
930 if ((inst->SrcReg[0].File == PROGRAM_INPUT &&
931 inst->SrcReg[1].File == PROGRAM_INPUT &&
932 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
933 (inst->SrcReg[0].File == PROGRAM_INPUT &&
934 inst->SrcReg[2].File == PROGRAM_INPUT &&
935 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
936 (inst->SrcReg[1].File == PROGRAM_INPUT &&
937 inst->SrcReg[2].File == PROGRAM_INPUT &&
938 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
939 RETURN_ERROR1("Can only reference one input register");
940
941 return GL_TRUE;
942 }
943
944
945 static GLboolean
946 Parse_ScalarInstruction(struct parse_state *parseState,
947 struct prog_instruction *inst,
948 enum prog_opcode opcode)
949 {
950 if (opcode == OPCODE_RCC && !parseState->isVersion1_1)
951 RETURN_ERROR1("RCC illegal for vertex program 1.0");
952
953 inst->Opcode = opcode;
954 inst->StringPos = parseState->curLine - parseState->start;
955
956 /* dest reg */
957 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
958 RETURN_ERROR;
959
960 /* comma */
961 if (!Parse_String(parseState, ","))
962 RETURN_ERROR;
963
964 /* first src arg */
965 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
966 RETURN_ERROR;
967
968 /* semicolon */
969 if (!Parse_String(parseState, ";"))
970 RETURN_ERROR;
971
972 return GL_TRUE;
973 }
974
975
976 static GLboolean
977 Parse_AddressInstruction(struct parse_state *parseState, struct prog_instruction *inst)
978 {
979 inst->Opcode = OPCODE_ARL;
980 inst->StringPos = parseState->curLine - parseState->start;
981
982 /* Make ARB_vp backends happy */
983 inst->DstReg.File = PROGRAM_ADDRESS;
984 inst->DstReg.WriteMask = WRITEMASK_X;
985 inst->DstReg.Index = 0;
986
987 /* dest A0 reg */
988 if (!Parse_AddrReg(parseState))
989 RETURN_ERROR;
990
991 /* comma */
992 if (!Parse_String(parseState, ","))
993 RETURN_ERROR;
994
995 /* parse src reg */
996 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
997 RETURN_ERROR;
998
999 /* semicolon */
1000 if (!Parse_String(parseState, ";"))
1001 RETURN_ERROR;
1002
1003 return GL_TRUE;
1004 }
1005
1006
1007 static GLboolean
1008 Parse_EndInstruction(struct parse_state *parseState, struct prog_instruction *inst)
1009 {
1010 GLubyte token[100];
1011
1012 inst->Opcode = OPCODE_END;
1013 inst->StringPos = parseState->curLine - parseState->start;
1014
1015 /* this should fail! */
1016 if (Parse_Token(parseState, token))
1017 RETURN_ERROR2("Unexpected token after END:", token);
1018 else
1019 return GL_TRUE;
1020 }
1021
1022
1023 /**
1024 * The PRINT instruction is Mesa-specific and is meant as a debugging aid for
1025 * the vertex program developer.
1026 * The NV_vertex_program extension grammar is modified as follows:
1027 *
1028 * <instruction> ::= <ARL-instruction>
1029 * | ...
1030 * | <PRINT-instruction>
1031 *
1032 * <PRINT-instruction> ::= "PRINT" <string literal>
1033 * | "PRINT" <string literal> "," <srcReg>
1034 * | "PRINT" <string literal> "," <dstReg>
1035 */
1036 static GLboolean
1037 Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *inst)
1038 {
1039 const GLubyte *str;
1040 GLubyte *msg;
1041 GLuint len;
1042 GLubyte token[100];
1043 struct prog_src_register *srcReg = &inst->SrcReg[0];
1044 GLint idx;
1045
1046 inst->Opcode = OPCODE_PRINT;
1047 inst->StringPos = parseState->curLine - parseState->start;
1048
1049 /* The first argument is a literal string 'just like this' */
1050 if (!Parse_String(parseState, "'"))
1051 RETURN_ERROR;
1052
1053 str = parseState->pos;
1054 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1055 ;
1056 parseState->pos += len + 1;
1057 msg = (GLubyte*) _mesa_malloc(len + 1);
1058
1059 _mesa_memcpy(msg, str, len);
1060 msg[len] = 0;
1061 inst->Data = msg;
1062
1063 /* comma */
1064 if (Parse_String(parseState, ",")) {
1065
1066 /* The second argument is a register name */
1067 if (!Peek_Token(parseState, token))
1068 RETURN_ERROR;
1069
1070 srcReg->RelAddr = GL_FALSE;
1071 srcReg->NegateBase = NEGATE_NONE;
1072 srcReg->Swizzle = SWIZZLE_NOOP;
1073
1074 /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
1075 * or an o[n] output register.
1076 */
1077 if (token[0] == 'R') {
1078 srcReg->File = PROGRAM_TEMPORARY;
1079 if (!Parse_TempReg(parseState, &idx))
1080 RETURN_ERROR;
1081 srcReg->Index = idx;
1082 }
1083 else if (token[0] == 'c') {
1084 srcReg->File = PROGRAM_ENV_PARAM;
1085 if (!Parse_ParamReg(parseState, srcReg))
1086 RETURN_ERROR;
1087 }
1088 else if (token[0] == 'v') {
1089 srcReg->File = PROGRAM_INPUT;
1090 if (!Parse_AttribReg(parseState, &idx))
1091 RETURN_ERROR;
1092 srcReg->Index = idx;
1093 }
1094 else if (token[0] == 'o') {
1095 srcReg->File = PROGRAM_OUTPUT;
1096 if (!Parse_OutputReg(parseState, &idx))
1097 RETURN_ERROR;
1098 srcReg->Index = idx;
1099 }
1100 else {
1101 RETURN_ERROR2("Bad source register name", token);
1102 }
1103 }
1104 else {
1105 srcReg->File = 0;
1106 }
1107
1108 /* semicolon */
1109 if (!Parse_String(parseState, ";"))
1110 RETURN_ERROR;
1111
1112 return GL_TRUE;
1113 }
1114
1115
1116 static GLboolean
1117 Parse_OptionSequence(struct parse_state *parseState,
1118 struct prog_instruction program[])
1119 {
1120 (void) program;
1121 while (1) {
1122 if (!Parse_String(parseState, "OPTION"))
1123 return GL_TRUE; /* ok, not an OPTION statement */
1124 if (Parse_String(parseState, "NV_position_invariant")) {
1125 parseState->isPositionInvariant = GL_TRUE;
1126 }
1127 else {
1128 RETURN_ERROR1("unexpected OPTION statement");
1129 }
1130 if (!Parse_String(parseState, ";"))
1131 return GL_FALSE;
1132 }
1133 }
1134
1135
1136 static GLboolean
1137 Parse_InstructionSequence(struct parse_state *parseState,
1138 struct prog_instruction program[])
1139 {
1140 while (1) {
1141 struct prog_instruction *inst = program + parseState->numInst;
1142
1143 /* Initialize the instruction */
1144 _mesa_init_instructions(inst, 1);
1145
1146 if (Parse_String(parseState, "MOV")) {
1147 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_MOV))
1148 RETURN_ERROR;
1149 }
1150 else if (Parse_String(parseState, "LIT")) {
1151 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_LIT))
1152 RETURN_ERROR;
1153 }
1154 else if (Parse_String(parseState, "ABS")) {
1155 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_ABS))
1156 RETURN_ERROR;
1157 }
1158 else if (Parse_String(parseState, "MUL")) {
1159 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MUL))
1160 RETURN_ERROR;
1161 }
1162 else if (Parse_String(parseState, "ADD")) {
1163 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_ADD))
1164 RETURN_ERROR;
1165 }
1166 else if (Parse_String(parseState, "DP3")) {
1167 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP3))
1168 RETURN_ERROR;
1169 }
1170 else if (Parse_String(parseState, "DP4")) {
1171 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP4))
1172 RETURN_ERROR;
1173 }
1174 else if (Parse_String(parseState, "DST")) {
1175 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DST))
1176 RETURN_ERROR;
1177 }
1178 else if (Parse_String(parseState, "MIN")) {
1179 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MIN))
1180 RETURN_ERROR;
1181 }
1182 else if (Parse_String(parseState, "MAX")) {
1183 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MAX))
1184 RETURN_ERROR;
1185 }
1186 else if (Parse_String(parseState, "SLT")) {
1187 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SLT))
1188 RETURN_ERROR;
1189 }
1190 else if (Parse_String(parseState, "SGE")) {
1191 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SGE))
1192 RETURN_ERROR;
1193 }
1194 else if (Parse_String(parseState, "DPH")) {
1195 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DPH))
1196 RETURN_ERROR;
1197 }
1198 else if (Parse_String(parseState, "SUB")) {
1199 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SUB))
1200 RETURN_ERROR;
1201 }
1202 else if (Parse_String(parseState, "MAD")) {
1203 if (!Parse_TriOpInstruction(parseState, inst, OPCODE_MAD))
1204 RETURN_ERROR;
1205 }
1206 else if (Parse_String(parseState, "RCP")) {
1207 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCP))
1208 RETURN_ERROR;
1209 }
1210 else if (Parse_String(parseState, "RSQ")) {
1211 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RSQ))
1212 RETURN_ERROR;
1213 }
1214 else if (Parse_String(parseState, "EXP")) {
1215 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_EXP))
1216 RETURN_ERROR;
1217 }
1218 else if (Parse_String(parseState, "LOG")) {
1219 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_LOG))
1220 RETURN_ERROR;
1221 }
1222 else if (Parse_String(parseState, "RCC")) {
1223 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCC))
1224 RETURN_ERROR;
1225 }
1226 else if (Parse_String(parseState, "ARL")) {
1227 if (!Parse_AddressInstruction(parseState, inst))
1228 RETURN_ERROR;
1229 }
1230 else if (Parse_String(parseState, "PRINT")) {
1231 if (!Parse_PrintInstruction(parseState, inst))
1232 RETURN_ERROR;
1233 }
1234 else if (Parse_String(parseState, "END")) {
1235 if (!Parse_EndInstruction(parseState, inst))
1236 RETURN_ERROR;
1237 else {
1238 parseState->numInst++;
1239 return GL_TRUE; /* all done */
1240 }
1241 }
1242 else {
1243 /* bad instruction name */
1244 RETURN_ERROR1("Unexpected token");
1245 }
1246
1247 /* examine input/output registers */
1248 if (inst->DstReg.File == PROGRAM_OUTPUT)
1249 parseState->outputsWritten |= (1 << inst->DstReg.Index);
1250 else if (inst->DstReg.File == PROGRAM_ENV_PARAM)
1251 parseState->anyProgRegsWritten = GL_TRUE;
1252
1253 if (inst->SrcReg[0].File == PROGRAM_INPUT)
1254 parseState->inputsRead |= (1 << inst->SrcReg[0].Index);
1255 if (inst->SrcReg[1].File == PROGRAM_INPUT)
1256 parseState->inputsRead |= (1 << inst->SrcReg[1].Index);
1257 if (inst->SrcReg[2].File == PROGRAM_INPUT)
1258 parseState->inputsRead |= (1 << inst->SrcReg[2].Index);
1259
1260 parseState->numInst++;
1261
1262 if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
1263 RETURN_ERROR1("Program too long");
1264 }
1265
1266 RETURN_ERROR;
1267 }
1268
1269
1270 static GLboolean
1271 Parse_Program(struct parse_state *parseState,
1272 struct prog_instruction instBuffer[])
1273 {
1274 if (parseState->isVersion1_1) {
1275 if (!Parse_OptionSequence(parseState, instBuffer)) {
1276 return GL_FALSE;
1277 }
1278 }
1279 return Parse_InstructionSequence(parseState, instBuffer);
1280 }
1281
1282
1283 /**
1284 * Parse/compile the 'str' returning the compiled 'program'.
1285 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1286 * indicates the position of the error in 'str'.
1287 */
1288 void
1289 _mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
1290 const GLubyte *str, GLsizei len,
1291 struct gl_vertex_program *program)
1292 {
1293 struct parse_state parseState;
1294 struct prog_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1295 struct prog_instruction *newInst;
1296 GLenum target;
1297 GLubyte *programString;
1298
1299 /* Make a null-terminated copy of the program string */
1300 programString = (GLubyte *) MALLOC(len + 1);
1301 if (!programString) {
1302 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1303 return;
1304 }
1305 MEMCPY(programString, str, len);
1306 programString[len] = 0;
1307
1308 /* Get ready to parse */
1309 parseState.ctx = ctx;
1310 parseState.start = programString;
1311 parseState.isPositionInvariant = GL_FALSE;
1312 parseState.isVersion1_1 = GL_FALSE;
1313 parseState.numInst = 0;
1314 parseState.inputsRead = 0;
1315 parseState.outputsWritten = 0;
1316 parseState.anyProgRegsWritten = GL_FALSE;
1317
1318 /* Reset error state */
1319 _mesa_set_program_error(ctx, -1, NULL);
1320
1321 /* check the program header */
1322 if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
1323 target = GL_VERTEX_PROGRAM_NV;
1324 parseState.pos = programString + 7;
1325 parseState.isStateProgram = GL_FALSE;
1326 }
1327 else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
1328 target = GL_VERTEX_PROGRAM_NV;
1329 parseState.pos = programString + 7;
1330 parseState.isStateProgram = GL_FALSE;
1331 parseState.isVersion1_1 = GL_TRUE;
1332 }
1333 else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
1334 target = GL_VERTEX_STATE_PROGRAM_NV;
1335 parseState.pos = programString + 8;
1336 parseState.isStateProgram = GL_TRUE;
1337 }
1338 else {
1339 /* invalid header */
1340 ctx->Program.ErrorPos = 0;
1341 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1342 return;
1343 }
1344
1345 /* make sure target and header match */
1346 if (target != dstTarget) {
1347 _mesa_error(ctx, GL_INVALID_OPERATION,
1348 "glLoadProgramNV(target mismatch)");
1349 return;
1350 }
1351
1352
1353 if (Parse_Program(&parseState, instBuffer)) {
1354 /* successful parse! */
1355
1356 if (parseState.isStateProgram) {
1357 if (!parseState.anyProgRegsWritten) {
1358 _mesa_error(ctx, GL_INVALID_OPERATION,
1359 "glLoadProgramNV(c[#] not written)");
1360 return;
1361 }
1362 }
1363 else {
1364 if (!parseState.isPositionInvariant &&
1365 !(parseState.outputsWritten & (1 << VERT_RESULT_HPOS))) {
1366 /* bit 1 = HPOS register */
1367 _mesa_error(ctx, GL_INVALID_OPERATION,
1368 "glLoadProgramNV(HPOS not written)");
1369 return;
1370 }
1371 }
1372
1373 /* copy the compiled instructions */
1374 assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
1375 newInst = _mesa_alloc_instructions(parseState.numInst);
1376 if (!newInst) {
1377 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1378 _mesa_free(programString);
1379 return; /* out of memory */
1380 }
1381 _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
1382
1383 /* install the program */
1384 program->Base.Target = target;
1385 if (program->Base.String) {
1386 _mesa_free(program->Base.String);
1387 }
1388 program->Base.String = programString;
1389 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1390 if (program->Base.Instructions) {
1391 _mesa_free(program->Base.Instructions);
1392 }
1393 program->Base.Instructions = newInst;
1394 program->Base.InputsRead = parseState.inputsRead;
1395 if (parseState.isPositionInvariant)
1396 program->Base.InputsRead |= VERT_BIT_POS;
1397 program->Base.NumInstructions = parseState.numInst;
1398 program->Base.OutputsWritten = parseState.outputsWritten;
1399 program->IsPositionInvariant = parseState.isPositionInvariant;
1400 program->IsNVProgram = GL_TRUE;
1401
1402 #ifdef DEBUG_foo
1403 _mesa_printf("--- glLoadProgramNV result ---\n");
1404 _mesa_print_nv_vertex_program(program);
1405 _mesa_printf("------------------------------\n");
1406 #endif
1407 }
1408 else {
1409 /* Error! */
1410 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1411 /* NOTE: _mesa_set_program_error would have been called already */
1412 /* GL_NV_vertex_program isn't supposed to set the error string
1413 * so we reset it here.
1414 */
1415 _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
1416 }
1417 }
1418
1419
1420 static void
1421 PrintSrcReg(const struct prog_src_register *src)
1422 {
1423 static const char comps[5] = "xyzw";
1424 if (src->NegateBase)
1425 _mesa_printf("-");
1426 if (src->RelAddr) {
1427 if (src->Index > 0)
1428 _mesa_printf("c[A0.x + %d]", src->Index);
1429 else if (src->Index < 0)
1430 _mesa_printf("c[A0.x - %d]", -src->Index);
1431 else
1432 _mesa_printf("c[A0.x]");
1433 }
1434 else if (src->File == PROGRAM_OUTPUT) {
1435 _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1436 }
1437 else if (src->File == PROGRAM_INPUT) {
1438 _mesa_printf("v[%s]", InputRegisters[src->Index]);
1439 }
1440 else if (src->File == PROGRAM_ENV_PARAM) {
1441 _mesa_printf("c[%d]", src->Index);
1442 }
1443 else {
1444 ASSERT(src->File == PROGRAM_TEMPORARY);
1445 _mesa_printf("R%d", src->Index);
1446 }
1447
1448 if (GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 1) &&
1449 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 2) &&
1450 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 3)) {
1451 _mesa_printf(".%c", comps[GET_SWZ(src->Swizzle, 0)]);
1452 }
1453 else if (src->Swizzle != SWIZZLE_NOOP) {
1454 _mesa_printf(".%c%c%c%c",
1455 comps[GET_SWZ(src->Swizzle, 0)],
1456 comps[GET_SWZ(src->Swizzle, 1)],
1457 comps[GET_SWZ(src->Swizzle, 2)],
1458 comps[GET_SWZ(src->Swizzle, 3)]);
1459 }
1460 }
1461
1462
1463 static void
1464 PrintDstReg(const struct prog_dst_register *dst)
1465 {
1466 if (dst->File == PROGRAM_OUTPUT) {
1467 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1468 }
1469 else if (dst->File == PROGRAM_INPUT) {
1470 _mesa_printf("v[%s]", InputRegisters[dst->Index]);
1471 }
1472 else if (dst->File == PROGRAM_ENV_PARAM) {
1473 _mesa_printf("c[%d]", dst->Index);
1474 }
1475 else {
1476 ASSERT(dst->File == PROGRAM_TEMPORARY);
1477 _mesa_printf("R%d", dst->Index);
1478 }
1479
1480 if (dst->WriteMask != 0 && dst->WriteMask != WRITEMASK_XYZW) {
1481 _mesa_printf(".");
1482 if (dst->WriteMask & WRITEMASK_X)
1483 _mesa_printf("x");
1484 if (dst->WriteMask & WRITEMASK_Y)
1485 _mesa_printf("y");
1486 if (dst->WriteMask & WRITEMASK_Z)
1487 _mesa_printf("z");
1488 if (dst->WriteMask & WRITEMASK_W)
1489 _mesa_printf("w");
1490 }
1491 }
1492
1493
1494 /**
1495 * Print a single NVIDIA vertex program instruction.
1496 */
1497 void
1498 _mesa_print_nv_vertex_instruction(const struct prog_instruction *inst)
1499 {
1500 GLuint i, n;
1501
1502 switch (inst->Opcode) {
1503 case OPCODE_MOV:
1504 case OPCODE_LIT:
1505 case OPCODE_RCP:
1506 case OPCODE_RSQ:
1507 case OPCODE_EXP:
1508 case OPCODE_LOG:
1509 case OPCODE_RCC:
1510 case OPCODE_ABS:
1511 case OPCODE_MUL:
1512 case OPCODE_ADD:
1513 case OPCODE_DP3:
1514 case OPCODE_DP4:
1515 case OPCODE_DST:
1516 case OPCODE_MIN:
1517 case OPCODE_MAX:
1518 case OPCODE_SLT:
1519 case OPCODE_SGE:
1520 case OPCODE_DPH:
1521 case OPCODE_SUB:
1522 case OPCODE_MAD:
1523 _mesa_printf("%s ", _mesa_opcode_string(inst->Opcode));
1524 PrintDstReg(&inst->DstReg);
1525 _mesa_printf(", ");
1526 n = _mesa_num_inst_src_regs(inst->Opcode);
1527 for (i = 0; i < n; i++) {
1528 PrintSrcReg(&inst->SrcReg[i]);
1529 if (i + 1 < n)
1530 _mesa_printf(", ");
1531 }
1532 _mesa_printf(";\n");
1533 break;
1534 case OPCODE_ARL:
1535 _mesa_printf("ARL A0.x, ");
1536 PrintSrcReg(&inst->SrcReg[0]);
1537 _mesa_printf(";\n");
1538 break;
1539 case OPCODE_PRINT:
1540 _mesa_printf("PRINT '%s'", inst->Data);
1541 if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
1542 _mesa_printf(", ");
1543 PrintSrcReg(&inst->SrcReg[0]);
1544 _mesa_printf(";\n");
1545 }
1546 else {
1547 _mesa_printf("\n");
1548 }
1549 break;
1550 case OPCODE_END:
1551 _mesa_printf("END\n");
1552 break;
1553 default:
1554 _mesa_printf("BAD INSTRUCTION\n");
1555 }
1556 }
1557
1558
1559 /**
1560 * Print (unparse) the given vertex program. Just for debugging.
1561 */
1562 void
1563 _mesa_print_nv_vertex_program(const struct gl_vertex_program *program)
1564 {
1565 const struct prog_instruction *inst;
1566
1567 for (inst = program->Base.Instructions; ; inst++) {
1568 _mesa_print_nv_vertex_instruction(inst);
1569 if (inst->Opcode == OPCODE_END)
1570 return;
1571 }
1572 }
1573
1574
1575 const char *
1576 _mesa_nv_vertex_input_register_name(GLuint i)
1577 {
1578 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1579 return InputRegisters[i];
1580 }
1581
1582
1583 const char *
1584 _mesa_nv_vertex_output_register_name(GLuint i)
1585 {
1586 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1587 return OutputRegisters[i];
1588 }
1589