• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
record_error(struct parse_state * parseState,const char * msg,int lineNo)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 
IsLetter(GLubyte b)124 static GLboolean IsLetter(GLubyte b)
125 {
126    return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z');
127 }
128 
129 
IsDigit(GLubyte b)130 static GLboolean IsDigit(GLubyte b)
131 {
132    return b >= '0' && b <= '9';
133 }
134 
135 
IsWhitespace(GLubyte b)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
GetToken(struct parse_state * parseState,GLubyte * token)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
Parse_Token(struct parse_state * parseState,GLubyte * token)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
Peek_Token(struct parse_state * parseState,GLubyte * token)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
Parse_String(struct parse_state * parseState,const char * pattern)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
Parse_TempReg(struct parse_state * parseState,GLint * tempRegNum)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
Parse_AddrReg(struct parse_state * parseState)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
Parse_AbsParamReg(struct parse_state * parseState,GLint * regNum)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
Parse_ParamReg(struct parse_state * parseState,struct prog_src_register * srcReg)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
Parse_AttribReg(struct parse_state * parseState,GLint * tempRegNum)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
Parse_OutputReg(struct parse_state * parseState,GLint * outputRegNum)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
Parse_MaskedDstReg(struct parse_state * parseState,struct prog_dst_register * dstReg)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
Parse_SwizzleSrcReg(struct parse_state * parseState,struct prog_src_register * srcReg)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
Parse_ScalarSrcReg(struct parse_state * parseState,struct prog_src_register * srcReg)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
Parse_UnaryOpInstruction(struct parse_state * parseState,struct prog_instruction * inst,enum prog_opcode opcode)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
Parse_BiOpInstruction(struct parse_state * parseState,struct prog_instruction * inst,enum prog_opcode opcode)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
Parse_TriOpInstruction(struct parse_state * parseState,struct prog_instruction * inst,enum prog_opcode opcode)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
Parse_ScalarInstruction(struct parse_state * parseState,struct prog_instruction * inst,enum prog_opcode opcode)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
Parse_AddressInstruction(struct parse_state * parseState,struct prog_instruction * inst)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
Parse_EndInstruction(struct parse_state * parseState,struct prog_instruction * inst)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
Parse_PrintInstruction(struct parse_state * parseState,struct prog_instruction * inst)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
Parse_OptionSequence(struct parse_state * parseState,struct prog_instruction program[])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
Parse_InstructionSequence(struct parse_state * parseState,struct prog_instruction program[])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
Parse_Program(struct parse_state * parseState,struct prog_instruction instBuffer[])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
_mesa_parse_nv_vertex_program(struct gl_context * ctx,GLenum dstTarget,const GLubyte * str,GLsizei len,struct gl_vertex_program * program)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 *
_mesa_nv_vertex_input_register_name(GLuint i)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 *
_mesa_nv_vertex_output_register_name(GLuint i)1455 _mesa_nv_vertex_output_register_name(GLuint i)
1456 {
1457    ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS);
1458    return OutputRegisters[i];
1459 }
1460 
1461