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