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