mesa: rename, reorder FRAG_RESULT_x tokens
[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
388 static const char *OutputRegisters[MAX_NV_FRAGMENT_PROGRAM_OUTPUTS + 1] = {
389 "DEPR", "COLR", "DATA0", NULL
390 };
391
392
393 /**********************************************************************/
394
395 /**
396 * Try to match 'pattern' as the next token after any whitespace/comments.
397 */
398 static GLboolean
399 Parse_String(struct parse_state *parseState, const char *pattern)
400 {
401 const GLubyte *m;
402 GLint i;
403
404 /* skip whitespace and comments */
405 while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
406 if (*parseState->pos == '#') {
407 while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
408 parseState->pos += 1;
409 }
410 if (*parseState->pos == '\n' || *parseState->pos == '\r')
411 parseState->curLine = parseState->pos + 1;
412 }
413 else {
414 /* skip whitespace */
415 if (*parseState->pos == '\n' || *parseState->pos == '\r')
416 parseState->curLine = parseState->pos + 1;
417 parseState->pos += 1;
418 }
419 }
420
421 /* Try to match the pattern */
422 m = parseState->pos;
423 for (i = 0; pattern[i]; i++) {
424 if (*m != (GLubyte) pattern[i])
425 return GL_FALSE;
426 m += 1;
427 }
428 parseState->pos = m;
429
430 return GL_TRUE; /* success */
431 }
432
433
434 static GLboolean
435 Parse_Identifier(struct parse_state *parseState, GLubyte *ident)
436 {
437 if (!Parse_Token(parseState, ident))
438 RETURN_ERROR;
439 if (IsLetter(ident[0]))
440 return GL_TRUE;
441 else
442 RETURN_ERROR1("Expected an identfier");
443 }
444
445
446 /**
447 * Parse a floating point constant, or a defined symbol name.
448 * [+/-]N[.N[eN]]
449 * Output: number[0 .. 3] will get the value.
450 */
451 static GLboolean
452 Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number)
453 {
454 char *end = NULL;
455
456 *number = (GLfloat) _mesa_strtod((const char *) parseState->pos, &end);
457
458 if (end && end > (char *) parseState->pos) {
459 /* got a number */
460 parseState->pos = (GLubyte *) end;
461 number[1] = *number;
462 number[2] = *number;
463 number[3] = *number;
464 return GL_TRUE;
465 }
466 else {
467 /* should be an identifier */
468 GLubyte ident[100];
469 const GLfloat *constant;
470 if (!Parse_Identifier(parseState, ident))
471 RETURN_ERROR1("Expected an identifier");
472 constant = _mesa_lookup_parameter_value(parseState->parameters,
473 -1, (const char *) ident);
474 /* XXX Check that it's a constant and not a parameter */
475 if (!constant) {
476 RETURN_ERROR1("Undefined symbol");
477 }
478 else {
479 COPY_4V(number, constant);
480 return GL_TRUE;
481 }
482 }
483 }
484
485
486
487 /**
488 * Parse a vector constant, one of:
489 * { float }
490 * { float, float }
491 * { float, float, float }
492 * { float, float, float, float }
493 */
494 static GLboolean
495 Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
496 {
497 /* "{" was already consumed */
498
499 ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0);
500
501 if (!Parse_ScalarConstant(parseState, vec+0)) /* X */
502 return GL_FALSE;
503
504 if (Parse_String(parseState, "}")) {
505 return GL_TRUE;
506 }
507
508 if (!Parse_String(parseState, ","))
509 RETURN_ERROR1("Expected comma in vector constant");
510
511 if (!Parse_ScalarConstant(parseState, vec+1)) /* Y */
512 return GL_FALSE;
513
514 if (Parse_String(parseState, "}")) {
515 return GL_TRUE;
516 }
517
518 if (!Parse_String(parseState, ","))
519 RETURN_ERROR1("Expected comma in vector constant");
520
521 if (!Parse_ScalarConstant(parseState, vec+2)) /* Z */
522 return GL_FALSE;
523
524 if (Parse_String(parseState, "}")) {
525 return GL_TRUE;
526 }
527
528 if (!Parse_String(parseState, ","))
529 RETURN_ERROR1("Expected comma in vector constant");
530
531 if (!Parse_ScalarConstant(parseState, vec+3)) /* W */
532 return GL_FALSE;
533
534 if (!Parse_String(parseState, "}"))
535 RETURN_ERROR1("Expected closing brace in vector constant");
536
537 return GL_TRUE;
538 }
539
540
541 /**
542 * Parse <number>, <varname> or {a, b, c, d}.
543 * Return number of values in the vector or scalar, or zero if parse error.
544 */
545 static GLuint
546 Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec)
547 {
548 if (Parse_String(parseState, "{")) {
549 return Parse_VectorConstant(parseState, vec);
550 }
551 else {
552 GLboolean b = Parse_ScalarConstant(parseState, vec);
553 if (b) {
554 vec[1] = vec[2] = vec[3] = vec[0];
555 }
556 return b;
557 }
558 }
559
560
561 /**
562 * Parse a texture image source:
563 * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
564 */
565 static GLboolean
566 Parse_TextureImageId(struct parse_state *parseState,
567 GLubyte *texUnit, GLubyte *texTargetBit)
568 {
569 GLubyte imageSrc[100];
570 GLint unit;
571
572 if (!Parse_Token(parseState, imageSrc))
573 RETURN_ERROR;
574
575 if (imageSrc[0] != 'T' ||
576 imageSrc[1] != 'E' ||
577 imageSrc[2] != 'X') {
578 RETURN_ERROR1("Expected TEX# source");
579 }
580 unit = _mesa_atoi((const char *) imageSrc + 3);
581 if ((unit < 0 || unit > MAX_TEXTURE_IMAGE_UNITS) ||
582 (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) {
583 RETURN_ERROR1("Invalied TEX# source index");
584 }
585 *texUnit = unit;
586
587 if (!Parse_String(parseState, ","))
588 RETURN_ERROR1("Expected ,");
589
590 if (Parse_String(parseState, "1D")) {
591 *texTargetBit = TEXTURE_1D_BIT;
592 }
593 else if (Parse_String(parseState, "2D")) {
594 *texTargetBit = TEXTURE_2D_BIT;
595 }
596 else if (Parse_String(parseState, "3D")) {
597 *texTargetBit = TEXTURE_3D_BIT;
598 }
599 else if (Parse_String(parseState, "CUBE")) {
600 *texTargetBit = TEXTURE_CUBE_BIT;
601 }
602 else if (Parse_String(parseState, "RECT")) {
603 *texTargetBit = TEXTURE_RECT_BIT;
604 }
605 else {
606 RETURN_ERROR1("Invalid texture target token");
607 }
608
609 /* update record of referenced texture units */
610 parseState->texturesUsed[*texUnit] |= *texTargetBit;
611 if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) {
612 RETURN_ERROR1("Only one texture target can be used per texture unit.");
613 }
614
615 return GL_TRUE;
616 }
617
618
619 /**
620 * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
621 * like .wxyz, .xxyy, etc and return the swizzle indexes.
622 */
623 static GLboolean
624 Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4])
625 {
626 if (token[1] == 0) {
627 /* single letter swizzle (scalar) */
628 if (token[0] == 'x')
629 ASSIGN_4V(swizzle, 0, 0, 0, 0);
630 else if (token[0] == 'y')
631 ASSIGN_4V(swizzle, 1, 1, 1, 1);
632 else if (token[0] == 'z')
633 ASSIGN_4V(swizzle, 2, 2, 2, 2);
634 else if (token[0] == 'w')
635 ASSIGN_4V(swizzle, 3, 3, 3, 3);
636 else
637 return GL_FALSE;
638 }
639 else {
640 /* 4-component swizzle (vector) */
641 GLint k;
642 for (k = 0; token[k] && k < 4; k++) {
643 if (token[k] == 'x')
644 swizzle[k] = 0;
645 else if (token[k] == 'y')
646 swizzle[k] = 1;
647 else if (token[k] == 'z')
648 swizzle[k] = 2;
649 else if (token[k] == 'w')
650 swizzle[k] = 3;
651 else
652 return GL_FALSE;
653 }
654 if (k != 4)
655 return GL_FALSE;
656 }
657 return GL_TRUE;
658 }
659
660
661 static GLboolean
662 Parse_CondCodeMask(struct parse_state *parseState,
663 struct prog_dst_register *dstReg)
664 {
665 if (Parse_String(parseState, "EQ"))
666 dstReg->CondMask = COND_EQ;
667 else if (Parse_String(parseState, "GE"))
668 dstReg->CondMask = COND_GE;
669 else if (Parse_String(parseState, "GT"))
670 dstReg->CondMask = COND_GT;
671 else if (Parse_String(parseState, "LE"))
672 dstReg->CondMask = COND_LE;
673 else if (Parse_String(parseState, "LT"))
674 dstReg->CondMask = COND_LT;
675 else if (Parse_String(parseState, "NE"))
676 dstReg->CondMask = COND_NE;
677 else if (Parse_String(parseState, "TR"))
678 dstReg->CondMask = COND_TR;
679 else if (Parse_String(parseState, "FL"))
680 dstReg->CondMask = COND_FL;
681 else
682 RETURN_ERROR1("Invalid condition code mask");
683
684 /* look for optional .xyzw swizzle */
685 if (Parse_String(parseState, ".")) {
686 GLubyte token[100];
687 GLuint swz[4];
688
689 if (!Parse_Token(parseState, token)) /* get xyzw suffix */
690 RETURN_ERROR;
691
692 if (!Parse_SwizzleSuffix(token, swz))
693 RETURN_ERROR1("Invalid swizzle suffix");
694
695 dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
696 }
697
698 return GL_TRUE;
699 }
700
701
702 /**
703 * Parse a temporary register: Rnn or Hnn
704 */
705 static GLboolean
706 Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
707 {
708 GLubyte token[100];
709
710 /* Should be 'R##' or 'H##' */
711 if (!Parse_Token(parseState, token))
712 RETURN_ERROR;
713 if (token[0] != 'R' && token[0] != 'H')
714 RETURN_ERROR1("Expected R## or H##");
715
716 if (IsDigit(token[1])) {
717 GLint reg = _mesa_atoi((const char *) (token + 1));
718 if (token[0] == 'H')
719 reg += 32;
720 if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS)
721 RETURN_ERROR1("Invalid temporary register name");
722 *tempRegNum = reg;
723 }
724 else {
725 RETURN_ERROR1("Invalid temporary register name");
726 }
727
728 return GL_TRUE;
729 }
730
731
732 /**
733 * Parse a write-only dummy register: RC or HC.
734 */
735 static GLboolean
736 Parse_DummyReg(struct parse_state *parseState, GLint *regNum)
737 {
738 if (Parse_String(parseState, "RC")) {
739 *regNum = 0;
740 }
741 else if (Parse_String(parseState, "HC")) {
742 *regNum = 1;
743 }
744 else {
745 RETURN_ERROR1("Invalid write-only register name");
746 }
747
748 return GL_TRUE;
749 }
750
751
752 /**
753 * Parse a program local parameter register "p[##]"
754 */
755 static GLboolean
756 Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum)
757 {
758 GLubyte token[100];
759
760 if (!Parse_String(parseState, "p["))
761 RETURN_ERROR1("Expected p[");
762
763 if (!Parse_Token(parseState, token))
764 RETURN_ERROR;
765
766 if (IsDigit(token[0])) {
767 /* a numbered program parameter register */
768 GLint reg = _mesa_atoi((const char *) token);
769 if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS)
770 RETURN_ERROR1("Invalid constant program number");
771 *regNum = reg;
772 }
773 else {
774 RETURN_ERROR;
775 }
776
777 if (!Parse_String(parseState, "]"))
778 RETURN_ERROR1("Expected ]");
779
780 return GL_TRUE;
781 }
782
783
784 /**
785 * Parse f[name] - fragment input register
786 */
787 static GLboolean
788 Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum)
789 {
790 GLubyte token[100];
791 GLint j;
792
793 /* Match 'f[' */
794 if (!Parse_String(parseState, "f["))
795 RETURN_ERROR1("Expected f[");
796
797 /* get <name> and look for match */
798 if (!Parse_Token(parseState, token)) {
799 RETURN_ERROR;
800 }
801 for (j = 0; InputRegisters[j]; j++) {
802 if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
803 *tempRegNum = j;
804 parseState->inputsRead |= (1 << j);
805 break;
806 }
807 }
808 if (!InputRegisters[j]) {
809 /* unknown input register label */
810 RETURN_ERROR2("Invalid register name", token);
811 }
812
813 /* Match '[' */
814 if (!Parse_String(parseState, "]"))
815 RETURN_ERROR1("Expected ]");
816
817 return GL_TRUE;
818 }
819
820
821 static GLboolean
822 Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
823 {
824 GLubyte token[100];
825
826 /* Match "o[" */
827 if (!Parse_String(parseState, "o["))
828 RETURN_ERROR1("Expected o[");
829
830 /* Get output reg name */
831 if (!Parse_Token(parseState, token))
832 RETURN_ERROR;
833
834 /* try to match an output register name */
835 if (_mesa_strcmp((char *) token, "COLR") == 0 ||
836 _mesa_strcmp((char *) token, "COLH") == 0) {
837 /* note that we don't distinguish between COLR and COLH */
838 *outputRegNum = FRAG_RESULT_COLOR;
839 parseState->outputsWritten |= (1 << FRAG_RESULT_COLOR);
840 }
841 else if (_mesa_strcmp((char *) token, "DEPR") == 0) {
842 *outputRegNum = FRAG_RESULT_DEPTH;
843 parseState->outputsWritten |= (1 << FRAG_RESULT_DEPTH);
844 }
845 else {
846 RETURN_ERROR1("Invalid output register name");
847 }
848
849 /* Match ']' */
850 if (!Parse_String(parseState, "]"))
851 RETURN_ERROR1("Expected ]");
852
853 return GL_TRUE;
854 }
855
856
857 static GLboolean
858 Parse_MaskedDstReg(struct parse_state *parseState,
859 struct prog_dst_register *dstReg)
860 {
861 GLubyte token[100];
862 GLint idx;
863
864 /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
865 if (!Peek_Token(parseState, token))
866 RETURN_ERROR;
867
868 if (_mesa_strcmp((const char *) token, "RC") == 0 ||
869 _mesa_strcmp((const char *) token, "HC") == 0) {
870 /* a write-only register */
871 dstReg->File = PROGRAM_WRITE_ONLY;
872 if (!Parse_DummyReg(parseState, &idx))
873 RETURN_ERROR;
874 dstReg->Index = idx;
875 }
876 else if (token[0] == 'R' || token[0] == 'H') {
877 /* a temporary register */
878 dstReg->File = PROGRAM_TEMPORARY;
879 if (!Parse_TempReg(parseState, &idx))
880 RETURN_ERROR;
881 dstReg->Index = idx;
882 }
883 else if (token[0] == 'o') {
884 /* an output register */
885 dstReg->File = PROGRAM_OUTPUT;
886 if (!Parse_OutputReg(parseState, &idx))
887 RETURN_ERROR;
888 dstReg->Index = idx;
889 }
890 else {
891 RETURN_ERROR1("Invalid destination register name");
892 }
893
894 /* Parse optional write mask */
895 if (Parse_String(parseState, ".")) {
896 /* got a mask */
897 GLint k = 0;
898
899 if (!Parse_Token(parseState, token)) /* get xyzw writemask */
900 RETURN_ERROR;
901
902 dstReg->WriteMask = 0;
903
904 if (token[k] == 'x') {
905 dstReg->WriteMask |= WRITEMASK_X;
906 k++;
907 }
908 if (token[k] == 'y') {
909 dstReg->WriteMask |= WRITEMASK_Y;
910 k++;
911 }
912 if (token[k] == 'z') {
913 dstReg->WriteMask |= WRITEMASK_Z;
914 k++;
915 }
916 if (token[k] == 'w') {
917 dstReg->WriteMask |= WRITEMASK_W;
918 k++;
919 }
920 if (k == 0) {
921 RETURN_ERROR1("Invalid writemask character");
922 }
923
924 }
925 else {
926 dstReg->WriteMask = WRITEMASK_XYZW;
927 }
928
929 /* optional condition code mask */
930 if (Parse_String(parseState, "(")) {
931 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
932 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
933 if (!Parse_CondCodeMask(parseState, dstReg))
934 RETURN_ERROR;
935
936 if (!Parse_String(parseState, ")")) /* consume ")" */
937 RETURN_ERROR1("Expected )");
938
939 return GL_TRUE;
940 }
941 else {
942 /* no cond code mask */
943 dstReg->CondMask = COND_TR;
944 dstReg->CondSwizzle = SWIZZLE_NOOP;
945 return GL_TRUE;
946 }
947 }
948
949
950 /**
951 * Parse a vector source (register, constant, etc):
952 * <vectorSrc> ::= <absVectorSrc>
953 * | <baseVectorSrc>
954 * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
955 */
956 static GLboolean
957 Parse_VectorSrc(struct parse_state *parseState,
958 struct prog_src_register *srcReg)
959 {
960 GLfloat sign = 1.0F;
961 GLubyte token[100];
962 GLint idx;
963
964 /*
965 * First, take care of +/- and absolute value stuff.
966 */
967 if (Parse_String(parseState, "-"))
968 sign = -1.0F;
969 else if (Parse_String(parseState, "+"))
970 sign = +1.0F;
971
972 if (Parse_String(parseState, "|")) {
973 srcReg->Abs = GL_TRUE;
974 srcReg->NegateAbs = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
975
976 if (Parse_String(parseState, "-"))
977 srcReg->NegateBase = NEGATE_XYZW;
978 else if (Parse_String(parseState, "+"))
979 srcReg->NegateBase = NEGATE_NONE;
980 else
981 srcReg->NegateBase = NEGATE_NONE;
982 }
983 else {
984 srcReg->Abs = GL_FALSE;
985 srcReg->NegateAbs = GL_FALSE;
986 srcReg->NegateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
987 }
988
989 /* This should be the real src vector/register name */
990 if (!Peek_Token(parseState, token))
991 RETURN_ERROR;
992
993 /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
994 * literal or vector literal.
995 */
996 if (token[0] == 'R' || token[0] == 'H') {
997 srcReg->File = PROGRAM_TEMPORARY;
998 if (!Parse_TempReg(parseState, &idx))
999 RETURN_ERROR;
1000 srcReg->Index = idx;
1001 }
1002 else if (token[0] == 'f') {
1003 /* XXX this might be an identifier! */
1004 srcReg->File = PROGRAM_INPUT;
1005 if (!Parse_FragReg(parseState, &idx))
1006 RETURN_ERROR;
1007 srcReg->Index = idx;
1008 }
1009 else if (token[0] == 'p') {
1010 /* XXX this might be an identifier! */
1011 srcReg->File = PROGRAM_LOCAL_PARAM;
1012 if (!Parse_ProgramParamReg(parseState, &idx))
1013 RETURN_ERROR;
1014 srcReg->Index = idx;
1015 }
1016 else if (IsLetter(token[0])){
1017 GLubyte ident[100];
1018 GLint paramIndex;
1019 if (!Parse_Identifier(parseState, ident))
1020 RETURN_ERROR;
1021 paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1022 -1, (const char *) ident);
1023 if (paramIndex < 0) {
1024 RETURN_ERROR2("Undefined constant or parameter: ", ident);
1025 }
1026 srcReg->File = PROGRAM_NAMED_PARAM;
1027 srcReg->Index = paramIndex;
1028 }
1029 else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){
1030 /* literal scalar constant */
1031 GLfloat values[4];
1032 GLuint paramIndex;
1033 if (!Parse_ScalarConstant(parseState, values))
1034 RETURN_ERROR;
1035 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1036 values, 4, NULL);
1037 srcReg->File = PROGRAM_NAMED_PARAM;
1038 srcReg->Index = paramIndex;
1039 }
1040 else if (token[0] == '{'){
1041 /* literal vector constant */
1042 GLfloat values[4];
1043 GLuint paramIndex;
1044 (void) Parse_String(parseState, "{");
1045 if (!Parse_VectorConstant(parseState, values))
1046 RETURN_ERROR;
1047 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1048 values, 4, NULL);
1049 srcReg->File = PROGRAM_NAMED_PARAM;
1050 srcReg->Index = paramIndex;
1051 }
1052 else {
1053 RETURN_ERROR2("Invalid source register name", token);
1054 }
1055
1056 /* init swizzle fields */
1057 srcReg->Swizzle = SWIZZLE_NOOP;
1058
1059 /* Look for optional swizzle suffix */
1060 if (Parse_String(parseState, ".")) {
1061 GLuint swz[4];
1062
1063 if (!Parse_Token(parseState, token))
1064 RETURN_ERROR;
1065
1066 if (!Parse_SwizzleSuffix(token, swz))
1067 RETURN_ERROR1("Invalid swizzle suffix");
1068
1069 srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
1070 }
1071
1072 /* Finish absolute value */
1073 if (srcReg->Abs && !Parse_String(parseState, "|")) {
1074 RETURN_ERROR1("Expected |");
1075 }
1076
1077 return GL_TRUE;
1078 }
1079
1080
1081 static GLboolean
1082 Parse_ScalarSrcReg(struct parse_state *parseState,
1083 struct prog_src_register *srcReg)
1084 {
1085 GLubyte token[100];
1086 GLfloat sign = 1.0F;
1087 GLboolean needSuffix = GL_TRUE;
1088 GLint idx;
1089
1090 /*
1091 * First, take care of +/- and absolute value stuff.
1092 */
1093 if (Parse_String(parseState, "-"))
1094 sign = -1.0F;
1095 else if (Parse_String(parseState, "+"))
1096 sign = +1.0F;
1097
1098 if (Parse_String(parseState, "|")) {
1099 srcReg->Abs = GL_TRUE;
1100 srcReg->NegateAbs = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
1101
1102 if (Parse_String(parseState, "-"))
1103 srcReg->NegateBase = NEGATE_XYZW;
1104 else if (Parse_String(parseState, "+"))
1105 srcReg->NegateBase = NEGATE_NONE;
1106 else
1107 srcReg->NegateBase = NEGATE_NONE;
1108 }
1109 else {
1110 srcReg->Abs = GL_FALSE;
1111 srcReg->NegateAbs = GL_FALSE;
1112 srcReg->NegateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
1113 }
1114
1115 if (!Peek_Token(parseState, token))
1116 RETURN_ERROR;
1117
1118 /* Src reg can be R<n>, H<n> or a named fragment attrib */
1119 if (token[0] == 'R' || token[0] == 'H') {
1120 srcReg->File = PROGRAM_TEMPORARY;
1121 if (!Parse_TempReg(parseState, &idx))
1122 RETURN_ERROR;
1123 srcReg->Index = idx;
1124 }
1125 else if (token[0] == 'f') {
1126 srcReg->File = PROGRAM_INPUT;
1127 if (!Parse_FragReg(parseState, &idx))
1128 RETURN_ERROR;
1129 srcReg->Index = idx;
1130 }
1131 else if (token[0] == '{') {
1132 /* vector literal */
1133 GLfloat values[4];
1134 GLuint paramIndex;
1135 (void) Parse_String(parseState, "{");
1136 if (!Parse_VectorConstant(parseState, values))
1137 RETURN_ERROR;
1138 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1139 values, 4, NULL);
1140 srcReg->File = PROGRAM_NAMED_PARAM;
1141 srcReg->Index = paramIndex;
1142 }
1143 else if (IsLetter(token[0])){
1144 /* named param/constant */
1145 GLubyte ident[100];
1146 GLint paramIndex;
1147 if (!Parse_Identifier(parseState, ident))
1148 RETURN_ERROR;
1149 paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1150 -1, (const char *) ident);
1151 if (paramIndex < 0) {
1152 RETURN_ERROR2("Undefined constant or parameter: ", ident);
1153 }
1154 srcReg->File = PROGRAM_NAMED_PARAM;
1155 srcReg->Index = paramIndex;
1156 }
1157 else if (IsDigit(token[0])) {
1158 /* scalar literal */
1159 GLfloat values[4];
1160 GLuint paramIndex;
1161 if (!Parse_ScalarConstant(parseState, values))
1162 RETURN_ERROR;
1163 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1164 values, 4, NULL);
1165 srcReg->Index = paramIndex;
1166 srcReg->File = PROGRAM_NAMED_PARAM;
1167 needSuffix = GL_FALSE;
1168 }
1169 else {
1170 RETURN_ERROR2("Invalid scalar source argument", token);
1171 }
1172
1173 srcReg->Swizzle = 0;
1174 if (needSuffix) {
1175 /* parse .[xyzw] suffix */
1176 if (!Parse_String(parseState, "."))
1177 RETURN_ERROR1("Expected .");
1178
1179 if (!Parse_Token(parseState, token))
1180 RETURN_ERROR;
1181
1182 if (token[0] == 'x' && token[1] == 0) {
1183 srcReg->Swizzle = 0;
1184 }
1185 else if (token[0] == 'y' && token[1] == 0) {
1186 srcReg->Swizzle = 1;
1187 }
1188 else if (token[0] == 'z' && token[1] == 0) {
1189 srcReg->Swizzle = 2;
1190 }
1191 else if (token[0] == 'w' && token[1] == 0) {
1192 srcReg->Swizzle = 3;
1193 }
1194 else {
1195 RETURN_ERROR1("Invalid scalar source suffix");
1196 }
1197 }
1198
1199 /* Finish absolute value */
1200 if (srcReg->Abs && !Parse_String(parseState, "|")) {
1201 RETURN_ERROR1("Expected |");
1202 }
1203
1204 return GL_TRUE;
1205 }
1206
1207
1208 static GLboolean
1209 Parse_PrintInstruction(struct parse_state *parseState,
1210 struct prog_instruction *inst)
1211 {
1212 const GLubyte *str;
1213 GLubyte *msg;
1214 GLuint len;
1215 GLint idx;
1216
1217 /* The first argument is a literal string 'just like this' */
1218 if (!Parse_String(parseState, "'"))
1219 RETURN_ERROR1("Expected '");
1220
1221 str = parseState->pos;
1222 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1223 ;
1224 parseState->pos += len + 1;
1225 msg = (GLubyte*) _mesa_malloc(len + 1);
1226
1227 _mesa_memcpy(msg, str, len);
1228 msg[len] = 0;
1229 inst->Data = msg;
1230
1231 if (Parse_String(parseState, ",")) {
1232 /* got an optional register to print */
1233 GLubyte token[100];
1234 GetToken(parseState, token);
1235 if (token[0] == 'o') {
1236 /* dst reg */
1237 if (!Parse_OutputReg(parseState, &idx))
1238 RETURN_ERROR;
1239 inst->SrcReg[0].Index = idx;
1240 inst->SrcReg[0].File = PROGRAM_OUTPUT;
1241 }
1242 else {
1243 /* src reg */
1244 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1245 RETURN_ERROR;
1246 }
1247 }
1248 else {
1249 inst->SrcReg[0].File = PROGRAM_UNDEFINED;
1250 }
1251
1252 inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
1253 inst->SrcReg[0].NegateBase = NEGATE_NONE;
1254 inst->SrcReg[0].Abs = GL_FALSE;
1255 inst->SrcReg[0].NegateAbs = GL_FALSE;
1256
1257 return GL_TRUE;
1258 }
1259
1260
1261 static GLboolean
1262 Parse_InstructionSequence(struct parse_state *parseState,
1263 struct prog_instruction program[])
1264 {
1265 while (1) {
1266 struct prog_instruction *inst = program + parseState->numInst;
1267 struct instruction_pattern instMatch;
1268 GLubyte token[100];
1269
1270 /* Initialize the instruction */
1271 _mesa_init_instructions(inst, 1);
1272
1273 /* special instructions */
1274 if (Parse_String(parseState, "DEFINE")) {
1275 GLubyte id[100];
1276 GLfloat value[7]; /* yes, 7 to be safe */
1277 if (!Parse_Identifier(parseState, id))
1278 RETURN_ERROR;
1279 /* XXX make sure id is not a reserved identifer, like R9 */
1280 if (!Parse_String(parseState, "="))
1281 RETURN_ERROR1("Expected =");
1282 if (!Parse_VectorOrScalarConstant(parseState, value))
1283 RETURN_ERROR;
1284 if (!Parse_String(parseState, ";"))
1285 RETURN_ERROR1("Expected ;");
1286 if (_mesa_lookup_parameter_index(parseState->parameters,
1287 -1, (const char *) id) >= 0) {
1288 RETURN_ERROR2(id, "already defined");
1289 }
1290 _mesa_add_named_parameter(parseState->parameters,
1291 (const char *) id, value);
1292 }
1293 else if (Parse_String(parseState, "DECLARE")) {
1294 GLubyte id[100];
1295 GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */
1296 if (!Parse_Identifier(parseState, id))
1297 RETURN_ERROR;
1298 /* XXX make sure id is not a reserved identifer, like R9 */
1299 if (Parse_String(parseState, "=")) {
1300 if (!Parse_VectorOrScalarConstant(parseState, value))
1301 RETURN_ERROR;
1302 }
1303 if (!Parse_String(parseState, ";"))
1304 RETURN_ERROR1("Expected ;");
1305 if (_mesa_lookup_parameter_index(parseState->parameters,
1306 -1, (const char *) id) >= 0) {
1307 RETURN_ERROR2(id, "already declared");
1308 }
1309 _mesa_add_named_parameter(parseState->parameters,
1310 (const char *) id, value);
1311 }
1312 else if (Parse_String(parseState, "END")) {
1313 inst->Opcode = OPCODE_END;
1314 inst->StringPos = parseState->curLine - parseState->start;
1315 assert(inst->StringPos >= 0);
1316 parseState->numInst++;
1317 if (Parse_Token(parseState, token)) {
1318 RETURN_ERROR1("Code after END opcode.");
1319 }
1320 break;
1321 }
1322 else {
1323 /* general/arithmetic instruction */
1324
1325 /* get token */
1326 if (!Parse_Token(parseState, token)) {
1327 RETURN_ERROR1("Missing END instruction.");
1328 }
1329
1330 /* try to find matching instuction */
1331 instMatch = MatchInstruction(token);
1332 if (instMatch.opcode >= MAX_OPCODE) {
1333 /* bad instruction name */
1334 RETURN_ERROR2("Unexpected token: ", token);
1335 }
1336
1337 inst->Opcode = instMatch.opcode;
1338 inst->Precision = instMatch.suffixes & (_R | _H | _X);
1339 inst->SaturateMode = (instMatch.suffixes & (_S))
1340 ? SATURATE_ZERO_ONE : SATURATE_OFF;
1341 inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
1342 inst->StringPos = parseState->curLine - parseState->start;
1343 assert(inst->StringPos >= 0);
1344
1345 /*
1346 * parse the input and output operands
1347 */
1348 if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
1349 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
1350 RETURN_ERROR;
1351 if (!Parse_String(parseState, ","))
1352 RETURN_ERROR1("Expected ,");
1353 }
1354 else if (instMatch.outputs == OUTPUT_NONE) {
1355 if (instMatch.opcode == OPCODE_KIL_NV) {
1356 /* This is a little weird, the cond code info is in
1357 * the dest register.
1358 */
1359 if (!Parse_CondCodeMask(parseState, &inst->DstReg))
1360 RETURN_ERROR;
1361 }
1362 else {
1363 ASSERT(instMatch.opcode == OPCODE_PRINT);
1364 }
1365 }
1366
1367 if (instMatch.inputs == INPUT_1V) {
1368 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1369 RETURN_ERROR;
1370 }
1371 else if (instMatch.inputs == INPUT_2V) {
1372 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1373 RETURN_ERROR;
1374 if (!Parse_String(parseState, ","))
1375 RETURN_ERROR1("Expected ,");
1376 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1377 RETURN_ERROR;
1378 }
1379 else if (instMatch.inputs == INPUT_3V) {
1380 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1381 RETURN_ERROR;
1382 if (!Parse_String(parseState, ","))
1383 RETURN_ERROR1("Expected ,");
1384 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1385 RETURN_ERROR;
1386 if (!Parse_String(parseState, ","))
1387 RETURN_ERROR1("Expected ,");
1388 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1389 RETURN_ERROR;
1390 }
1391 else if (instMatch.inputs == INPUT_1S) {
1392 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1393 RETURN_ERROR;
1394 }
1395 else if (instMatch.inputs == INPUT_2S) {
1396 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1397 RETURN_ERROR;
1398 if (!Parse_String(parseState, ","))
1399 RETURN_ERROR1("Expected ,");
1400 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
1401 RETURN_ERROR;
1402 }
1403 else if (instMatch.inputs == INPUT_CC) {
1404 /* XXX to-do */
1405 }
1406 else if (instMatch.inputs == INPUT_1V_T) {
1407 GLubyte unit, idx;
1408 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1409 RETURN_ERROR;
1410 if (!Parse_String(parseState, ","))
1411 RETURN_ERROR1("Expected ,");
1412 if (!Parse_TextureImageId(parseState, &unit, &idx))
1413 RETURN_ERROR;
1414 inst->TexSrcUnit = unit;
1415 inst->TexSrcTarget = idx;
1416 }
1417 else if (instMatch.inputs == INPUT_3V_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_VectorSrc(parseState, &inst->SrcReg[1]))
1424 RETURN_ERROR;
1425 if (!Parse_String(parseState, ","))
1426 RETURN_ERROR1("Expected ,");
1427 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1428 RETURN_ERROR;
1429 if (!Parse_String(parseState, ","))
1430 RETURN_ERROR1("Expected ,");
1431 if (!Parse_TextureImageId(parseState, &unit, &idx))
1432 RETURN_ERROR;
1433 inst->TexSrcUnit = unit;
1434 inst->TexSrcTarget = idx;
1435 }
1436 else if (instMatch.inputs == INPUT_1V_S) {
1437 if (!Parse_PrintInstruction(parseState, inst))
1438 RETURN_ERROR;
1439 }
1440
1441 /* end of statement semicolon */
1442 if (!Parse_String(parseState, ";"))
1443 RETURN_ERROR1("Expected ;");
1444
1445 parseState->numInst++;
1446
1447 if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
1448 RETURN_ERROR1("Program too long");
1449 }
1450 }
1451 return GL_TRUE;
1452 }
1453
1454
1455
1456 /**
1457 * Parse/compile the 'str' returning the compiled 'program'.
1458 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1459 * indicates the position of the error in 'str'.
1460 */
1461 void
1462 _mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget,
1463 const GLubyte *str, GLsizei len,
1464 struct gl_fragment_program *program)
1465 {
1466 struct parse_state parseState;
1467 struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
1468 struct prog_instruction *newInst;
1469 GLenum target;
1470 GLubyte *programString;
1471
1472 /* Make a null-terminated copy of the program string */
1473 programString = (GLubyte *) MALLOC(len + 1);
1474 if (!programString) {
1475 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1476 return;
1477 }
1478 MEMCPY(programString, str, len);
1479 programString[len] = 0;
1480
1481 /* Get ready to parse */
1482 _mesa_bzero(&parseState, sizeof(struct parse_state));
1483 parseState.ctx = ctx;
1484 parseState.start = programString;
1485 parseState.program = program;
1486 parseState.numInst = 0;
1487 parseState.curLine = programString;
1488 parseState.parameters = _mesa_new_parameter_list();
1489
1490 /* Reset error state */
1491 _mesa_set_program_error(ctx, -1, NULL);
1492
1493 /* check the program header */
1494 if (_mesa_strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
1495 target = GL_FRAGMENT_PROGRAM_NV;
1496 parseState.pos = programString + 7;
1497 }
1498 else if (_mesa_strncmp((const char *) programString, "!!FCP1.0", 8) == 0) {
1499 /* fragment / register combiner program - not supported */
1500 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1501 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1502 return;
1503 }
1504 else {
1505 /* invalid header */
1506 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1507 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1508 return;
1509 }
1510
1511 /* make sure target and header match */
1512 if (target != dstTarget) {
1513 _mesa_error(ctx, GL_INVALID_OPERATION,
1514 "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1515 target, dstTarget);
1516 return;
1517 }
1518
1519 if (Parse_InstructionSequence(&parseState, instBuffer)) {
1520 GLuint u;
1521 /* successful parse! */
1522
1523 if (parseState.outputsWritten == 0) {
1524 /* must write at least one output! */
1525 _mesa_error(ctx, GL_INVALID_OPERATION,
1526 "Invalid fragment program - no outputs written.");
1527 return;
1528 }
1529
1530 /* copy the compiled instructions */
1531 assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
1532 newInst = _mesa_alloc_instructions(parseState.numInst);
1533 if (!newInst) {
1534 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1535 return; /* out of memory */
1536 }
1537 _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
1538
1539 /* install the program */
1540 program->Base.Target = target;
1541 if (program->Base.String) {
1542 FREE(program->Base.String);
1543 }
1544 program->Base.String = programString;
1545 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1546 if (program->Base.Instructions) {
1547 _mesa_free(program->Base.Instructions);
1548 }
1549 program->Base.Instructions = newInst;
1550 program->Base.NumInstructions = parseState.numInst;
1551 program->Base.InputsRead = parseState.inputsRead;
1552 program->Base.OutputsWritten = parseState.outputsWritten;
1553 for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
1554 program->Base.TexturesUsed[u] = parseState.texturesUsed[u];
1555
1556 /* save program parameters */
1557 program->Base.Parameters = parseState.parameters;
1558
1559 /* allocate registers for declared program parameters */
1560 #if 00
1561 _mesa_assign_program_registers(&(program->SymbolTable));
1562 #endif
1563
1564 #ifdef DEBUG_foo
1565 _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
1566 _mesa_print_nv_fragment_program(program);
1567 _mesa_printf("----------------------------------\n");
1568 #endif
1569 }
1570 else {
1571 /* Error! */
1572 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1573 /* NOTE: _mesa_set_program_error would have been called already */
1574 }
1575 }
1576
1577
1578 static void
1579 PrintSrcReg(const struct gl_fragment_program *program,
1580 const struct prog_src_register *src)
1581 {
1582 static const char comps[5] = "xyzw";
1583
1584 if (src->NegateAbs) {
1585 _mesa_printf("-");
1586 }
1587 if (src->Abs) {
1588 _mesa_printf("|");
1589 }
1590 if (src->NegateBase) {
1591 _mesa_printf("-");
1592 }
1593 if (src->File == PROGRAM_NAMED_PARAM) {
1594 if (program->Base.Parameters->Parameters[src->Index].Type
1595 == PROGRAM_CONSTANT) {
1596 const GLfloat *v;
1597 v = program->Base.Parameters->ParameterValues[src->Index];
1598 _mesa_printf("{%g, %g, %g, %g}", v[0], v[1], v[2], v[3]);
1599 }
1600 else {
1601 ASSERT(program->Base.Parameters->Parameters[src->Index].Type
1602 == PROGRAM_NAMED_PARAM);
1603 _mesa_printf("%s", program->Base.Parameters->Parameters[src->Index].Name);
1604 }
1605 }
1606 else if (src->File == PROGRAM_OUTPUT) {
1607 _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1608 }
1609 else if (src->File == PROGRAM_INPUT) {
1610 _mesa_printf("f[%s]", InputRegisters[src->Index]);
1611 }
1612 else if (src->File == PROGRAM_LOCAL_PARAM) {
1613 _mesa_printf("p[%d]", src->Index);
1614 }
1615 else if (src->File == PROGRAM_TEMPORARY) {
1616 if (src->Index >= 32)
1617 _mesa_printf("H%d", src->Index);
1618 else
1619 _mesa_printf("R%d", src->Index);
1620 }
1621 else if (src->File == PROGRAM_WRITE_ONLY) {
1622 _mesa_printf("%cC", "HR"[src->Index]);
1623 }
1624 else {
1625 _mesa_problem(NULL, "Invalid fragment register %d", src->Index);
1626 return;
1627 }
1628 if (GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 1) &&
1629 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 2) &&
1630 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 3)) {
1631 _mesa_printf(".%c", comps[GET_SWZ(src->Swizzle, 0)]);
1632 }
1633 else if (src->Swizzle != SWIZZLE_NOOP) {
1634 _mesa_printf(".%c%c%c%c",
1635 comps[GET_SWZ(src->Swizzle, 0)],
1636 comps[GET_SWZ(src->Swizzle, 1)],
1637 comps[GET_SWZ(src->Swizzle, 2)],
1638 comps[GET_SWZ(src->Swizzle, 3)]);
1639 }
1640 if (src->Abs) {
1641 _mesa_printf("|");
1642 }
1643 }
1644
1645 static void
1646 PrintTextureSrc(const struct prog_instruction *inst)
1647 {
1648 _mesa_printf("TEX%d, ", inst->TexSrcUnit);
1649 switch (inst->TexSrcTarget) {
1650 case TEXTURE_1D_INDEX:
1651 _mesa_printf("1D");
1652 break;
1653 case TEXTURE_2D_INDEX:
1654 _mesa_printf("2D");
1655 break;
1656 case TEXTURE_3D_INDEX:
1657 _mesa_printf("3D");
1658 break;
1659 case TEXTURE_RECT_INDEX:
1660 _mesa_printf("RECT");
1661 break;
1662 case TEXTURE_CUBE_INDEX:
1663 _mesa_printf("CUBE");
1664 break;
1665 default:
1666 _mesa_problem(NULL, "Invalid textue target in PrintTextureSrc");
1667 }
1668 }
1669
1670 static void
1671 PrintCondCode(const struct prog_dst_register *dst)
1672 {
1673 static const char *comps = "xyzw";
1674 static const char *ccString[] = {
1675 "??", "GT", "EQ", "LT", "UN", "GE", "LE", "NE", "TR", "FL", "??"
1676 };
1677
1678 _mesa_printf("%s", ccString[dst->CondMask]);
1679 if (GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 1) &&
1680 GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 2) &&
1681 GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 3)) {
1682 _mesa_printf(".%c", comps[GET_SWZ(dst->CondSwizzle, 0)]);
1683 }
1684 else if (dst->CondSwizzle != SWIZZLE_NOOP) {
1685 _mesa_printf(".%c%c%c%c",
1686 comps[GET_SWZ(dst->CondSwizzle, 0)],
1687 comps[GET_SWZ(dst->CondSwizzle, 1)],
1688 comps[GET_SWZ(dst->CondSwizzle, 2)],
1689 comps[GET_SWZ(dst->CondSwizzle, 3)]);
1690 }
1691 }
1692
1693
1694 static void
1695 PrintDstReg(const struct prog_dst_register *dst)
1696 {
1697 if (dst->File == PROGRAM_OUTPUT) {
1698 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1699 }
1700 else if (dst->File == PROGRAM_TEMPORARY) {
1701 if (dst->Index >= 32)
1702 _mesa_printf("H%d", dst->Index);
1703 else
1704 _mesa_printf("R%d", dst->Index);
1705 }
1706 else if (dst->File == PROGRAM_LOCAL_PARAM) {
1707 _mesa_printf("p[%d]", dst->Index);
1708 }
1709 else if (dst->File == PROGRAM_WRITE_ONLY) {
1710 _mesa_printf("%cC", "HR"[dst->Index]);
1711 }
1712 else {
1713 _mesa_printf("???");
1714 }
1715
1716 if (dst->WriteMask != 0 && dst->WriteMask != WRITEMASK_XYZW) {
1717 _mesa_printf(".");
1718 if (dst->WriteMask & WRITEMASK_X)
1719 _mesa_printf("x");
1720 if (dst->WriteMask & WRITEMASK_Y)
1721 _mesa_printf("y");
1722 if (dst->WriteMask & WRITEMASK_Z)
1723 _mesa_printf("z");
1724 if (dst->WriteMask & WRITEMASK_W)
1725 _mesa_printf("w");
1726 }
1727
1728 if (dst->CondMask != COND_TR ||
1729 dst->CondSwizzle != SWIZZLE_NOOP) {
1730 _mesa_printf(" (");
1731 PrintCondCode(dst);
1732 _mesa_printf(")");
1733 }
1734 }
1735
1736
1737 /**
1738 * Print (unparse) the given vertex program. Just for debugging.
1739 */
1740 void
1741 _mesa_print_nv_fragment_program(const struct gl_fragment_program *program)
1742 {
1743 const struct prog_instruction *inst;
1744
1745 for (inst = program->Base.Instructions; inst->Opcode != OPCODE_END; inst++) {
1746 int i;
1747 for (i = 0; Instructions[i].name; i++) {
1748 if (inst->Opcode == Instructions[i].opcode) {
1749 /* print instruction name */
1750 _mesa_printf("%s", Instructions[i].name);
1751 if (inst->Precision == FLOAT16)
1752 _mesa_printf("H");
1753 else if (inst->Precision == FIXED12)
1754 _mesa_printf("X");
1755 if (inst->CondUpdate)
1756 _mesa_printf("C");
1757 if (inst->SaturateMode == SATURATE_ZERO_ONE)
1758 _mesa_printf("_SAT");
1759 _mesa_printf(" ");
1760
1761 if (Instructions[i].inputs == INPUT_CC) {
1762 PrintCondCode(&inst->DstReg);
1763 }
1764 else if (Instructions[i].outputs == OUTPUT_V ||
1765 Instructions[i].outputs == OUTPUT_S) {
1766 /* print dest register */
1767 PrintDstReg(&inst->DstReg);
1768 _mesa_printf(", ");
1769 }
1770
1771 /* print source register(s) */
1772 if (Instructions[i].inputs == INPUT_1V ||
1773 Instructions[i].inputs == INPUT_1S) {
1774 PrintSrcReg(program, &inst->SrcReg[0]);
1775 }
1776 else if (Instructions[i].inputs == INPUT_2V ||
1777 Instructions[i].inputs == INPUT_2S) {
1778 PrintSrcReg(program, &inst->SrcReg[0]);
1779 _mesa_printf(", ");
1780 PrintSrcReg(program, &inst->SrcReg[1]);
1781 }
1782 else if (Instructions[i].inputs == INPUT_3V) {
1783 PrintSrcReg(program, &inst->SrcReg[0]);
1784 _mesa_printf(", ");
1785 PrintSrcReg(program, &inst->SrcReg[1]);
1786 _mesa_printf(", ");
1787 PrintSrcReg(program, &inst->SrcReg[2]);
1788 }
1789 else if (Instructions[i].inputs == INPUT_1V_T) {
1790 PrintSrcReg(program, &inst->SrcReg[0]);
1791 _mesa_printf(", ");
1792 PrintTextureSrc(inst);
1793 }
1794 else if (Instructions[i].inputs == INPUT_3V_T) {
1795 PrintSrcReg(program, &inst->SrcReg[0]);
1796 _mesa_printf(", ");
1797 PrintSrcReg(program, &inst->SrcReg[1]);
1798 _mesa_printf(", ");
1799 PrintSrcReg(program, &inst->SrcReg[2]);
1800 _mesa_printf(", ");
1801 PrintTextureSrc(inst);
1802 }
1803 _mesa_printf(";\n");
1804 break;
1805 }
1806 }
1807 if (!Instructions[i].name) {
1808 _mesa_printf("Invalid opcode %d\n", inst->Opcode);
1809 }
1810 }
1811 _mesa_printf("END\n");
1812 }
1813
1814
1815 const char *
1816 _mesa_nv_fragment_input_register_name(GLuint i)
1817 {
1818 ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
1819 return InputRegisters[i];
1820 }
1821