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