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