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