Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1901 serge 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
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
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
 
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
 
275
static GLboolean IsDigit(GLubyte b)
276
{
277
   return b >= '0' && b <= '9';
278
}
279
 
280
 
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
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
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
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
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
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
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 = _mesa_lookup_parameter_value(parseState->parameters,
476
                                              -1, (const char *) ident);
477
      /* XXX Check that it's a constant and not a parameter */
478
      if (!constant) {
479
         RETURN_ERROR1("Undefined symbol");
480
      }
481
      else {
482
         COPY_4V(number, constant);
483
         return GL_TRUE;
484
      }
485
   }
486
}
487
 
488
 
489
 
490
/**
491
 * Parse a vector constant, one of:
492
 *   { float }
493
 *   { float, float }
494
 *   { float, float, float }
495
 *   { float, float, float, float }
496
 */
497
static GLboolean
498
Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
499
{
500
   /* "{" was already consumed */
501
 
502
   ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0);
503
 
504
   if (!Parse_ScalarConstant(parseState, vec+0))  /* X */
505
      return GL_FALSE;
506
 
507
   if (Parse_String(parseState, "}")) {
508
      return GL_TRUE;
509
   }
510
 
511
   if (!Parse_String(parseState, ","))
512
      RETURN_ERROR1("Expected comma in vector constant");
513
 
514
   if (!Parse_ScalarConstant(parseState, vec+1))  /* Y */
515
      return GL_FALSE;
516
 
517
   if (Parse_String(parseState, "}")) {
518
      return GL_TRUE;
519
   }
520
 
521
   if (!Parse_String(parseState, ","))
522
      RETURN_ERROR1("Expected comma in vector constant");
523
 
524
   if (!Parse_ScalarConstant(parseState, vec+2))  /* Z */
525
      return GL_FALSE;
526
 
527
   if (Parse_String(parseState, "}")) {
528
      return GL_TRUE;
529
   }
530
 
531
   if (!Parse_String(parseState, ","))
532
      RETURN_ERROR1("Expected comma in vector constant");
533
 
534
   if (!Parse_ScalarConstant(parseState, vec+3))  /* W */
535
      return GL_FALSE;
536
 
537
   if (!Parse_String(parseState, "}"))
538
      RETURN_ERROR1("Expected closing brace in vector constant");
539
 
540
   return GL_TRUE;
541
}
542
 
543
 
544
/**
545
 * Parse ,  or {a, b, c, d}.
546
 * Return number of values in the vector or scalar, or zero if parse error.
547
 */
548
static GLuint
549
Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec)
550
{
551
   if (Parse_String(parseState, "{")) {
552
      return Parse_VectorConstant(parseState, vec);
553
   }
554
   else {
555
      GLboolean b = Parse_ScalarConstant(parseState, vec);
556
      if (b) {
557
         vec[1] = vec[2] = vec[3] = vec[0];
558
      }
559
      return b;
560
   }
561
}
562
 
563
 
564
/**
565
 * Parse a texture image source:
566
 *    [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
567
 */
568
static GLboolean
569
Parse_TextureImageId(struct parse_state *parseState,
570
                     GLubyte *texUnit, GLubyte *texTargetBit)
571
{
572
   GLubyte imageSrc[100];
573
   GLint unit;
574
 
575
   if (!Parse_Token(parseState, imageSrc))
576
      RETURN_ERROR;
577
 
578
   if (imageSrc[0] != 'T' ||
579
       imageSrc[1] != 'E' ||
580
       imageSrc[2] != 'X') {
581
      RETURN_ERROR1("Expected TEX# source");
582
   }
583
   unit = atoi((const char *) imageSrc + 3);
584
   if ((unit < 0 || unit > MAX_TEXTURE_IMAGE_UNITS) ||
585
       (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) {
586
      RETURN_ERROR1("Invalied TEX# source index");
587
   }
588
   *texUnit = unit;
589
 
590
   if (!Parse_String(parseState, ","))
591
      RETURN_ERROR1("Expected ,");
592
 
593
   if (Parse_String(parseState, "1D")) {
594
      *texTargetBit = TEXTURE_1D_BIT;
595
   }
596
   else if (Parse_String(parseState, "2D")) {
597
      *texTargetBit = TEXTURE_2D_BIT;
598
   }
599
   else if (Parse_String(parseState, "3D")) {
600
      *texTargetBit = TEXTURE_3D_BIT;
601
   }
602
   else if (Parse_String(parseState, "CUBE")) {
603
      *texTargetBit = TEXTURE_CUBE_BIT;
604
   }
605
   else if (Parse_String(parseState, "RECT")) {
606
      *texTargetBit = TEXTURE_RECT_BIT;
607
   }
608
   else {
609
      RETURN_ERROR1("Invalid texture target token");
610
   }
611
 
612
   /* update record of referenced texture units */
613
   parseState->texturesUsed[*texUnit] |= *texTargetBit;
614
   if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) {
615
      RETURN_ERROR1("Only one texture target can be used per texture unit.");
616
   }
617
 
618
   return GL_TRUE;
619
}
620
 
621
 
622
/**
623
 * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
624
 * like .wxyz, .xxyy, etc and return the swizzle indexes.
625
 */
626
static GLboolean
627
Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4])
628
{
629
   if (token[1] == 0) {
630
      /* single letter swizzle (scalar) */
631
      if (token[0] == 'x')
632
         ASSIGN_4V(swizzle, 0, 0, 0, 0);
633
      else if (token[0] == 'y')
634
         ASSIGN_4V(swizzle, 1, 1, 1, 1);
635
      else if (token[0] == 'z')
636
         ASSIGN_4V(swizzle, 2, 2, 2, 2);
637
      else if (token[0] == 'w')
638
         ASSIGN_4V(swizzle, 3, 3, 3, 3);
639
      else
640
         return GL_FALSE;
641
   }
642
   else {
643
      /* 4-component swizzle (vector) */
644
      GLint k;
645
      for (k = 0; k < 4 && token[k]; k++) {
646
         if (token[k] == 'x')
647
            swizzle[k] = 0;
648
         else if (token[k] == 'y')
649
            swizzle[k] = 1;
650
         else if (token[k] == 'z')
651
            swizzle[k] = 2;
652
         else if (token[k] == 'w')
653
            swizzle[k] = 3;
654
         else
655
            return GL_FALSE;
656
      }
657
      if (k != 4)
658
         return GL_FALSE;
659
   }
660
   return GL_TRUE;
661
}
662
 
663
 
664
static GLboolean
665
Parse_CondCodeMask(struct parse_state *parseState,
666
                   struct prog_dst_register *dstReg)
667
{
668
   if (Parse_String(parseState, "EQ"))
669
      dstReg->CondMask = COND_EQ;
670
   else if (Parse_String(parseState, "GE"))
671
      dstReg->CondMask = COND_GE;
672
   else if (Parse_String(parseState, "GT"))
673
      dstReg->CondMask = COND_GT;
674
   else if (Parse_String(parseState, "LE"))
675
      dstReg->CondMask = COND_LE;
676
   else if (Parse_String(parseState, "LT"))
677
      dstReg->CondMask = COND_LT;
678
   else if (Parse_String(parseState, "NE"))
679
      dstReg->CondMask = COND_NE;
680
   else if (Parse_String(parseState, "TR"))
681
      dstReg->CondMask = COND_TR;
682
   else if (Parse_String(parseState, "FL"))
683
      dstReg->CondMask = COND_FL;
684
   else
685
      RETURN_ERROR1("Invalid condition code mask");
686
 
687
   /* look for optional .xyzw swizzle */
688
   if (Parse_String(parseState, ".")) {
689
      GLubyte token[100];
690
      GLuint swz[4];
691
 
692
      if (!Parse_Token(parseState, token))  /* get xyzw suffix */
693
         RETURN_ERROR;
694
 
695
      if (!Parse_SwizzleSuffix(token, swz))
696
         RETURN_ERROR1("Invalid swizzle suffix");
697
 
698
      dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
699
   }
700
 
701
   return GL_TRUE;
702
}
703
 
704
 
705
/**
706
 * Parse a temporary register: Rnn or Hnn
707
 */
708
static GLboolean
709
Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
710
{
711
   GLubyte token[100];
712
 
713
   /* Should be 'R##' or 'H##' */
714
   if (!Parse_Token(parseState, token))
715
      RETURN_ERROR;
716
   if (token[0] != 'R' && token[0] != 'H')
717
      RETURN_ERROR1("Expected R## or H##");
718
 
719
   if (IsDigit(token[1])) {
720
      GLint reg = atoi((const char *) (token + 1));
721
      if (token[0] == 'H')
722
         reg += 32;
723
      if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS)
724
         RETURN_ERROR1("Invalid temporary register name");
725
      *tempRegNum = reg;
726
   }
727
   else {
728
      RETURN_ERROR1("Invalid temporary register name");
729
   }
730
 
731
   return GL_TRUE;
732
}
733
 
734
 
735
/**
736
 * Parse a write-only dummy register: RC or HC.
737
 */
738
static GLboolean
739
Parse_DummyReg(struct parse_state *parseState, GLint *regNum)
740
{
741
   if (Parse_String(parseState, "RC")) {
742
       *regNum = 0;
743
   }
744
   else if (Parse_String(parseState, "HC")) {
745
       *regNum = 1;
746
   }
747
   else {
748
      RETURN_ERROR1("Invalid write-only register name");
749
   }
750
 
751
   return GL_TRUE;
752
}
753
 
754
 
755
/**
756
 * Parse a program local parameter register "p[##]"
757
 */
758
static GLboolean
759
Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum)
760
{
761
   GLubyte token[100];
762
 
763
   if (!Parse_String(parseState, "p["))
764
      RETURN_ERROR1("Expected p[");
765
 
766
   if (!Parse_Token(parseState, token))
767
      RETURN_ERROR;
768
 
769
   if (IsDigit(token[0])) {
770
      /* a numbered program parameter register */
771
      GLint reg = atoi((const char *) token);
772
      if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS)
773
         RETURN_ERROR1("Invalid constant program number");
774
      *regNum = reg;
775
   }
776
   else {
777
      RETURN_ERROR;
778
   }
779
 
780
   if (!Parse_String(parseState, "]"))
781
      RETURN_ERROR1("Expected ]");
782
 
783
   return GL_TRUE;
784
}
785
 
786
 
787
/**
788
 * Parse f[name]  - fragment input register
789
 */
790
static GLboolean
791
Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum)
792
{
793
   GLubyte token[100];
794
   GLint j;
795
 
796
   /* Match 'f[' */
797
   if (!Parse_String(parseState, "f["))
798
      RETURN_ERROR1("Expected f[");
799
 
800
   /* get  and look for match */
801
   if (!Parse_Token(parseState, token)) {
802
      RETURN_ERROR;
803
   }
804
   for (j = 0; InputRegisters[j]; j++) {
805
      if (strcmp((const char *) token, InputRegisters[j]) == 0) {
806
         *tempRegNum = j;
807
         parseState->inputsRead |= (1 << j);
808
         break;
809
      }
810
   }
811
   if (!InputRegisters[j]) {
812
      /* unknown input register label */
813
      RETURN_ERROR2("Invalid register name", token);
814
   }
815
 
816
   /* Match '[' */
817
   if (!Parse_String(parseState, "]"))
818
      RETURN_ERROR1("Expected ]");
819
 
820
   return GL_TRUE;
821
}
822
 
823
 
824
static GLboolean
825
Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
826
{
827
   GLubyte token[100];
828
 
829
   /* Match "o[" */
830
   if (!Parse_String(parseState, "o["))
831
      RETURN_ERROR1("Expected o[");
832
 
833
   /* Get output reg name */
834
   if (!Parse_Token(parseState, token))
835
      RETURN_ERROR;
836
 
837
   /* try to match an output register name */
838
   if (strcmp((char *) token, "COLR") == 0 ||
839
       strcmp((char *) token, "COLH") == 0) {
840
      /* note that we don't distinguish between COLR and COLH */
841
      *outputRegNum = FRAG_RESULT_COLOR;
842
      parseState->outputsWritten |= (1 << FRAG_RESULT_COLOR);
843
   }
844
   else if (strcmp((char *) token, "DEPR") == 0) {
845
      *outputRegNum = FRAG_RESULT_DEPTH;
846
      parseState->outputsWritten |= (1 << FRAG_RESULT_DEPTH);
847
   }
848
   else {
849
      RETURN_ERROR1("Invalid output register name");
850
   }
851
 
852
   /* Match ']' */
853
   if (!Parse_String(parseState, "]"))
854
      RETURN_ERROR1("Expected ]");
855
 
856
   return GL_TRUE;
857
}
858
 
859
 
860
static GLboolean
861
Parse_MaskedDstReg(struct parse_state *parseState,
862
                   struct prog_dst_register *dstReg)
863
{
864
   GLubyte token[100];
865
   GLint idx;
866
 
867
   /* Dst reg can be R, H, o[n], RC or HC */
868
   if (!Peek_Token(parseState, token))
869
      RETURN_ERROR;
870
 
871
   if (strcmp((const char *) token, "RC") == 0 ||
872
       strcmp((const char *) token, "HC") == 0) {
873
      /* a write-only register */
874
      dstReg->File = PROGRAM_WRITE_ONLY;
875
      if (!Parse_DummyReg(parseState, &idx))
876
         RETURN_ERROR;
877
      dstReg->Index = idx;
878
   }
879
   else if (token[0] == 'R' || token[0] == 'H') {
880
      /* a temporary register */
881
      dstReg->File = PROGRAM_TEMPORARY;
882
      if (!Parse_TempReg(parseState, &idx))
883
         RETURN_ERROR;
884
      dstReg->Index = idx;
885
   }
886
   else if (token[0] == 'o') {
887
      /* an output register */
888
      dstReg->File = PROGRAM_OUTPUT;
889
      if (!Parse_OutputReg(parseState, &idx))
890
         RETURN_ERROR;
891
      dstReg->Index = idx;
892
   }
893
   else {
894
      RETURN_ERROR1("Invalid destination register name");
895
   }
896
 
897
   /* Parse optional write mask */
898
   if (Parse_String(parseState, ".")) {
899
      /* got a mask */
900
      GLint k = 0;
901
 
902
      if (!Parse_Token(parseState, token))  /* get xyzw writemask */
903
         RETURN_ERROR;
904
 
905
      dstReg->WriteMask = 0;
906
 
907
      if (token[k] == 'x') {
908
         dstReg->WriteMask |= WRITEMASK_X;
909
         k++;
910
      }
911
      if (token[k] == 'y') {
912
         dstReg->WriteMask |= WRITEMASK_Y;
913
         k++;
914
      }
915
      if (token[k] == 'z') {
916
         dstReg->WriteMask |= WRITEMASK_Z;
917
         k++;
918
      }
919
      if (token[k] == 'w') {
920
         dstReg->WriteMask |= WRITEMASK_W;
921
         k++;
922
      }
923
      if (k == 0) {
924
         RETURN_ERROR1("Invalid writemask character");
925
      }
926
 
927
   }
928
   else {
929
      dstReg->WriteMask = WRITEMASK_XYZW;
930
   }
931
 
932
   /* optional condition code mask */
933
   if (Parse_String(parseState, "(")) {
934
      /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
935
      /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
936
      if (!Parse_CondCodeMask(parseState, dstReg))
937
         RETURN_ERROR;
938
 
939
      if (!Parse_String(parseState, ")"))  /* consume ")" */
940
         RETURN_ERROR1("Expected )");
941
 
942
      return GL_TRUE;
943
   }
944
   else {
945
      /* no cond code mask */
946
      dstReg->CondMask = COND_TR;
947
      dstReg->CondSwizzle = SWIZZLE_NOOP;
948
      return GL_TRUE;
949
   }
950
}
951
 
952
 
953
/**
954
 * Parse a vector source (register, constant, etc):
955
 *       ::= 
956
 *                    | 
957
 *    ::=  "|"  "|"
958
 */
959
static GLboolean
960
Parse_VectorSrc(struct parse_state *parseState,
961
                struct prog_src_register *srcReg)
962
{
963
   GLfloat sign = 1.0F;
964
   GLubyte token[100];
965
   GLint idx;
966
   GLuint negateBase, negateAbs;
967
 
968
   /*
969
    * First, take care of +/- and absolute value stuff.
970
    */
971
   if (Parse_String(parseState, "-"))
972
      sign = -1.0F;
973
   else if (Parse_String(parseState, "+"))
974
      sign = +1.0F;
975
 
976
   if (Parse_String(parseState, "|")) {
977
      srcReg->Abs = GL_TRUE;
978
      negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
979
 
980
      if (Parse_String(parseState, "-"))
981
         negateBase = NEGATE_XYZW;
982
      else if (Parse_String(parseState, "+"))
983
         negateBase = NEGATE_NONE;
984
      else
985
         negateBase = NEGATE_NONE;
986
   }
987
   else {
988
      srcReg->Abs = GL_FALSE;
989
      negateAbs = NEGATE_NONE;
990
      negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
991
   }
992
 
993
   srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
994
 
995
   /* This should be the real src vector/register name */
996
   if (!Peek_Token(parseState, token))
997
      RETURN_ERROR;
998
 
999
   /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
1000
    * literal or vector literal.
1001
    */
1002
   if (token[0] == 'R' || token[0] == 'H') {
1003
      srcReg->File = PROGRAM_TEMPORARY;
1004
      if (!Parse_TempReg(parseState, &idx))
1005
         RETURN_ERROR;
1006
      srcReg->Index = idx;
1007
   }
1008
   else if (token[0] == 'f') {
1009
      /* XXX this might be an identifier! */
1010
      srcReg->File = PROGRAM_INPUT;
1011
      if (!Parse_FragReg(parseState, &idx))
1012
         RETURN_ERROR;
1013
      srcReg->Index = idx;
1014
   }
1015
   else if (token[0] == 'p') {
1016
      /* XXX this might be an identifier! */
1017
      srcReg->File = PROGRAM_LOCAL_PARAM;
1018
      if (!Parse_ProgramParamReg(parseState, &idx))
1019
         RETURN_ERROR;
1020
      srcReg->Index = idx;
1021
   }
1022
   else if (IsLetter(token[0])){
1023
      GLubyte ident[100];
1024
      GLint paramIndex;
1025
      if (!Parse_Identifier(parseState, ident))
1026
         RETURN_ERROR;
1027
      paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1028
                                                -1, (const char *) ident);
1029
      if (paramIndex < 0) {
1030
         RETURN_ERROR2("Undefined constant or parameter: ", ident);
1031
      }
1032
      srcReg->File = PROGRAM_NAMED_PARAM;
1033
      srcReg->Index = paramIndex;
1034
   }
1035
   else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){
1036
      /* literal scalar constant */
1037
      GLfloat values[4];
1038
      GLuint paramIndex;
1039
      if (!Parse_ScalarConstant(parseState, values))
1040
         RETURN_ERROR;
1041
      paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1042
                                              values, 4, NULL);
1043
      srcReg->File = PROGRAM_NAMED_PARAM;
1044
      srcReg->Index = paramIndex;
1045
   }
1046
   else if (token[0] == '{'){
1047
      /* literal vector constant */
1048
      GLfloat values[4];
1049
      GLuint paramIndex;
1050
      (void) Parse_String(parseState, "{");
1051
      if (!Parse_VectorConstant(parseState, values))
1052
         RETURN_ERROR;
1053
      paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1054
                                              values, 4, NULL);
1055
      srcReg->File = PROGRAM_NAMED_PARAM;
1056
      srcReg->Index = paramIndex;
1057
   }
1058
   else {
1059
      RETURN_ERROR2("Invalid source register name", token);
1060
   }
1061
 
1062
   /* init swizzle fields */
1063
   srcReg->Swizzle = SWIZZLE_NOOP;
1064
 
1065
   /* Look for optional swizzle suffix */
1066
   if (Parse_String(parseState, ".")) {
1067
      GLuint swz[4];
1068
 
1069
      if (!Parse_Token(parseState, token))
1070
         RETURN_ERROR;
1071
 
1072
      if (!Parse_SwizzleSuffix(token, swz))
1073
         RETURN_ERROR1("Invalid swizzle suffix");
1074
 
1075
      srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
1076
   }
1077
 
1078
   /* Finish absolute value */
1079
   if (srcReg->Abs && !Parse_String(parseState, "|")) {
1080
      RETURN_ERROR1("Expected |");
1081
   }
1082
 
1083
   return GL_TRUE;
1084
}
1085
 
1086
 
1087
static GLboolean
1088
Parse_ScalarSrcReg(struct parse_state *parseState,
1089
                   struct prog_src_register *srcReg)
1090
{
1091
   GLubyte token[100];
1092
   GLfloat sign = 1.0F;
1093
   GLboolean needSuffix = GL_TRUE;
1094
   GLint idx;
1095
   GLuint negateBase, negateAbs;
1096
 
1097
   /*
1098
    * First, take care of +/- and absolute value stuff.
1099
    */
1100
   if (Parse_String(parseState, "-"))
1101
      sign = -1.0F;
1102
   else if (Parse_String(parseState, "+"))
1103
      sign = +1.0F;
1104
 
1105
   if (Parse_String(parseState, "|")) {
1106
      srcReg->Abs = GL_TRUE;
1107
      negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
1108
 
1109
      if (Parse_String(parseState, "-"))
1110
         negateBase = NEGATE_XYZW;
1111
      else if (Parse_String(parseState, "+"))
1112
         negateBase = NEGATE_NONE;
1113
      else
1114
         negateBase = NEGATE_NONE;
1115
   }
1116
   else {
1117
      srcReg->Abs = GL_FALSE;
1118
      negateAbs = NEGATE_NONE;
1119
      negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
1120
   }
1121
 
1122
   srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
1123
 
1124
   if (!Peek_Token(parseState, token))
1125
      RETURN_ERROR;
1126
 
1127
   /* Src reg can be R, H or a named fragment attrib */
1128
   if (token[0] == 'R' || token[0] == 'H') {
1129
      srcReg->File = PROGRAM_TEMPORARY;
1130
      if (!Parse_TempReg(parseState, &idx))
1131
         RETURN_ERROR;
1132
      srcReg->Index = idx;
1133
   }
1134
   else if (token[0] == 'f') {
1135
      srcReg->File = PROGRAM_INPUT;
1136
      if (!Parse_FragReg(parseState, &idx))
1137
         RETURN_ERROR;
1138
      srcReg->Index = idx;
1139
   }
1140
   else if (token[0] == '{') {
1141
      /* vector literal */
1142
      GLfloat values[4];
1143
      GLuint paramIndex;
1144
      (void) Parse_String(parseState, "{");
1145
      if (!Parse_VectorConstant(parseState, values))
1146
         RETURN_ERROR;
1147
      paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1148
                                              values, 4, NULL);
1149
      srcReg->File = PROGRAM_NAMED_PARAM;
1150
      srcReg->Index = paramIndex;
1151
   }
1152
   else if (IsLetter(token[0])){
1153
      /* named param/constant */
1154
      GLubyte ident[100];
1155
      GLint paramIndex;
1156
      if (!Parse_Identifier(parseState, ident))
1157
         RETURN_ERROR;
1158
      paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1159
                                                -1, (const char *) ident);
1160
      if (paramIndex < 0) {
1161
         RETURN_ERROR2("Undefined constant or parameter: ", ident);
1162
      }
1163
      srcReg->File = PROGRAM_NAMED_PARAM;
1164
      srcReg->Index = paramIndex;
1165
   }
1166
   else if (IsDigit(token[0])) {
1167
      /* scalar literal */
1168
      GLfloat values[4];
1169
      GLuint paramIndex;
1170
      if (!Parse_ScalarConstant(parseState, values))
1171
         RETURN_ERROR;
1172
      paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1173
                                              values, 4, NULL);
1174
      srcReg->Index = paramIndex;
1175
      srcReg->File = PROGRAM_NAMED_PARAM;
1176
      needSuffix = GL_FALSE;
1177
   }
1178
   else {
1179
      RETURN_ERROR2("Invalid scalar source argument", token);
1180
   }
1181
 
1182
   srcReg->Swizzle = 0;
1183
   if (needSuffix) {
1184
      /* parse .[xyzw] suffix */
1185
      if (!Parse_String(parseState, "."))
1186
         RETURN_ERROR1("Expected .");
1187
 
1188
      if (!Parse_Token(parseState, token))
1189
         RETURN_ERROR;
1190
 
1191
      if (token[0] == 'x' && token[1] == 0) {
1192
         srcReg->Swizzle = 0;
1193
      }
1194
      else if (token[0] == 'y' && token[1] == 0) {
1195
         srcReg->Swizzle = 1;
1196
      }
1197
      else if (token[0] == 'z' && token[1] == 0) {
1198
         srcReg->Swizzle = 2;
1199
      }
1200
      else if (token[0] == 'w' && token[1] == 0) {
1201
         srcReg->Swizzle = 3;
1202
      }
1203
      else {
1204
         RETURN_ERROR1("Invalid scalar source suffix");
1205
      }
1206
   }
1207
 
1208
   /* Finish absolute value */
1209
   if (srcReg->Abs && !Parse_String(parseState, "|")) {
1210
      RETURN_ERROR1("Expected |");
1211
   }
1212
 
1213
   return GL_TRUE;
1214
}
1215
 
1216
 
1217
static GLboolean
1218
Parse_PrintInstruction(struct parse_state *parseState,
1219
                       struct prog_instruction *inst)
1220
{
1221
   const GLubyte *str;
1222
   GLubyte *msg;
1223
   GLuint len;
1224
   GLint idx;
1225
 
1226
   /* The first argument is a literal string 'just like this' */
1227
   if (!Parse_String(parseState, "'"))
1228
      RETURN_ERROR1("Expected '");
1229
 
1230
   str = parseState->pos;
1231
   for (len = 0; str[len] != '\''; len++) /* find closing quote */
1232
      ;
1233
   parseState->pos += len + 1;
1234
   msg = (GLubyte*) malloc(len + 1);
1235
 
1236
   memcpy(msg, str, len);
1237
   msg[len] = 0;
1238
   inst->Data = msg;
1239
 
1240
   if (Parse_String(parseState, ",")) {
1241
      /* got an optional register to print */
1242
      GLubyte token[100];
1243
      GetToken(parseState, token);
1244
      if (token[0] == 'o') {
1245
         /* dst reg */
1246
         if (!Parse_OutputReg(parseState, &idx))
1247
            RETURN_ERROR;
1248
	 inst->SrcReg[0].Index = idx;
1249
         inst->SrcReg[0].File = PROGRAM_OUTPUT;
1250
      }
1251
      else {
1252
         /* src reg */
1253
         if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1254
            RETURN_ERROR;
1255
      }
1256
   }
1257
   else {
1258
      inst->SrcReg[0].File = PROGRAM_UNDEFINED;
1259
   }
1260
 
1261
   inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
1262
   inst->SrcReg[0].Abs = GL_FALSE;
1263
   inst->SrcReg[0].Negate = NEGATE_NONE;
1264
 
1265
   return GL_TRUE;
1266
}
1267
 
1268
 
1269
static GLboolean
1270
Parse_InstructionSequence(struct parse_state *parseState,
1271
                          struct prog_instruction program[])
1272
{
1273
   while (1) {
1274
      struct prog_instruction *inst = program + parseState->numInst;
1275
      struct instruction_pattern instMatch;
1276
      GLubyte token[100];
1277
 
1278
      /* Initialize the instruction */
1279
      _mesa_init_instructions(inst, 1);
1280
 
1281
      /* special instructions */
1282
      if (Parse_String(parseState, "DEFINE")) {
1283
         GLubyte id[100];
1284
         GLfloat value[7];  /* yes, 7 to be safe */
1285
         if (!Parse_Identifier(parseState, id))
1286
            RETURN_ERROR;
1287
         /* XXX make sure id is not a reserved identifer, like R9 */
1288
         if (!Parse_String(parseState, "="))
1289
            RETURN_ERROR1("Expected =");
1290
         if (!Parse_VectorOrScalarConstant(parseState, value))
1291
            RETURN_ERROR;
1292
         if (!Parse_String(parseState, ";"))
1293
            RETURN_ERROR1("Expected ;");
1294
         if (_mesa_lookup_parameter_index(parseState->parameters,
1295
                                          -1, (const char *) id) >= 0) {
1296
            RETURN_ERROR2(id, "already defined");
1297
         }
1298
         _mesa_add_named_parameter(parseState->parameters,
1299
                                   (const char *) id, value);
1300
      }
1301
      else if (Parse_String(parseState, "DECLARE")) {
1302
         GLubyte id[100];
1303
         GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0};  /* yes, to be safe */
1304
         if (!Parse_Identifier(parseState, id))
1305
            RETURN_ERROR;
1306
         /* XXX make sure id is not a reserved identifer, like R9 */
1307
         if (Parse_String(parseState, "=")) {
1308
            if (!Parse_VectorOrScalarConstant(parseState, value))
1309
               RETURN_ERROR;
1310
         }
1311
         if (!Parse_String(parseState, ";"))
1312
            RETURN_ERROR1("Expected ;");
1313
         if (_mesa_lookup_parameter_index(parseState->parameters,
1314
                                          -1, (const char *) id) >= 0) {
1315
            RETURN_ERROR2(id, "already declared");
1316
         }
1317
         _mesa_add_named_parameter(parseState->parameters,
1318
                                   (const char *) id, value);
1319
      }
1320
      else if (Parse_String(parseState, "END")) {
1321
         inst->Opcode = OPCODE_END;
1322
         parseState->numInst++;
1323
         if (Parse_Token(parseState, token)) {
1324
            RETURN_ERROR1("Code after END opcode.");
1325
         }
1326
         break;
1327
      }
1328
      else {
1329
         /* general/arithmetic instruction */
1330
 
1331
         /* get token */
1332
         if (!Parse_Token(parseState, token)) {
1333
            RETURN_ERROR1("Missing END instruction.");
1334
         }
1335
 
1336
         /* try to find matching instuction */
1337
         instMatch = MatchInstruction(token);
1338
         if (instMatch.opcode >= MAX_OPCODE) {
1339
            /* bad instruction name */
1340
            RETURN_ERROR2("Unexpected token: ", token);
1341
         }
1342
 
1343
         inst->Opcode = instMatch.opcode;
1344
         inst->Precision = instMatch.suffixes & (_R | _H | _X);
1345
         inst->SaturateMode = (instMatch.suffixes & (_S))
1346
            ? SATURATE_ZERO_ONE : SATURATE_OFF;
1347
         inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
1348
 
1349
         /*
1350
          * parse the input and output operands
1351
          */
1352
         if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
1353
            if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
1354
               RETURN_ERROR;
1355
            if (!Parse_String(parseState, ","))
1356
               RETURN_ERROR1("Expected ,");
1357
         }
1358
         else if (instMatch.outputs == OUTPUT_NONE) {
1359
            if (instMatch.opcode == OPCODE_KIL_NV) {
1360
               /* This is a little weird, the cond code info is in
1361
                * the dest register.
1362
                */
1363
               if (!Parse_CondCodeMask(parseState, &inst->DstReg))
1364
                  RETURN_ERROR;
1365
            }
1366
            else {
1367
               ASSERT(instMatch.opcode == OPCODE_PRINT);
1368
            }
1369
         }
1370
 
1371
         if (instMatch.inputs == INPUT_1V) {
1372
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1373
               RETURN_ERROR;
1374
         }
1375
         else if (instMatch.inputs == INPUT_2V) {
1376
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1377
               RETURN_ERROR;
1378
            if (!Parse_String(parseState, ","))
1379
               RETURN_ERROR1("Expected ,");
1380
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1381
               RETURN_ERROR;
1382
         }
1383
         else if (instMatch.inputs == INPUT_3V) {
1384
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1385
               RETURN_ERROR;
1386
            if (!Parse_String(parseState, ","))
1387
               RETURN_ERROR1("Expected ,");
1388
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1389
               RETURN_ERROR;
1390
            if (!Parse_String(parseState, ","))
1391
               RETURN_ERROR1("Expected ,");
1392
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1393
               RETURN_ERROR;
1394
         }
1395
         else if (instMatch.inputs == INPUT_1S) {
1396
            if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1397
               RETURN_ERROR;
1398
         }
1399
         else if (instMatch.inputs == INPUT_2S) {
1400
            if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1401
               RETURN_ERROR;
1402
            if (!Parse_String(parseState, ","))
1403
               RETURN_ERROR1("Expected ,");
1404
            if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
1405
               RETURN_ERROR;
1406
         }
1407
         else if (instMatch.inputs == INPUT_CC) {
1408
            /* XXX to-do */
1409
         }
1410
         else if (instMatch.inputs == INPUT_1V_T) {
1411
	    GLubyte unit, idx;
1412
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1413
               RETURN_ERROR;
1414
            if (!Parse_String(parseState, ","))
1415
               RETURN_ERROR1("Expected ,");
1416
            if (!Parse_TextureImageId(parseState, &unit, &idx))
1417
               RETURN_ERROR;
1418
	    inst->TexSrcUnit = unit;
1419
	    inst->TexSrcTarget = idx;
1420
         }
1421
         else if (instMatch.inputs == INPUT_3V_T) {
1422
	    GLubyte unit, idx;
1423
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1424
               RETURN_ERROR;
1425
            if (!Parse_String(parseState, ","))
1426
               RETURN_ERROR1("Expected ,");
1427
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1428
               RETURN_ERROR;
1429
            if (!Parse_String(parseState, ","))
1430
               RETURN_ERROR1("Expected ,");
1431
            if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1432
               RETURN_ERROR;
1433
            if (!Parse_String(parseState, ","))
1434
               RETURN_ERROR1("Expected ,");
1435
            if (!Parse_TextureImageId(parseState, &unit, &idx))
1436
               RETURN_ERROR;
1437
	    inst->TexSrcUnit = unit;
1438
	    inst->TexSrcTarget = idx;
1439
         }
1440
         else if (instMatch.inputs == INPUT_1V_S) {
1441
            if (!Parse_PrintInstruction(parseState, inst))
1442
               RETURN_ERROR;
1443
         }
1444
 
1445
         /* end of statement semicolon */
1446
         if (!Parse_String(parseState, ";"))
1447
            RETURN_ERROR1("Expected ;");
1448
 
1449
         parseState->numInst++;
1450
 
1451
         if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
1452
            RETURN_ERROR1("Program too long");
1453
      }
1454
   }
1455
   return GL_TRUE;
1456
}
1457
 
1458
 
1459
 
1460
/**
1461
 * Parse/compile the 'str' returning the compiled 'program'.
1462
 * ctx->Program.ErrorPos will be -1 if successful.  Otherwise, ErrorPos
1463
 * indicates the position of the error in 'str'.
1464
 */
1465
void
1466
_mesa_parse_nv_fragment_program(struct gl_context *ctx, GLenum dstTarget,
1467
                                const GLubyte *str, GLsizei len,
1468
                                struct gl_fragment_program *program)
1469
{
1470
   struct parse_state parseState;
1471
   struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
1472
   struct prog_instruction *newInst;
1473
   GLenum target;
1474
   GLubyte *programString;
1475
 
1476
   /* Make a null-terminated copy of the program string */
1477
   programString = (GLubyte *) MALLOC(len + 1);
1478
   if (!programString) {
1479
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1480
      return;
1481
   }
1482
   memcpy(programString, str, len);
1483
   programString[len] = 0;
1484
 
1485
   /* Get ready to parse */
1486
   memset(&parseState, 0, sizeof(struct parse_state));
1487
   parseState.ctx = ctx;
1488
   parseState.start = programString;
1489
   parseState.program = program;
1490
   parseState.numInst = 0;
1491
   parseState.curLine = programString;
1492
   parseState.parameters = _mesa_new_parameter_list();
1493
 
1494
   /* Reset error state */
1495
   _mesa_set_program_error(ctx, -1, NULL);
1496
 
1497
   /* check the program header */
1498
   if (strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
1499
      target = GL_FRAGMENT_PROGRAM_NV;
1500
      parseState.pos = programString + 7;
1501
   }
1502
   else if (strncmp((const char *) programString, "!!FCP1.0", 8) == 0) {
1503
      /* fragment / register combiner program - not supported */
1504
      _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1505
      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1506
      return;
1507
   }
1508
   else {
1509
      /* invalid header */
1510
      _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1511
      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1512
      return;
1513
   }
1514
 
1515
   /* make sure target and header match */
1516
   if (target != dstTarget) {
1517
      _mesa_error(ctx, GL_INVALID_OPERATION,
1518
                  "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1519
                  target, dstTarget);
1520
      return;
1521
   }
1522
 
1523
   if (Parse_InstructionSequence(&parseState, instBuffer)) {
1524
      GLuint u;
1525
      /* successful parse! */
1526
 
1527
      if (parseState.outputsWritten == 0) {
1528
         /* must write at least one output! */
1529
         _mesa_error(ctx, GL_INVALID_OPERATION,
1530
                     "Invalid fragment program - no outputs written.");
1531
         return;
1532
      }
1533
 
1534
      /* copy the compiled instructions */
1535
      assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
1536
      newInst = _mesa_alloc_instructions(parseState.numInst);
1537
      if (!newInst) {
1538
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1539
         return;  /* out of memory */
1540
      }
1541
      _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
1542
 
1543
      /* install the program */
1544
      program->Base.Target = target;
1545
      if (program->Base.String) {
1546
         FREE(program->Base.String);
1547
      }
1548
      program->Base.String = programString;
1549
      program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1550
      if (program->Base.Instructions) {
1551
         free(program->Base.Instructions);
1552
      }
1553
      program->Base.Instructions = newInst;
1554
      program->Base.NumInstructions = parseState.numInst;
1555
      program->Base.InputsRead = parseState.inputsRead;
1556
      program->Base.OutputsWritten = parseState.outputsWritten;
1557
      for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
1558
         program->Base.TexturesUsed[u] = parseState.texturesUsed[u];
1559
 
1560
      /* save program parameters */
1561
      program->Base.Parameters = parseState.parameters;
1562
 
1563
      /* allocate registers for declared program parameters */
1564
#if 00
1565
      _mesa_assign_program_registers(&(program->SymbolTable));
1566
#endif
1567
 
1568
#ifdef DEBUG_foo
1569
      printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
1570
      _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
1571
      printf("----------------------------------\n");
1572
#endif
1573
   }
1574
   else {
1575
      /* Error! */
1576
      _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1577
      /* NOTE: _mesa_set_program_error would have been called already */
1578
   }
1579
}
1580
 
1581
 
1582
const char *
1583
_mesa_nv_fragment_input_register_name(GLuint i)
1584
{
1585
   ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
1586
   return InputRegisters[i];
1587
}
1588