• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Mesa 3-D graphics library
3  * Version:  6.5
4  *
5  * Copyright (C) 1999-2005  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 nvfragparse.c
27  * NVIDIA fragment program parser.
28  * \author Brian Paul
29  */
30 
31 /*
32  * Regarding GL_NV_fragment_program:
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/macros.h"
44 #include "program.h"
45 #include "prog_parameter.h"
46 #include "prog_print.h"
47 #include "prog_instruction.h"
48 #include "nvfragparse.h"
49 
50 
51 #define INPUT_1V     1
52 #define INPUT_2V     2
53 #define INPUT_3V     3
54 #define INPUT_1S     4
55 #define INPUT_2S     5
56 #define INPUT_CC     6
57 #define INPUT_1V_T   7  /* one source vector, plus textureId */
58 #define INPUT_3V_T   8  /* one source vector, plus textureId */
59 #define INPUT_NONE   9
60 #define INPUT_1V_S  10  /* a string and a vector register */
61 #define OUTPUT_V    20
62 #define OUTPUT_S    21
63 #define OUTPUT_NONE 22
64 
65 /* IRIX defines some of these */
66 #undef _R
67 #undef _H
68 #undef _X
69 #undef _C
70 #undef _S
71 
72 /* Optional suffixes */
73 #define _R  FLOAT32  /* float */
74 #define _H  FLOAT16  /* half-float */
75 #define _X  FIXED12  /* fixed */
76 #define _C  0x08     /* set cond codes */
77 #define _S  0x10     /* saturate, clamp result to [0,1] */
78 
79 struct instruction_pattern {
80    const char *name;
81    enum prog_opcode opcode;
82    GLuint inputs;
83    GLuint outputs;
84    GLuint suffixes;
85 };
86 
87 static const struct instruction_pattern Instructions[] = {
88    { "ADD", OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
89    { "COS", OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
90    { "DDX", OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H |      _C | _S },
91    { "DDY", OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H |      _C | _S },
92    { "DP3", OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
93    { "DP4", OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
94    { "DST", OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H |      _C | _S },
95    { "EX2", OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
96    { "FLR", OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
97    { "FRC", OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
98    { "KIL", OPCODE_KIL_NV, INPUT_CC, OUTPUT_NONE, 0                },
99    { "LG2", OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
100    { "LIT", OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H |      _C | _S },
101    { "LRP", OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
102    { "MAD", OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
103    { "MAX", OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
104    { "MIN", OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
105    { "MOV", OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
106    { "MUL", OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
107    { "PK2H",  OPCODE_PK2H,  INPUT_1V, OUTPUT_S, 0                  },
108    { "PK2US", OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0                  },
109    { "PK4B",  OPCODE_PK4B,  INPUT_1V, OUTPUT_S, 0                  },
110    { "PK4UB", OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0                  },
111    { "POW", OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H |      _C | _S },
112    { "RCP", OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
113    { "RFL", OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H |      _C | _S },
114    { "RSQ", OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
115    { "SEQ", OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
116    { "SFL", OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
117    { "SGE", OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
118    { "SGT", OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
119    { "SIN", OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H |      _C | _S },
120    { "SLE", OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
121    { "SLT", OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
122    { "SNE", OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
123    { "STR", OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
124    { "SUB", OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
125    { "TEX", OPCODE_TEX, INPUT_1V_T, OUTPUT_V,              _C | _S },
126    { "TXD", OPCODE_TXD, INPUT_3V_T, OUTPUT_V,              _C | _S },
127    { "TXP", OPCODE_TXP_NV, INPUT_1V_T, OUTPUT_V,           _C | _S },
128    { "UP2H",  OPCODE_UP2H,  INPUT_1S, OUTPUT_V,            _C | _S },
129    { "UP2US", OPCODE_UP2US, INPUT_1S, OUTPUT_V,            _C | _S },
130    { "UP4B",  OPCODE_UP4B,  INPUT_1S, OUTPUT_V,            _C | _S },
131    { "UP4UB", OPCODE_UP4UB, INPUT_1S, OUTPUT_V,            _C | _S },
132    { "X2D", OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H |      _C | _S },
133    { "PRINT", OPCODE_PRINT, INPUT_1V_S, OUTPUT_NONE, 0               },
134    { NULL, (enum prog_opcode) -1, 0, 0, 0 }
135 };
136 
137 
138 /*
139  * Information needed or computed during parsing.
140  * Remember, we can't modify the target program object until we've
141  * _successfully_ parsed the program text.
142  */
143 struct parse_state {
144    struct gl_context *ctx;
145    const GLubyte *start;              /* start of program string */
146    const GLubyte *pos;                /* current position */
147    const GLubyte *curLine;
148    struct gl_fragment_program *program;  /* current program */
149 
150    struct gl_program_parameter_list *parameters;
151 
152    GLuint numInst;                    /* number of instructions parsed */
153    GLuint inputsRead;                 /* bitmask of input registers used */
154    GLuint outputsWritten;             /* bitmask of 1 << FRAG_OUTPUT_* bits */
155    GLuint texturesUsed[MAX_TEXTURE_IMAGE_UNITS];
156 };
157 
158 
159 
160 /*
161  * Called whenever we find an error during parsing.
162  */
163 static void
record_error(struct parse_state * parseState,const char * msg,int lineNo)164 record_error(struct parse_state *parseState, const char *msg, int lineNo)
165 {
166 #ifdef DEBUG
167    GLint line, column;
168    const GLubyte *lineStr;
169    lineStr = _mesa_find_line_column(parseState->start,
170                                     parseState->pos, &line, &column);
171    _mesa_debug(parseState->ctx,
172                "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
173                lineNo, line, column, (char *) lineStr, msg);
174    free((void *) lineStr);
175 #else
176    (void) lineNo;
177 #endif
178 
179    /* Check that no error was already recorded.  Only record the first one. */
180    if (parseState->ctx->Program.ErrorString[0] == 0) {
181       _mesa_set_program_error(parseState->ctx,
182                               parseState->pos - parseState->start,
183                               msg);
184    }
185 }
186 
187 
188 #define RETURN_ERROR							\
189 do {									\
190    record_error(parseState, "Unexpected end of input.", __LINE__);	\
191    return GL_FALSE;							\
192 } while(0)
193 
194 #define RETURN_ERROR1(msg)						\
195 do {									\
196    record_error(parseState, msg, __LINE__);				\
197    return GL_FALSE;							\
198 } while(0)
199 
200 #define RETURN_ERROR2(msg1, msg2)					\
201 do {									\
202    char err[1000];							\
203    sprintf(err, "%s %s", msg1, msg2);				\
204    record_error(parseState, err, __LINE__);				\
205    return GL_FALSE;							\
206 } while(0)
207 
208 
209 
210 
211 /*
212  * Search a list of instruction structures for a match.
213  */
214 static struct instruction_pattern
MatchInstruction(const GLubyte * token)215 MatchInstruction(const GLubyte *token)
216 {
217    const struct instruction_pattern *inst;
218    struct instruction_pattern result;
219 
220    result.name = NULL;
221    result.opcode = MAX_OPCODE; /* i.e. invalid instruction */
222    result.inputs = 0;
223    result.outputs = 0;
224    result.suffixes = 0;
225 
226    for (inst = Instructions; inst->name; inst++) {
227       if (strncmp((const char *) token, inst->name, 3) == 0) {
228          /* matched! */
229          int i = 3;
230          result = *inst;
231          result.suffixes = 0;
232          /* look at suffix */
233          if (token[i] == 'R') {
234             result.suffixes |= _R;
235             i++;
236          }
237          else if (token[i] == 'H') {
238             result.suffixes |= _H;
239             i++;
240          }
241          else if (token[i] == 'X') {
242             result.suffixes |= _X;
243             i++;
244          }
245          if (token[i] == 'C') {
246             result.suffixes |= _C;
247             i++;
248          }
249          if (token[i] == '_' && token[i+1] == 'S' &&
250              token[i+2] == 'A' && token[i+3] == 'T') {
251             result.suffixes |= _S;
252          }
253          return result;
254       }
255    }
256 
257    return result;
258 }
259 
260 
261 
262 
263 /**********************************************************************/
264 
265 
IsLetter(GLubyte b)266 static GLboolean IsLetter(GLubyte b)
267 {
268    return (b >= 'a' && b <= 'z') ||
269           (b >= 'A' && b <= 'Z') ||
270           (b == '_') ||
271           (b == '$');
272 }
273 
274 
IsDigit(GLubyte b)275 static GLboolean IsDigit(GLubyte b)
276 {
277    return b >= '0' && b <= '9';
278 }
279 
280 
IsWhitespace(GLubyte b)281 static GLboolean IsWhitespace(GLubyte b)
282 {
283    return b == ' ' || b == '\t' || b == '\n' || b == '\r';
284 }
285 
286 
287 /**
288  * Starting at 'str' find the next token.  A token can be an integer,
289  * an identifier or punctuation symbol.
290  * \return <= 0 we found an error, else, return number of characters parsed.
291  */
292 static GLint
GetToken(struct parse_state * parseState,GLubyte * token)293 GetToken(struct parse_state *parseState, GLubyte *token)
294 {
295    const GLubyte *str = parseState->pos;
296    GLint i = 0, j = 0;
297 
298    token[0] = 0;
299 
300    /* skip whitespace and comments */
301    while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
302       if (str[i] == '#') {
303          /* skip comment */
304          while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
305             i++;
306          }
307          if (str[i] == '\n' || str[i] == '\r')
308             parseState->curLine = str + i + 1;
309       }
310       else {
311          /* skip whitespace */
312          if (str[i] == '\n' || str[i] == '\r')
313             parseState->curLine = str + i + 1;
314          i++;
315       }
316    }
317 
318    if (str[i] == 0)
319       return -i;
320 
321    /* try matching an integer */
322    while (str[i] && IsDigit(str[i])) {
323       token[j++] = str[i++];
324    }
325    if (j > 0 || !str[i]) {
326       token[j] = 0;
327       return i;
328    }
329 
330    /* try matching an identifier */
331    if (IsLetter(str[i])) {
332       while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
333          token[j++] = str[i++];
334       }
335       token[j] = 0;
336       return i;
337    }
338 
339    /* punctuation character */
340    if (str[i]) {
341       token[0] = str[i++];
342       token[1] = 0;
343       return i;
344    }
345 
346    /* end of input */
347    token[0] = 0;
348    return i;
349 }
350 
351 
352 /**
353  * Get next token from input stream and increment stream pointer past token.
354  */
355 static GLboolean
Parse_Token(struct parse_state * parseState,GLubyte * token)356 Parse_Token(struct parse_state *parseState, GLubyte *token)
357 {
358    GLint i;
359    i = GetToken(parseState, token);
360    if (i <= 0) {
361       parseState->pos += (-i);
362       return GL_FALSE;
363    }
364    parseState->pos += i;
365    return GL_TRUE;
366 }
367 
368 
369 /**
370  * Get next token from input stream but don't increment stream pointer.
371  */
372 static GLboolean
Peek_Token(struct parse_state * parseState,GLubyte * token)373 Peek_Token(struct parse_state *parseState, GLubyte *token)
374 {
375    GLint i, len;
376    i = GetToken(parseState, token);
377    if (i <= 0) {
378       parseState->pos += (-i);
379       return GL_FALSE;
380    }
381    len = (GLint) strlen((const char *) token);
382    parseState->pos += (i - len);
383    return GL_TRUE;
384 }
385 
386 
387 /**********************************************************************/
388 
389 static const char *InputRegisters[MAX_NV_FRAGMENT_PROGRAM_INPUTS + 1] = {
390    "WPOS", "COL0", "COL1", "FOGC",
391    "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
392 };
393 
394 
395 
396 /**********************************************************************/
397 
398 /**
399  * Try to match 'pattern' as the next token after any whitespace/comments.
400  */
401 static GLboolean
Parse_String(struct parse_state * parseState,const char * pattern)402 Parse_String(struct parse_state *parseState, const char *pattern)
403 {
404    const GLubyte *m;
405    GLint i;
406 
407    /* skip whitespace and comments */
408    while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
409       if (*parseState->pos == '#') {
410          while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
411             parseState->pos += 1;
412          }
413          if (*parseState->pos == '\n' || *parseState->pos == '\r')
414             parseState->curLine = parseState->pos + 1;
415       }
416       else {
417          /* skip whitespace */
418          if (*parseState->pos == '\n' || *parseState->pos == '\r')
419             parseState->curLine = parseState->pos + 1;
420          parseState->pos += 1;
421       }
422    }
423 
424    /* Try to match the pattern */
425    m = parseState->pos;
426    for (i = 0; pattern[i]; i++) {
427       if (*m != (GLubyte) pattern[i])
428          return GL_FALSE;
429       m += 1;
430    }
431    parseState->pos = m;
432 
433    return GL_TRUE; /* success */
434 }
435 
436 
437 static GLboolean
Parse_Identifier(struct parse_state * parseState,GLubyte * ident)438 Parse_Identifier(struct parse_state *parseState, GLubyte *ident)
439 {
440    if (!Parse_Token(parseState, ident))
441       RETURN_ERROR;
442    if (IsLetter(ident[0]))
443       return GL_TRUE;
444    else
445       RETURN_ERROR1("Expected an identfier");
446 }
447 
448 
449 /**
450  * Parse a floating point constant, or a defined symbol name.
451  * [+/-]N[.N[eN]]
452  * Output:  number[0 .. 3] will get the value.
453  */
454 static GLboolean
Parse_ScalarConstant(struct parse_state * parseState,GLfloat * number)455 Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number)
456 {
457    char *end = NULL;
458 
459    *number = (GLfloat) _mesa_strtof((const char *) parseState->pos, &end);
460 
461    if (end && end > (char *) parseState->pos) {
462       /* got a number */
463       parseState->pos = (GLubyte *) end;
464       number[1] = *number;
465       number[2] = *number;
466       number[3] = *number;
467       return GL_TRUE;
468    }
469    else {
470       /* should be an identifier */
471       GLubyte ident[100];
472       const GLfloat *constant;
473       if (!Parse_Identifier(parseState, ident))
474          RETURN_ERROR1("Expected an identifier");
475       constant = (GLfloat *)_mesa_lookup_parameter_value(parseState->parameters,
476                                                          -1,
477                                                          (const char *) ident);
478       /* XXX Check that it's a constant and not a parameter */
479       if (!constant) {
480          RETURN_ERROR1("Undefined symbol");
481       }
482       else {
483          COPY_4V(number, constant);
484          return GL_TRUE;
485       }
486    }
487 }
488 
489 
490 
491 /**
492  * Parse a vector constant, one of:
493  *   { float }
494  *   { float, float }
495  *   { float, float, float }
496  *   { float, float, float, float }
497  */
498 static GLboolean
Parse_VectorConstant(struct parse_state * parseState,GLfloat * vec)499 Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
500 {
501    /* "{" was already consumed */
502 
503    ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0);
504 
505    if (!Parse_ScalarConstant(parseState, vec+0))  /* X */
506       return GL_FALSE;
507 
508    if (Parse_String(parseState, "}")) {
509       return GL_TRUE;
510    }
511 
512    if (!Parse_String(parseState, ","))
513       RETURN_ERROR1("Expected comma in vector constant");
514 
515    if (!Parse_ScalarConstant(parseState, vec+1))  /* Y */
516       return GL_FALSE;
517 
518    if (Parse_String(parseState, "}")) {
519       return GL_TRUE;
520    }
521 
522    if (!Parse_String(parseState, ","))
523       RETURN_ERROR1("Expected comma in vector constant");
524 
525    if (!Parse_ScalarConstant(parseState, vec+2))  /* Z */
526       return GL_FALSE;
527 
528    if (Parse_String(parseState, "}")) {
529       return GL_TRUE;
530    }
531 
532    if (!Parse_String(parseState, ","))
533       RETURN_ERROR1("Expected comma in vector constant");
534 
535    if (!Parse_ScalarConstant(parseState, vec+3))  /* W */
536       return GL_FALSE;
537 
538    if (!Parse_String(parseState, "}"))
539       RETURN_ERROR1("Expected closing brace in vector constant");
540 
541    return GL_TRUE;
542 }
543 
544 
545 /**
546  * Parse <number>, <varname> or {a, b, c, d}.
547  * Return number of values in the vector or scalar, or zero if parse error.
548  */
549 static GLuint
Parse_VectorOrScalarConstant(struct parse_state * parseState,GLfloat * vec)550 Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec)
551 {
552    if (Parse_String(parseState, "{")) {
553       return Parse_VectorConstant(parseState, vec);
554    }
555    else {
556       GLboolean b = Parse_ScalarConstant(parseState, vec);
557       if (b) {
558          vec[1] = vec[2] = vec[3] = vec[0];
559       }
560       return b;
561    }
562 }
563 
564 
565 /**
566  * Parse a texture image source:
567  *    [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
568  */
569 static GLboolean
Parse_TextureImageId(struct parse_state * parseState,GLubyte * texUnit,GLubyte * texTarget)570 Parse_TextureImageId(struct parse_state *parseState,
571                      GLubyte *texUnit, GLubyte *texTarget)
572 {
573    GLubyte imageSrc[100];
574    GLint unit;
575 
576    if (!Parse_Token(parseState, imageSrc))
577       RETURN_ERROR;
578 
579    if (imageSrc[0] != 'T' ||
580        imageSrc[1] != 'E' ||
581        imageSrc[2] != 'X') {
582       RETURN_ERROR1("Expected TEX# source");
583    }
584    unit = atoi((const char *) imageSrc + 3);
585    if ((unit < 0 || unit >= MAX_TEXTURE_IMAGE_UNITS) ||
586        (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) {
587       RETURN_ERROR1("Invalied TEX# source index");
588    }
589    *texUnit = unit;
590 
591    if (!Parse_String(parseState, ","))
592       RETURN_ERROR1("Expected ,");
593 
594    if (Parse_String(parseState, "1D")) {
595       *texTarget = TEXTURE_1D_INDEX;
596    }
597    else if (Parse_String(parseState, "2D")) {
598       *texTarget = TEXTURE_2D_INDEX;
599    }
600    else if (Parse_String(parseState, "3D")) {
601       *texTarget = TEXTURE_3D_INDEX;
602    }
603    else if (Parse_String(parseState, "CUBE")) {
604       *texTarget = TEXTURE_CUBE_INDEX;
605    }
606    else if (Parse_String(parseState, "RECT")) {
607       *texTarget = TEXTURE_RECT_INDEX;
608    }
609    else {
610       RETURN_ERROR1("Invalid texture target token");
611    }
612 
613    /* update record of referenced texture units */
614    parseState->texturesUsed[*texUnit] |= (1 << *texTarget);
615    if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) {
616       RETURN_ERROR1("Only one texture target can be used per texture unit.");
617    }
618 
619    return GL_TRUE;
620 }
621 
622 
623 /**
624  * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
625  * like .wxyz, .xxyy, etc and return the swizzle indexes.
626  */
627 static GLboolean
Parse_SwizzleSuffix(const GLubyte * token,GLuint swizzle[4])628 Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4])
629 {
630    if (token[1] == 0) {
631       /* single letter swizzle (scalar) */
632       if (token[0] == 'x')
633          ASSIGN_4V(swizzle, 0, 0, 0, 0);
634       else if (token[0] == 'y')
635          ASSIGN_4V(swizzle, 1, 1, 1, 1);
636       else if (token[0] == 'z')
637          ASSIGN_4V(swizzle, 2, 2, 2, 2);
638       else if (token[0] == 'w')
639          ASSIGN_4V(swizzle, 3, 3, 3, 3);
640       else
641          return GL_FALSE;
642    }
643    else {
644       /* 4-component swizzle (vector) */
645       GLint k;
646       for (k = 0; k < 4 && token[k]; k++) {
647          if (token[k] == 'x')
648             swizzle[k] = 0;
649          else if (token[k] == 'y')
650             swizzle[k] = 1;
651          else if (token[k] == 'z')
652             swizzle[k] = 2;
653          else if (token[k] == 'w')
654             swizzle[k] = 3;
655          else
656             return GL_FALSE;
657       }
658       if (k != 4)
659          return GL_FALSE;
660    }
661    return GL_TRUE;
662 }
663 
664 
665 static GLboolean
Parse_CondCodeMask(struct parse_state * parseState,struct prog_dst_register * dstReg)666 Parse_CondCodeMask(struct parse_state *parseState,
667                    struct prog_dst_register *dstReg)
668 {
669    if (Parse_String(parseState, "EQ"))
670       dstReg->CondMask = COND_EQ;
671    else if (Parse_String(parseState, "GE"))
672       dstReg->CondMask = COND_GE;
673    else if (Parse_String(parseState, "GT"))
674       dstReg->CondMask = COND_GT;
675    else if (Parse_String(parseState, "LE"))
676       dstReg->CondMask = COND_LE;
677    else if (Parse_String(parseState, "LT"))
678       dstReg->CondMask = COND_LT;
679    else if (Parse_String(parseState, "NE"))
680       dstReg->CondMask = COND_NE;
681    else if (Parse_String(parseState, "TR"))
682       dstReg->CondMask = COND_TR;
683    else if (Parse_String(parseState, "FL"))
684       dstReg->CondMask = COND_FL;
685    else
686       RETURN_ERROR1("Invalid condition code mask");
687 
688    /* look for optional .xyzw swizzle */
689    if (Parse_String(parseState, ".")) {
690       GLubyte token[100];
691       GLuint swz[4];
692 
693       if (!Parse_Token(parseState, token))  /* get xyzw suffix */
694          RETURN_ERROR;
695 
696       if (!Parse_SwizzleSuffix(token, swz))
697          RETURN_ERROR1("Invalid swizzle suffix");
698 
699       dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
700    }
701 
702    return GL_TRUE;
703 }
704 
705 
706 /**
707  * Parse a temporary register: Rnn or Hnn
708  */
709 static GLboolean
Parse_TempReg(struct parse_state * parseState,GLint * tempRegNum)710 Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
711 {
712    GLubyte token[100];
713 
714    /* Should be 'R##' or 'H##' */
715    if (!Parse_Token(parseState, token))
716       RETURN_ERROR;
717    if (token[0] != 'R' && token[0] != 'H')
718       RETURN_ERROR1("Expected R## or H##");
719 
720    if (IsDigit(token[1])) {
721       GLint reg = atoi((const char *) (token + 1));
722       if (token[0] == 'H')
723          reg += 32;
724       if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS)
725          RETURN_ERROR1("Invalid temporary register name");
726       *tempRegNum = reg;
727    }
728    else {
729       RETURN_ERROR1("Invalid temporary register name");
730    }
731 
732    return GL_TRUE;
733 }
734 
735 
736 /**
737  * Parse a write-only dummy register: RC or HC.
738  */
739 static GLboolean
Parse_DummyReg(struct parse_state * parseState,GLint * regNum)740 Parse_DummyReg(struct parse_state *parseState, GLint *regNum)
741 {
742    if (Parse_String(parseState, "RC")) {
743        *regNum = 0;
744    }
745    else if (Parse_String(parseState, "HC")) {
746        *regNum = 1;
747    }
748    else {
749       RETURN_ERROR1("Invalid write-only register name");
750    }
751 
752    return GL_TRUE;
753 }
754 
755 
756 /**
757  * Parse a program local parameter register "p[##]"
758  */
759 static GLboolean
Parse_ProgramParamReg(struct parse_state * parseState,GLint * regNum)760 Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum)
761 {
762    GLubyte token[100];
763 
764    if (!Parse_String(parseState, "p["))
765       RETURN_ERROR1("Expected p[");
766 
767    if (!Parse_Token(parseState, token))
768       RETURN_ERROR;
769 
770    if (IsDigit(token[0])) {
771       /* a numbered program parameter register */
772       GLint reg = atoi((const char *) token);
773       if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS)
774          RETURN_ERROR1("Invalid constant program number");
775       *regNum = reg;
776    }
777    else {
778       RETURN_ERROR;
779    }
780 
781    if (!Parse_String(parseState, "]"))
782       RETURN_ERROR1("Expected ]");
783 
784    return GL_TRUE;
785 }
786 
787 
788 /**
789  * Parse f[name]  - fragment input register
790  */
791 static GLboolean
Parse_FragReg(struct parse_state * parseState,GLint * tempRegNum)792 Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum)
793 {
794    GLubyte token[100];
795    GLint j;
796 
797    /* Match 'f[' */
798    if (!Parse_String(parseState, "f["))
799       RETURN_ERROR1("Expected f[");
800 
801    /* get <name> and look for match */
802    if (!Parse_Token(parseState, token)) {
803       RETURN_ERROR;
804    }
805    for (j = 0; InputRegisters[j]; j++) {
806       if (strcmp((const char *) token, InputRegisters[j]) == 0) {
807          *tempRegNum = j;
808          parseState->inputsRead |= (1 << j);
809          break;
810       }
811    }
812    if (!InputRegisters[j]) {
813       /* unknown input register label */
814       RETURN_ERROR2("Invalid register name", token);
815    }
816 
817    /* Match '[' */
818    if (!Parse_String(parseState, "]"))
819       RETURN_ERROR1("Expected ]");
820 
821    return GL_TRUE;
822 }
823 
824 
825 static GLboolean
Parse_OutputReg(struct parse_state * parseState,GLint * outputRegNum)826 Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
827 {
828    GLubyte token[100];
829 
830    /* Match "o[" */
831    if (!Parse_String(parseState, "o["))
832       RETURN_ERROR1("Expected o[");
833 
834    /* Get output reg name */
835    if (!Parse_Token(parseState, token))
836       RETURN_ERROR;
837 
838    /* try to match an output register name */
839    if (strcmp((char *) token, "COLR") == 0 ||
840        strcmp((char *) token, "COLH") == 0) {
841       /* note that we don't distinguish between COLR and COLH */
842       *outputRegNum = FRAG_RESULT_COLOR;
843       parseState->outputsWritten |= (1 << FRAG_RESULT_COLOR);
844    }
845    else if (strcmp((char *) token, "DEPR") == 0) {
846       *outputRegNum = FRAG_RESULT_DEPTH;
847       parseState->outputsWritten |= (1 << FRAG_RESULT_DEPTH);
848    }
849    else {
850       RETURN_ERROR1("Invalid output register name");
851    }
852 
853    /* Match ']' */
854    if (!Parse_String(parseState, "]"))
855       RETURN_ERROR1("Expected ]");
856 
857    return GL_TRUE;
858 }
859 
860 
861 static GLboolean
Parse_MaskedDstReg(struct parse_state * parseState,struct prog_dst_register * dstReg)862 Parse_MaskedDstReg(struct parse_state *parseState,
863                    struct prog_dst_register *dstReg)
864 {
865    GLubyte token[100];
866    GLint idx;
867 
868    /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
869    if (!Peek_Token(parseState, token))
870       RETURN_ERROR;
871 
872    if (strcmp((const char *) token, "RC") == 0 ||
873        strcmp((const char *) token, "HC") == 0) {
874       /* a write-only register */
875       dstReg->File = PROGRAM_WRITE_ONLY;
876       if (!Parse_DummyReg(parseState, &idx))
877          RETURN_ERROR;
878       dstReg->Index = idx;
879    }
880    else if (token[0] == 'R' || token[0] == 'H') {
881       /* a temporary register */
882       dstReg->File = PROGRAM_TEMPORARY;
883       if (!Parse_TempReg(parseState, &idx))
884          RETURN_ERROR;
885       dstReg->Index = idx;
886    }
887    else if (token[0] == 'o') {
888       /* an output register */
889       dstReg->File = PROGRAM_OUTPUT;
890       if (!Parse_OutputReg(parseState, &idx))
891          RETURN_ERROR;
892       dstReg->Index = idx;
893    }
894    else {
895       RETURN_ERROR1("Invalid destination register name");
896    }
897 
898    /* Parse optional write mask */
899    if (Parse_String(parseState, ".")) {
900       /* got a mask */
901       GLint k = 0;
902 
903       if (!Parse_Token(parseState, token))  /* get xyzw writemask */
904          RETURN_ERROR;
905 
906       dstReg->WriteMask = 0;
907 
908       if (token[k] == 'x') {
909          dstReg->WriteMask |= WRITEMASK_X;
910          k++;
911       }
912       if (token[k] == 'y') {
913          dstReg->WriteMask |= WRITEMASK_Y;
914          k++;
915       }
916       if (token[k] == 'z') {
917          dstReg->WriteMask |= WRITEMASK_Z;
918          k++;
919       }
920       if (token[k] == 'w') {
921          dstReg->WriteMask |= WRITEMASK_W;
922          k++;
923       }
924       if (k == 0) {
925          RETURN_ERROR1("Invalid writemask character");
926       }
927 
928    }
929    else {
930       dstReg->WriteMask = WRITEMASK_XYZW;
931    }
932 
933    /* optional condition code mask */
934    if (Parse_String(parseState, "(")) {
935       /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
936       /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
937       if (!Parse_CondCodeMask(parseState, dstReg))
938          RETURN_ERROR;
939 
940       if (!Parse_String(parseState, ")"))  /* consume ")" */
941          RETURN_ERROR1("Expected )");
942 
943       return GL_TRUE;
944    }
945    else {
946       /* no cond code mask */
947       dstReg->CondMask = COND_TR;
948       dstReg->CondSwizzle = SWIZZLE_NOOP;
949       return GL_TRUE;
950    }
951 }
952 
953 
954 /**
955  * Parse a vector source (register, constant, etc):
956  *   <vectorSrc>    ::= <absVectorSrc>
957  *                    | <baseVectorSrc>
958  *   <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
959  */
960 static GLboolean
Parse_VectorSrc(struct parse_state * parseState,struct prog_src_register * srcReg)961 Parse_VectorSrc(struct parse_state *parseState,
962                 struct prog_src_register *srcReg)
963 {
964    GLfloat sign = 1.0F;
965    GLubyte token[100];
966    GLint idx;
967    GLuint negateBase, negateAbs;
968 
969    /*
970     * First, take care of +/- and absolute value stuff.
971     */
972    if (Parse_String(parseState, "-"))
973       sign = -1.0F;
974    else if (Parse_String(parseState, "+"))
975       sign = +1.0F;
976 
977    if (Parse_String(parseState, "|")) {
978       srcReg->Abs = GL_TRUE;
979       negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
980 
981       if (Parse_String(parseState, "-"))
982          negateBase = NEGATE_XYZW;
983       else if (Parse_String(parseState, "+"))
984          negateBase = NEGATE_NONE;
985       else
986          negateBase = NEGATE_NONE;
987    }
988    else {
989       srcReg->Abs = GL_FALSE;
990       negateAbs = NEGATE_NONE;
991       negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
992    }
993 
994    srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
995 
996    /* This should be the real src vector/register name */
997    if (!Peek_Token(parseState, token))
998       RETURN_ERROR;
999 
1000    /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
1001     * literal or vector literal.
1002     */
1003    if (token[0] == 'R' || token[0] == 'H') {
1004       srcReg->File = PROGRAM_TEMPORARY;
1005       if (!Parse_TempReg(parseState, &idx))
1006          RETURN_ERROR;
1007       srcReg->Index = idx;
1008    }
1009    else if (token[0] == 'f') {
1010       /* XXX this might be an identifier! */
1011       srcReg->File = PROGRAM_INPUT;
1012       if (!Parse_FragReg(parseState, &idx))
1013          RETURN_ERROR;
1014       srcReg->Index = idx;
1015    }
1016    else if (token[0] == 'p') {
1017       /* XXX this might be an identifier! */
1018       srcReg->File = PROGRAM_LOCAL_PARAM;
1019       if (!Parse_ProgramParamReg(parseState, &idx))
1020          RETURN_ERROR;
1021       srcReg->Index = idx;
1022    }
1023    else if (IsLetter(token[0])){
1024       GLubyte ident[100];
1025       GLint paramIndex;
1026       if (!Parse_Identifier(parseState, ident))
1027          RETURN_ERROR;
1028       paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1029                                                 -1, (const char *) ident);
1030       if (paramIndex < 0) {
1031          RETURN_ERROR2("Undefined constant or parameter: ", ident);
1032       }
1033       srcReg->File = PROGRAM_NAMED_PARAM;
1034       srcReg->Index = paramIndex;
1035    }
1036    else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){
1037       /* literal scalar constant */
1038       GLfloat values[4];
1039       GLuint paramIndex;
1040       if (!Parse_ScalarConstant(parseState, values))
1041          RETURN_ERROR;
1042       paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1043                                               (gl_constant_value *) values,
1044                                               4, NULL);
1045       srcReg->File = PROGRAM_NAMED_PARAM;
1046       srcReg->Index = paramIndex;
1047    }
1048    else if (token[0] == '{'){
1049       /* literal vector constant */
1050       GLfloat values[4];
1051       GLuint paramIndex;
1052       (void) Parse_String(parseState, "{");
1053       if (!Parse_VectorConstant(parseState, values))
1054          RETURN_ERROR;
1055       paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1056                                               (gl_constant_value *) values,
1057                                               4, NULL);
1058       srcReg->File = PROGRAM_NAMED_PARAM;
1059       srcReg->Index = paramIndex;
1060    }
1061    else {
1062       RETURN_ERROR2("Invalid source register name", token);
1063    }
1064 
1065    /* init swizzle fields */
1066    srcReg->Swizzle = SWIZZLE_NOOP;
1067 
1068    /* Look for optional swizzle suffix */
1069    if (Parse_String(parseState, ".")) {
1070       GLuint swz[4];
1071 
1072       if (!Parse_Token(parseState, token))
1073          RETURN_ERROR;
1074 
1075       if (!Parse_SwizzleSuffix(token, swz))
1076          RETURN_ERROR1("Invalid swizzle suffix");
1077 
1078       srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
1079    }
1080 
1081    /* Finish absolute value */
1082    if (srcReg->Abs && !Parse_String(parseState, "|")) {
1083       RETURN_ERROR1("Expected |");
1084    }
1085 
1086    return GL_TRUE;
1087 }
1088 
1089 
1090 static GLboolean
Parse_ScalarSrcReg(struct parse_state * parseState,struct prog_src_register * srcReg)1091 Parse_ScalarSrcReg(struct parse_state *parseState,
1092                    struct prog_src_register *srcReg)
1093 {
1094    GLubyte token[100];
1095    GLfloat sign = 1.0F;
1096    GLboolean needSuffix = GL_TRUE;
1097    GLint idx;
1098    GLuint negateBase, negateAbs;
1099 
1100    /*
1101     * First, take care of +/- and absolute value stuff.
1102     */
1103    if (Parse_String(parseState, "-"))
1104       sign = -1.0F;
1105    else if (Parse_String(parseState, "+"))
1106       sign = +1.0F;
1107 
1108    if (Parse_String(parseState, "|")) {
1109       srcReg->Abs = GL_TRUE;
1110       negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
1111 
1112       if (Parse_String(parseState, "-"))
1113          negateBase = NEGATE_XYZW;
1114       else if (Parse_String(parseState, "+"))
1115          negateBase = NEGATE_NONE;
1116       else
1117          negateBase = NEGATE_NONE;
1118    }
1119    else {
1120       srcReg->Abs = GL_FALSE;
1121       negateAbs = NEGATE_NONE;
1122       negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
1123    }
1124 
1125    srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
1126 
1127    if (!Peek_Token(parseState, token))
1128       RETURN_ERROR;
1129 
1130    /* Src reg can be R<n>, H<n> or a named fragment attrib */
1131    if (token[0] == 'R' || token[0] == 'H') {
1132       srcReg->File = PROGRAM_TEMPORARY;
1133       if (!Parse_TempReg(parseState, &idx))
1134          RETURN_ERROR;
1135       srcReg->Index = idx;
1136    }
1137    else if (token[0] == 'f') {
1138       srcReg->File = PROGRAM_INPUT;
1139       if (!Parse_FragReg(parseState, &idx))
1140          RETURN_ERROR;
1141       srcReg->Index = idx;
1142    }
1143    else if (token[0] == '{') {
1144       /* vector literal */
1145       GLfloat values[4];
1146       GLuint paramIndex;
1147       (void) Parse_String(parseState, "{");
1148       if (!Parse_VectorConstant(parseState, values))
1149          RETURN_ERROR;
1150       paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1151                                               (gl_constant_value *) values,
1152                                               4, NULL);
1153       srcReg->File = PROGRAM_NAMED_PARAM;
1154       srcReg->Index = paramIndex;
1155    }
1156    else if (IsLetter(token[0])){
1157       /* named param/constant */
1158       GLubyte ident[100];
1159       GLint paramIndex;
1160       if (!Parse_Identifier(parseState, ident))
1161          RETURN_ERROR;
1162       paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1163                                                 -1, (const char *) ident);
1164       if (paramIndex < 0) {
1165          RETURN_ERROR2("Undefined constant or parameter: ", ident);
1166       }
1167       srcReg->File = PROGRAM_NAMED_PARAM;
1168       srcReg->Index = paramIndex;
1169    }
1170    else if (IsDigit(token[0])) {
1171       /* scalar literal */
1172       GLfloat values[4];
1173       GLuint paramIndex;
1174       if (!Parse_ScalarConstant(parseState, values))
1175          RETURN_ERROR;
1176       paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1177                                               (gl_constant_value *) values,
1178                                               4, NULL);
1179       srcReg->Index = paramIndex;
1180       srcReg->File = PROGRAM_NAMED_PARAM;
1181       needSuffix = GL_FALSE;
1182    }
1183    else {
1184       RETURN_ERROR2("Invalid scalar source argument", token);
1185    }
1186 
1187    srcReg->Swizzle = 0;
1188    if (needSuffix) {
1189       /* parse .[xyzw] suffix */
1190       if (!Parse_String(parseState, "."))
1191          RETURN_ERROR1("Expected .");
1192 
1193       if (!Parse_Token(parseState, token))
1194          RETURN_ERROR;
1195 
1196       if (token[0] == 'x' && token[1] == 0) {
1197          srcReg->Swizzle = 0;
1198       }
1199       else if (token[0] == 'y' && token[1] == 0) {
1200          srcReg->Swizzle = 1;
1201       }
1202       else if (token[0] == 'z' && token[1] == 0) {
1203          srcReg->Swizzle = 2;
1204       }
1205       else if (token[0] == 'w' && token[1] == 0) {
1206          srcReg->Swizzle = 3;
1207       }
1208       else {
1209          RETURN_ERROR1("Invalid scalar source suffix");
1210       }
1211    }
1212 
1213    /* Finish absolute value */
1214    if (srcReg->Abs && !Parse_String(parseState, "|")) {
1215       RETURN_ERROR1("Expected |");
1216    }
1217 
1218    return GL_TRUE;
1219 }
1220 
1221 
1222 static GLboolean
Parse_PrintInstruction(struct parse_state * parseState,struct prog_instruction * inst)1223 Parse_PrintInstruction(struct parse_state *parseState,
1224                        struct prog_instruction *inst)
1225 {
1226    const GLubyte *str;
1227    GLubyte *msg;
1228    GLuint len;
1229    GLint idx;
1230 
1231    /* The first argument is a literal string 'just like this' */
1232    if (!Parse_String(parseState, "'"))
1233       RETURN_ERROR1("Expected '");
1234 
1235    str = parseState->pos;
1236    for (len = 0; str[len] != '\''; len++) /* find closing quote */
1237       ;
1238    parseState->pos += len + 1;
1239    msg = (GLubyte*) malloc(len + 1);
1240 
1241    memcpy(msg, str, len);
1242    msg[len] = 0;
1243    inst->Data = msg;
1244 
1245    if (Parse_String(parseState, ",")) {
1246       /* got an optional register to print */
1247       GLubyte token[100];
1248       GetToken(parseState, token);
1249       if (token[0] == 'o') {
1250          /* dst reg */
1251          if (!Parse_OutputReg(parseState, &idx))
1252             RETURN_ERROR;
1253 	 inst->SrcReg[0].Index = idx;
1254          inst->SrcReg[0].File = PROGRAM_OUTPUT;
1255       }
1256       else {
1257          /* src reg */
1258          if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1259             RETURN_ERROR;
1260       }
1261    }
1262    else {
1263       inst->SrcReg[0].File = PROGRAM_UNDEFINED;
1264    }
1265 
1266    inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
1267    inst->SrcReg[0].Abs = GL_FALSE;
1268    inst->SrcReg[0].Negate = NEGATE_NONE;
1269 
1270    return GL_TRUE;
1271 }
1272 
1273 
1274 static GLboolean
Parse_InstructionSequence(struct parse_state * parseState,struct prog_instruction program[])1275 Parse_InstructionSequence(struct parse_state *parseState,
1276                           struct prog_instruction program[])
1277 {
1278    while (1) {
1279       struct prog_instruction *inst = program + parseState->numInst;
1280       struct instruction_pattern instMatch;
1281       GLubyte token[100];
1282 
1283       /* Initialize the instruction */
1284       _mesa_init_instructions(inst, 1);
1285 
1286       /* special instructions */
1287       if (Parse_String(parseState, "DEFINE")) {
1288          GLubyte id[100];
1289          GLfloat value[7];  /* yes, 7 to be safe */
1290          if (!Parse_Identifier(parseState, id))
1291             RETURN_ERROR;
1292          /* XXX make sure id is not a reserved identifer, like R9 */
1293          if (!Parse_String(parseState, "="))
1294             RETURN_ERROR1("Expected =");
1295          if (!Parse_VectorOrScalarConstant(parseState, value))
1296             RETURN_ERROR;
1297          if (!Parse_String(parseState, ";"))
1298             RETURN_ERROR1("Expected ;");
1299          if (_mesa_lookup_parameter_index(parseState->parameters,
1300                                           -1, (const char *) id) >= 0) {
1301             RETURN_ERROR2(id, "already defined");
1302          }
1303          _mesa_add_named_parameter(parseState->parameters,
1304                                    (const char *) id,
1305                                    (gl_constant_value *) value);
1306       }
1307       else if (Parse_String(parseState, "DECLARE")) {
1308          GLubyte id[100];
1309          GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0};  /* yes, to be safe */
1310          if (!Parse_Identifier(parseState, id))
1311             RETURN_ERROR;
1312          /* XXX make sure id is not a reserved identifer, like R9 */
1313          if (Parse_String(parseState, "=")) {
1314             if (!Parse_VectorOrScalarConstant(parseState, value))
1315                RETURN_ERROR;
1316          }
1317          if (!Parse_String(parseState, ";"))
1318             RETURN_ERROR1("Expected ;");
1319          if (_mesa_lookup_parameter_index(parseState->parameters,
1320                                           -1, (const char *) id) >= 0) {
1321             RETURN_ERROR2(id, "already declared");
1322          }
1323          _mesa_add_named_parameter(parseState->parameters,
1324                                    (const char *) id,
1325                                    (gl_constant_value *) value);
1326       }
1327       else if (Parse_String(parseState, "END")) {
1328          inst->Opcode = OPCODE_END;
1329          parseState->numInst++;
1330          if (Parse_Token(parseState, token)) {
1331             RETURN_ERROR1("Code after END opcode.");
1332          }
1333          break;
1334       }
1335       else {
1336          /* general/arithmetic instruction */
1337 
1338          /* get token */
1339          if (!Parse_Token(parseState, token)) {
1340             RETURN_ERROR1("Missing END instruction.");
1341          }
1342 
1343          /* try to find matching instuction */
1344          instMatch = MatchInstruction(token);
1345          if (instMatch.opcode >= MAX_OPCODE) {
1346             /* bad instruction name */
1347             RETURN_ERROR2("Unexpected token: ", token);
1348          }
1349 
1350          inst->Opcode = instMatch.opcode;
1351          inst->Precision = instMatch.suffixes & (_R | _H | _X);
1352          inst->SaturateMode = (instMatch.suffixes & (_S))
1353             ? SATURATE_ZERO_ONE : SATURATE_OFF;
1354          inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
1355 
1356          /*
1357           * parse the input and output operands
1358           */
1359          if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
1360             if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
1361                RETURN_ERROR;
1362             if (!Parse_String(parseState, ","))
1363                RETURN_ERROR1("Expected ,");
1364          }
1365          else if (instMatch.outputs == OUTPUT_NONE) {
1366             if (instMatch.opcode == OPCODE_KIL_NV) {
1367                /* This is a little weird, the cond code info is in
1368                 * the dest register.
1369                 */
1370                if (!Parse_CondCodeMask(parseState, &inst->DstReg))
1371                   RETURN_ERROR;
1372             }
1373             else {
1374                ASSERT(instMatch.opcode == OPCODE_PRINT);
1375             }
1376          }
1377 
1378          if (instMatch.inputs == INPUT_1V) {
1379             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1380                RETURN_ERROR;
1381          }
1382          else if (instMatch.inputs == INPUT_2V) {
1383             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1384                RETURN_ERROR;
1385             if (!Parse_String(parseState, ","))
1386                RETURN_ERROR1("Expected ,");
1387             if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1388                RETURN_ERROR;
1389          }
1390          else if (instMatch.inputs == INPUT_3V) {
1391             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1392                RETURN_ERROR;
1393             if (!Parse_String(parseState, ","))
1394                RETURN_ERROR1("Expected ,");
1395             if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1396                RETURN_ERROR;
1397             if (!Parse_String(parseState, ","))
1398                RETURN_ERROR1("Expected ,");
1399             if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1400                RETURN_ERROR;
1401          }
1402          else if (instMatch.inputs == INPUT_1S) {
1403             if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1404                RETURN_ERROR;
1405          }
1406          else if (instMatch.inputs == INPUT_2S) {
1407             if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1408                RETURN_ERROR;
1409             if (!Parse_String(parseState, ","))
1410                RETURN_ERROR1("Expected ,");
1411             if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
1412                RETURN_ERROR;
1413          }
1414          else if (instMatch.inputs == INPUT_CC) {
1415             /* XXX to-do */
1416          }
1417          else if (instMatch.inputs == INPUT_1V_T) {
1418 	    GLubyte unit, idx;
1419             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1420                RETURN_ERROR;
1421             if (!Parse_String(parseState, ","))
1422                RETURN_ERROR1("Expected ,");
1423             if (!Parse_TextureImageId(parseState, &unit, &idx))
1424                RETURN_ERROR;
1425 	    inst->TexSrcUnit = unit;
1426 	    inst->TexSrcTarget = idx;
1427          }
1428          else if (instMatch.inputs == INPUT_3V_T) {
1429 	    GLubyte unit, idx;
1430             if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1431                RETURN_ERROR;
1432             if (!Parse_String(parseState, ","))
1433                RETURN_ERROR1("Expected ,");
1434             if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1435                RETURN_ERROR;
1436             if (!Parse_String(parseState, ","))
1437                RETURN_ERROR1("Expected ,");
1438             if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1439                RETURN_ERROR;
1440             if (!Parse_String(parseState, ","))
1441                RETURN_ERROR1("Expected ,");
1442             if (!Parse_TextureImageId(parseState, &unit, &idx))
1443                RETURN_ERROR;
1444 	    inst->TexSrcUnit = unit;
1445 	    inst->TexSrcTarget = idx;
1446          }
1447          else if (instMatch.inputs == INPUT_1V_S) {
1448             if (!Parse_PrintInstruction(parseState, inst))
1449                RETURN_ERROR;
1450          }
1451 
1452          /* end of statement semicolon */
1453          if (!Parse_String(parseState, ";"))
1454             RETURN_ERROR1("Expected ;");
1455 
1456          parseState->numInst++;
1457 
1458          if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
1459             RETURN_ERROR1("Program too long");
1460       }
1461    }
1462    return GL_TRUE;
1463 }
1464 
1465 
1466 
1467 /**
1468  * Parse/compile the 'str' returning the compiled 'program'.
1469  * ctx->Program.ErrorPos will be -1 if successful.  Otherwise, ErrorPos
1470  * indicates the position of the error in 'str'.
1471  */
1472 void
_mesa_parse_nv_fragment_program(struct gl_context * ctx,GLenum dstTarget,const GLubyte * str,GLsizei len,struct gl_fragment_program * program)1473 _mesa_parse_nv_fragment_program(struct gl_context *ctx, GLenum dstTarget,
1474                                 const GLubyte *str, GLsizei len,
1475                                 struct gl_fragment_program *program)
1476 {
1477    struct parse_state parseState;
1478    struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
1479    struct prog_instruction *newInst;
1480    GLenum target;
1481    GLubyte *programString;
1482 
1483    /* Make a null-terminated copy of the program string */
1484    programString = (GLubyte *) MALLOC(len + 1);
1485    if (!programString) {
1486       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1487       return;
1488    }
1489    memcpy(programString, str, len);
1490    programString[len] = 0;
1491 
1492    /* Get ready to parse */
1493    memset(&parseState, 0, sizeof(struct parse_state));
1494    parseState.ctx = ctx;
1495    parseState.start = programString;
1496    parseState.program = program;
1497    parseState.numInst = 0;
1498    parseState.curLine = programString;
1499    parseState.parameters = _mesa_new_parameter_list();
1500 
1501    /* Reset error state */
1502    _mesa_set_program_error(ctx, -1, NULL);
1503 
1504    /* check the program header */
1505    if (strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
1506       target = GL_FRAGMENT_PROGRAM_NV;
1507       parseState.pos = programString + 7;
1508    }
1509    else if (strncmp((const char *) programString, "!!FCP1.0", 8) == 0) {
1510       /* fragment / register combiner program - not supported */
1511       _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1512       _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1513       return;
1514    }
1515    else {
1516       /* invalid header */
1517       _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1518       _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1519       return;
1520    }
1521 
1522    /* make sure target and header match */
1523    if (target != dstTarget) {
1524       _mesa_error(ctx, GL_INVALID_OPERATION,
1525                   "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1526                   target, dstTarget);
1527       return;
1528    }
1529 
1530    if (Parse_InstructionSequence(&parseState, instBuffer)) {
1531       GLuint u;
1532       /* successful parse! */
1533 
1534       if (parseState.outputsWritten == 0) {
1535          /* must write at least one output! */
1536          _mesa_error(ctx, GL_INVALID_OPERATION,
1537                      "Invalid fragment program - no outputs written.");
1538          return;
1539       }
1540 
1541       /* copy the compiled instructions */
1542       assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
1543       newInst = _mesa_alloc_instructions(parseState.numInst);
1544       if (!newInst) {
1545          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1546          return;  /* out of memory */
1547       }
1548       _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
1549 
1550       /* install the program */
1551       program->Base.Target = target;
1552       if (program->Base.String) {
1553          FREE(program->Base.String);
1554       }
1555       program->Base.String = programString;
1556       program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1557       if (program->Base.Instructions) {
1558          free(program->Base.Instructions);
1559       }
1560       program->Base.Instructions = newInst;
1561       program->Base.NumInstructions = parseState.numInst;
1562       program->Base.InputsRead = parseState.inputsRead;
1563       program->Base.OutputsWritten = parseState.outputsWritten;
1564       for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
1565          program->Base.TexturesUsed[u] = parseState.texturesUsed[u];
1566 
1567       /* save program parameters */
1568       program->Base.Parameters = parseState.parameters;
1569 
1570       /* allocate registers for declared program parameters */
1571 #if 00
1572       _mesa_assign_program_registers(&(program->SymbolTable));
1573 #endif
1574 
1575 #ifdef DEBUG_foo
1576       printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
1577       _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
1578       printf("----------------------------------\n");
1579 #endif
1580    }
1581    else {
1582       /* Error! */
1583       _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1584       /* NOTE: _mesa_set_program_error would have been called already */
1585    }
1586 }
1587 
1588 
1589 const char *
_mesa_nv_fragment_input_register_name(GLuint i)1590 _mesa_nv_fragment_input_register_name(GLuint i)
1591 {
1592    ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
1593    return InputRegisters[i];
1594 }
1595 
1596