Lots of clean-up in arb program parser.
[mesa.git] / src / mesa / shader / nvvertparse.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.3
4 *
5 * Copyright (C) 1999-2004 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 "nvvertprog.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", "BFC0", "BFC1", "FOGC", "PSIZ",
292 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
293 };
294
295 /* NOTE: the order here must match opcodes in nvvertprog.h */
296 static const char *Opcodes[] = {
297 "MOV", "LIT", "RCP", "RSQ", "EXP", "LOG", "MUL", "ADD", "DP3", "DP4",
298 "DST", "MIN", "MAX", "SLT", "SGE", "MAD", "ARL", "DPH", "RCC", "SUB",
299 "ABS", "END",
300 /* GL_ARB_vertex_program */
301 "FLR", "FRC", "EX2", "LG2", "POW", "XPD", "SWZ",
302 /* Mesa-specific */
303 "PRINT",
304 NULL
305 };
306
307
308
309 /**
310 * Parse a temporary register: Rnn
311 */
312 static GLboolean
313 Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
314 {
315 GLubyte token[100];
316
317 /* Should be 'R##' */
318 if (!Parse_Token(parseState, token))
319 RETURN_ERROR;
320 if (token[0] != 'R')
321 RETURN_ERROR1("Expected R##");
322
323 if (IsDigit(token[1])) {
324 GLint reg = _mesa_atoi((char *) (token + 1));
325 if (reg >= MAX_NV_VERTEX_PROGRAM_TEMPS)
326 RETURN_ERROR1("Bad temporary register name");
327 *tempRegNum = reg;
328 }
329 else {
330 RETURN_ERROR1("Bad temporary register name");
331 }
332
333 return GL_TRUE;
334 }
335
336
337 /**
338 * Parse address register "A0.x"
339 */
340 static GLboolean
341 Parse_AddrReg(struct parse_state *parseState)
342 {
343 /* match 'A0' */
344 if (!Parse_String(parseState, "A0"))
345 RETURN_ERROR;
346
347 /* match '.' */
348 if (!Parse_String(parseState, "."))
349 RETURN_ERROR;
350
351 /* match 'x' */
352 if (!Parse_String(parseState, "x"))
353 RETURN_ERROR;
354
355 return GL_TRUE;
356 }
357
358
359 /**
360 * Parse absolute program parameter register "c[##]"
361 */
362 static GLboolean
363 Parse_AbsParamReg(struct parse_state *parseState, GLint *regNum)
364 {
365 GLubyte token[100];
366
367 if (!Parse_String(parseState, "c"))
368 RETURN_ERROR;
369
370 if (!Parse_String(parseState, "["))
371 RETURN_ERROR;
372
373 if (!Parse_Token(parseState, token))
374 RETURN_ERROR;
375
376 if (IsDigit(token[0])) {
377 /* a numbered program parameter register */
378 GLint reg = _mesa_atoi((char *) token);
379 if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
380 RETURN_ERROR1("Bad program parameter number");
381 *regNum = reg;
382 }
383 else {
384 RETURN_ERROR;
385 }
386
387 if (!Parse_String(parseState, "]"))
388 RETURN_ERROR;
389
390 return GL_TRUE;
391 }
392
393
394 static GLboolean
395 Parse_ParamReg(struct parse_state *parseState, struct vp_src_register *srcReg)
396 {
397 GLubyte token[100];
398
399 if (!Parse_String(parseState, "c"))
400 RETURN_ERROR;
401
402 if (!Parse_String(parseState, "["))
403 RETURN_ERROR;
404
405 if (!Peek_Token(parseState, token))
406 RETURN_ERROR;
407
408 if (IsDigit(token[0])) {
409 /* a numbered program parameter register */
410 GLint reg;
411 (void) Parse_Token(parseState, token);
412 reg = _mesa_atoi((char *) token);
413 if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS)
414 RETURN_ERROR1("Bad program parameter number");
415 srcReg->File = PROGRAM_ENV_PARAM;
416 srcReg->Index = reg;
417 }
418 else if (_mesa_strcmp((const char *) token, "A0") == 0) {
419 /* address register "A0.x" */
420 if (!Parse_AddrReg(parseState))
421 RETURN_ERROR;
422
423 srcReg->RelAddr = GL_TRUE;
424 srcReg->File = PROGRAM_ENV_PARAM;
425 /* Look for +/-N offset */
426 if (!Peek_Token(parseState, token))
427 RETURN_ERROR;
428
429 if (token[0] == '-' || token[0] == '+') {
430 const GLubyte sign = token[0];
431 (void) Parse_Token(parseState, token); /* consume +/- */
432
433 /* an integer should be next */
434 if (!Parse_Token(parseState, token))
435 RETURN_ERROR;
436
437 if (IsDigit(token[0])) {
438 const GLint k = _mesa_atoi((char *) token);
439 if (sign == '-') {
440 if (k > 64)
441 RETURN_ERROR1("Bad address offset");
442 srcReg->Index = -k;
443 }
444 else {
445 if (k > 63)
446 RETURN_ERROR1("Bad address offset");
447 srcReg->Index = k;
448 }
449 }
450 else {
451 RETURN_ERROR;
452 }
453 }
454 else {
455 /* probably got a ']', catch it below */
456 }
457 }
458 else {
459 RETURN_ERROR;
460 }
461
462 /* Match closing ']' */
463 if (!Parse_String(parseState, "]"))
464 RETURN_ERROR;
465
466 return GL_TRUE;
467 }
468
469
470 /**
471 * Parse v[#] or v[<name>]
472 */
473 static GLboolean
474 Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum)
475 {
476 GLubyte token[100];
477 GLint j;
478
479 /* Match 'v' */
480 if (!Parse_String(parseState, "v"))
481 RETURN_ERROR;
482
483 /* Match '[' */
484 if (!Parse_String(parseState, "["))
485 RETURN_ERROR;
486
487 /* match number or named register */
488 if (!Parse_Token(parseState, token))
489 RETURN_ERROR;
490
491 if (parseState->isStateProgram && token[0] != '0')
492 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
493
494 if (IsDigit(token[0])) {
495 GLint reg = _mesa_atoi((char *) token);
496 if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS)
497 RETURN_ERROR1("Bad vertex attribute register name");
498 *tempRegNum = reg;
499 }
500 else {
501 for (j = 0; InputRegisters[j]; j++) {
502 if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
503 *tempRegNum = j;
504 break;
505 }
506 }
507 if (!InputRegisters[j]) {
508 /* unknown input register label */
509 RETURN_ERROR2("Bad register name", token);
510 }
511 }
512
513 /* Match '[' */
514 if (!Parse_String(parseState, "]"))
515 RETURN_ERROR;
516
517 return GL_TRUE;
518 }
519
520
521 static GLboolean
522 Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
523 {
524 GLubyte token[100];
525 GLint start, j;
526
527 /* Match 'o' */
528 if (!Parse_String(parseState, "o"))
529 RETURN_ERROR;
530
531 /* Match '[' */
532 if (!Parse_String(parseState, "["))
533 RETURN_ERROR;
534
535 /* Get output reg name */
536 if (!Parse_Token(parseState, token))
537 RETURN_ERROR;
538
539 if (parseState->isPositionInvariant)
540 start = 1; /* skip HPOS register name */
541 else
542 start = 0;
543
544 /* try to match an output register name */
545 for (j = start; OutputRegisters[j]; j++) {
546 if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) {
547 *outputRegNum = j;
548 break;
549 }
550 }
551 if (!OutputRegisters[j])
552 RETURN_ERROR1("Unrecognized output register name");
553
554 /* Match ']' */
555 if (!Parse_String(parseState, "]"))
556 RETURN_ERROR1("Expected ]");
557
558 return GL_TRUE;
559 }
560
561
562 static GLboolean
563 Parse_MaskedDstReg(struct parse_state *parseState, struct vp_dst_register *dstReg)
564 {
565 GLubyte token[100];
566 GLint idx;
567
568 /* Dst reg can be R<n> or o[n] */
569 if (!Peek_Token(parseState, token))
570 RETURN_ERROR;
571
572 if (token[0] == 'R') {
573 /* a temporary register */
574 dstReg->File = PROGRAM_TEMPORARY;
575 if (!Parse_TempReg(parseState, &idx))
576 RETURN_ERROR;
577 dstReg->Index = idx;
578 }
579 else if (!parseState->isStateProgram && token[0] == 'o') {
580 /* an output register */
581 dstReg->File = PROGRAM_OUTPUT;
582 if (!Parse_OutputReg(parseState, &idx))
583 RETURN_ERROR;
584 dstReg->Index = idx;
585 }
586 else if (parseState->isStateProgram && token[0] == 'c' &&
587 parseState->isStateProgram) {
588 /* absolute program parameter register */
589 /* Only valid for vertex state programs */
590 dstReg->File = PROGRAM_ENV_PARAM;
591 if (!Parse_AbsParamReg(parseState, &idx))
592 RETURN_ERROR;
593 dstReg->Index = idx;
594 }
595 else {
596 RETURN_ERROR1("Bad destination register name");
597 }
598
599 /* Parse optional write mask */
600 if (!Peek_Token(parseState, token))
601 RETURN_ERROR;
602
603 if (token[0] == '.') {
604 /* got a mask */
605 GLint k = 0;
606
607 if (!Parse_String(parseState, "."))
608 RETURN_ERROR;
609
610 if (!Parse_Token(parseState, token))
611 RETURN_ERROR;
612
613 dstReg->WriteMask = 0;
614
615 if (token[k] == 'x') {
616 dstReg->WriteMask |= WRITEMASK_X;
617 k++;
618 }
619 if (token[k] == 'y') {
620 dstReg->WriteMask |= WRITEMASK_Y;
621 k++;
622 }
623 if (token[k] == 'z') {
624 dstReg->WriteMask |= WRITEMASK_Z;
625 k++;
626 }
627 if (token[k] == 'w') {
628 dstReg->WriteMask |= WRITEMASK_W;
629 k++;
630 }
631 if (k == 0) {
632 RETURN_ERROR1("Bad writemask character");
633 }
634 return GL_TRUE;
635 }
636 else {
637 dstReg->WriteMask = WRITEMASK_XYZW;
638 return GL_TRUE;
639 }
640 }
641
642
643 static GLboolean
644 Parse_SwizzleSrcReg(struct parse_state *parseState, struct vp_src_register *srcReg)
645 {
646 GLubyte token[100];
647 GLint idx;
648
649 srcReg->RelAddr = GL_FALSE;
650
651 /* check for '-' */
652 if (!Peek_Token(parseState, token))
653 RETURN_ERROR;
654 if (token[0] == '-') {
655 (void) Parse_String(parseState, "-");
656 srcReg->Negate = GL_TRUE;
657 if (!Peek_Token(parseState, token))
658 RETURN_ERROR;
659 }
660 else {
661 srcReg->Negate = GL_FALSE;
662 }
663
664 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
665 if (token[0] == 'R') {
666 srcReg->File = PROGRAM_TEMPORARY;
667 if (!Parse_TempReg(parseState, &idx))
668 RETURN_ERROR;
669 srcReg->Index = idx;
670 }
671 else if (token[0] == 'c') {
672 if (!Parse_ParamReg(parseState, srcReg))
673 RETURN_ERROR;
674 }
675 else if (token[0] == 'v') {
676 srcReg->File = PROGRAM_INPUT;
677 if (!Parse_AttribReg(parseState, &idx))
678 RETURN_ERROR;
679 srcReg->Index = idx;
680 }
681 else {
682 RETURN_ERROR2("Bad source register name", token);
683 }
684
685 /* init swizzle fields */
686 srcReg->Swizzle = SWIZZLE_NOOP;
687
688 /* Look for optional swizzle suffix */
689 if (!Peek_Token(parseState, token))
690 RETURN_ERROR;
691 if (token[0] == '.') {
692 (void) Parse_String(parseState, "."); /* consume . */
693
694 if (!Parse_Token(parseState, token))
695 RETURN_ERROR;
696
697 if (token[1] == 0) {
698 /* single letter swizzle */
699 if (token[0] == 'x')
700 srcReg->Swizzle = MAKE_SWIZZLE4(0, 0, 0, 0);
701 else if (token[0] == 'y')
702 srcReg->Swizzle = MAKE_SWIZZLE4(1, 1, 1, 1);
703 else if (token[0] == 'z')
704 srcReg->Swizzle = MAKE_SWIZZLE4(2, 2, 2, 2);
705 else if (token[0] == 'w')
706 srcReg->Swizzle = MAKE_SWIZZLE4(3, 3, 3, 3);
707 else
708 RETURN_ERROR1("Expected x, y, z, or w");
709 }
710 else {
711 /* 2, 3 or 4-component swizzle */
712 GLint k;
713 for (k = 0; token[k] && k < 5; k++) {
714 if (token[k] == 'x')
715 srcReg->Swizzle |= 0 << (k*3);
716 else if (token[k] == 'y')
717 srcReg->Swizzle |= 1 << (k*3);
718 else if (token[k] == 'z')
719 srcReg->Swizzle |= 2 << (k*3);
720 else if (token[k] == 'w')
721 srcReg->Swizzle |= 3 << (k*3);
722 else
723 RETURN_ERROR;
724 }
725 if (k >= 5)
726 RETURN_ERROR;
727 }
728 }
729
730 return GL_TRUE;
731 }
732
733
734 static GLboolean
735 Parse_ScalarSrcReg(struct parse_state *parseState, struct vp_src_register *srcReg)
736 {
737 GLubyte token[100];
738 GLint idx;
739
740 srcReg->RelAddr = GL_FALSE;
741
742 /* check for '-' */
743 if (!Peek_Token(parseState, token))
744 RETURN_ERROR;
745 if (token[0] == '-') {
746 srcReg->Negate = GL_TRUE;
747 (void) Parse_String(parseState, "-"); /* consume '-' */
748 if (!Peek_Token(parseState, token))
749 RETURN_ERROR;
750 }
751 else {
752 srcReg->Negate = GL_FALSE;
753 }
754
755 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
756 if (token[0] == 'R') {
757 srcReg->File = PROGRAM_TEMPORARY;
758 if (!Parse_TempReg(parseState, &idx))
759 RETURN_ERROR;
760 srcReg->Index = idx;
761 }
762 else if (token[0] == 'c') {
763 if (!Parse_ParamReg(parseState, srcReg))
764 RETURN_ERROR;
765 }
766 else if (token[0] == 'v') {
767 srcReg->File = PROGRAM_INPUT;
768 if (!Parse_AttribReg(parseState, &idx))
769 RETURN_ERROR;
770 srcReg->Index = idx;
771 }
772 else {
773 RETURN_ERROR2("Bad source register name", token);
774 }
775
776 /* Look for .[xyzw] suffix */
777 if (!Parse_String(parseState, "."))
778 RETURN_ERROR;
779
780 if (!Parse_Token(parseState, token))
781 RETURN_ERROR;
782
783 if (token[0] == 'x' && token[1] == 0) {
784 srcReg->Swizzle = 0;
785 }
786 else if (token[0] == 'y' && token[1] == 0) {
787 srcReg->Swizzle = 1;
788 }
789 else if (token[0] == 'z' && token[1] == 0) {
790 srcReg->Swizzle = 2;
791 }
792 else if (token[0] == 'w' && token[1] == 0) {
793 srcReg->Swizzle = 3;
794 }
795 else {
796 RETURN_ERROR1("Bad scalar source suffix");
797 }
798
799 return GL_TRUE;
800 }
801
802
803 static GLint
804 Parse_UnaryOpInstruction(struct parse_state *parseState,
805 struct vp_instruction *inst, enum vp_opcode opcode)
806 {
807 if (opcode == VP_OPCODE_ABS && !parseState->isVersion1_1)
808 RETURN_ERROR1("ABS illegal for vertex program 1.0");
809
810 inst->Opcode = opcode;
811 inst->StringPos = parseState->curLine - parseState->start;
812
813 /* dest reg */
814 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
815 RETURN_ERROR;
816
817 /* comma */
818 if (!Parse_String(parseState, ","))
819 RETURN_ERROR;
820
821 /* src arg */
822 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
823 RETURN_ERROR;
824
825 /* semicolon */
826 if (!Parse_String(parseState, ";"))
827 RETURN_ERROR;
828
829 return GL_TRUE;
830 }
831
832
833 static GLboolean
834 Parse_BiOpInstruction(struct parse_state *parseState,
835 struct vp_instruction *inst, enum vp_opcode opcode)
836 {
837 if (opcode == VP_OPCODE_DPH && !parseState->isVersion1_1)
838 RETURN_ERROR1("DPH illegal for vertex program 1.0");
839 if (opcode == VP_OPCODE_SUB && !parseState->isVersion1_1)
840 RETURN_ERROR1("SUB illegal for vertex program 1.0");
841
842 inst->Opcode = opcode;
843 inst->StringPos = parseState->curLine - parseState->start;
844
845 /* dest reg */
846 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
847 RETURN_ERROR;
848
849 /* comma */
850 if (!Parse_String(parseState, ","))
851 RETURN_ERROR;
852
853 /* first src arg */
854 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
855 RETURN_ERROR;
856
857 /* comma */
858 if (!Parse_String(parseState, ","))
859 RETURN_ERROR;
860
861 /* second src arg */
862 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
863 RETURN_ERROR;
864
865 /* semicolon */
866 if (!Parse_String(parseState, ";"))
867 RETURN_ERROR;
868
869 /* make sure we don't reference more than one program parameter register */
870 if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
871 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
872 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
873 RETURN_ERROR1("Can't reference two program parameter registers");
874
875 /* make sure we don't reference more than one vertex attribute register */
876 if (inst->SrcReg[0].File == PROGRAM_INPUT &&
877 inst->SrcReg[1].File == PROGRAM_INPUT &&
878 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
879 RETURN_ERROR1("Can't reference two vertex attribute registers");
880
881 return GL_TRUE;
882 }
883
884
885 static GLboolean
886 Parse_TriOpInstruction(struct parse_state *parseState,
887 struct vp_instruction *inst, enum vp_opcode opcode)
888 {
889 inst->Opcode = opcode;
890 inst->StringPos = parseState->curLine - parseState->start;
891
892 /* dest reg */
893 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
894 RETURN_ERROR;
895
896 /* comma */
897 if (!Parse_String(parseState, ","))
898 RETURN_ERROR;
899
900 /* first src arg */
901 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
902 RETURN_ERROR;
903
904 /* comma */
905 if (!Parse_String(parseState, ","))
906 RETURN_ERROR;
907
908 /* second src arg */
909 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
910 RETURN_ERROR;
911
912 /* comma */
913 if (!Parse_String(parseState, ","))
914 RETURN_ERROR;
915
916 /* third src arg */
917 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2]))
918 RETURN_ERROR;
919
920 /* semicolon */
921 if (!Parse_String(parseState, ";"))
922 RETURN_ERROR;
923
924 /* make sure we don't reference more than one program parameter register */
925 if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
926 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
927 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
928 (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
929 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
930 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
931 (inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
932 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
933 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
934 RETURN_ERROR1("Can only reference one program register");
935
936 /* make sure we don't reference more than one vertex attribute register */
937 if ((inst->SrcReg[0].File == PROGRAM_INPUT &&
938 inst->SrcReg[1].File == PROGRAM_INPUT &&
939 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
940 (inst->SrcReg[0].File == PROGRAM_INPUT &&
941 inst->SrcReg[2].File == PROGRAM_INPUT &&
942 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
943 (inst->SrcReg[1].File == PROGRAM_INPUT &&
944 inst->SrcReg[2].File == PROGRAM_INPUT &&
945 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
946 RETURN_ERROR1("Can only reference one input register");
947
948 return GL_TRUE;
949 }
950
951
952 static GLboolean
953 Parse_ScalarInstruction(struct parse_state *parseState,
954 struct vp_instruction *inst, enum vp_opcode opcode)
955 {
956 if (opcode == VP_OPCODE_RCC && !parseState->isVersion1_1)
957 RETURN_ERROR1("RCC illegal for vertex program 1.0");
958
959 inst->Opcode = opcode;
960 inst->StringPos = parseState->curLine - parseState->start;
961
962 /* dest reg */
963 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
964 RETURN_ERROR;
965
966 /* comma */
967 if (!Parse_String(parseState, ","))
968 RETURN_ERROR;
969
970 /* first src arg */
971 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
972 RETURN_ERROR;
973
974 /* semicolon */
975 if (!Parse_String(parseState, ";"))
976 RETURN_ERROR;
977
978 return GL_TRUE;
979 }
980
981
982 static GLboolean
983 Parse_AddressInstruction(struct parse_state *parseState, struct vp_instruction *inst)
984 {
985 inst->Opcode = VP_OPCODE_ARL;
986 inst->StringPos = parseState->curLine - parseState->start;
987
988 /* dest A0 reg */
989 if (!Parse_AddrReg(parseState))
990 RETURN_ERROR;
991
992 /* comma */
993 if (!Parse_String(parseState, ","))
994 RETURN_ERROR;
995
996 /* parse src reg */
997 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
998 RETURN_ERROR;
999
1000 /* semicolon */
1001 if (!Parse_String(parseState, ";"))
1002 RETURN_ERROR;
1003
1004 return GL_TRUE;
1005 }
1006
1007
1008 static GLboolean
1009 Parse_EndInstruction(struct parse_state *parseState, struct vp_instruction *inst)
1010 {
1011 GLubyte token[100];
1012
1013 inst->Opcode = VP_OPCODE_END;
1014 inst->StringPos = parseState->curLine - parseState->start;
1015
1016 /* this should fail! */
1017 if (Parse_Token(parseState, token))
1018 RETURN_ERROR2("Unexpected token after END:", token);
1019 else
1020 return GL_TRUE;
1021 }
1022
1023
1024 /**
1025 * The PRINT instruction is Mesa-specific and is meant as a debugging aid for
1026 * the vertex program developer.
1027 * The NV_vertex_program extension grammar is modified as follows:
1028 *
1029 * <instruction> ::= <ARL-instruction>
1030 * | ...
1031 * | <PRINT-instruction>
1032 *
1033 * <PRINT-instruction> ::= "PRINT" <string literal>
1034 * | "PRINT" <string literal> "," <srcReg>
1035 * | "PRINT" <string literal> "," <dstReg>
1036 */
1037 static GLboolean
1038 Parse_PrintInstruction(struct parse_state *parseState, struct vp_instruction *inst)
1039 {
1040 const GLubyte *str;
1041 GLubyte *msg;
1042 GLuint len;
1043 GLubyte token[100];
1044 struct vp_src_register *srcReg = &inst->SrcReg[0];
1045 GLint idx;
1046
1047 inst->Opcode = VP_OPCODE_PRINT;
1048 inst->StringPos = parseState->curLine - parseState->start;
1049
1050 /* The first argument is a literal string 'just like this' */
1051 if (!Parse_String(parseState, "'"))
1052 RETURN_ERROR;
1053
1054 str = parseState->pos;
1055 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1056 ;
1057 parseState->pos += len + 1;
1058 msg = _mesa_malloc(len + 1);
1059
1060 _mesa_memcpy(msg, str, len);
1061 msg[len] = 0;
1062 inst->Data = msg;
1063
1064 /* comma */
1065 if (Parse_String(parseState, ",")) {
1066
1067 /* The second argument is a register name */
1068 if (!Peek_Token(parseState, token))
1069 RETURN_ERROR;
1070
1071 srcReg->RelAddr = GL_FALSE;
1072 srcReg->Negate = GL_FALSE;
1073 srcReg->Swizzle = SWIZZLE_NOOP;
1074
1075 /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
1076 * or an o[n] output register.
1077 */
1078 if (token[0] == 'R') {
1079 srcReg->File = PROGRAM_TEMPORARY;
1080 if (!Parse_TempReg(parseState, &idx))
1081 RETURN_ERROR;
1082 srcReg->Index = idx;
1083 }
1084 else if (token[0] == 'c') {
1085 srcReg->File = PROGRAM_ENV_PARAM;
1086 if (!Parse_ParamReg(parseState, srcReg))
1087 RETURN_ERROR;
1088 }
1089 else if (token[0] == 'v') {
1090 srcReg->File = PROGRAM_INPUT;
1091 if (!Parse_AttribReg(parseState, &idx))
1092 RETURN_ERROR;
1093 srcReg->Index = idx;
1094 }
1095 else if (token[0] == 'o') {
1096 srcReg->File = PROGRAM_OUTPUT;
1097 if (!Parse_OutputReg(parseState, &idx))
1098 RETURN_ERROR;
1099 srcReg->Index = idx;
1100 }
1101 else {
1102 RETURN_ERROR2("Bad source register name", token);
1103 }
1104 }
1105 else {
1106 srcReg->File = 0;
1107 }
1108
1109 /* semicolon */
1110 if (!Parse_String(parseState, ";"))
1111 RETURN_ERROR;
1112
1113 return GL_TRUE;
1114 }
1115
1116
1117 static GLboolean
1118 Parse_OptionSequence(struct parse_state *parseState,
1119 struct vp_instruction program[])
1120 {
1121 (void) program;
1122 while (1) {
1123 if (!Parse_String(parseState, "OPTION"))
1124 return GL_TRUE; /* ok, not an OPTION statement */
1125 if (Parse_String(parseState, "NV_position_invariant")) {
1126 parseState->isPositionInvariant = GL_TRUE;
1127 }
1128 else {
1129 RETURN_ERROR1("unexpected OPTION statement");
1130 }
1131 if (!Parse_String(parseState, ";"))
1132 return GL_FALSE;
1133 }
1134 }
1135
1136
1137 static GLboolean
1138 Parse_InstructionSequence(struct parse_state *parseState,
1139 struct vp_instruction program[])
1140 {
1141 while (1) {
1142 struct vp_instruction *inst = program + parseState->numInst;
1143
1144 /* Initialize the instruction */
1145 _mesa_init_vp_instruction(inst);
1146
1147 if (Parse_String(parseState, "MOV")) {
1148 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_MOV))
1149 RETURN_ERROR;
1150 }
1151 else if (Parse_String(parseState, "LIT")) {
1152 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_LIT))
1153 RETURN_ERROR;
1154 }
1155 else if (Parse_String(parseState, "ABS")) {
1156 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_ABS))
1157 RETURN_ERROR;
1158 }
1159 else if (Parse_String(parseState, "MUL")) {
1160 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MUL))
1161 RETURN_ERROR;
1162 }
1163 else if (Parse_String(parseState, "ADD")) {
1164 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_ADD))
1165 RETURN_ERROR;
1166 }
1167 else if (Parse_String(parseState, "DP3")) {
1168 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP3))
1169 RETURN_ERROR;
1170 }
1171 else if (Parse_String(parseState, "DP4")) {
1172 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP4))
1173 RETURN_ERROR;
1174 }
1175 else if (Parse_String(parseState, "DST")) {
1176 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DST))
1177 RETURN_ERROR;
1178 }
1179 else if (Parse_String(parseState, "MIN")) {
1180 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MIN))
1181 RETURN_ERROR;
1182 }
1183 else if (Parse_String(parseState, "MAX")) {
1184 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MAX))
1185 RETURN_ERROR;
1186 }
1187 else if (Parse_String(parseState, "SLT")) {
1188 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SLT))
1189 RETURN_ERROR;
1190 }
1191 else if (Parse_String(parseState, "SGE")) {
1192 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SGE))
1193 RETURN_ERROR;
1194 }
1195 else if (Parse_String(parseState, "DPH")) {
1196 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DPH))
1197 RETURN_ERROR;
1198 }
1199 else if (Parse_String(parseState, "SUB")) {
1200 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SUB))
1201 RETURN_ERROR;
1202 }
1203 else if (Parse_String(parseState, "MAD")) {
1204 if (!Parse_TriOpInstruction(parseState, inst, VP_OPCODE_MAD))
1205 RETURN_ERROR;
1206 }
1207 else if (Parse_String(parseState, "RCP")) {
1208 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCP))
1209 RETURN_ERROR;
1210 }
1211 else if (Parse_String(parseState, "RSQ")) {
1212 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RSQ))
1213 RETURN_ERROR;
1214 }
1215 else if (Parse_String(parseState, "EXP")) {
1216 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_EXP))
1217 RETURN_ERROR;
1218 }
1219 else if (Parse_String(parseState, "LOG")) {
1220 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_LOG))
1221 RETURN_ERROR;
1222 }
1223 else if (Parse_String(parseState, "RCC")) {
1224 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCC))
1225 RETURN_ERROR;
1226 }
1227 else if (Parse_String(parseState, "ARL")) {
1228 if (!Parse_AddressInstruction(parseState, inst))
1229 RETURN_ERROR;
1230 }
1231 else if (Parse_String(parseState, "PRINT")) {
1232 if (!Parse_PrintInstruction(parseState, inst))
1233 RETURN_ERROR;
1234 }
1235 else if (Parse_String(parseState, "END")) {
1236 if (!Parse_EndInstruction(parseState, inst))
1237 RETURN_ERROR;
1238 else {
1239 parseState->numInst++;
1240 return GL_TRUE; /* all done */
1241 }
1242 }
1243 else {
1244 /* bad instruction name */
1245 RETURN_ERROR1("Unexpected token");
1246 }
1247
1248 /* examine input/output registers */
1249 if (inst->DstReg.File == PROGRAM_OUTPUT)
1250 parseState->outputsWritten |= (1 << inst->DstReg.Index);
1251 else if (inst->DstReg.File == PROGRAM_ENV_PARAM)
1252 parseState->anyProgRegsWritten = GL_TRUE;
1253
1254 if (inst->SrcReg[0].File == PROGRAM_INPUT)
1255 parseState->inputsRead |= (1 << inst->SrcReg[0].Index);
1256 if (inst->SrcReg[1].File == PROGRAM_INPUT)
1257 parseState->inputsRead |= (1 << inst->SrcReg[1].Index);
1258 if (inst->SrcReg[2].File == PROGRAM_INPUT)
1259 parseState->inputsRead |= (1 << inst->SrcReg[2].Index);
1260
1261 parseState->numInst++;
1262
1263 if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
1264 RETURN_ERROR1("Program too long");
1265 }
1266
1267 RETURN_ERROR;
1268 }
1269
1270
1271 static GLboolean
1272 Parse_Program(struct parse_state *parseState,
1273 struct vp_instruction instBuffer[])
1274 {
1275 if (parseState->isVersion1_1) {
1276 if (!Parse_OptionSequence(parseState, instBuffer)) {
1277 return GL_FALSE;
1278 }
1279 }
1280 return Parse_InstructionSequence(parseState, instBuffer);
1281 }
1282
1283
1284 /**
1285 * Parse/compile the 'str' returning the compiled 'program'.
1286 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1287 * indicates the position of the error in 'str'.
1288 */
1289 void
1290 _mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
1291 const GLubyte *str, GLsizei len,
1292 struct vertex_program *program)
1293 {
1294 struct parse_state parseState;
1295 struct vp_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1296 struct vp_instruction *newInst;
1297 GLenum target;
1298 GLubyte *programString;
1299
1300 /* Make a null-terminated copy of the program string */
1301 programString = (GLubyte *) MALLOC(len + 1);
1302 if (!programString) {
1303 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1304 return;
1305 }
1306 MEMCPY(programString, str, len);
1307 programString[len] = 0;
1308
1309 /* Get ready to parse */
1310 parseState.ctx = ctx;
1311 parseState.start = programString;
1312 parseState.isPositionInvariant = GL_FALSE;
1313 parseState.isVersion1_1 = GL_FALSE;
1314 parseState.numInst = 0;
1315 parseState.inputsRead = 0;
1316 parseState.outputsWritten = 0;
1317 parseState.anyProgRegsWritten = GL_FALSE;
1318
1319 /* Reset error state */
1320 _mesa_set_program_error(ctx, -1, NULL);
1321
1322 /* check the program header */
1323 if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
1324 target = GL_VERTEX_PROGRAM_NV;
1325 parseState.pos = programString + 7;
1326 parseState.isStateProgram = GL_FALSE;
1327 }
1328 else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
1329 target = GL_VERTEX_PROGRAM_NV;
1330 parseState.pos = programString + 7;
1331 parseState.isStateProgram = GL_FALSE;
1332 parseState.isVersion1_1 = GL_TRUE;
1333 }
1334 else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
1335 target = GL_VERTEX_STATE_PROGRAM_NV;
1336 parseState.pos = programString + 8;
1337 parseState.isStateProgram = GL_TRUE;
1338 }
1339 else {
1340 /* invalid header */
1341 ctx->Program.ErrorPos = 0;
1342 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1343 return;
1344 }
1345
1346 /* make sure target and header match */
1347 if (target != dstTarget) {
1348 _mesa_error(ctx, GL_INVALID_OPERATION,
1349 "glLoadProgramNV(target mismatch)");
1350 return;
1351 }
1352
1353
1354 if (Parse_Program(&parseState, instBuffer)) {
1355 /* successful parse! */
1356
1357 if (parseState.isStateProgram) {
1358 if (!parseState.anyProgRegsWritten) {
1359 _mesa_error(ctx, GL_INVALID_OPERATION,
1360 "glLoadProgramNV(c[#] not written)");
1361 return;
1362 }
1363 }
1364 else {
1365 if (!parseState.isPositionInvariant &&
1366 !(parseState.outputsWritten & 1)) {
1367 /* bit 1 = HPOS register */
1368 _mesa_error(ctx, GL_INVALID_OPERATION,
1369 "glLoadProgramNV(HPOS not written)");
1370 return;
1371 }
1372 }
1373
1374 /* copy the compiled instructions */
1375 assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
1376 newInst = (struct vp_instruction *)
1377 MALLOC(parseState.numInst * sizeof(struct vp_instruction));
1378 if (!newInst) {
1379 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1380 FREE(programString);
1381 return; /* out of memory */
1382 }
1383 MEMCPY(newInst, instBuffer,
1384 parseState.numInst * sizeof(struct vp_instruction));
1385
1386 /* install the program */
1387 program->Base.Target = target;
1388 if (program->Base.String) {
1389 FREE(program->Base.String);
1390 }
1391 program->Base.String = programString;
1392 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1393 if (program->Instructions) {
1394 FREE(program->Instructions);
1395 }
1396 program->Instructions = newInst;
1397 program->InputsRead = parseState.inputsRead;
1398 program->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 vp_src_register *src)
1422 {
1423 static const char comps[5] = "xyzw";
1424 if (src->Negate)
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 vp_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 != 0xf) {
1481 _mesa_printf(".");
1482 if (dst->WriteMask & 0x1)
1483 _mesa_printf("x");
1484 if (dst->WriteMask & 0x2)
1485 _mesa_printf("y");
1486 if (dst->WriteMask & 0x4)
1487 _mesa_printf("z");
1488 if (dst->WriteMask & 0x8)
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 vp_instruction *inst)
1499 {
1500 switch (inst->Opcode) {
1501 case VP_OPCODE_MOV:
1502 case VP_OPCODE_LIT:
1503 case VP_OPCODE_RCP:
1504 case VP_OPCODE_RSQ:
1505 case VP_OPCODE_EXP:
1506 case VP_OPCODE_LOG:
1507 case VP_OPCODE_RCC:
1508 case VP_OPCODE_ABS:
1509 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1510 PrintDstReg(&inst->DstReg);
1511 _mesa_printf(", ");
1512 PrintSrcReg(&inst->SrcReg[0]);
1513 _mesa_printf(";\n");
1514 break;
1515 case VP_OPCODE_MUL:
1516 case VP_OPCODE_ADD:
1517 case VP_OPCODE_DP3:
1518 case VP_OPCODE_DP4:
1519 case VP_OPCODE_DST:
1520 case VP_OPCODE_MIN:
1521 case VP_OPCODE_MAX:
1522 case VP_OPCODE_SLT:
1523 case VP_OPCODE_SGE:
1524 case VP_OPCODE_DPH:
1525 case VP_OPCODE_SUB:
1526 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1527 PrintDstReg(&inst->DstReg);
1528 _mesa_printf(", ");
1529 PrintSrcReg(&inst->SrcReg[0]);
1530 _mesa_printf(", ");
1531 PrintSrcReg(&inst->SrcReg[1]);
1532 _mesa_printf(";\n");
1533 break;
1534 case VP_OPCODE_MAD:
1535 _mesa_printf("MAD ");
1536 PrintDstReg(&inst->DstReg);
1537 _mesa_printf(", ");
1538 PrintSrcReg(&inst->SrcReg[0]);
1539 _mesa_printf(", ");
1540 PrintSrcReg(&inst->SrcReg[1]);
1541 _mesa_printf(", ");
1542 PrintSrcReg(&inst->SrcReg[2]);
1543 _mesa_printf(";\n");
1544 break;
1545 case VP_OPCODE_ARL:
1546 _mesa_printf("ARL A0.x, ");
1547 PrintSrcReg(&inst->SrcReg[0]);
1548 _mesa_printf(";\n");
1549 break;
1550 case VP_OPCODE_PRINT:
1551 _mesa_printf("PRINT '%s'", inst->Data);
1552 if (inst->SrcReg[0].File) {
1553 _mesa_printf(", ");
1554 PrintSrcReg(&inst->SrcReg[0]);
1555 _mesa_printf(";\n");
1556 }
1557 else {
1558 _mesa_printf("\n");
1559 }
1560 break;
1561 case VP_OPCODE_END:
1562 _mesa_printf("END\n");
1563 break;
1564 default:
1565 _mesa_printf("BAD INSTRUCTION\n");
1566 }
1567 }
1568
1569
1570 /**
1571 * Print (unparse) the given vertex program. Just for debugging.
1572 */
1573 void
1574 _mesa_print_nv_vertex_program(const struct vertex_program *program)
1575 {
1576 const struct vp_instruction *inst;
1577
1578 for (inst = program->Instructions; ; inst++) {
1579 _mesa_print_nv_vertex_instruction(inst);
1580 if (inst->Opcode == VP_OPCODE_END)
1581 return;
1582 }
1583 }
1584
1585
1586 const char *
1587 _mesa_nv_vertex_input_register_name(GLuint i)
1588 {
1589 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1590 return InputRegisters[i];
1591 }
1592
1593
1594 const char *
1595 _mesa_nv_vertex_output_register_name(GLuint i)
1596 {
1597 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1598 return OutputRegisters[i];
1599 }
1600
1601
1602 /**
1603 * Initialize vertex program instruction fields to defaults.
1604 */
1605 void
1606 _mesa_init_vp_instruction(struct vp_instruction *inst)
1607 {
1608 _mesa_bzero(inst, sizeof(struct vp_instruction));
1609 inst->SrcReg[0].File = PROGRAM_UNDEFINED;
1610 inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
1611 inst->SrcReg[1].File = PROGRAM_UNDEFINED;
1612 inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
1613 inst->SrcReg[2].File = PROGRAM_UNDEFINED;
1614 inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
1615 inst->DstReg.File = PROGRAM_UNDEFINED;
1616 inst->DstReg.WriteMask = 0xf;
1617 }
1618