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