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