cosmetic changes;
[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 = _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
567 /* Dst reg can be R<n> or o[n] */
568 if (!Peek_Token(parseState, token))
569 RETURN_ERROR;
570
571 if (token[0] == 'R') {
572 /* a temporary register */
573 dstReg->File = PROGRAM_TEMPORARY;
574 if (!Parse_TempReg(parseState, &dstReg->Index))
575 RETURN_ERROR;
576 }
577 else if (!parseState->isStateProgram && token[0] == 'o') {
578 /* an output register */
579 dstReg->File = PROGRAM_OUTPUT;
580 if (!Parse_OutputReg(parseState, &dstReg->Index))
581 RETURN_ERROR;
582 }
583 else if (parseState->isStateProgram && token[0] == 'c' &&
584 parseState->isStateProgram) {
585 /* absolute program parameter register */
586 /* Only valid for vertex state programs */
587 dstReg->File = PROGRAM_ENV_PARAM;
588 if (!Parse_AbsParamReg(parseState, &dstReg->Index))
589 RETURN_ERROR;
590 }
591 else {
592 RETURN_ERROR1("Bad destination register name");
593 }
594
595 /* Parse optional write mask */
596 if (!Peek_Token(parseState, token))
597 RETURN_ERROR;
598
599 if (token[0] == '.') {
600 /* got a mask */
601 GLint k = 0;
602
603 if (!Parse_String(parseState, "."))
604 RETURN_ERROR;
605
606 if (!Parse_Token(parseState, token))
607 RETURN_ERROR;
608
609 dstReg->WriteMask[0] = GL_FALSE;
610 dstReg->WriteMask[1] = GL_FALSE;
611 dstReg->WriteMask[2] = GL_FALSE;
612 dstReg->WriteMask[3] = GL_FALSE;
613
614 if (token[k] == 'x') {
615 dstReg->WriteMask[0] = GL_TRUE;
616 k++;
617 }
618 if (token[k] == 'y') {
619 dstReg->WriteMask[1] = GL_TRUE;
620 k++;
621 }
622 if (token[k] == 'z') {
623 dstReg->WriteMask[2] = GL_TRUE;
624 k++;
625 }
626 if (token[k] == 'w') {
627 dstReg->WriteMask[3] = GL_TRUE;
628 k++;
629 }
630 if (k == 0) {
631 RETURN_ERROR1("Bad writemask character");
632 }
633 return GL_TRUE;
634 }
635 else {
636 dstReg->WriteMask[0] = GL_TRUE;
637 dstReg->WriteMask[1] = GL_TRUE;
638 dstReg->WriteMask[2] = GL_TRUE;
639 dstReg->WriteMask[3] = GL_TRUE;
640 return GL_TRUE;
641 }
642 }
643
644
645 static GLboolean
646 Parse_SwizzleSrcReg(struct parse_state *parseState, struct vp_src_register *srcReg)
647 {
648 GLubyte token[100];
649
650 srcReg->RelAddr = GL_FALSE;
651
652 /* check for '-' */
653 if (!Peek_Token(parseState, token))
654 RETURN_ERROR;
655 if (token[0] == '-') {
656 (void) Parse_String(parseState, "-");
657 srcReg->Negate = GL_TRUE;
658 if (!Peek_Token(parseState, token))
659 RETURN_ERROR;
660 }
661 else {
662 srcReg->Negate = GL_FALSE;
663 }
664
665 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
666 if (token[0] == 'R') {
667 srcReg->File = PROGRAM_TEMPORARY;
668 if (!Parse_TempReg(parseState, &srcReg->Index))
669 RETURN_ERROR;
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, &srcReg->Index))
678 RETURN_ERROR;
679 }
680 else {
681 RETURN_ERROR2("Bad source register name", token);
682 }
683
684 /* init swizzle fields */
685 srcReg->Swizzle[0] = 0;
686 srcReg->Swizzle[1] = 1;
687 srcReg->Swizzle[2] = 2;
688 srcReg->Swizzle[3] = 3;
689
690 /* Look for optional swizzle suffix */
691 if (!Peek_Token(parseState, token))
692 RETURN_ERROR;
693 if (token[0] == '.') {
694 (void) Parse_String(parseState, "."); /* consume . */
695
696 if (!Parse_Token(parseState, token))
697 RETURN_ERROR;
698
699 if (token[1] == 0) {
700 /* single letter swizzle */
701 if (token[0] == 'x')
702 ASSIGN_4V(srcReg->Swizzle, 0, 0, 0, 0);
703 else if (token[0] == 'y')
704 ASSIGN_4V(srcReg->Swizzle, 1, 1, 1, 1);
705 else if (token[0] == 'z')
706 ASSIGN_4V(srcReg->Swizzle, 2, 2, 2, 2);
707 else if (token[0] == 'w')
708 ASSIGN_4V(srcReg->Swizzle, 3, 3, 3, 3);
709 else
710 RETURN_ERROR1("Expected x, y, z, or w");
711 }
712 else {
713 /* 2, 3 or 4-component swizzle */
714 GLint k;
715 for (k = 0; token[k] && k < 5; k++) {
716 if (token[k] == 'x')
717 srcReg->Swizzle[k] = 0;
718 else if (token[k] == 'y')
719 srcReg->Swizzle[k] = 1;
720 else if (token[k] == 'z')
721 srcReg->Swizzle[k] = 2;
722 else if (token[k] == 'w')
723 srcReg->Swizzle[k] = 3;
724 else
725 RETURN_ERROR;
726 }
727 if (k >= 5)
728 RETURN_ERROR;
729 }
730 }
731
732 return GL_TRUE;
733 }
734
735
736 static GLboolean
737 Parse_ScalarSrcReg(struct parse_state *parseState, struct vp_src_register *srcReg)
738 {
739 GLubyte token[100];
740
741 srcReg->RelAddr = GL_FALSE;
742
743 /* check for '-' */
744 if (!Peek_Token(parseState, token))
745 RETURN_ERROR;
746 if (token[0] == '-') {
747 srcReg->Negate = GL_TRUE;
748 (void) Parse_String(parseState, "-"); /* consume '-' */
749 if (!Peek_Token(parseState, token))
750 RETURN_ERROR;
751 }
752 else {
753 srcReg->Negate = GL_FALSE;
754 }
755
756 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
757 if (token[0] == 'R') {
758 srcReg->File = PROGRAM_TEMPORARY;
759 if (!Parse_TempReg(parseState, &srcReg->Index))
760 RETURN_ERROR;
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, &srcReg->Index))
769 RETURN_ERROR;
770 }
771 else {
772 RETURN_ERROR2("Bad source register name", token);
773 }
774
775 /* Look for .[xyzw] suffix */
776 if (!Parse_String(parseState, "."))
777 RETURN_ERROR;
778
779 if (!Parse_Token(parseState, token))
780 RETURN_ERROR;
781
782 if (token[0] == 'x' && token[1] == 0) {
783 srcReg->Swizzle[0] = 0;
784 }
785 else if (token[0] == 'y' && token[1] == 0) {
786 srcReg->Swizzle[0] = 1;
787 }
788 else if (token[0] == 'z' && token[1] == 0) {
789 srcReg->Swizzle[0] = 2;
790 }
791 else if (token[0] == 'w' && token[1] == 0) {
792 srcReg->Swizzle[0] = 3;
793 }
794 else {
795 RETURN_ERROR1("Bad scalar source suffix");
796 }
797 srcReg->Swizzle[1] = srcReg->Swizzle[2] = srcReg->Swizzle[3] = 0;
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
1046 inst->Opcode = VP_OPCODE_PRINT;
1047 inst->StringPos = parseState->curLine - parseState->start;
1048
1049 /* The first argument is a literal string 'just like this' */
1050 if (!Parse_String(parseState, "'"))
1051 RETURN_ERROR;
1052
1053 str = parseState->pos;
1054 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1055 ;
1056 parseState->pos += len + 1;
1057 msg = _mesa_malloc(len + 1);
1058
1059 _mesa_memcpy(msg, str, len);
1060 msg[len] = 0;
1061 inst->Data = msg;
1062
1063 /* comma */
1064 if (Parse_String(parseState, ",")) {
1065
1066 /* The second argument is a register name */
1067 if (!Peek_Token(parseState, token))
1068 RETURN_ERROR;
1069
1070 srcReg->RelAddr = GL_FALSE;
1071 srcReg->Negate = GL_FALSE;
1072 srcReg->Swizzle[0] = 0;
1073 srcReg->Swizzle[1] = 1;
1074 srcReg->Swizzle[2] = 2;
1075 srcReg->Swizzle[3] = 3;
1076
1077 /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
1078 * or an o[n] output register.
1079 */
1080 if (token[0] == 'R') {
1081 srcReg->File = PROGRAM_TEMPORARY;
1082 if (!Parse_TempReg(parseState, &srcReg->Index))
1083 RETURN_ERROR;
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, &srcReg->Index))
1093 RETURN_ERROR;
1094 }
1095 else if (token[0] == 'o') {
1096 srcReg->File = PROGRAM_OUTPUT;
1097 if (!Parse_OutputReg(parseState, &srcReg->Index))
1098 RETURN_ERROR;
1099 }
1100 else {
1101 RETURN_ERROR2("Bad source register name", token);
1102 }
1103 }
1104 else {
1105 srcReg->File = 0;
1106 }
1107
1108 /* semicolon */
1109 if (!Parse_String(parseState, ";"))
1110 RETURN_ERROR;
1111
1112 return GL_TRUE;
1113 }
1114
1115
1116 static GLboolean
1117 Parse_OptionSequence(struct parse_state *parseState,
1118 struct vp_instruction program[])
1119 {
1120 (void) program;
1121 while (1) {
1122 if (!Parse_String(parseState, "OPTION"))
1123 return GL_TRUE; /* ok, not an OPTION statement */
1124 if (Parse_String(parseState, "NV_position_invariant")) {
1125 parseState->isPositionInvariant = GL_TRUE;
1126 }
1127 else {
1128 RETURN_ERROR1("unexpected OPTION statement");
1129 }
1130 if (!Parse_String(parseState, ";"))
1131 return GL_FALSE;
1132 }
1133 }
1134
1135
1136 static GLboolean
1137 Parse_InstructionSequence(struct parse_state *parseState,
1138 struct vp_instruction program[])
1139 {
1140 while (1) {
1141 struct vp_instruction *inst = program + parseState->numInst;
1142
1143 /* Initialize the instruction */
1144 inst->SrcReg[0].File = (enum register_file) -1;
1145 inst->SrcReg[1].File = (enum register_file) -1;
1146 inst->SrcReg[2].File = (enum register_file) -1;
1147 inst->DstReg.File = (enum register_file) -1;
1148 inst->Data = NULL;
1149
1150 if (Parse_String(parseState, "MOV")) {
1151 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_MOV))
1152 RETURN_ERROR;
1153 }
1154 else if (Parse_String(parseState, "LIT")) {
1155 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_LIT))
1156 RETURN_ERROR;
1157 }
1158 else if (Parse_String(parseState, "ABS")) {
1159 if (!Parse_UnaryOpInstruction(parseState, inst, VP_OPCODE_ABS))
1160 RETURN_ERROR;
1161 }
1162 else if (Parse_String(parseState, "MUL")) {
1163 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MUL))
1164 RETURN_ERROR;
1165 }
1166 else if (Parse_String(parseState, "ADD")) {
1167 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_ADD))
1168 RETURN_ERROR;
1169 }
1170 else if (Parse_String(parseState, "DP3")) {
1171 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP3))
1172 RETURN_ERROR;
1173 }
1174 else if (Parse_String(parseState, "DP4")) {
1175 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DP4))
1176 RETURN_ERROR;
1177 }
1178 else if (Parse_String(parseState, "DST")) {
1179 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DST))
1180 RETURN_ERROR;
1181 }
1182 else if (Parse_String(parseState, "MIN")) {
1183 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MIN))
1184 RETURN_ERROR;
1185 }
1186 else if (Parse_String(parseState, "MAX")) {
1187 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_MAX))
1188 RETURN_ERROR;
1189 }
1190 else if (Parse_String(parseState, "SLT")) {
1191 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SLT))
1192 RETURN_ERROR;
1193 }
1194 else if (Parse_String(parseState, "SGE")) {
1195 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SGE))
1196 RETURN_ERROR;
1197 }
1198 else if (Parse_String(parseState, "DPH")) {
1199 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_DPH))
1200 RETURN_ERROR;
1201 }
1202 else if (Parse_String(parseState, "SUB")) {
1203 if (!Parse_BiOpInstruction(parseState, inst, VP_OPCODE_SUB))
1204 RETURN_ERROR;
1205 }
1206 else if (Parse_String(parseState, "MAD")) {
1207 if (!Parse_TriOpInstruction(parseState, inst, VP_OPCODE_MAD))
1208 RETURN_ERROR;
1209 }
1210 else if (Parse_String(parseState, "RCP")) {
1211 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCP))
1212 RETURN_ERROR;
1213 }
1214 else if (Parse_String(parseState, "RSQ")) {
1215 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RSQ))
1216 RETURN_ERROR;
1217 }
1218 else if (Parse_String(parseState, "EXP")) {
1219 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_EXP))
1220 RETURN_ERROR;
1221 }
1222 else if (Parse_String(parseState, "LOG")) {
1223 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_LOG))
1224 RETURN_ERROR;
1225 }
1226 else if (Parse_String(parseState, "RCC")) {
1227 if (!Parse_ScalarInstruction(parseState, inst, VP_OPCODE_RCC))
1228 RETURN_ERROR;
1229 }
1230 else if (Parse_String(parseState, "ARL")) {
1231 if (!Parse_AddressInstruction(parseState, inst))
1232 RETURN_ERROR;
1233 }
1234 else if (Parse_String(parseState, "PRINT")) {
1235 if (!Parse_PrintInstruction(parseState, inst))
1236 RETURN_ERROR;
1237 }
1238 else if (Parse_String(parseState, "END")) {
1239 if (!Parse_EndInstruction(parseState, inst))
1240 RETURN_ERROR;
1241 else {
1242 parseState->numInst++;
1243 return GL_TRUE; /* all done */
1244 }
1245 }
1246 else {
1247 /* bad instruction name */
1248 RETURN_ERROR1("Unexpected token");
1249 }
1250
1251 /* examine input/output registers */
1252 if (inst->DstReg.File == PROGRAM_OUTPUT)
1253 parseState->outputsWritten |= (1 << inst->DstReg.Index);
1254 else if (inst->DstReg.File == PROGRAM_ENV_PARAM)
1255 parseState->anyProgRegsWritten = GL_TRUE;
1256
1257 if (inst->SrcReg[0].File == PROGRAM_INPUT)
1258 parseState->inputsRead |= (1 << inst->SrcReg[0].Index);
1259 if (inst->SrcReg[1].File == PROGRAM_INPUT)
1260 parseState->inputsRead |= (1 << inst->SrcReg[1].Index);
1261 if (inst->SrcReg[2].File == PROGRAM_INPUT)
1262 parseState->inputsRead |= (1 << inst->SrcReg[2].Index);
1263
1264 parseState->numInst++;
1265
1266 if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
1267 RETURN_ERROR1("Program too long");
1268 }
1269
1270 RETURN_ERROR;
1271 }
1272
1273
1274 static GLboolean
1275 Parse_Program(struct parse_state *parseState,
1276 struct vp_instruction instBuffer[])
1277 {
1278 if (parseState->isVersion1_1) {
1279 if (!Parse_OptionSequence(parseState, instBuffer)) {
1280 return GL_FALSE;
1281 }
1282 }
1283 return Parse_InstructionSequence(parseState, instBuffer);
1284 }
1285
1286
1287 /**
1288 * Parse/compile the 'str' returning the compiled 'program'.
1289 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1290 * indicates the position of the error in 'str'.
1291 */
1292 void
1293 _mesa_parse_nv_vertex_program(GLcontext *ctx, GLenum dstTarget,
1294 const GLubyte *str, GLsizei len,
1295 struct vertex_program *program)
1296 {
1297 struct parse_state parseState;
1298 struct vp_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1299 struct vp_instruction *newInst;
1300 GLenum target;
1301 GLubyte *programString;
1302
1303 /* Make a null-terminated copy of the program string */
1304 programString = (GLubyte *) MALLOC(len + 1);
1305 if (!programString) {
1306 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1307 return;
1308 }
1309 MEMCPY(programString, str, len);
1310 programString[len] = 0;
1311
1312 /* Get ready to parse */
1313 parseState.ctx = ctx;
1314 parseState.start = programString;
1315 parseState.isPositionInvariant = GL_FALSE;
1316 parseState.isVersion1_1 = GL_FALSE;
1317 parseState.numInst = 0;
1318 parseState.inputsRead = 0;
1319 parseState.outputsWritten = 0;
1320 parseState.anyProgRegsWritten = GL_FALSE;
1321
1322 /* Reset error state */
1323 _mesa_set_program_error(ctx, -1, NULL);
1324
1325 /* check the program header */
1326 if (_mesa_strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
1327 target = GL_VERTEX_PROGRAM_NV;
1328 parseState.pos = programString + 7;
1329 parseState.isStateProgram = GL_FALSE;
1330 }
1331 else if (_mesa_strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
1332 target = GL_VERTEX_PROGRAM_NV;
1333 parseState.pos = programString + 7;
1334 parseState.isStateProgram = GL_FALSE;
1335 parseState.isVersion1_1 = GL_TRUE;
1336 }
1337 else if (_mesa_strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
1338 target = GL_VERTEX_STATE_PROGRAM_NV;
1339 parseState.pos = programString + 8;
1340 parseState.isStateProgram = GL_TRUE;
1341 }
1342 else {
1343 /* invalid header */
1344 ctx->Program.ErrorPos = 0;
1345 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1346 return;
1347 }
1348
1349 /* make sure target and header match */
1350 if (target != dstTarget) {
1351 _mesa_error(ctx, GL_INVALID_OPERATION,
1352 "glLoadProgramNV(target mismatch)");
1353 return;
1354 }
1355
1356
1357 if (Parse_Program(&parseState, instBuffer)) {
1358 /* successful parse! */
1359
1360 if (parseState.isStateProgram) {
1361 if (!parseState.anyProgRegsWritten) {
1362 _mesa_error(ctx, GL_INVALID_OPERATION,
1363 "glLoadProgramNV(c[#] not written)");
1364 return;
1365 }
1366 }
1367 else {
1368 if (!parseState.isPositionInvariant &&
1369 !(parseState.outputsWritten & 1)) {
1370 /* bit 1 = HPOS register */
1371 _mesa_error(ctx, GL_INVALID_OPERATION,
1372 "glLoadProgramNV(HPOS not written)");
1373 return;
1374 }
1375 }
1376
1377 /* copy the compiled instructions */
1378 assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
1379 newInst = (struct vp_instruction *)
1380 MALLOC(parseState.numInst * sizeof(struct vp_instruction));
1381 if (!newInst) {
1382 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1383 FREE(programString);
1384 return; /* out of memory */
1385 }
1386 MEMCPY(newInst, instBuffer,
1387 parseState.numInst * sizeof(struct vp_instruction));
1388
1389 /* install the program */
1390 program->Base.Target = target;
1391 if (program->Base.String) {
1392 FREE(program->Base.String);
1393 }
1394 program->Base.String = programString;
1395 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1396 if (program->Instructions) {
1397 FREE(program->Instructions);
1398 }
1399 program->Instructions = newInst;
1400 program->InputsRead = parseState.inputsRead;
1401 program->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 vp_src_register *src)
1425 {
1426 static const char comps[5] = "xyzw";
1427 if (src->Negate)
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 (src->Swizzle[0] == src->Swizzle[1] &&
1452 src->Swizzle[0] == src->Swizzle[2] &&
1453 src->Swizzle[0] == src->Swizzle[3]) {
1454 _mesa_printf(".%c", comps[src->Swizzle[0]]);
1455 }
1456 else if (src->Swizzle[0] != 0 ||
1457 src->Swizzle[1] != 1 ||
1458 src->Swizzle[2] != 2 ||
1459 src->Swizzle[3] != 3) {
1460 _mesa_printf(".%c%c%c%c",
1461 comps[src->Swizzle[0]],
1462 comps[src->Swizzle[1]],
1463 comps[src->Swizzle[2]],
1464 comps[src->Swizzle[3]]);
1465 }
1466 }
1467
1468
1469 static void
1470 PrintDstReg(const struct vp_dst_register *dst)
1471 {
1472 GLint w = dst->WriteMask[0] + dst->WriteMask[1]
1473 + dst->WriteMask[2] + dst->WriteMask[3];
1474
1475 if (dst->File == PROGRAM_OUTPUT) {
1476 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1477 }
1478 else if (dst->File == PROGRAM_INPUT) {
1479 _mesa_printf("v[%s]", InputRegisters[dst->Index]);
1480 }
1481 else if (dst->File == PROGRAM_ENV_PARAM) {
1482 _mesa_printf("c[%d]", dst->Index);
1483 }
1484 else {
1485 ASSERT(dst->File == PROGRAM_TEMPORARY);
1486 _mesa_printf("R%d", dst->Index);
1487 }
1488
1489 if (w != 0 && w != 4) {
1490 _mesa_printf(".");
1491 if (dst->WriteMask[0])
1492 _mesa_printf("x");
1493 if (dst->WriteMask[1])
1494 _mesa_printf("y");
1495 if (dst->WriteMask[2])
1496 _mesa_printf("z");
1497 if (dst->WriteMask[3])
1498 _mesa_printf("w");
1499 }
1500 }
1501
1502
1503 /**
1504 * Print a single NVIDIA vertex program instruction.
1505 */
1506 void
1507 _mesa_print_nv_vertex_instruction(const struct vp_instruction *inst)
1508 {
1509 switch (inst->Opcode) {
1510 case VP_OPCODE_MOV:
1511 case VP_OPCODE_LIT:
1512 case VP_OPCODE_RCP:
1513 case VP_OPCODE_RSQ:
1514 case VP_OPCODE_EXP:
1515 case VP_OPCODE_LOG:
1516 case VP_OPCODE_RCC:
1517 case VP_OPCODE_ABS:
1518 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1519 PrintDstReg(&inst->DstReg);
1520 _mesa_printf(", ");
1521 PrintSrcReg(&inst->SrcReg[0]);
1522 _mesa_printf(";\n");
1523 break;
1524 case VP_OPCODE_MUL:
1525 case VP_OPCODE_ADD:
1526 case VP_OPCODE_DP3:
1527 case VP_OPCODE_DP4:
1528 case VP_OPCODE_DST:
1529 case VP_OPCODE_MIN:
1530 case VP_OPCODE_MAX:
1531 case VP_OPCODE_SLT:
1532 case VP_OPCODE_SGE:
1533 case VP_OPCODE_DPH:
1534 case VP_OPCODE_SUB:
1535 _mesa_printf("%s ", Opcodes[(int) inst->Opcode]);
1536 PrintDstReg(&inst->DstReg);
1537 _mesa_printf(", ");
1538 PrintSrcReg(&inst->SrcReg[0]);
1539 _mesa_printf(", ");
1540 PrintSrcReg(&inst->SrcReg[1]);
1541 _mesa_printf(";\n");
1542 break;
1543 case VP_OPCODE_MAD:
1544 _mesa_printf("MAD ");
1545 PrintDstReg(&inst->DstReg);
1546 _mesa_printf(", ");
1547 PrintSrcReg(&inst->SrcReg[0]);
1548 _mesa_printf(", ");
1549 PrintSrcReg(&inst->SrcReg[1]);
1550 _mesa_printf(", ");
1551 PrintSrcReg(&inst->SrcReg[2]);
1552 _mesa_printf(";\n");
1553 break;
1554 case VP_OPCODE_ARL:
1555 _mesa_printf("ARL A0.x, ");
1556 PrintSrcReg(&inst->SrcReg[0]);
1557 _mesa_printf(";\n");
1558 break;
1559 case VP_OPCODE_PRINT:
1560 _mesa_printf("PRINT '%s'", inst->Data);
1561 if (inst->SrcReg[0].File) {
1562 _mesa_printf(", ");
1563 PrintSrcReg(&inst->SrcReg[0]);
1564 _mesa_printf(";\n");
1565 }
1566 else {
1567 _mesa_printf("\n");
1568 }
1569 break;
1570 case VP_OPCODE_END:
1571 _mesa_printf("END\n");
1572 break;
1573 default:
1574 _mesa_printf("BAD INSTRUCTION\n");
1575 }
1576 }
1577
1578
1579 /**
1580 * Print (unparse) the given vertex program. Just for debugging.
1581 */
1582 void
1583 _mesa_print_nv_vertex_program(const struct vertex_program *program)
1584 {
1585 const struct vp_instruction *inst;
1586
1587 for (inst = program->Instructions; ; inst++) {
1588 _mesa_print_nv_vertex_instruction(inst);
1589 if (inst->Opcode == VP_OPCODE_END)
1590 return;
1591 }
1592 }
1593
1594
1595 const char *
1596 _mesa_nv_vertex_input_register_name(GLuint i)
1597 {
1598 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1599 return InputRegisters[i];
1600 }
1601
1602
1603 const char *
1604 _mesa_nv_vertex_output_register_name(GLuint i)
1605 {
1606 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1607 return OutputRegisters[i];
1608 }