62b27b9f4db3967fb54503bd05a667273f4a6068
[mesa.git] / src / mesa / program / nvvertparse.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
4 *
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /**
26 * \file nvvertparse.c
27 * NVIDIA vertex program parser.
28 * \author Brian Paul
29 */
30
31 /*
32 * Regarding GL_NV_vertex_program, GL_NV_vertex_program1_1:
33 *
34 * Portions of this software may use or implement intellectual
35 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
36 * any and all warranties with respect to such intellectual property,
37 * including any use thereof or modifications thereto.
38 */
39
40 #include "main/glheader.h"
41 #include "main/context.h"
42 #include "main/imports.h"
43 #include "main/nvprogram.h"
44 #include "nvvertparse.h"
45 #include "prog_instruction.h"
46 #include "prog_parameter.h"
47 #include "prog_print.h"
48 #include "program.h"
49
50
51 /**
52 * Current parsing state. This structure is passed among the parsing
53 * functions and keeps track of the current parser position and various
54 * program attributes.
55 */
56 struct parse_state {
57 struct gl_context *ctx;
58 const GLubyte *start;
59 const GLubyte *pos;
60 const GLubyte *curLine;
61 GLboolean isStateProgram;
62 GLboolean isPositionInvariant;
63 GLboolean isVersion1_1;
64 GLbitfield inputsRead;
65 GLbitfield outputsWritten;
66 GLboolean anyProgRegsWritten;
67 GLboolean indirectRegisterFiles;
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 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 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) 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 = 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 = 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 = 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 (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 parseState->indirectRegisterFiles |= (1 << srcReg->File);
415 /* Look for +/-N offset */
416 if (!Peek_Token(parseState, token))
417 RETURN_ERROR;
418
419 if (token[0] == '-' || token[0] == '+') {
420 const GLubyte sign = token[0];
421 (void) Parse_Token(parseState, token); /* consume +/- */
422
423 /* an integer should be next */
424 if (!Parse_Token(parseState, token))
425 RETURN_ERROR;
426
427 if (IsDigit(token[0])) {
428 const GLint k = atoi((char *) token);
429 if (sign == '-') {
430 if (k > 64)
431 RETURN_ERROR1("Bad address offset");
432 srcReg->Index = -k;
433 }
434 else {
435 if (k > 63)
436 RETURN_ERROR1("Bad address offset");
437 srcReg->Index = k;
438 }
439 }
440 else {
441 RETURN_ERROR;
442 }
443 }
444 else {
445 /* probably got a ']', catch it below */
446 }
447 }
448 else {
449 RETURN_ERROR;
450 }
451
452 /* Match closing ']' */
453 if (!Parse_String(parseState, "]"))
454 RETURN_ERROR;
455
456 return GL_TRUE;
457 }
458
459
460 /**
461 * Parse v[#] or v[<name>]
462 */
463 static GLboolean
464 Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum)
465 {
466 GLubyte token[100];
467 GLint j;
468
469 /* Match 'v' */
470 if (!Parse_String(parseState, "v"))
471 RETURN_ERROR;
472
473 /* Match '[' */
474 if (!Parse_String(parseState, "["))
475 RETURN_ERROR;
476
477 /* match number or named register */
478 if (!Parse_Token(parseState, token))
479 RETURN_ERROR;
480
481 if (parseState->isStateProgram && token[0] != '0')
482 RETURN_ERROR1("Only v[0] accessible in vertex state programs");
483
484 if (IsDigit(token[0])) {
485 GLint reg = atoi((char *) token);
486 if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS)
487 RETURN_ERROR1("Bad vertex attribute register name");
488 *tempRegNum = reg;
489 }
490 else {
491 for (j = 0; InputRegisters[j]; j++) {
492 if (strcmp((const char *) token, InputRegisters[j]) == 0) {
493 *tempRegNum = j;
494 break;
495 }
496 }
497 if (!InputRegisters[j]) {
498 /* unknown input register label */
499 RETURN_ERROR2("Bad register name", token);
500 }
501 }
502
503 /* Match '[' */
504 if (!Parse_String(parseState, "]"))
505 RETURN_ERROR;
506
507 return GL_TRUE;
508 }
509
510
511 static GLboolean
512 Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
513 {
514 GLubyte token[100];
515 GLint start, j;
516
517 /* Match 'o' */
518 if (!Parse_String(parseState, "o"))
519 RETURN_ERROR;
520
521 /* Match '[' */
522 if (!Parse_String(parseState, "["))
523 RETURN_ERROR;
524
525 /* Get output reg name */
526 if (!Parse_Token(parseState, token))
527 RETURN_ERROR;
528
529 if (parseState->isPositionInvariant)
530 start = 1; /* skip HPOS register name */
531 else
532 start = 0;
533
534 /* try to match an output register name */
535 for (j = start; OutputRegisters[j]; j++) {
536 if (strcmp((const char *) token, OutputRegisters[j]) == 0) {
537 *outputRegNum = j;
538 break;
539 }
540 }
541 if (!OutputRegisters[j])
542 RETURN_ERROR1("Unrecognized output register name");
543
544 /* Match ']' */
545 if (!Parse_String(parseState, "]"))
546 RETURN_ERROR1("Expected ]");
547
548 return GL_TRUE;
549 }
550
551
552 static GLboolean
553 Parse_MaskedDstReg(struct parse_state *parseState, struct prog_dst_register *dstReg)
554 {
555 GLubyte token[100];
556 GLint idx;
557
558 /* Dst reg can be R<n> or o[n] */
559 if (!Peek_Token(parseState, token))
560 RETURN_ERROR;
561
562 if (token[0] == 'R') {
563 /* a temporary register */
564 dstReg->File = PROGRAM_TEMPORARY;
565 if (!Parse_TempReg(parseState, &idx))
566 RETURN_ERROR;
567 dstReg->Index = idx;
568 }
569 else if (!parseState->isStateProgram && token[0] == 'o') {
570 /* an output register */
571 dstReg->File = PROGRAM_OUTPUT;
572 if (!Parse_OutputReg(parseState, &idx))
573 RETURN_ERROR;
574 dstReg->Index = idx;
575 }
576 else if (parseState->isStateProgram && token[0] == 'c' &&
577 parseState->isStateProgram) {
578 /* absolute program parameter register */
579 /* Only valid for vertex state programs */
580 dstReg->File = PROGRAM_ENV_PARAM;
581 if (!Parse_AbsParamReg(parseState, &idx))
582 RETURN_ERROR;
583 dstReg->Index = idx;
584 }
585 else {
586 RETURN_ERROR1("Bad destination register name");
587 }
588
589 /* Parse optional write mask */
590 if (!Peek_Token(parseState, token))
591 RETURN_ERROR;
592
593 if (token[0] == '.') {
594 /* got a mask */
595 GLint k = 0;
596
597 if (!Parse_String(parseState, "."))
598 RETURN_ERROR;
599
600 if (!Parse_Token(parseState, token))
601 RETURN_ERROR;
602
603 dstReg->WriteMask = 0;
604
605 if (token[k] == 'x') {
606 dstReg->WriteMask |= WRITEMASK_X;
607 k++;
608 }
609 if (token[k] == 'y') {
610 dstReg->WriteMask |= WRITEMASK_Y;
611 k++;
612 }
613 if (token[k] == 'z') {
614 dstReg->WriteMask |= WRITEMASK_Z;
615 k++;
616 }
617 if (token[k] == 'w') {
618 dstReg->WriteMask |= WRITEMASK_W;
619 k++;
620 }
621 if (k == 0) {
622 RETURN_ERROR1("Bad writemask character");
623 }
624 return GL_TRUE;
625 }
626 else {
627 dstReg->WriteMask = WRITEMASK_XYZW;
628 return GL_TRUE;
629 }
630 }
631
632
633 static GLboolean
634 Parse_SwizzleSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
635 {
636 GLubyte token[100];
637 GLint idx;
638
639 srcReg->RelAddr = GL_FALSE;
640
641 /* check for '-' */
642 if (!Peek_Token(parseState, token))
643 RETURN_ERROR;
644 if (token[0] == '-') {
645 (void) Parse_String(parseState, "-");
646 srcReg->Negate = NEGATE_XYZW;
647 if (!Peek_Token(parseState, token))
648 RETURN_ERROR;
649 }
650 else {
651 srcReg->Negate = NEGATE_NONE;
652 }
653
654 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
655 if (token[0] == 'R') {
656 srcReg->File = PROGRAM_TEMPORARY;
657 if (!Parse_TempReg(parseState, &idx))
658 RETURN_ERROR;
659 srcReg->Index = idx;
660 }
661 else if (token[0] == 'c') {
662 if (!Parse_ParamReg(parseState, srcReg))
663 RETURN_ERROR;
664 }
665 else if (token[0] == 'v') {
666 srcReg->File = PROGRAM_INPUT;
667 if (!Parse_AttribReg(parseState, &idx))
668 RETURN_ERROR;
669 srcReg->Index = idx;
670 }
671 else {
672 RETURN_ERROR2("Bad source register name", token);
673 }
674
675 /* init swizzle fields */
676 srcReg->Swizzle = SWIZZLE_NOOP;
677
678 /* Look for optional swizzle suffix */
679 if (!Peek_Token(parseState, token))
680 RETURN_ERROR;
681 if (token[0] == '.') {
682 (void) Parse_String(parseState, "."); /* consume . */
683
684 if (!Parse_Token(parseState, token))
685 RETURN_ERROR;
686
687 if (token[1] == 0) {
688 /* single letter swizzle */
689 if (token[0] == 'x')
690 srcReg->Swizzle = SWIZZLE_XXXX;
691 else if (token[0] == 'y')
692 srcReg->Swizzle = SWIZZLE_YYYY;
693 else if (token[0] == 'z')
694 srcReg->Swizzle = SWIZZLE_ZZZZ;
695 else if (token[0] == 'w')
696 srcReg->Swizzle = SWIZZLE_WWWW;
697 else
698 RETURN_ERROR1("Expected x, y, z, or w");
699 }
700 else {
701 /* 2, 3 or 4-component swizzle */
702 GLint k;
703
704 srcReg->Swizzle = 0;
705
706 for (k = 0; token[k] && k < 5; k++) {
707 if (token[k] == 'x')
708 srcReg->Swizzle |= 0 << (k*3);
709 else if (token[k] == 'y')
710 srcReg->Swizzle |= 1 << (k*3);
711 else if (token[k] == 'z')
712 srcReg->Swizzle |= 2 << (k*3);
713 else if (token[k] == 'w')
714 srcReg->Swizzle |= 3 << (k*3);
715 else
716 RETURN_ERROR;
717 }
718 if (k >= 5)
719 RETURN_ERROR;
720 }
721 }
722
723 return GL_TRUE;
724 }
725
726
727 static GLboolean
728 Parse_ScalarSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg)
729 {
730 GLubyte token[100];
731 GLint idx;
732
733 srcReg->RelAddr = GL_FALSE;
734
735 /* check for '-' */
736 if (!Peek_Token(parseState, token))
737 RETURN_ERROR;
738 if (token[0] == '-') {
739 srcReg->Negate = NEGATE_XYZW;
740 (void) Parse_String(parseState, "-"); /* consume '-' */
741 if (!Peek_Token(parseState, token))
742 RETURN_ERROR;
743 }
744 else {
745 srcReg->Negate = NEGATE_NONE;
746 }
747
748 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */
749 if (token[0] == 'R') {
750 srcReg->File = PROGRAM_TEMPORARY;
751 if (!Parse_TempReg(parseState, &idx))
752 RETURN_ERROR;
753 srcReg->Index = idx;
754 }
755 else if (token[0] == 'c') {
756 if (!Parse_ParamReg(parseState, srcReg))
757 RETURN_ERROR;
758 }
759 else if (token[0] == 'v') {
760 srcReg->File = PROGRAM_INPUT;
761 if (!Parse_AttribReg(parseState, &idx))
762 RETURN_ERROR;
763 srcReg->Index = idx;
764 }
765 else {
766 RETURN_ERROR2("Bad source register name", token);
767 }
768
769 /* Look for .[xyzw] suffix */
770 if (!Parse_String(parseState, "."))
771 RETURN_ERROR;
772
773 if (!Parse_Token(parseState, token))
774 RETURN_ERROR;
775
776 if (token[0] == 'x' && token[1] == 0) {
777 srcReg->Swizzle = 0;
778 }
779 else if (token[0] == 'y' && token[1] == 0) {
780 srcReg->Swizzle = 1;
781 }
782 else if (token[0] == 'z' && token[1] == 0) {
783 srcReg->Swizzle = 2;
784 }
785 else if (token[0] == 'w' && token[1] == 0) {
786 srcReg->Swizzle = 3;
787 }
788 else {
789 RETURN_ERROR1("Bad scalar source suffix");
790 }
791
792 return GL_TRUE;
793 }
794
795
796 static GLint
797 Parse_UnaryOpInstruction(struct parse_state *parseState,
798 struct prog_instruction *inst,
799 enum prog_opcode opcode)
800 {
801 if (opcode == OPCODE_ABS && !parseState->isVersion1_1)
802 RETURN_ERROR1("ABS illegal for vertex program 1.0");
803
804 inst->Opcode = opcode;
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
838 /* dest reg */
839 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
840 RETURN_ERROR;
841
842 /* comma */
843 if (!Parse_String(parseState, ","))
844 RETURN_ERROR;
845
846 /* first src arg */
847 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
848 RETURN_ERROR;
849
850 /* comma */
851 if (!Parse_String(parseState, ","))
852 RETURN_ERROR;
853
854 /* second src arg */
855 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
856 RETURN_ERROR;
857
858 /* semicolon */
859 if (!Parse_String(parseState, ";"))
860 RETURN_ERROR;
861
862 /* make sure we don't reference more than one program parameter register */
863 if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
864 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
865 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
866 RETURN_ERROR1("Can't reference two program parameter registers");
867
868 /* make sure we don't reference more than one vertex attribute register */
869 if (inst->SrcReg[0].File == PROGRAM_INPUT &&
870 inst->SrcReg[1].File == PROGRAM_INPUT &&
871 inst->SrcReg[0].Index != inst->SrcReg[1].Index)
872 RETURN_ERROR1("Can't reference two vertex attribute registers");
873
874 return GL_TRUE;
875 }
876
877
878 static GLboolean
879 Parse_TriOpInstruction(struct parse_state *parseState,
880 struct prog_instruction *inst,
881 enum prog_opcode opcode)
882 {
883 inst->Opcode = opcode;
884
885 /* dest reg */
886 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
887 RETURN_ERROR;
888
889 /* comma */
890 if (!Parse_String(parseState, ","))
891 RETURN_ERROR;
892
893 /* first src arg */
894 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0]))
895 RETURN_ERROR;
896
897 /* comma */
898 if (!Parse_String(parseState, ","))
899 RETURN_ERROR;
900
901 /* second src arg */
902 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1]))
903 RETURN_ERROR;
904
905 /* comma */
906 if (!Parse_String(parseState, ","))
907 RETURN_ERROR;
908
909 /* third src arg */
910 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2]))
911 RETURN_ERROR;
912
913 /* semicolon */
914 if (!Parse_String(parseState, ";"))
915 RETURN_ERROR;
916
917 /* make sure we don't reference more than one program parameter register */
918 if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
919 inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
920 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
921 (inst->SrcReg[0].File == PROGRAM_ENV_PARAM &&
922 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
923 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
924 (inst->SrcReg[1].File == PROGRAM_ENV_PARAM &&
925 inst->SrcReg[2].File == PROGRAM_ENV_PARAM &&
926 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
927 RETURN_ERROR1("Can only reference one program register");
928
929 /* make sure we don't reference more than one vertex attribute register */
930 if ((inst->SrcReg[0].File == PROGRAM_INPUT &&
931 inst->SrcReg[1].File == PROGRAM_INPUT &&
932 inst->SrcReg[0].Index != inst->SrcReg[1].Index) ||
933 (inst->SrcReg[0].File == PROGRAM_INPUT &&
934 inst->SrcReg[2].File == PROGRAM_INPUT &&
935 inst->SrcReg[0].Index != inst->SrcReg[2].Index) ||
936 (inst->SrcReg[1].File == PROGRAM_INPUT &&
937 inst->SrcReg[2].File == PROGRAM_INPUT &&
938 inst->SrcReg[1].Index != inst->SrcReg[2].Index))
939 RETURN_ERROR1("Can only reference one input register");
940
941 return GL_TRUE;
942 }
943
944
945 static GLboolean
946 Parse_ScalarInstruction(struct parse_state *parseState,
947 struct prog_instruction *inst,
948 enum prog_opcode opcode)
949 {
950 if (opcode == OPCODE_RCC && !parseState->isVersion1_1)
951 RETURN_ERROR1("RCC illegal for vertex program 1.0");
952
953 inst->Opcode = opcode;
954
955 /* dest reg */
956 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
957 RETURN_ERROR;
958
959 /* comma */
960 if (!Parse_String(parseState, ","))
961 RETURN_ERROR;
962
963 /* first src arg */
964 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
965 RETURN_ERROR;
966
967 /* semicolon */
968 if (!Parse_String(parseState, ";"))
969 RETURN_ERROR;
970
971 return GL_TRUE;
972 }
973
974
975 static GLboolean
976 Parse_AddressInstruction(struct parse_state *parseState, struct prog_instruction *inst)
977 {
978 inst->Opcode = OPCODE_ARL;
979
980 /* Make ARB_vp backends happy */
981 inst->DstReg.File = PROGRAM_ADDRESS;
982 inst->DstReg.WriteMask = WRITEMASK_X;
983 inst->DstReg.Index = 0;
984
985 /* dest A0 reg */
986 if (!Parse_AddrReg(parseState))
987 RETURN_ERROR;
988
989 /* comma */
990 if (!Parse_String(parseState, ","))
991 RETURN_ERROR;
992
993 /* parse src reg */
994 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
995 RETURN_ERROR;
996
997 /* semicolon */
998 if (!Parse_String(parseState, ";"))
999 RETURN_ERROR;
1000
1001 return GL_TRUE;
1002 }
1003
1004
1005 static GLboolean
1006 Parse_EndInstruction(struct parse_state *parseState, struct prog_instruction *inst)
1007 {
1008 GLubyte token[100];
1009
1010 inst->Opcode = OPCODE_END;
1011
1012 /* this should fail! */
1013 if (Parse_Token(parseState, token))
1014 RETURN_ERROR2("Unexpected token after END:", token);
1015 else
1016 return GL_TRUE;
1017 }
1018
1019
1020 /**
1021 * The PRINT instruction is Mesa-specific and is meant as a debugging aid for
1022 * the vertex program developer.
1023 * The NV_vertex_program extension grammar is modified as follows:
1024 *
1025 * <instruction> ::= <ARL-instruction>
1026 * | ...
1027 * | <PRINT-instruction>
1028 *
1029 * <PRINT-instruction> ::= "PRINT" <string literal>
1030 * | "PRINT" <string literal> "," <srcReg>
1031 * | "PRINT" <string literal> "," <dstReg>
1032 */
1033 static GLboolean
1034 Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *inst)
1035 {
1036 const GLubyte *str;
1037 GLubyte *msg;
1038 GLuint len;
1039 GLubyte token[100];
1040 struct prog_src_register *srcReg = &inst->SrcReg[0];
1041 GLint idx;
1042
1043 inst->Opcode = OPCODE_PRINT;
1044
1045 /* The first argument is a literal string 'just like this' */
1046 if (!Parse_String(parseState, "'"))
1047 RETURN_ERROR;
1048
1049 str = parseState->pos;
1050 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1051 ;
1052 parseState->pos += len + 1;
1053 msg = (GLubyte*) malloc(len + 1);
1054
1055 memcpy(msg, str, len);
1056 msg[len] = 0;
1057 inst->Data = msg;
1058
1059 /* comma */
1060 if (Parse_String(parseState, ",")) {
1061
1062 /* The second argument is a register name */
1063 if (!Peek_Token(parseState, token))
1064 RETURN_ERROR;
1065
1066 srcReg->RelAddr = GL_FALSE;
1067 srcReg->Negate = NEGATE_NONE;
1068 srcReg->Swizzle = SWIZZLE_NOOP;
1069
1070 /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib,
1071 * or an o[n] output register.
1072 */
1073 if (token[0] == 'R') {
1074 srcReg->File = PROGRAM_TEMPORARY;
1075 if (!Parse_TempReg(parseState, &idx))
1076 RETURN_ERROR;
1077 srcReg->Index = idx;
1078 }
1079 else if (token[0] == 'c') {
1080 srcReg->File = PROGRAM_ENV_PARAM;
1081 if (!Parse_ParamReg(parseState, srcReg))
1082 RETURN_ERROR;
1083 }
1084 else if (token[0] == 'v') {
1085 srcReg->File = PROGRAM_INPUT;
1086 if (!Parse_AttribReg(parseState, &idx))
1087 RETURN_ERROR;
1088 srcReg->Index = idx;
1089 }
1090 else if (token[0] == 'o') {
1091 srcReg->File = PROGRAM_OUTPUT;
1092 if (!Parse_OutputReg(parseState, &idx))
1093 RETURN_ERROR;
1094 srcReg->Index = idx;
1095 }
1096 else {
1097 RETURN_ERROR2("Bad source register name", token);
1098 }
1099 }
1100 else {
1101 srcReg->File = PROGRAM_UNDEFINED;
1102 }
1103
1104 /* semicolon */
1105 if (!Parse_String(parseState, ";"))
1106 RETURN_ERROR;
1107
1108 return GL_TRUE;
1109 }
1110
1111
1112 static GLboolean
1113 Parse_OptionSequence(struct parse_state *parseState,
1114 struct prog_instruction program[])
1115 {
1116 (void) program;
1117 while (1) {
1118 if (!Parse_String(parseState, "OPTION"))
1119 return GL_TRUE; /* ok, not an OPTION statement */
1120 if (Parse_String(parseState, "NV_position_invariant")) {
1121 parseState->isPositionInvariant = GL_TRUE;
1122 }
1123 else {
1124 RETURN_ERROR1("unexpected OPTION statement");
1125 }
1126 if (!Parse_String(parseState, ";"))
1127 return GL_FALSE;
1128 }
1129 }
1130
1131
1132 static GLboolean
1133 Parse_InstructionSequence(struct parse_state *parseState,
1134 struct prog_instruction program[])
1135 {
1136 while (1) {
1137 struct prog_instruction *inst = program + parseState->numInst;
1138
1139 /* Initialize the instruction */
1140 _mesa_init_instructions(inst, 1);
1141
1142 if (Parse_String(parseState, "MOV")) {
1143 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_MOV))
1144 RETURN_ERROR;
1145 }
1146 else if (Parse_String(parseState, "LIT")) {
1147 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_LIT))
1148 RETURN_ERROR;
1149 }
1150 else if (Parse_String(parseState, "ABS")) {
1151 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_ABS))
1152 RETURN_ERROR;
1153 }
1154 else if (Parse_String(parseState, "MUL")) {
1155 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MUL))
1156 RETURN_ERROR;
1157 }
1158 else if (Parse_String(parseState, "ADD")) {
1159 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_ADD))
1160 RETURN_ERROR;
1161 }
1162 else if (Parse_String(parseState, "DP3")) {
1163 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP3))
1164 RETURN_ERROR;
1165 }
1166 else if (Parse_String(parseState, "DP4")) {
1167 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP4))
1168 RETURN_ERROR;
1169 }
1170 else if (Parse_String(parseState, "DST")) {
1171 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DST))
1172 RETURN_ERROR;
1173 }
1174 else if (Parse_String(parseState, "MIN")) {
1175 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MIN))
1176 RETURN_ERROR;
1177 }
1178 else if (Parse_String(parseState, "MAX")) {
1179 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MAX))
1180 RETURN_ERROR;
1181 }
1182 else if (Parse_String(parseState, "SLT")) {
1183 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SLT))
1184 RETURN_ERROR;
1185 }
1186 else if (Parse_String(parseState, "SGE")) {
1187 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SGE))
1188 RETURN_ERROR;
1189 }
1190 else if (Parse_String(parseState, "DPH")) {
1191 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DPH))
1192 RETURN_ERROR;
1193 }
1194 else if (Parse_String(parseState, "SUB")) {
1195 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SUB))
1196 RETURN_ERROR;
1197 }
1198 else if (Parse_String(parseState, "MAD")) {
1199 if (!Parse_TriOpInstruction(parseState, inst, OPCODE_MAD))
1200 RETURN_ERROR;
1201 }
1202 else if (Parse_String(parseState, "RCP")) {
1203 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCP))
1204 RETURN_ERROR;
1205 }
1206 else if (Parse_String(parseState, "RSQ")) {
1207 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RSQ))
1208 RETURN_ERROR;
1209 }
1210 else if (Parse_String(parseState, "EXP")) {
1211 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_EXP))
1212 RETURN_ERROR;
1213 }
1214 else if (Parse_String(parseState, "LOG")) {
1215 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_LOG))
1216 RETURN_ERROR;
1217 }
1218 else if (Parse_String(parseState, "RCC")) {
1219 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCC))
1220 RETURN_ERROR;
1221 }
1222 else if (Parse_String(parseState, "ARL")) {
1223 if (!Parse_AddressInstruction(parseState, inst))
1224 RETURN_ERROR;
1225 }
1226 else if (Parse_String(parseState, "PRINT")) {
1227 if (!Parse_PrintInstruction(parseState, inst))
1228 RETURN_ERROR;
1229 }
1230 else if (Parse_String(parseState, "END")) {
1231 if (!Parse_EndInstruction(parseState, inst))
1232 RETURN_ERROR;
1233 else {
1234 parseState->numInst++;
1235 return GL_TRUE; /* all done */
1236 }
1237 }
1238 else {
1239 /* bad instruction name */
1240 RETURN_ERROR1("Unexpected token");
1241 }
1242
1243 /* examine input/output registers */
1244 if (inst->DstReg.File == PROGRAM_OUTPUT)
1245 parseState->outputsWritten |= (1 << inst->DstReg.Index);
1246 else if (inst->DstReg.File == PROGRAM_ENV_PARAM)
1247 parseState->anyProgRegsWritten = GL_TRUE;
1248
1249 if (inst->SrcReg[0].File == PROGRAM_INPUT)
1250 parseState->inputsRead |= (1 << inst->SrcReg[0].Index);
1251 if (inst->SrcReg[1].File == PROGRAM_INPUT)
1252 parseState->inputsRead |= (1 << inst->SrcReg[1].Index);
1253 if (inst->SrcReg[2].File == PROGRAM_INPUT)
1254 parseState->inputsRead |= (1 << inst->SrcReg[2].Index);
1255
1256 parseState->numInst++;
1257
1258 if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
1259 RETURN_ERROR1("Program too long");
1260 }
1261
1262 RETURN_ERROR;
1263 }
1264
1265
1266 static GLboolean
1267 Parse_Program(struct parse_state *parseState,
1268 struct prog_instruction instBuffer[])
1269 {
1270 if (parseState->isVersion1_1) {
1271 if (!Parse_OptionSequence(parseState, instBuffer)) {
1272 return GL_FALSE;
1273 }
1274 }
1275 return Parse_InstructionSequence(parseState, instBuffer);
1276 }
1277
1278
1279 /**
1280 * Parse/compile the 'str' returning the compiled 'program'.
1281 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1282 * indicates the position of the error in 'str'.
1283 */
1284 void
1285 _mesa_parse_nv_vertex_program(struct gl_context *ctx, GLenum dstTarget,
1286 const GLubyte *str, GLsizei len,
1287 struct gl_vertex_program *program)
1288 {
1289 struct parse_state parseState;
1290 struct prog_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS];
1291 struct prog_instruction *newInst;
1292 GLenum target;
1293 GLubyte *programString;
1294
1295 /* Make a null-terminated copy of the program string */
1296 programString = (GLubyte *) malloc(len + 1);
1297 if (!programString) {
1298 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1299 return;
1300 }
1301 memcpy(programString, str, len);
1302 programString[len] = 0;
1303
1304 /* Get ready to parse */
1305 parseState.ctx = ctx;
1306 parseState.start = programString;
1307 parseState.isPositionInvariant = GL_FALSE;
1308 parseState.isVersion1_1 = GL_FALSE;
1309 parseState.numInst = 0;
1310 parseState.inputsRead = 0;
1311 parseState.outputsWritten = 0;
1312 parseState.anyProgRegsWritten = GL_FALSE;
1313 parseState.indirectRegisterFiles = 0x0;
1314
1315 /* Reset error state */
1316 _mesa_set_program_error(ctx, -1, NULL);
1317
1318 /* check the program header */
1319 if (strncmp((const char *) programString, "!!VP1.0", 7) == 0) {
1320 target = GL_VERTEX_PROGRAM_NV;
1321 parseState.pos = programString + 7;
1322 parseState.isStateProgram = GL_FALSE;
1323 }
1324 else if (strncmp((const char *) programString, "!!VP1.1", 7) == 0) {
1325 target = GL_VERTEX_PROGRAM_NV;
1326 parseState.pos = programString + 7;
1327 parseState.isStateProgram = GL_FALSE;
1328 parseState.isVersion1_1 = GL_TRUE;
1329 }
1330 else if (strncmp((const char *) programString, "!!VSP1.0", 8) == 0) {
1331 target = GL_VERTEX_STATE_PROGRAM_NV;
1332 parseState.pos = programString + 8;
1333 parseState.isStateProgram = GL_TRUE;
1334 }
1335 else {
1336 /* invalid header */
1337 ctx->Program.ErrorPos = 0;
1338 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1339 return;
1340 }
1341
1342 /* make sure target and header match */
1343 if (target != dstTarget) {
1344 _mesa_error(ctx, GL_INVALID_OPERATION,
1345 "glLoadProgramNV(target mismatch)");
1346 return;
1347 }
1348
1349
1350 if (Parse_Program(&parseState, instBuffer)) {
1351 gl_state_index state_tokens[STATE_LENGTH] = {0, 0, 0, 0, 0};
1352 int i;
1353
1354 /* successful parse! */
1355
1356 if (parseState.isStateProgram) {
1357 if (!parseState.anyProgRegsWritten) {
1358 _mesa_error(ctx, GL_INVALID_OPERATION,
1359 "glLoadProgramNV(c[#] not written)");
1360 return;
1361 }
1362 }
1363 else {
1364 if (!parseState.isPositionInvariant &&
1365 !(parseState.outputsWritten & (1 << VERT_RESULT_HPOS))) {
1366 /* bit 1 = HPOS register */
1367 _mesa_error(ctx, GL_INVALID_OPERATION,
1368 "glLoadProgramNV(HPOS not written)");
1369 return;
1370 }
1371 }
1372
1373 /* copy the compiled instructions */
1374 assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS);
1375 newInst = _mesa_alloc_instructions(parseState.numInst);
1376 if (!newInst) {
1377 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1378 free(programString);
1379 return; /* out of memory */
1380 }
1381 _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
1382
1383 /* install the program */
1384 program->Base.Target = target;
1385 if (program->Base.String) {
1386 free(program->Base.String);
1387 }
1388 program->Base.String = programString;
1389 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1390 if (program->Base.Instructions) {
1391 free(program->Base.Instructions);
1392 }
1393 program->Base.Instructions = newInst;
1394 program->Base.InputsRead = parseState.inputsRead;
1395 if (parseState.isPositionInvariant)
1396 program->Base.InputsRead |= VERT_BIT_POS;
1397 program->Base.NumInstructions = parseState.numInst;
1398 program->Base.OutputsWritten = parseState.outputsWritten;
1399 program->IsPositionInvariant = parseState.isPositionInvariant;
1400 program->IsNVProgram = GL_TRUE;
1401
1402 #ifdef DEBUG_foo
1403 printf("--- glLoadProgramNV result ---\n");
1404 _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
1405 printf("------------------------------\n");
1406 #endif
1407
1408 if (program->Base.Parameters)
1409 _mesa_free_parameter_list(program->Base.Parameters);
1410
1411 program->Base.Parameters = _mesa_new_parameter_list ();
1412 program->Base.NumParameters = 0;
1413
1414 program->Base.IndirectRegisterFiles = parseState.indirectRegisterFiles;
1415
1416 state_tokens[0] = STATE_VERTEX_PROGRAM;
1417 state_tokens[1] = STATE_ENV;
1418 /* Add refs to all of the potential params, in order. If we want to not
1419 * upload everything, _mesa_layout_parameters is the answer.
1420 */
1421 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS; i++) {
1422 GLint index;
1423 state_tokens[2] = i;
1424 index = _mesa_add_state_reference(program->Base.Parameters,
1425 state_tokens);
1426 assert(index == i);
1427 (void)index;
1428 }
1429 program->Base.NumParameters = program->Base.Parameters->NumParameters;
1430
1431 _mesa_setup_nv_temporary_count(&program->Base);
1432 _mesa_emit_nv_temp_initialization(ctx, &program->Base);
1433 }
1434 else {
1435 /* Error! */
1436 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1437 /* NOTE: _mesa_set_program_error would have been called already */
1438 /* GL_NV_vertex_program isn't supposed to set the error string
1439 * so we reset it here.
1440 */
1441 _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL);
1442 }
1443 }
1444
1445
1446 const char *
1447 _mesa_nv_vertex_input_register_name(GLuint i)
1448 {
1449 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS);
1450 return InputRegisters[i];
1451 }
1452
1453
1454 const char *
1455 _mesa_nv_vertex_output_register_name(GLuint i)
1456 {
1457 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1458 return OutputRegisters[i];
1459 }
1460