Merge commit 'origin/gallium-0.1' into gallium-0.2
[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 "main/glheader.h"
41 #include "main/context.h"
42 #include "main/imports.h"
43 #include "main/macros.h"
44 #include "program.h"
45 #include "prog_parameter.h"
46 #include "prog_instruction.h"
47 #include "nvfragparse.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;
1040 if (!Parse_ScalarConstant(parseState, values))
1041 RETURN_ERROR;
1042 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1043 values, 4, NULL);
1044 srcReg->File = PROGRAM_NAMED_PARAM;
1045 srcReg->Index = paramIndex;
1046 }
1047 else if (token[0] == '{'){
1048 /* literal vector constant */
1049 GLfloat values[4];
1050 GLuint paramIndex;
1051 (void) Parse_String(parseState, "{");
1052 if (!Parse_VectorConstant(parseState, values))
1053 RETURN_ERROR;
1054 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1055 values, 4, NULL);
1056 srcReg->File = PROGRAM_NAMED_PARAM;
1057 srcReg->Index = paramIndex;
1058 }
1059 else {
1060 RETURN_ERROR2("Invalid source register name", token);
1061 }
1062
1063 /* init swizzle fields */
1064 srcReg->Swizzle = SWIZZLE_NOOP;
1065
1066 /* Look for optional swizzle suffix */
1067 if (Parse_String(parseState, ".")) {
1068 GLuint swz[4];
1069
1070 if (!Parse_Token(parseState, token))
1071 RETURN_ERROR;
1072
1073 if (!Parse_SwizzleSuffix(token, swz))
1074 RETURN_ERROR1("Invalid swizzle suffix");
1075
1076 srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
1077 }
1078
1079 /* Finish absolute value */
1080 if (srcReg->Abs && !Parse_String(parseState, "|")) {
1081 RETURN_ERROR1("Expected |");
1082 }
1083
1084 return GL_TRUE;
1085 }
1086
1087
1088 static GLboolean
1089 Parse_ScalarSrcReg(struct parse_state *parseState,
1090 struct prog_src_register *srcReg)
1091 {
1092 GLubyte token[100];
1093 GLfloat sign = 1.0F;
1094 GLboolean needSuffix = GL_TRUE;
1095 GLint idx;
1096
1097 /*
1098 * First, take care of +/- and absolute value stuff.
1099 */
1100 if (Parse_String(parseState, "-"))
1101 sign = -1.0F;
1102 else if (Parse_String(parseState, "+"))
1103 sign = +1.0F;
1104
1105 if (Parse_String(parseState, "|")) {
1106 srcReg->Abs = GL_TRUE;
1107 srcReg->NegateAbs = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
1108
1109 if (Parse_String(parseState, "-"))
1110 srcReg->NegateBase = NEGATE_XYZW;
1111 else if (Parse_String(parseState, "+"))
1112 srcReg->NegateBase = NEGATE_NONE;
1113 else
1114 srcReg->NegateBase = NEGATE_NONE;
1115 }
1116 else {
1117 srcReg->Abs = GL_FALSE;
1118 srcReg->NegateAbs = GL_FALSE;
1119 srcReg->NegateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
1120 }
1121
1122 if (!Peek_Token(parseState, token))
1123 RETURN_ERROR;
1124
1125 /* Src reg can be R<n>, H<n> or a named fragment attrib */
1126 if (token[0] == 'R' || token[0] == 'H') {
1127 srcReg->File = PROGRAM_TEMPORARY;
1128 if (!Parse_TempReg(parseState, &idx))
1129 RETURN_ERROR;
1130 srcReg->Index = idx;
1131 }
1132 else if (token[0] == 'f') {
1133 srcReg->File = PROGRAM_INPUT;
1134 if (!Parse_FragReg(parseState, &idx))
1135 RETURN_ERROR;
1136 srcReg->Index = idx;
1137 }
1138 else if (token[0] == '{') {
1139 /* vector literal */
1140 GLfloat values[4];
1141 GLuint paramIndex;
1142 (void) Parse_String(parseState, "{");
1143 if (!Parse_VectorConstant(parseState, values))
1144 RETURN_ERROR;
1145 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1146 values, 4, NULL);
1147 srcReg->File = PROGRAM_NAMED_PARAM;
1148 srcReg->Index = paramIndex;
1149 }
1150 else if (IsLetter(token[0])){
1151 /* named param/constant */
1152 GLubyte ident[100];
1153 GLint paramIndex;
1154 if (!Parse_Identifier(parseState, ident))
1155 RETURN_ERROR;
1156 paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1157 -1, (const char *) ident);
1158 if (paramIndex < 0) {
1159 RETURN_ERROR2("Undefined constant or parameter: ", ident);
1160 }
1161 srcReg->File = PROGRAM_NAMED_PARAM;
1162 srcReg->Index = paramIndex;
1163 }
1164 else if (IsDigit(token[0])) {
1165 /* scalar literal */
1166 GLfloat values[4];
1167 GLuint paramIndex;
1168 if (!Parse_ScalarConstant(parseState, values))
1169 RETURN_ERROR;
1170 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1171 values, 4, NULL);
1172 srcReg->Index = paramIndex;
1173 srcReg->File = PROGRAM_NAMED_PARAM;
1174 needSuffix = GL_FALSE;
1175 }
1176 else {
1177 RETURN_ERROR2("Invalid scalar source argument", token);
1178 }
1179
1180 srcReg->Swizzle = 0;
1181 if (needSuffix) {
1182 /* parse .[xyzw] suffix */
1183 if (!Parse_String(parseState, "."))
1184 RETURN_ERROR1("Expected .");
1185
1186 if (!Parse_Token(parseState, token))
1187 RETURN_ERROR;
1188
1189 if (token[0] == 'x' && token[1] == 0) {
1190 srcReg->Swizzle = 0;
1191 }
1192 else if (token[0] == 'y' && token[1] == 0) {
1193 srcReg->Swizzle = 1;
1194 }
1195 else if (token[0] == 'z' && token[1] == 0) {
1196 srcReg->Swizzle = 2;
1197 }
1198 else if (token[0] == 'w' && token[1] == 0) {
1199 srcReg->Swizzle = 3;
1200 }
1201 else {
1202 RETURN_ERROR1("Invalid scalar source suffix");
1203 }
1204 }
1205
1206 /* Finish absolute value */
1207 if (srcReg->Abs && !Parse_String(parseState, "|")) {
1208 RETURN_ERROR1("Expected |");
1209 }
1210
1211 return GL_TRUE;
1212 }
1213
1214
1215 static GLboolean
1216 Parse_PrintInstruction(struct parse_state *parseState,
1217 struct prog_instruction *inst)
1218 {
1219 const GLubyte *str;
1220 GLubyte *msg;
1221 GLuint len;
1222 GLint idx;
1223
1224 /* The first argument is a literal string 'just like this' */
1225 if (!Parse_String(parseState, "'"))
1226 RETURN_ERROR1("Expected '");
1227
1228 str = parseState->pos;
1229 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1230 ;
1231 parseState->pos += len + 1;
1232 msg = (GLubyte*) _mesa_malloc(len + 1);
1233
1234 _mesa_memcpy(msg, str, len);
1235 msg[len] = 0;
1236 inst->Data = msg;
1237
1238 if (Parse_String(parseState, ",")) {
1239 /* got an optional register to print */
1240 GLubyte token[100];
1241 GetToken(parseState, token);
1242 if (token[0] == 'o') {
1243 /* dst reg */
1244 if (!Parse_OutputReg(parseState, &idx))
1245 RETURN_ERROR;
1246 inst->SrcReg[0].Index = idx;
1247 inst->SrcReg[0].File = PROGRAM_OUTPUT;
1248 }
1249 else {
1250 /* src reg */
1251 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1252 RETURN_ERROR;
1253 }
1254 }
1255 else {
1256 inst->SrcReg[0].File = PROGRAM_UNDEFINED;
1257 }
1258
1259 inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
1260 inst->SrcReg[0].NegateBase = NEGATE_NONE;
1261 inst->SrcReg[0].Abs = GL_FALSE;
1262 inst->SrcReg[0].NegateAbs = GL_FALSE;
1263
1264 return GL_TRUE;
1265 }
1266
1267
1268 static GLboolean
1269 Parse_InstructionSequence(struct parse_state *parseState,
1270 struct prog_instruction program[])
1271 {
1272 while (1) {
1273 struct prog_instruction *inst = program + parseState->numInst;
1274 struct instruction_pattern instMatch;
1275 GLubyte token[100];
1276
1277 /* Initialize the instruction */
1278 _mesa_init_instructions(inst, 1);
1279
1280 /* special instructions */
1281 if (Parse_String(parseState, "DEFINE")) {
1282 GLubyte id[100];
1283 GLfloat value[7]; /* yes, 7 to be safe */
1284 if (!Parse_Identifier(parseState, id))
1285 RETURN_ERROR;
1286 /* XXX make sure id is not a reserved identifer, like R9 */
1287 if (!Parse_String(parseState, "="))
1288 RETURN_ERROR1("Expected =");
1289 if (!Parse_VectorOrScalarConstant(parseState, value))
1290 RETURN_ERROR;
1291 if (!Parse_String(parseState, ";"))
1292 RETURN_ERROR1("Expected ;");
1293 if (_mesa_lookup_parameter_index(parseState->parameters,
1294 -1, (const char *) id) >= 0) {
1295 RETURN_ERROR2(id, "already defined");
1296 }
1297 _mesa_add_named_parameter(parseState->parameters,
1298 (const char *) id, value);
1299 }
1300 else if (Parse_String(parseState, "DECLARE")) {
1301 GLubyte id[100];
1302 GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */
1303 if (!Parse_Identifier(parseState, id))
1304 RETURN_ERROR;
1305 /* XXX make sure id is not a reserved identifer, like R9 */
1306 if (Parse_String(parseState, "=")) {
1307 if (!Parse_VectorOrScalarConstant(parseState, value))
1308 RETURN_ERROR;
1309 }
1310 if (!Parse_String(parseState, ";"))
1311 RETURN_ERROR1("Expected ;");
1312 if (_mesa_lookup_parameter_index(parseState->parameters,
1313 -1, (const char *) id) >= 0) {
1314 RETURN_ERROR2(id, "already declared");
1315 }
1316 _mesa_add_named_parameter(parseState->parameters,
1317 (const char *) id, value);
1318 }
1319 else if (Parse_String(parseState, "END")) {
1320 inst->Opcode = OPCODE_END;
1321 inst->StringPos = parseState->curLine - parseState->start;
1322 assert(inst->StringPos >= 0);
1323 parseState->numInst++;
1324 if (Parse_Token(parseState, token)) {
1325 RETURN_ERROR1("Code after END opcode.");
1326 }
1327 break;
1328 }
1329 else {
1330 /* general/arithmetic instruction */
1331
1332 /* get token */
1333 if (!Parse_Token(parseState, token)) {
1334 RETURN_ERROR1("Missing END instruction.");
1335 }
1336
1337 /* try to find matching instuction */
1338 instMatch = MatchInstruction(token);
1339 if (instMatch.opcode >= MAX_OPCODE) {
1340 /* bad instruction name */
1341 RETURN_ERROR2("Unexpected token: ", token);
1342 }
1343
1344 inst->Opcode = instMatch.opcode;
1345 inst->Precision = instMatch.suffixes & (_R | _H | _X);
1346 inst->SaturateMode = (instMatch.suffixes & (_S))
1347 ? SATURATE_ZERO_ONE : SATURATE_OFF;
1348 inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
1349 inst->StringPos = parseState->curLine - parseState->start;
1350 assert(inst->StringPos >= 0);
1351
1352 /*
1353 * parse the input and output operands
1354 */
1355 if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
1356 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
1357 RETURN_ERROR;
1358 if (!Parse_String(parseState, ","))
1359 RETURN_ERROR1("Expected ,");
1360 }
1361 else if (instMatch.outputs == OUTPUT_NONE) {
1362 if (instMatch.opcode == OPCODE_KIL_NV) {
1363 /* This is a little weird, the cond code info is in
1364 * the dest register.
1365 */
1366 if (!Parse_CondCodeMask(parseState, &inst->DstReg))
1367 RETURN_ERROR;
1368 }
1369 else {
1370 ASSERT(instMatch.opcode == OPCODE_PRINT);
1371 }
1372 }
1373
1374 if (instMatch.inputs == INPUT_1V) {
1375 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1376 RETURN_ERROR;
1377 }
1378 else if (instMatch.inputs == INPUT_2V) {
1379 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1380 RETURN_ERROR;
1381 if (!Parse_String(parseState, ","))
1382 RETURN_ERROR1("Expected ,");
1383 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1384 RETURN_ERROR;
1385 }
1386 else if (instMatch.inputs == INPUT_3V) {
1387 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1388 RETURN_ERROR;
1389 if (!Parse_String(parseState, ","))
1390 RETURN_ERROR1("Expected ,");
1391 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1392 RETURN_ERROR;
1393 if (!Parse_String(parseState, ","))
1394 RETURN_ERROR1("Expected ,");
1395 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1396 RETURN_ERROR;
1397 }
1398 else if (instMatch.inputs == INPUT_1S) {
1399 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1400 RETURN_ERROR;
1401 }
1402 else if (instMatch.inputs == INPUT_2S) {
1403 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1404 RETURN_ERROR;
1405 if (!Parse_String(parseState, ","))
1406 RETURN_ERROR1("Expected ,");
1407 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
1408 RETURN_ERROR;
1409 }
1410 else if (instMatch.inputs == INPUT_CC) {
1411 /* XXX to-do */
1412 }
1413 else if (instMatch.inputs == INPUT_1V_T) {
1414 GLubyte unit, idx;
1415 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1416 RETURN_ERROR;
1417 if (!Parse_String(parseState, ","))
1418 RETURN_ERROR1("Expected ,");
1419 if (!Parse_TextureImageId(parseState, &unit, &idx))
1420 RETURN_ERROR;
1421 inst->TexSrcUnit = unit;
1422 inst->TexSrcTarget = idx;
1423 }
1424 else if (instMatch.inputs == INPUT_3V_T) {
1425 GLubyte unit, idx;
1426 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1427 RETURN_ERROR;
1428 if (!Parse_String(parseState, ","))
1429 RETURN_ERROR1("Expected ,");
1430 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1431 RETURN_ERROR;
1432 if (!Parse_String(parseState, ","))
1433 RETURN_ERROR1("Expected ,");
1434 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1435 RETURN_ERROR;
1436 if (!Parse_String(parseState, ","))
1437 RETURN_ERROR1("Expected ,");
1438 if (!Parse_TextureImageId(parseState, &unit, &idx))
1439 RETURN_ERROR;
1440 inst->TexSrcUnit = unit;
1441 inst->TexSrcTarget = idx;
1442 }
1443 else if (instMatch.inputs == INPUT_1V_S) {
1444 if (!Parse_PrintInstruction(parseState, inst))
1445 RETURN_ERROR;
1446 }
1447
1448 /* end of statement semicolon */
1449 if (!Parse_String(parseState, ";"))
1450 RETURN_ERROR1("Expected ;");
1451
1452 parseState->numInst++;
1453
1454 if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
1455 RETURN_ERROR1("Program too long");
1456 }
1457 }
1458 return GL_TRUE;
1459 }
1460
1461
1462
1463 /**
1464 * Parse/compile the 'str' returning the compiled 'program'.
1465 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1466 * indicates the position of the error in 'str'.
1467 */
1468 void
1469 _mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget,
1470 const GLubyte *str, GLsizei len,
1471 struct gl_fragment_program *program)
1472 {
1473 struct parse_state parseState;
1474 struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
1475 struct prog_instruction *newInst;
1476 GLenum target;
1477 GLubyte *programString;
1478
1479 /* Make a null-terminated copy of the program string */
1480 programString = (GLubyte *) MALLOC(len + 1);
1481 if (!programString) {
1482 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1483 return;
1484 }
1485 MEMCPY(programString, str, len);
1486 programString[len] = 0;
1487
1488 /* Get ready to parse */
1489 _mesa_bzero(&parseState, sizeof(struct parse_state));
1490 parseState.ctx = ctx;
1491 parseState.start = programString;
1492 parseState.program = program;
1493 parseState.numInst = 0;
1494 parseState.curLine = programString;
1495 parseState.parameters = _mesa_new_parameter_list();
1496
1497 /* Reset error state */
1498 _mesa_set_program_error(ctx, -1, NULL);
1499
1500 /* check the program header */
1501 if (_mesa_strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
1502 target = GL_FRAGMENT_PROGRAM_NV;
1503 parseState.pos = programString + 7;
1504 }
1505 else if (_mesa_strncmp((const char *) programString, "!!FCP1.0", 8) == 0) {
1506 /* fragment / register combiner program - not supported */
1507 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1508 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1509 return;
1510 }
1511 else {
1512 /* invalid header */
1513 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1514 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1515 return;
1516 }
1517
1518 /* make sure target and header match */
1519 if (target != dstTarget) {
1520 _mesa_error(ctx, GL_INVALID_OPERATION,
1521 "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1522 target, dstTarget);
1523 return;
1524 }
1525
1526 if (Parse_InstructionSequence(&parseState, instBuffer)) {
1527 GLuint u;
1528 /* successful parse! */
1529
1530 if (parseState.outputsWritten == 0) {
1531 /* must write at least one output! */
1532 _mesa_error(ctx, GL_INVALID_OPERATION,
1533 "Invalid fragment program - no outputs written.");
1534 return;
1535 }
1536
1537 /* copy the compiled instructions */
1538 assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
1539 newInst = _mesa_alloc_instructions(parseState.numInst);
1540 if (!newInst) {
1541 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1542 return; /* out of memory */
1543 }
1544 _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
1545
1546 /* install the program */
1547 program->Base.Target = target;
1548 if (program->Base.String) {
1549 FREE(program->Base.String);
1550 }
1551 program->Base.String = programString;
1552 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1553 if (program->Base.Instructions) {
1554 _mesa_free(program->Base.Instructions);
1555 }
1556 program->Base.Instructions = newInst;
1557 program->Base.NumInstructions = parseState.numInst;
1558 program->Base.InputsRead = parseState.inputsRead;
1559 program->Base.OutputsWritten = parseState.outputsWritten;
1560 for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
1561 program->Base.TexturesUsed[u] = parseState.texturesUsed[u];
1562
1563 /* save program parameters */
1564 program->Base.Parameters = parseState.parameters;
1565
1566 /* allocate registers for declared program parameters */
1567 #if 00
1568 _mesa_assign_program_registers(&(program->SymbolTable));
1569 #endif
1570
1571 #ifdef DEBUG_foo
1572 _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
1573 _mesa_print_nv_fragment_program(program);
1574 _mesa_printf("----------------------------------\n");
1575 #endif
1576 }
1577 else {
1578 /* Error! */
1579 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1580 /* NOTE: _mesa_set_program_error would have been called already */
1581 }
1582 }
1583
1584
1585 static void
1586 PrintSrcReg(const struct gl_fragment_program *program,
1587 const struct prog_src_register *src)
1588 {
1589 static const char comps[5] = "xyzw";
1590
1591 if (src->NegateAbs) {
1592 _mesa_printf("-");
1593 }
1594 if (src->Abs) {
1595 _mesa_printf("|");
1596 }
1597 if (src->NegateBase) {
1598 _mesa_printf("-");
1599 }
1600 if (src->File == PROGRAM_NAMED_PARAM) {
1601 if (program->Base.Parameters->Parameters[src->Index].Type
1602 == PROGRAM_CONSTANT) {
1603 const GLfloat *v;
1604 v = program->Base.Parameters->ParameterValues[src->Index];
1605 _mesa_printf("{%g, %g, %g, %g}", v[0], v[1], v[2], v[3]);
1606 }
1607 else {
1608 ASSERT(program->Base.Parameters->Parameters[src->Index].Type
1609 == PROGRAM_NAMED_PARAM);
1610 _mesa_printf("%s", program->Base.Parameters->Parameters[src->Index].Name);
1611 }
1612 }
1613 else if (src->File == PROGRAM_OUTPUT) {
1614 _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1615 }
1616 else if (src->File == PROGRAM_INPUT) {
1617 _mesa_printf("f[%s]", InputRegisters[src->Index]);
1618 }
1619 else if (src->File == PROGRAM_LOCAL_PARAM) {
1620 _mesa_printf("p[%d]", src->Index);
1621 }
1622 else if (src->File == PROGRAM_TEMPORARY) {
1623 if (src->Index >= 32)
1624 _mesa_printf("H%d", src->Index);
1625 else
1626 _mesa_printf("R%d", src->Index);
1627 }
1628 else if (src->File == PROGRAM_WRITE_ONLY) {
1629 _mesa_printf("%cC", "HR"[src->Index]);
1630 }
1631 else {
1632 _mesa_problem(NULL, "Invalid fragment register %d", src->Index);
1633 return;
1634 }
1635 if (GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 1) &&
1636 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 2) &&
1637 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 3)) {
1638 _mesa_printf(".%c", comps[GET_SWZ(src->Swizzle, 0)]);
1639 }
1640 else if (src->Swizzle != SWIZZLE_NOOP) {
1641 _mesa_printf(".%c%c%c%c",
1642 comps[GET_SWZ(src->Swizzle, 0)],
1643 comps[GET_SWZ(src->Swizzle, 1)],
1644 comps[GET_SWZ(src->Swizzle, 2)],
1645 comps[GET_SWZ(src->Swizzle, 3)]);
1646 }
1647 if (src->Abs) {
1648 _mesa_printf("|");
1649 }
1650 }
1651
1652 static void
1653 PrintTextureSrc(const struct prog_instruction *inst)
1654 {
1655 _mesa_printf("TEX%d, ", inst->TexSrcUnit);
1656 switch (inst->TexSrcTarget) {
1657 case TEXTURE_1D_INDEX:
1658 _mesa_printf("1D");
1659 break;
1660 case TEXTURE_2D_INDEX:
1661 _mesa_printf("2D");
1662 break;
1663 case TEXTURE_3D_INDEX:
1664 _mesa_printf("3D");
1665 break;
1666 case TEXTURE_RECT_INDEX:
1667 _mesa_printf("RECT");
1668 break;
1669 case TEXTURE_CUBE_INDEX:
1670 _mesa_printf("CUBE");
1671 break;
1672 default:
1673 _mesa_problem(NULL, "Invalid textue target in PrintTextureSrc");
1674 }
1675 }
1676
1677 static void
1678 PrintCondCode(const struct prog_dst_register *dst)
1679 {
1680 static const char *comps = "xyzw";
1681 static const char *ccString[] = {
1682 "??", "GT", "EQ", "LT", "UN", "GE", "LE", "NE", "TR", "FL", "??"
1683 };
1684
1685 _mesa_printf("%s", ccString[dst->CondMask]);
1686 if (GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 1) &&
1687 GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 2) &&
1688 GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 3)) {
1689 _mesa_printf(".%c", comps[GET_SWZ(dst->CondSwizzle, 0)]);
1690 }
1691 else if (dst->CondSwizzle != SWIZZLE_NOOP) {
1692 _mesa_printf(".%c%c%c%c",
1693 comps[GET_SWZ(dst->CondSwizzle, 0)],
1694 comps[GET_SWZ(dst->CondSwizzle, 1)],
1695 comps[GET_SWZ(dst->CondSwizzle, 2)],
1696 comps[GET_SWZ(dst->CondSwizzle, 3)]);
1697 }
1698 }
1699
1700
1701 static void
1702 PrintDstReg(const struct prog_dst_register *dst)
1703 {
1704 if (dst->File == PROGRAM_OUTPUT) {
1705 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1706 }
1707 else if (dst->File == PROGRAM_TEMPORARY) {
1708 if (dst->Index >= 32)
1709 _mesa_printf("H%d", dst->Index);
1710 else
1711 _mesa_printf("R%d", dst->Index);
1712 }
1713 else if (dst->File == PROGRAM_LOCAL_PARAM) {
1714 _mesa_printf("p[%d]", dst->Index);
1715 }
1716 else if (dst->File == PROGRAM_WRITE_ONLY) {
1717 _mesa_printf("%cC", "HR"[dst->Index]);
1718 }
1719 else {
1720 _mesa_printf("???");
1721 }
1722
1723 if (dst->WriteMask != 0 && dst->WriteMask != WRITEMASK_XYZW) {
1724 _mesa_printf(".");
1725 if (dst->WriteMask & WRITEMASK_X)
1726 _mesa_printf("x");
1727 if (dst->WriteMask & WRITEMASK_Y)
1728 _mesa_printf("y");
1729 if (dst->WriteMask & WRITEMASK_Z)
1730 _mesa_printf("z");
1731 if (dst->WriteMask & WRITEMASK_W)
1732 _mesa_printf("w");
1733 }
1734
1735 if (dst->CondMask != COND_TR ||
1736 dst->CondSwizzle != SWIZZLE_NOOP) {
1737 _mesa_printf(" (");
1738 PrintCondCode(dst);
1739 _mesa_printf(")");
1740 }
1741 }
1742
1743
1744 /**
1745 * Print (unparse) the given vertex program. Just for debugging.
1746 */
1747 void
1748 _mesa_print_nv_fragment_program(const struct gl_fragment_program *program)
1749 {
1750 const struct prog_instruction *inst;
1751
1752 for (inst = program->Base.Instructions; inst->Opcode != OPCODE_END; inst++) {
1753 int i;
1754 for (i = 0; Instructions[i].name; i++) {
1755 if (inst->Opcode == Instructions[i].opcode) {
1756 /* print instruction name */
1757 _mesa_printf("%s", Instructions[i].name);
1758 if (inst->Precision == FLOAT16)
1759 _mesa_printf("H");
1760 else if (inst->Precision == FIXED12)
1761 _mesa_printf("X");
1762 if (inst->CondUpdate)
1763 _mesa_printf("C");
1764 if (inst->SaturateMode == SATURATE_ZERO_ONE)
1765 _mesa_printf("_SAT");
1766 _mesa_printf(" ");
1767
1768 if (Instructions[i].inputs == INPUT_CC) {
1769 PrintCondCode(&inst->DstReg);
1770 }
1771 else if (Instructions[i].outputs == OUTPUT_V ||
1772 Instructions[i].outputs == OUTPUT_S) {
1773 /* print dest register */
1774 PrintDstReg(&inst->DstReg);
1775 _mesa_printf(", ");
1776 }
1777
1778 /* print source register(s) */
1779 if (Instructions[i].inputs == INPUT_1V ||
1780 Instructions[i].inputs == INPUT_1S) {
1781 PrintSrcReg(program, &inst->SrcReg[0]);
1782 }
1783 else if (Instructions[i].inputs == INPUT_2V ||
1784 Instructions[i].inputs == INPUT_2S) {
1785 PrintSrcReg(program, &inst->SrcReg[0]);
1786 _mesa_printf(", ");
1787 PrintSrcReg(program, &inst->SrcReg[1]);
1788 }
1789 else if (Instructions[i].inputs == INPUT_3V) {
1790 PrintSrcReg(program, &inst->SrcReg[0]);
1791 _mesa_printf(", ");
1792 PrintSrcReg(program, &inst->SrcReg[1]);
1793 _mesa_printf(", ");
1794 PrintSrcReg(program, &inst->SrcReg[2]);
1795 }
1796 else if (Instructions[i].inputs == INPUT_1V_T) {
1797 PrintSrcReg(program, &inst->SrcReg[0]);
1798 _mesa_printf(", ");
1799 PrintTextureSrc(inst);
1800 }
1801 else if (Instructions[i].inputs == INPUT_3V_T) {
1802 PrintSrcReg(program, &inst->SrcReg[0]);
1803 _mesa_printf(", ");
1804 PrintSrcReg(program, &inst->SrcReg[1]);
1805 _mesa_printf(", ");
1806 PrintSrcReg(program, &inst->SrcReg[2]);
1807 _mesa_printf(", ");
1808 PrintTextureSrc(inst);
1809 }
1810 _mesa_printf(";\n");
1811 break;
1812 }
1813 }
1814 if (!Instructions[i].name) {
1815 _mesa_printf("Invalid opcode %d\n", inst->Opcode);
1816 }
1817 }
1818 _mesa_printf("END\n");
1819 }
1820
1821
1822 const char *
1823 _mesa_nv_fragment_input_register_name(GLuint i)
1824 {
1825 ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
1826 return InputRegisters[i];
1827 }
1828
1829
1830 const char *
1831 _mesa_nv_fragment_output_register_name(GLuint i)
1832 {
1833 ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_OUTPUTS);
1834 return OutputRegisters[i];
1835 }