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