Implement ARB_f_p KIL correctly.
[mesa.git] / src / mesa / shader / nvfragparse.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.0
4 *
5 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /**
26 * \file nvfragparse.c
27 * NVIDIA fragment program parser.
28 * \author Brian Paul
29 */
30
31 /*
32 * Regarding GL_NV_fragment_program:
33 *
34 * Portions of this software may use or implement intellectual
35 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
36 * any and all warranties with respect to such intellectual property,
37 * including any use thereof or modifications thereto.
38 */
39
40 #include "glheader.h"
41 #include "context.h"
42 #include "hash.h"
43 #include "imports.h"
44 #include "macros.h"
45 #include "mtypes.h"
46 #include "nvfragprog.h"
47 #include "nvfragparse.h"
48 #include "nvprogram.h"
49 #include "program.h"
50
51
52 #define INPUT_1V 1
53 #define INPUT_2V 2
54 #define INPUT_3V 3
55 #define INPUT_1S 4
56 #define INPUT_2S 5
57 #define INPUT_CC 6
58 #define INPUT_1V_T 7 /* one source vector, plus textureId */
59 #define INPUT_3V_T 8 /* one source vector, plus textureId */
60 #define INPUT_NONE 9
61 #define OUTPUT_V 20
62 #define OUTPUT_S 21
63 #define OUTPUT_NONE 22
64
65 /* IRIX defines some of these */
66 #undef _R
67 #undef _H
68 #undef _X
69 #undef _C
70 #undef _S
71
72 /* Optional suffixes */
73 #define _R FLOAT32 /* float */
74 #define _H FLOAT16 /* half-float */
75 #define _X FIXED12 /* fixed */
76 #define _C 0x08 /* set cond codes */
77 #define _S 0x10 /* saturate, clamp result to [0,1] */
78
79 struct instruction_pattern {
80 const char *name;
81 enum fp_opcode opcode;
82 GLuint inputs;
83 GLuint outputs;
84 GLuint suffixes;
85 };
86
87 static const struct instruction_pattern Instructions[] = {
88 { "ADD", FP_OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
89 { "COS", FP_OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
90 { "DDX", FP_OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
91 { "DDY", FP_OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
92 { "DP3", FP_OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
93 { "DP4", FP_OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
94 { "DST", FP_OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H | _C | _S },
95 { "EX2", FP_OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
96 { "FLR", FP_OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
97 { "FRC", FP_OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
98 { "KIL", FP_OPCODE_KIL_NV, INPUT_CC, OUTPUT_NONE, 0 },
99 { "LG2", FP_OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
100 { "LIT", FP_OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
101 { "LRP", FP_OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
102 { "MAD", FP_OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
103 { "MAX", FP_OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
104 { "MIN", FP_OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
105 { "MOV", FP_OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
106 { "MUL", FP_OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
107 { "PK2H", FP_OPCODE_PK2H, INPUT_1V, OUTPUT_S, 0 },
108 { "PK2US", FP_OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0 },
109 { "PK4B", FP_OPCODE_PK4B, INPUT_1V, OUTPUT_S, 0 },
110 { "PK4UB", FP_OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0 },
111 { "POW", FP_OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H | _C | _S },
112 { "RCP", FP_OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
113 { "RFL", FP_OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H | _C | _S },
114 { "RSQ", FP_OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
115 { "SEQ", FP_OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
116 { "SFL", FP_OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
117 { "SGE", FP_OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
118 { "SGT", FP_OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
119 { "SIN", FP_OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
120 { "SLE", FP_OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
121 { "SLT", FP_OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
122 { "SNE", FP_OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
123 { "STR", FP_OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
124 { "SUB", FP_OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
125 { "TEX", FP_OPCODE_TEX, INPUT_1V_T, OUTPUT_V, _C | _S },
126 { "TXD", FP_OPCODE_TXD, INPUT_3V_T, OUTPUT_V, _C | _S },
127 { "TXP", FP_OPCODE_TXP, INPUT_1V_T, OUTPUT_V, _C | _S },
128 { "UP2H", FP_OPCODE_UP2H, INPUT_1S, OUTPUT_V, _C | _S },
129 { "UP2US", FP_OPCODE_UP2US, INPUT_1S, OUTPUT_V, _C | _S },
130 { "UP4B", FP_OPCODE_UP4B, INPUT_1S, OUTPUT_V, _C | _S },
131 { "UP4UB", FP_OPCODE_UP4UB, INPUT_1S, OUTPUT_V, _C | _S },
132 { "X2D", FP_OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H | _C | _S },
133 { NULL, (enum fp_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 fragment_program *program; /* current program */
148
149 struct 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 = (enum fp_opcode) -1;
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 = _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 fp_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 if (!Parse_Token(parseState, token)) /* get xyzw suffix */
694 RETURN_ERROR;
695
696 if (!Parse_SwizzleSuffix(token, dstReg->CondSwizzle))
697 RETURN_ERROR1("Invalid swizzle suffix");
698 }
699
700 return GL_TRUE;
701 }
702
703
704 /**
705 * Parse a temporary register: Rnn or Hnn
706 */
707 static GLboolean
708 Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
709 {
710 GLubyte token[100];
711
712 /* Should be 'R##' or 'H##' */
713 if (!Parse_Token(parseState, token))
714 RETURN_ERROR;
715 if (token[0] != 'R' && token[0] != 'H')
716 RETURN_ERROR1("Expected R## or H##");
717
718 if (IsDigit(token[1])) {
719 GLint reg = _mesa_atoi((const char *) (token + 1));
720 if (token[0] == 'H')
721 reg += 32;
722 if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS)
723 RETURN_ERROR1("Invalid temporary register name");
724 *tempRegNum = reg;
725 }
726 else {
727 RETURN_ERROR1("Invalid temporary register name");
728 }
729
730 return GL_TRUE;
731 }
732
733
734 /**
735 * Parse a write-only dummy register: RC or HC.
736 */
737 static GLboolean
738 Parse_DummyReg(struct parse_state *parseState, GLint *regNum)
739 {
740 if (Parse_String(parseState, "RC")) {
741 *regNum = 0;
742 }
743 else if (Parse_String(parseState, "HC")) {
744 *regNum = 1;
745 }
746 else {
747 RETURN_ERROR1("Invalid write-only register name");
748 }
749
750 return GL_TRUE;
751 }
752
753
754 /**
755 * Parse a program local parameter register "p[##]"
756 */
757 static GLboolean
758 Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum)
759 {
760 GLubyte token[100];
761
762 if (!Parse_String(parseState, "p["))
763 RETURN_ERROR1("Expected p[");
764
765 if (!Parse_Token(parseState, token))
766 RETURN_ERROR;
767
768 if (IsDigit(token[0])) {
769 /* a numbered program parameter register */
770 GLint reg = _mesa_atoi((const char *) token);
771 if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS)
772 RETURN_ERROR1("Invalid constant program number");
773 *regNum = reg;
774 }
775 else {
776 RETURN_ERROR;
777 }
778
779 if (!Parse_String(parseState, "]"))
780 RETURN_ERROR1("Expected ]");
781
782 return GL_TRUE;
783 }
784
785
786 /**
787 * Parse f[name] - fragment input register
788 */
789 static GLboolean
790 Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum)
791 {
792 GLubyte token[100];
793 GLint j;
794
795 /* Match 'f[' */
796 if (!Parse_String(parseState, "f["))
797 RETURN_ERROR1("Expected f[");
798
799 /* get <name> and look for match */
800 if (!Parse_Token(parseState, token)) {
801 RETURN_ERROR;
802 }
803 for (j = 0; InputRegisters[j]; j++) {
804 if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
805 *tempRegNum = j;
806 parseState->inputsRead |= (1 << j);
807 break;
808 }
809 }
810 if (!InputRegisters[j]) {
811 /* unknown input register label */
812 RETURN_ERROR2("Invalid register name", token);
813 }
814
815 /* Match '[' */
816 if (!Parse_String(parseState, "]"))
817 RETURN_ERROR1("Expected ]");
818
819 return GL_TRUE;
820 }
821
822
823 static GLboolean
824 Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
825 {
826 GLubyte token[100];
827 GLint j;
828
829 /* Match "o[" */
830 if (!Parse_String(parseState, "o["))
831 RETURN_ERROR1("Expected o[");
832
833 /* Get output reg name */
834 if (!Parse_Token(parseState, token))
835 RETURN_ERROR;
836
837 /* try to match an output register name */
838 for (j = 0; OutputRegisters[j]; j++) {
839 if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) {
840 static GLuint bothColors = (1 << FRAG_OUTPUT_COLR) | (1 << FRAG_OUTPUT_COLH);
841 *outputRegNum = j;
842 parseState->outputsWritten |= (1 << j);
843 if ((parseState->outputsWritten & bothColors) == bothColors) {
844 RETURN_ERROR1("Illegal to write to both o[COLR] and o[COLH]");
845 }
846 break;
847 }
848 }
849 if (!OutputRegisters[j])
850 RETURN_ERROR1("Invalid output register name");
851
852 /* Match ']' */
853 if (!Parse_String(parseState, "]"))
854 RETURN_ERROR1("Expected ]");
855
856 return GL_TRUE;
857 }
858
859
860 static GLboolean
861 Parse_MaskedDstReg(struct parse_state *parseState,
862 struct fp_dst_register *dstReg)
863 {
864 GLubyte token[100];
865
866 /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
867 if (!Peek_Token(parseState, token))
868 RETURN_ERROR;
869
870 if (_mesa_strcmp((const char *) token, "RC") == 0 ||
871 _mesa_strcmp((const char *) token, "HC") == 0) {
872 /* a write-only register */
873 dstReg->File = PROGRAM_WRITE_ONLY;
874 if (!Parse_DummyReg(parseState, &dstReg->Index))
875 RETURN_ERROR;
876 }
877 else if (token[0] == 'R' || token[0] == 'H') {
878 /* a temporary register */
879 dstReg->File = PROGRAM_TEMPORARY;
880 if (!Parse_TempReg(parseState, &dstReg->Index))
881 RETURN_ERROR;
882 }
883 else if (token[0] == 'o') {
884 /* an output register */
885 dstReg->File = PROGRAM_OUTPUT;
886 if (!Parse_OutputReg(parseState, &dstReg->Index))
887 RETURN_ERROR;
888 }
889 else {
890 RETURN_ERROR1("Invalid destination register name");
891 }
892
893 /* Parse optional write mask */
894 if (Parse_String(parseState, ".")) {
895 /* got a mask */
896 GLint k = 0;
897
898 if (!Parse_Token(parseState, token)) /* get xyzw writemask */
899 RETURN_ERROR;
900
901 dstReg->WriteMask[0] = GL_FALSE;
902 dstReg->WriteMask[1] = GL_FALSE;
903 dstReg->WriteMask[2] = GL_FALSE;
904 dstReg->WriteMask[3] = GL_FALSE;
905
906 if (token[k] == 'x') {
907 dstReg->WriteMask[0] = GL_TRUE;
908 k++;
909 }
910 if (token[k] == 'y') {
911 dstReg->WriteMask[1] = GL_TRUE;
912 k++;
913 }
914 if (token[k] == 'z') {
915 dstReg->WriteMask[2] = GL_TRUE;
916 k++;
917 }
918 if (token[k] == 'w') {
919 dstReg->WriteMask[3] = GL_TRUE;
920 k++;
921 }
922 if (k == 0) {
923 RETURN_ERROR1("Invalid writemask character");
924 }
925
926 }
927 else {
928 dstReg->WriteMask[0] = GL_TRUE;
929 dstReg->WriteMask[1] = GL_TRUE;
930 dstReg->WriteMask[2] = GL_TRUE;
931 dstReg->WriteMask[3] = GL_TRUE;
932 }
933
934 /* optional condition code mask */
935 if (Parse_String(parseState, "(")) {
936 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
937 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
938 if (!Parse_CondCodeMask(parseState, dstReg))
939 RETURN_ERROR;
940
941 if (!Parse_String(parseState, ")")) /* consume ")" */
942 RETURN_ERROR1("Expected )");
943
944 return GL_TRUE;
945 }
946 else {
947 /* no cond code mask */
948 dstReg->CondMask = COND_TR;
949 dstReg->CondSwizzle[0] = 0;
950 dstReg->CondSwizzle[1] = 1;
951 dstReg->CondSwizzle[2] = 2;
952 dstReg->CondSwizzle[3] = 3;
953 return GL_TRUE;
954 }
955 }
956
957
958 /**
959 * Parse a vector source (register, constant, etc):
960 * <vectorSrc> ::= <absVectorSrc>
961 * | <baseVectorSrc>
962 * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
963 */
964 static GLboolean
965 Parse_VectorSrc(struct parse_state *parseState,
966 struct fp_src_register *srcReg)
967 {
968 GLfloat sign = 1.0F;
969 GLubyte token[100];
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 = GL_TRUE;
985 else if (Parse_String(parseState, "+"))
986 srcReg->NegateBase = GL_FALSE;
987 else
988 srcReg->NegateBase = GL_FALSE;
989 }
990 else {
991 srcReg->Abs = GL_FALSE;
992 srcReg->NegateAbs = GL_FALSE;
993 srcReg->NegateBase = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
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, &srcReg->Index))
1006 RETURN_ERROR;
1007 }
1008 else if (token[0] == 'f') {
1009 /* XXX this might be an identier! */
1010 srcReg->File = PROGRAM_INPUT;
1011 if (!Parse_FragReg(parseState, &srcReg->Index))
1012 RETURN_ERROR;
1013 }
1014 else if (token[0] == 'p') {
1015 /* XXX this might be an identier! */
1016 srcReg->File = PROGRAM_LOCAL_PARAM;
1017 if (!Parse_ProgramParamReg(parseState, &srcReg->Index))
1018 RETURN_ERROR;
1019 }
1020 else if (IsLetter(token[0])){
1021 GLubyte ident[100];
1022 GLint paramIndex;
1023 if (!Parse_Identifier(parseState, ident))
1024 RETURN_ERROR;
1025 paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1026 -1, (const char *) ident);
1027 if (paramIndex < 0) {
1028 RETURN_ERROR2("Undefined constant or parameter: ", ident);
1029 }
1030 srcReg->File = PROGRAM_NAMED_PARAM;
1031 srcReg->Index = paramIndex;
1032 }
1033 else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){
1034 /* literal scalar constant */
1035 GLfloat values[4];
1036 GLuint paramIndex;
1037 if (!Parse_ScalarConstant(parseState, values))
1038 RETURN_ERROR;
1039 paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
1040 srcReg->File = PROGRAM_NAMED_PARAM;
1041 srcReg->Index = paramIndex;
1042 }
1043 else if (token[0] == '{'){
1044 /* literal vector constant */
1045 GLfloat values[4];
1046 GLuint paramIndex;
1047 (void) Parse_String(parseState, "{");
1048 if (!Parse_VectorConstant(parseState, values))
1049 RETURN_ERROR;
1050 paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
1051 srcReg->File = PROGRAM_NAMED_PARAM;
1052 srcReg->Index = paramIndex;
1053 }
1054 else {
1055 RETURN_ERROR2("Invalid source register name", token);
1056 }
1057
1058 /* init swizzle fields */
1059 srcReg->Swizzle[0] = 0;
1060 srcReg->Swizzle[1] = 1;
1061 srcReg->Swizzle[2] = 2;
1062 srcReg->Swizzle[3] = 3;
1063
1064 /* Look for optional swizzle suffix */
1065 if (Parse_String(parseState, ".")) {
1066 if (!Parse_Token(parseState, token))
1067 RETURN_ERROR;
1068
1069 if (!Parse_SwizzleSuffix(token, srcReg->Swizzle))
1070 RETURN_ERROR1("Invalid swizzle suffix");
1071 }
1072
1073 /* Finish absolute value */
1074 if (srcReg->Abs && !Parse_String(parseState, "|")) {
1075 RETURN_ERROR1("Expected |");
1076 }
1077
1078 return GL_TRUE;
1079 }
1080
1081
1082 static GLboolean
1083 Parse_ScalarSrcReg(struct parse_state *parseState,
1084 struct fp_src_register *srcReg)
1085 {
1086 GLubyte token[100];
1087 GLfloat sign = 1.0F;
1088 GLboolean needSuffix = GL_TRUE;
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 = GL_TRUE;
1104 else if (Parse_String(parseState, "+"))
1105 srcReg->NegateBase = GL_FALSE;
1106 else
1107 srcReg->NegateBase = GL_FALSE;
1108 }
1109 else {
1110 srcReg->Abs = GL_FALSE;
1111 srcReg->NegateAbs = GL_FALSE;
1112 srcReg->NegateBase = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
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, &srcReg->Index))
1122 RETURN_ERROR;
1123 }
1124 else if (token[0] == 'f') {
1125 srcReg->File = PROGRAM_INPUT;
1126 if (!Parse_FragReg(parseState, &srcReg->Index))
1127 RETURN_ERROR;
1128 }
1129 else if (token[0] == '{') {
1130 /* vector literal */
1131 GLfloat values[4];
1132 GLuint paramIndex;
1133 (void) Parse_String(parseState, "{");
1134 if (!Parse_VectorConstant(parseState, values))
1135 RETURN_ERROR;
1136 paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
1137 srcReg->File = PROGRAM_NAMED_PARAM;
1138 srcReg->Index = paramIndex;
1139 }
1140 else if (IsDigit(token[0])) {
1141 /* scalar literal */
1142 GLfloat values[4];
1143 GLuint paramIndex;
1144 if (!Parse_ScalarConstant(parseState, values))
1145 RETURN_ERROR;
1146 paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
1147 srcReg->Index = paramIndex;
1148 srcReg->File = PROGRAM_NAMED_PARAM;
1149 needSuffix = GL_FALSE;
1150 }
1151 else {
1152 RETURN_ERROR2("Invalid scalar source argument", token);
1153 }
1154
1155 if (needSuffix) {
1156 /* parse .[xyzw] suffix */
1157 if (!Parse_String(parseState, "."))
1158 RETURN_ERROR1("Expected .");
1159
1160 if (!Parse_Token(parseState, token))
1161 RETURN_ERROR;
1162
1163 if (token[0] == 'x' && token[1] == 0) {
1164 srcReg->Swizzle[0] = 0;
1165 }
1166 else if (token[0] == 'y' && token[1] == 0) {
1167 srcReg->Swizzle[0] = 1;
1168 }
1169 else if (token[0] == 'z' && token[1] == 0) {
1170 srcReg->Swizzle[0] = 2;
1171 }
1172 else if (token[0] == 'w' && token[1] == 0) {
1173 srcReg->Swizzle[0] = 3;
1174 }
1175 else {
1176 RETURN_ERROR1("Invalid scalar source suffix");
1177 }
1178 }
1179 else {
1180 srcReg->Swizzle[0] = 0;
1181 }
1182 srcReg->Swizzle[1] = srcReg->Swizzle[2] = srcReg->Swizzle[3] = 0;
1183
1184 /* Finish absolute value */
1185 if (srcReg->Abs && !Parse_String(parseState, "|")) {
1186 RETURN_ERROR1("Expected |");
1187 }
1188
1189 return GL_TRUE;
1190 }
1191
1192
1193
1194 static GLboolean
1195 Parse_InstructionSequence(struct parse_state *parseState,
1196 struct fp_instruction program[])
1197 {
1198 while (1) {
1199 struct fp_instruction *inst = program + parseState->numInst;
1200 struct instruction_pattern instMatch;
1201 GLubyte token[100];
1202
1203 /* Initialize the instruction */
1204 inst->SrcReg[0].File = (enum register_file) -1;
1205 inst->SrcReg[1].File = (enum register_file) -1;
1206 inst->SrcReg[2].File = (enum register_file) -1;
1207 inst->DstReg.File = (enum register_file) -1;
1208 inst->DstReg.CondSwizzle[0] = 0;
1209 inst->DstReg.CondSwizzle[1] = 1;
1210 inst->DstReg.CondSwizzle[2] = 2;
1211 inst->DstReg.CondSwizzle[3] = 3;
1212
1213 /* special instructions */
1214 if (Parse_String(parseState, "DEFINE")) {
1215 GLubyte id[100];
1216 GLfloat value[7]; /* yes, 7 to be safe */
1217 if (!Parse_Identifier(parseState, id))
1218 RETURN_ERROR;
1219 /* XXX make sure id is not a reserved identifer, like R9 */
1220 if (!Parse_String(parseState, "="))
1221 RETURN_ERROR1("Expected =");
1222 if (!Parse_VectorOrScalarConstant(parseState, value))
1223 RETURN_ERROR;
1224 if (!Parse_String(parseState, ";"))
1225 RETURN_ERROR1("Expected ;");
1226 if (_mesa_lookup_parameter_index(parseState->parameters,
1227 -1, (const char *) id) >= 0) {
1228 RETURN_ERROR2(id, "already defined");
1229 }
1230 _mesa_add_named_parameter(parseState->parameters,
1231 (const char *) id, value);
1232 }
1233 else if (Parse_String(parseState, "DECLARE")) {
1234 GLubyte id[100];
1235 GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */
1236 if (!Parse_Identifier(parseState, id))
1237 RETURN_ERROR;
1238 /* XXX make sure id is not a reserved identifer, like R9 */
1239 if (Parse_String(parseState, "=")) {
1240 if (!Parse_VectorOrScalarConstant(parseState, value))
1241 RETURN_ERROR;
1242 }
1243 if (!Parse_String(parseState, ";"))
1244 RETURN_ERROR1("Expected ;");
1245 if (_mesa_lookup_parameter_index(parseState->parameters,
1246 -1, (const char *) id) >= 0) {
1247 RETURN_ERROR2(id, "already declared");
1248 }
1249 _mesa_add_named_parameter(parseState->parameters,
1250 (const char *) id, value);
1251 }
1252 else if (Parse_String(parseState, "END")) {
1253 inst->Opcode = FP_OPCODE_END;
1254 inst->StringPos = parseState->curLine - parseState->start;
1255 assert(inst->StringPos >= 0);
1256 parseState->numInst++;
1257 if (Parse_Token(parseState, token)) {
1258 RETURN_ERROR1("Code after END opcode.");
1259 }
1260 break;
1261 }
1262 else {
1263 /* general/arithmetic instruction */
1264
1265 /* get token */
1266 if (!Parse_Token(parseState, token)) {
1267 RETURN_ERROR1("Missing END instruction.");
1268 }
1269
1270 /* try to find matching instuction */
1271 instMatch = MatchInstruction(token);
1272 if (instMatch.opcode < 0) {
1273 /* bad instruction name */
1274 RETURN_ERROR2("Unexpected token: ", token);
1275 }
1276
1277 inst->Opcode = instMatch.opcode;
1278 inst->Precision = instMatch.suffixes & (_R | _H | _X);
1279 inst->Saturate = (instMatch.suffixes & (_S)) ? GL_TRUE : GL_FALSE;
1280 inst->UpdateCondRegister = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
1281 inst->StringPos = parseState->curLine - parseState->start;
1282 assert(inst->StringPos >= 0);
1283
1284 /*
1285 * parse the input and output operands
1286 */
1287 if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
1288 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
1289 RETURN_ERROR;
1290 if (!Parse_String(parseState, ","))
1291 RETURN_ERROR1("Expected ,");
1292 }
1293 else if (instMatch.outputs == OUTPUT_NONE) {
1294 ASSERT(instMatch.opcode == FP_OPCODE_KIL_NV);
1295 /* This is a little weird, the cond code info is in the dest register */
1296 if (!Parse_CondCodeMask(parseState, &inst->DstReg))
1297 RETURN_ERROR;
1298 }
1299
1300 if (instMatch.inputs == INPUT_1V) {
1301 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1302 RETURN_ERROR;
1303 }
1304 else if (instMatch.inputs == INPUT_2V) {
1305 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1306 RETURN_ERROR;
1307 if (!Parse_String(parseState, ","))
1308 RETURN_ERROR1("Expected ,");
1309 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1310 RETURN_ERROR;
1311 }
1312 else if (instMatch.inputs == INPUT_3V) {
1313 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1314 RETURN_ERROR;
1315 if (!Parse_String(parseState, ","))
1316 RETURN_ERROR1("Expected ,");
1317 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1318 RETURN_ERROR;
1319 if (!Parse_String(parseState, ","))
1320 RETURN_ERROR1("Expected ,");
1321 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1322 RETURN_ERROR;
1323 }
1324 else if (instMatch.inputs == INPUT_1S) {
1325 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1326 RETURN_ERROR;
1327 }
1328 else if (instMatch.inputs == INPUT_2S) {
1329 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1330 RETURN_ERROR;
1331 if (!Parse_String(parseState, ","))
1332 RETURN_ERROR1("Expected ,");
1333 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
1334 RETURN_ERROR;
1335 }
1336 else if (instMatch.inputs == INPUT_CC) {
1337 /* XXX to-do */
1338 }
1339 else if (instMatch.inputs == INPUT_1V_T) {
1340 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1341 RETURN_ERROR;
1342 if (!Parse_String(parseState, ","))
1343 RETURN_ERROR1("Expected ,");
1344 if (!Parse_TextureImageId(parseState, &inst->TexSrcUnit,
1345 &inst->TexSrcBit))
1346 RETURN_ERROR;
1347 }
1348 else if (instMatch.inputs == INPUT_3V_T) {
1349 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1350 RETURN_ERROR;
1351 if (!Parse_String(parseState, ","))
1352 RETURN_ERROR1("Expected ,");
1353 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1354 RETURN_ERROR;
1355 if (!Parse_String(parseState, ","))
1356 RETURN_ERROR1("Expected ,");
1357 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1358 RETURN_ERROR;
1359 if (!Parse_String(parseState, ","))
1360 RETURN_ERROR1("Expected ,");
1361 if (!Parse_TextureImageId(parseState, &inst->TexSrcUnit,
1362 &inst->TexSrcBit))
1363 RETURN_ERROR;
1364 }
1365
1366 /* end of statement semicolon */
1367 if (!Parse_String(parseState, ";"))
1368 RETURN_ERROR1("Expected ;");
1369
1370 parseState->numInst++;
1371
1372 if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
1373 RETURN_ERROR1("Program too long");
1374 }
1375 }
1376 return GL_TRUE;
1377 }
1378
1379
1380
1381 /**
1382 * Parse/compile the 'str' returning the compiled 'program'.
1383 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1384 * indicates the position of the error in 'str'.
1385 */
1386 void
1387 _mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget,
1388 const GLubyte *str, GLsizei len,
1389 struct fragment_program *program)
1390 {
1391 struct parse_state parseState;
1392 struct fp_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
1393 struct fp_instruction *newInst;
1394 GLenum target;
1395 GLubyte *programString;
1396
1397 /* Make a null-terminated copy of the program string */
1398 programString = (GLubyte *) MALLOC(len + 1);
1399 if (!programString) {
1400 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1401 return;
1402 }
1403 MEMCPY(programString, str, len);
1404 programString[len] = 0;
1405
1406 /* Get ready to parse */
1407 _mesa_bzero(&parseState, sizeof(struct parse_state));
1408 parseState.ctx = ctx;
1409 parseState.start = programString;
1410 parseState.program = program;
1411 parseState.numInst = 0;
1412 parseState.curLine = programString;
1413 parseState.parameters = _mesa_new_parameter_list();
1414
1415 /* Reset error state */
1416 _mesa_set_program_error(ctx, -1, NULL);
1417
1418 /* check the program header */
1419 if (_mesa_strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
1420 target = GL_FRAGMENT_PROGRAM_NV;
1421 parseState.pos = programString + 7;
1422 }
1423 else if (_mesa_strncmp((const char *) programString, "!!FCP1.0", 8) == 0) {
1424 /* fragment / register combiner program - not supported */
1425 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1426 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1427 return;
1428 }
1429 else {
1430 /* invalid header */
1431 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1432 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1433 return;
1434 }
1435
1436 /* make sure target and header match */
1437 if (target != dstTarget) {
1438 _mesa_error(ctx, GL_INVALID_OPERATION,
1439 "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1440 target, dstTarget);
1441 return;
1442 }
1443
1444 if (Parse_InstructionSequence(&parseState, instBuffer)) {
1445 GLuint u;
1446 /* successful parse! */
1447
1448 if (parseState.outputsWritten == 0) {
1449 /* must write at least one output! */
1450 _mesa_error(ctx, GL_INVALID_OPERATION,
1451 "Invalid fragment program - no outputs written.");
1452 return;
1453 }
1454
1455 /* copy the compiled instructions */
1456 assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
1457 newInst = (struct fp_instruction *)
1458 MALLOC(parseState.numInst * sizeof(struct fp_instruction));
1459 if (!newInst) {
1460 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1461 return; /* out of memory */
1462 }
1463 MEMCPY(newInst, instBuffer,
1464 parseState.numInst * sizeof(struct fp_instruction));
1465
1466 /* install the program */
1467 program->Base.Target = target;
1468 if (program->Base.String) {
1469 FREE(program->Base.String);
1470 }
1471 program->Base.String = programString;
1472 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1473 if (program->Instructions) {
1474 FREE(program->Instructions);
1475 }
1476 program->Instructions = newInst;
1477 program->InputsRead = parseState.inputsRead;
1478 program->OutputsWritten = parseState.outputsWritten;
1479 for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
1480 program->TexturesUsed[u] = parseState.texturesUsed[u];
1481
1482 /* save program parameters */
1483 program->Parameters = parseState.parameters;
1484
1485 /* allocate registers for declared program parameters */
1486 #if 00
1487 _mesa_assign_program_registers(&(program->SymbolTable));
1488 #endif
1489
1490 #ifdef DEBUG
1491 _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
1492 _mesa_print_nv_fragment_program(program);
1493 _mesa_printf("----------------------------------\n");
1494 #endif
1495 }
1496 else {
1497 /* Error! */
1498 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1499 /* NOTE: _mesa_set_program_error would have been called already */
1500 }
1501 }
1502
1503
1504 static void
1505 PrintSrcReg(const struct fragment_program *program,
1506 const struct fp_src_register *src)
1507 {
1508 static const char comps[5] = "xyzw";
1509
1510 if (src->NegateAbs) {
1511 _mesa_printf("-");
1512 }
1513 if (src->Abs) {
1514 _mesa_printf("|");
1515 }
1516 if (src->NegateBase) {
1517 _mesa_printf("-");
1518 }
1519 if (src->File == PROGRAM_NAMED_PARAM) {
1520 if (program->Parameters->Parameters[src->Index].Type == CONSTANT) {
1521 printf("{%g, %g, %g, %g}",
1522 program->Parameters->Parameters[src->Index].Values[0],
1523 program->Parameters->Parameters[src->Index].Values[1],
1524 program->Parameters->Parameters[src->Index].Values[2],
1525 program->Parameters->Parameters[src->Index].Values[3]);
1526 }
1527 else {
1528 ASSERT(program->Parameters->Parameters[src->Index].Type
1529 == NAMED_PARAMETER);
1530 printf("%s", program->Parameters->Parameters[src->Index].Name);
1531 }
1532 }
1533 else if (src->File == PROGRAM_OUTPUT) {
1534 _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1535 }
1536 else if (src->File == PROGRAM_INPUT) {
1537 _mesa_printf("f[%s]", InputRegisters[src->Index]);
1538 }
1539 else if (src->File == PROGRAM_LOCAL_PARAM) {
1540 _mesa_printf("p[%d]", src->Index);
1541 }
1542 else if (src->File == PROGRAM_TEMPORARY) {
1543 if (src->Index >= 32)
1544 _mesa_printf("H%d", src->Index);
1545 else
1546 _mesa_printf("R%d", src->Index);
1547 }
1548 else if (src->File == PROGRAM_WRITE_ONLY) {
1549 _mesa_printf("%cC", "HR"[src->Index]);
1550 }
1551 else {
1552 _mesa_problem(NULL, "Invalid fragment register %d", src->Index);
1553 return;
1554 }
1555 if (src->Swizzle[0] == src->Swizzle[1] &&
1556 src->Swizzle[0] == src->Swizzle[2] &&
1557 src->Swizzle[0] == src->Swizzle[3]) {
1558 _mesa_printf(".%c", comps[src->Swizzle[0]]);
1559 }
1560 else if (src->Swizzle[0] != 0 ||
1561 src->Swizzle[1] != 1 ||
1562 src->Swizzle[2] != 2 ||
1563 src->Swizzle[3] != 3) {
1564 _mesa_printf(".%c%c%c%c",
1565 comps[src->Swizzle[0]],
1566 comps[src->Swizzle[1]],
1567 comps[src->Swizzle[2]],
1568 comps[src->Swizzle[3]]);
1569 }
1570 if (src->Abs) {
1571 _mesa_printf("|");
1572 }
1573 }
1574
1575 static void
1576 PrintTextureSrc(const struct fp_instruction *inst)
1577 {
1578 _mesa_printf("TEX%d, ", inst->TexSrcUnit);
1579 switch (inst->TexSrcBit) {
1580 case TEXTURE_1D_BIT:
1581 _mesa_printf("1D");
1582 break;
1583 case TEXTURE_2D_BIT:
1584 _mesa_printf("2D");
1585 break;
1586 case TEXTURE_3D_BIT:
1587 _mesa_printf("3D");
1588 break;
1589 case TEXTURE_RECT_BIT:
1590 _mesa_printf("RECT");
1591 break;
1592 case TEXTURE_CUBE_BIT:
1593 _mesa_printf("CUBE");
1594 break;
1595 default:
1596 _mesa_problem(NULL, "Invalid textue target in PrintTextureSrc");
1597 }
1598 }
1599
1600 static void
1601 PrintCondCode(const struct fp_dst_register *dst)
1602 {
1603 static const char *comps = "xyzw";
1604 static const char *ccString[] = {
1605 "??", "GT", "EQ", "LT", "UN", "GE", "LE", "NE", "TR", "FL", "??"
1606 };
1607
1608 _mesa_printf("%s", ccString[dst->CondMask]);
1609 if (dst->CondSwizzle[0] == dst->CondSwizzle[1] &&
1610 dst->CondSwizzle[0] == dst->CondSwizzle[2] &&
1611 dst->CondSwizzle[0] == dst->CondSwizzle[3]) {
1612 _mesa_printf(".%c", comps[dst->CondSwizzle[0]]);
1613 }
1614 else if (dst->CondSwizzle[0] != 0 ||
1615 dst->CondSwizzle[1] != 1 ||
1616 dst->CondSwizzle[2] != 2 ||
1617 dst->CondSwizzle[3] != 3) {
1618 _mesa_printf(".%c%c%c%c",
1619 comps[dst->CondSwizzle[0]],
1620 comps[dst->CondSwizzle[1]],
1621 comps[dst->CondSwizzle[2]],
1622 comps[dst->CondSwizzle[3]]);
1623 }
1624 }
1625
1626
1627 static void
1628 PrintDstReg(const struct fp_dst_register *dst)
1629 {
1630 GLint w = dst->WriteMask[0] + dst->WriteMask[1]
1631 + dst->WriteMask[2] + dst->WriteMask[3];
1632
1633 if (dst->File == PROGRAM_OUTPUT) {
1634 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1635 }
1636 else if (dst->File == PROGRAM_TEMPORARY) {
1637 if (dst->Index >= 32)
1638 _mesa_printf("H%d", dst->Index);
1639 else
1640 _mesa_printf("R%d", dst->Index);
1641 }
1642 else if (dst->File == PROGRAM_LOCAL_PARAM) {
1643 _mesa_printf("p[%d]", dst->Index);
1644 }
1645 else if (dst->File == PROGRAM_WRITE_ONLY) {
1646 _mesa_printf("%cC", "HR"[dst->Index]);
1647 }
1648 else {
1649 _mesa_printf("???");
1650 }
1651
1652 if (w != 0 && w != 4) {
1653 _mesa_printf(".");
1654 if (dst->WriteMask[0])
1655 _mesa_printf("x");
1656 if (dst->WriteMask[1])
1657 _mesa_printf("y");
1658 if (dst->WriteMask[2])
1659 _mesa_printf("z");
1660 if (dst->WriteMask[3])
1661 _mesa_printf("w");
1662 }
1663
1664 if (dst->CondMask != COND_TR ||
1665 dst->CondSwizzle[0] != 0 ||
1666 dst->CondSwizzle[1] != 1 ||
1667 dst->CondSwizzle[2] != 2 ||
1668 dst->CondSwizzle[3] != 3) {
1669 _mesa_printf(" (");
1670 PrintCondCode(dst);
1671 _mesa_printf(")");
1672 }
1673 }
1674
1675
1676 /**
1677 * Print (unparse) the given vertex program. Just for debugging.
1678 */
1679 void
1680 _mesa_print_nv_fragment_program(const struct fragment_program *program)
1681 {
1682 const struct fp_instruction *inst;
1683
1684 for (inst = program->Instructions; inst->Opcode != FP_OPCODE_END; inst++) {
1685 int i;
1686 for (i = 0; Instructions[i].name; i++) {
1687 if (inst->Opcode == Instructions[i].opcode) {
1688 /* print instruction name */
1689 _mesa_printf("%s", Instructions[i].name);
1690 if (inst->Precision == FLOAT16)
1691 _mesa_printf("H");
1692 else if (inst->Precision == FIXED12)
1693 _mesa_printf("X");
1694 if (inst->UpdateCondRegister)
1695 _mesa_printf("C");
1696 if (inst->Saturate)
1697 _mesa_printf("_SAT");
1698 _mesa_printf(" ");
1699
1700 if (Instructions[i].inputs == INPUT_CC) {
1701 PrintCondCode(&inst->DstReg);
1702 }
1703 else if (Instructions[i].outputs == OUTPUT_V ||
1704 Instructions[i].outputs == OUTPUT_S) {
1705 /* print dest register */
1706 PrintDstReg(&inst->DstReg);
1707 _mesa_printf(", ");
1708 }
1709
1710 /* print source register(s) */
1711 if (Instructions[i].inputs == INPUT_1V ||
1712 Instructions[i].inputs == INPUT_1S) {
1713 PrintSrcReg(program, &inst->SrcReg[0]);
1714 }
1715 else if (Instructions[i].inputs == INPUT_2V ||
1716 Instructions[i].inputs == INPUT_2S) {
1717 PrintSrcReg(program, &inst->SrcReg[0]);
1718 _mesa_printf(", ");
1719 PrintSrcReg(program, &inst->SrcReg[1]);
1720 }
1721 else if (Instructions[i].inputs == INPUT_3V) {
1722 PrintSrcReg(program, &inst->SrcReg[0]);
1723 _mesa_printf(", ");
1724 PrintSrcReg(program, &inst->SrcReg[1]);
1725 _mesa_printf(", ");
1726 PrintSrcReg(program, &inst->SrcReg[2]);
1727 }
1728 else if (Instructions[i].inputs == INPUT_1V_T) {
1729 PrintSrcReg(program, &inst->SrcReg[0]);
1730 _mesa_printf(", ");
1731 PrintTextureSrc(inst);
1732 }
1733 else if (Instructions[i].inputs == INPUT_3V_T) {
1734 PrintSrcReg(program, &inst->SrcReg[0]);
1735 _mesa_printf(", ");
1736 PrintSrcReg(program, &inst->SrcReg[1]);
1737 _mesa_printf(", ");
1738 PrintSrcReg(program, &inst->SrcReg[2]);
1739 _mesa_printf(", ");
1740 PrintTextureSrc(inst);
1741 }
1742 _mesa_printf(";\n");
1743 break;
1744 }
1745 }
1746 if (!Instructions[i].name) {
1747 _mesa_printf("Invalid opcode %d\n", inst->Opcode);
1748 }
1749 }
1750 _mesa_printf("END\n");
1751 }
1752
1753
1754 const char *
1755 _mesa_nv_fragment_input_register_name(GLuint i)
1756 {
1757 ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
1758 return InputRegisters[i];
1759 }
1760
1761
1762 const char *
1763 _mesa_nv_fragment_output_register_name(GLuint i)
1764 {
1765 ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_OUTPUTS);
1766 return OutputRegisters[i];
1767 }