Don't cast the return value of malloc/realloc
[mesa.git] / src / mesa / program / 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 struct gl_context *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 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 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 result.name = NULL;
221 result.opcode = MAX_OPCODE; /* i.e. invalid instruction */
222 result.inputs = 0;
223 result.outputs = 0;
224 result.suffixes = 0;
225
226 for (inst = Instructions; inst->name; inst++) {
227 if (strncmp((const char *) token, inst->name, 3) == 0) {
228 /* matched! */
229 int i = 3;
230 result = *inst;
231 result.suffixes = 0;
232 /* look at suffix */
233 if (token[i] == 'R') {
234 result.suffixes |= _R;
235 i++;
236 }
237 else if (token[i] == 'H') {
238 result.suffixes |= _H;
239 i++;
240 }
241 else if (token[i] == 'X') {
242 result.suffixes |= _X;
243 i++;
244 }
245 if (token[i] == 'C') {
246 result.suffixes |= _C;
247 i++;
248 }
249 if (token[i] == '_' && token[i+1] == 'S' &&
250 token[i+2] == 'A' && token[i+3] == 'T') {
251 result.suffixes |= _S;
252 }
253 return result;
254 }
255 }
256
257 return result;
258 }
259
260
261
262
263 /**********************************************************************/
264
265
266 static GLboolean IsLetter(GLubyte b)
267 {
268 return (b >= 'a' && b <= 'z') ||
269 (b >= 'A' && b <= 'Z') ||
270 (b == '_') ||
271 (b == '$');
272 }
273
274
275 static GLboolean IsDigit(GLubyte b)
276 {
277 return b >= '0' && b <= '9';
278 }
279
280
281 static GLboolean IsWhitespace(GLubyte b)
282 {
283 return b == ' ' || b == '\t' || b == '\n' || b == '\r';
284 }
285
286
287 /**
288 * Starting at 'str' find the next token. A token can be an integer,
289 * an identifier or punctuation symbol.
290 * \return <= 0 we found an error, else, return number of characters parsed.
291 */
292 static GLint
293 GetToken(struct parse_state *parseState, GLubyte *token)
294 {
295 const GLubyte *str = parseState->pos;
296 GLint i = 0, j = 0;
297
298 token[0] = 0;
299
300 /* skip whitespace and comments */
301 while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
302 if (str[i] == '#') {
303 /* skip comment */
304 while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
305 i++;
306 }
307 if (str[i] == '\n' || str[i] == '\r')
308 parseState->curLine = str + i + 1;
309 }
310 else {
311 /* skip whitespace */
312 if (str[i] == '\n' || str[i] == '\r')
313 parseState->curLine = str + i + 1;
314 i++;
315 }
316 }
317
318 if (str[i] == 0)
319 return -i;
320
321 /* try matching an integer */
322 while (str[i] && IsDigit(str[i])) {
323 token[j++] = str[i++];
324 }
325 if (j > 0 || !str[i]) {
326 token[j] = 0;
327 return i;
328 }
329
330 /* try matching an identifier */
331 if (IsLetter(str[i])) {
332 while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
333 token[j++] = str[i++];
334 }
335 token[j] = 0;
336 return i;
337 }
338
339 /* punctuation character */
340 if (str[i]) {
341 token[0] = str[i++];
342 token[1] = 0;
343 return i;
344 }
345
346 /* end of input */
347 token[0] = 0;
348 return i;
349 }
350
351
352 /**
353 * Get next token from input stream and increment stream pointer past token.
354 */
355 static GLboolean
356 Parse_Token(struct parse_state *parseState, GLubyte *token)
357 {
358 GLint i;
359 i = GetToken(parseState, token);
360 if (i <= 0) {
361 parseState->pos += (-i);
362 return GL_FALSE;
363 }
364 parseState->pos += i;
365 return GL_TRUE;
366 }
367
368
369 /**
370 * Get next token from input stream but don't increment stream pointer.
371 */
372 static GLboolean
373 Peek_Token(struct parse_state *parseState, GLubyte *token)
374 {
375 GLint i, len;
376 i = GetToken(parseState, token);
377 if (i <= 0) {
378 parseState->pos += (-i);
379 return GL_FALSE;
380 }
381 len = (GLint) strlen((const char *) token);
382 parseState->pos += (i - len);
383 return GL_TRUE;
384 }
385
386
387 /**********************************************************************/
388
389 static const char *InputRegisters[MAX_NV_FRAGMENT_PROGRAM_INPUTS + 1] = {
390 "WPOS", "COL0", "COL1", "FOGC",
391 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
392 };
393
394
395
396 /**********************************************************************/
397
398 /**
399 * Try to match 'pattern' as the next token after any whitespace/comments.
400 */
401 static GLboolean
402 Parse_String(struct parse_state *parseState, const char *pattern)
403 {
404 const GLubyte *m;
405 GLint i;
406
407 /* skip whitespace and comments */
408 while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
409 if (*parseState->pos == '#') {
410 while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
411 parseState->pos += 1;
412 }
413 if (*parseState->pos == '\n' || *parseState->pos == '\r')
414 parseState->curLine = parseState->pos + 1;
415 }
416 else {
417 /* skip whitespace */
418 if (*parseState->pos == '\n' || *parseState->pos == '\r')
419 parseState->curLine = parseState->pos + 1;
420 parseState->pos += 1;
421 }
422 }
423
424 /* Try to match the pattern */
425 m = parseState->pos;
426 for (i = 0; pattern[i]; i++) {
427 if (*m != (GLubyte) pattern[i])
428 return GL_FALSE;
429 m += 1;
430 }
431 parseState->pos = m;
432
433 return GL_TRUE; /* success */
434 }
435
436
437 static GLboolean
438 Parse_Identifier(struct parse_state *parseState, GLubyte *ident)
439 {
440 if (!Parse_Token(parseState, ident))
441 RETURN_ERROR;
442 if (IsLetter(ident[0]))
443 return GL_TRUE;
444 else
445 RETURN_ERROR1("Expected an identfier");
446 }
447
448
449 /**
450 * Parse a floating point constant, or a defined symbol name.
451 * [+/-]N[.N[eN]]
452 * Output: number[0 .. 3] will get the value.
453 */
454 static GLboolean
455 Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number)
456 {
457 char *end = NULL;
458
459 *number = (GLfloat) _mesa_strtof((const char *) parseState->pos, &end);
460
461 if (end && end > (char *) parseState->pos) {
462 /* got a number */
463 parseState->pos = (GLubyte *) end;
464 number[1] = *number;
465 number[2] = *number;
466 number[3] = *number;
467 return GL_TRUE;
468 }
469 else {
470 /* should be an identifier */
471 GLubyte ident[100];
472 const GLfloat *constant;
473 if (!Parse_Identifier(parseState, ident))
474 RETURN_ERROR1("Expected an identifier");
475 constant = (GLfloat *)_mesa_lookup_parameter_value(parseState->parameters,
476 -1,
477 (const char *) ident);
478 /* XXX Check that it's a constant and not a parameter */
479 if (!constant) {
480 RETURN_ERROR1("Undefined symbol");
481 }
482 else {
483 COPY_4V(number, constant);
484 return GL_TRUE;
485 }
486 }
487 }
488
489
490
491 /**
492 * Parse a vector constant, one of:
493 * { float }
494 * { float, float }
495 * { float, float, float }
496 * { float, float, float, float }
497 */
498 static GLboolean
499 Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
500 {
501 /* "{" was already consumed */
502
503 ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0);
504
505 if (!Parse_ScalarConstant(parseState, vec+0)) /* X */
506 return GL_FALSE;
507
508 if (Parse_String(parseState, "}")) {
509 return GL_TRUE;
510 }
511
512 if (!Parse_String(parseState, ","))
513 RETURN_ERROR1("Expected comma in vector constant");
514
515 if (!Parse_ScalarConstant(parseState, vec+1)) /* Y */
516 return GL_FALSE;
517
518 if (Parse_String(parseState, "}")) {
519 return GL_TRUE;
520 }
521
522 if (!Parse_String(parseState, ","))
523 RETURN_ERROR1("Expected comma in vector constant");
524
525 if (!Parse_ScalarConstant(parseState, vec+2)) /* Z */
526 return GL_FALSE;
527
528 if (Parse_String(parseState, "}")) {
529 return GL_TRUE;
530 }
531
532 if (!Parse_String(parseState, ","))
533 RETURN_ERROR1("Expected comma in vector constant");
534
535 if (!Parse_ScalarConstant(parseState, vec+3)) /* W */
536 return GL_FALSE;
537
538 if (!Parse_String(parseState, "}"))
539 RETURN_ERROR1("Expected closing brace in vector constant");
540
541 return GL_TRUE;
542 }
543
544
545 /**
546 * Parse <number>, <varname> or {a, b, c, d}.
547 * Return number of values in the vector or scalar, or zero if parse error.
548 */
549 static GLuint
550 Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec)
551 {
552 if (Parse_String(parseState, "{")) {
553 return Parse_VectorConstant(parseState, vec);
554 }
555 else {
556 GLboolean b = Parse_ScalarConstant(parseState, vec);
557 if (b) {
558 vec[1] = vec[2] = vec[3] = vec[0];
559 }
560 return b;
561 }
562 }
563
564
565 /**
566 * Parse a texture image source:
567 * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
568 */
569 static GLboolean
570 Parse_TextureImageId(struct parse_state *parseState,
571 GLubyte *texUnit, GLubyte *texTarget)
572 {
573 GLubyte imageSrc[100];
574 GLint unit;
575
576 if (!Parse_Token(parseState, imageSrc))
577 RETURN_ERROR;
578
579 if (imageSrc[0] != 'T' ||
580 imageSrc[1] != 'E' ||
581 imageSrc[2] != 'X') {
582 RETURN_ERROR1("Expected TEX# source");
583 }
584 unit = atoi((const char *) imageSrc + 3);
585 if ((unit < 0 || unit >= MAX_TEXTURE_IMAGE_UNITS) ||
586 (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) {
587 RETURN_ERROR1("Invalied TEX# source index");
588 }
589 *texUnit = unit;
590
591 if (!Parse_String(parseState, ","))
592 RETURN_ERROR1("Expected ,");
593
594 if (Parse_String(parseState, "1D")) {
595 *texTarget = TEXTURE_1D_INDEX;
596 }
597 else if (Parse_String(parseState, "2D")) {
598 *texTarget = TEXTURE_2D_INDEX;
599 }
600 else if (Parse_String(parseState, "3D")) {
601 *texTarget = TEXTURE_3D_INDEX;
602 }
603 else if (Parse_String(parseState, "CUBE")) {
604 *texTarget = TEXTURE_CUBE_INDEX;
605 }
606 else if (Parse_String(parseState, "RECT")) {
607 *texTarget = TEXTURE_RECT_INDEX;
608 }
609 else {
610 RETURN_ERROR1("Invalid texture target token");
611 }
612
613 /* update record of referenced texture units */
614 parseState->texturesUsed[*texUnit] |= (1 << *texTarget);
615 if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) {
616 RETURN_ERROR1("Only one texture target can be used per texture unit.");
617 }
618
619 return GL_TRUE;
620 }
621
622
623 /**
624 * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
625 * like .wxyz, .xxyy, etc and return the swizzle indexes.
626 */
627 static GLboolean
628 Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4])
629 {
630 if (token[1] == 0) {
631 /* single letter swizzle (scalar) */
632 if (token[0] == 'x')
633 ASSIGN_4V(swizzle, 0, 0, 0, 0);
634 else if (token[0] == 'y')
635 ASSIGN_4V(swizzle, 1, 1, 1, 1);
636 else if (token[0] == 'z')
637 ASSIGN_4V(swizzle, 2, 2, 2, 2);
638 else if (token[0] == 'w')
639 ASSIGN_4V(swizzle, 3, 3, 3, 3);
640 else
641 return GL_FALSE;
642 }
643 else {
644 /* 4-component swizzle (vector) */
645 GLint k;
646 for (k = 0; k < 4 && token[k]; k++) {
647 if (token[k] == 'x')
648 swizzle[k] = 0;
649 else if (token[k] == 'y')
650 swizzle[k] = 1;
651 else if (token[k] == 'z')
652 swizzle[k] = 2;
653 else if (token[k] == 'w')
654 swizzle[k] = 3;
655 else
656 return GL_FALSE;
657 }
658 if (k != 4)
659 return GL_FALSE;
660 }
661 return GL_TRUE;
662 }
663
664
665 static GLboolean
666 Parse_CondCodeMask(struct parse_state *parseState,
667 struct prog_dst_register *dstReg)
668 {
669 if (Parse_String(parseState, "EQ"))
670 dstReg->CondMask = COND_EQ;
671 else if (Parse_String(parseState, "GE"))
672 dstReg->CondMask = COND_GE;
673 else if (Parse_String(parseState, "GT"))
674 dstReg->CondMask = COND_GT;
675 else if (Parse_String(parseState, "LE"))
676 dstReg->CondMask = COND_LE;
677 else if (Parse_String(parseState, "LT"))
678 dstReg->CondMask = COND_LT;
679 else if (Parse_String(parseState, "NE"))
680 dstReg->CondMask = COND_NE;
681 else if (Parse_String(parseState, "TR"))
682 dstReg->CondMask = COND_TR;
683 else if (Parse_String(parseState, "FL"))
684 dstReg->CondMask = COND_FL;
685 else
686 RETURN_ERROR1("Invalid condition code mask");
687
688 /* look for optional .xyzw swizzle */
689 if (Parse_String(parseState, ".")) {
690 GLubyte token[100];
691 GLuint swz[4];
692
693 if (!Parse_Token(parseState, token)) /* get xyzw suffix */
694 RETURN_ERROR;
695
696 if (!Parse_SwizzleSuffix(token, swz))
697 RETURN_ERROR1("Invalid swizzle suffix");
698
699 dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
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 = 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 = 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 (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
830 /* Match "o[" */
831 if (!Parse_String(parseState, "o["))
832 RETURN_ERROR1("Expected o[");
833
834 /* Get output reg name */
835 if (!Parse_Token(parseState, token))
836 RETURN_ERROR;
837
838 /* try to match an output register name */
839 if (strcmp((char *) token, "COLR") == 0 ||
840 strcmp((char *) token, "COLH") == 0) {
841 /* note that we don't distinguish between COLR and COLH */
842 *outputRegNum = FRAG_RESULT_COLOR;
843 parseState->outputsWritten |= (1 << FRAG_RESULT_COLOR);
844 }
845 else if (strcmp((char *) token, "DEPR") == 0) {
846 *outputRegNum = FRAG_RESULT_DEPTH;
847 parseState->outputsWritten |= (1 << FRAG_RESULT_DEPTH);
848 }
849 else {
850 RETURN_ERROR1("Invalid output register name");
851 }
852
853 /* Match ']' */
854 if (!Parse_String(parseState, "]"))
855 RETURN_ERROR1("Expected ]");
856
857 return GL_TRUE;
858 }
859
860
861 static GLboolean
862 Parse_MaskedDstReg(struct parse_state *parseState,
863 struct prog_dst_register *dstReg)
864 {
865 GLubyte token[100];
866 GLint idx;
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 (strcmp((const char *) token, "RC") == 0 ||
873 strcmp((const char *) token, "HC") == 0) {
874 /* a write-only register */
875 dstReg->File = PROGRAM_WRITE_ONLY;
876 if (!Parse_DummyReg(parseState, &idx))
877 RETURN_ERROR;
878 dstReg->Index = idx;
879 }
880 else if (token[0] == 'R' || token[0] == 'H') {
881 /* a temporary register */
882 dstReg->File = PROGRAM_TEMPORARY;
883 if (!Parse_TempReg(parseState, &idx))
884 RETURN_ERROR;
885 dstReg->Index = idx;
886 }
887 else if (token[0] == 'o') {
888 /* an output register */
889 dstReg->File = PROGRAM_OUTPUT;
890 if (!Parse_OutputReg(parseState, &idx))
891 RETURN_ERROR;
892 dstReg->Index = idx;
893 }
894 else {
895 RETURN_ERROR1("Invalid destination register name");
896 }
897
898 /* Parse optional write mask */
899 if (Parse_String(parseState, ".")) {
900 /* got a mask */
901 GLint k = 0;
902
903 if (!Parse_Token(parseState, token)) /* get xyzw writemask */
904 RETURN_ERROR;
905
906 dstReg->WriteMask = 0;
907
908 if (token[k] == 'x') {
909 dstReg->WriteMask |= WRITEMASK_X;
910 k++;
911 }
912 if (token[k] == 'y') {
913 dstReg->WriteMask |= WRITEMASK_Y;
914 k++;
915 }
916 if (token[k] == 'z') {
917 dstReg->WriteMask |= WRITEMASK_Z;
918 k++;
919 }
920 if (token[k] == 'w') {
921 dstReg->WriteMask |= WRITEMASK_W;
922 k++;
923 }
924 if (k == 0) {
925 RETURN_ERROR1("Invalid writemask character");
926 }
927
928 }
929 else {
930 dstReg->WriteMask = WRITEMASK_XYZW;
931 }
932
933 /* optional condition code mask */
934 if (Parse_String(parseState, "(")) {
935 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
936 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
937 if (!Parse_CondCodeMask(parseState, dstReg))
938 RETURN_ERROR;
939
940 if (!Parse_String(parseState, ")")) /* consume ")" */
941 RETURN_ERROR1("Expected )");
942
943 return GL_TRUE;
944 }
945 else {
946 /* no cond code mask */
947 dstReg->CondMask = COND_TR;
948 dstReg->CondSwizzle = SWIZZLE_NOOP;
949 return GL_TRUE;
950 }
951 }
952
953
954 /**
955 * Parse a vector source (register, constant, etc):
956 * <vectorSrc> ::= <absVectorSrc>
957 * | <baseVectorSrc>
958 * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
959 */
960 static GLboolean
961 Parse_VectorSrc(struct parse_state *parseState,
962 struct prog_src_register *srcReg)
963 {
964 GLfloat sign = 1.0F;
965 GLubyte token[100];
966 GLint idx;
967 GLuint negateBase, negateAbs;
968
969 /*
970 * First, take care of +/- and absolute value stuff.
971 */
972 if (Parse_String(parseState, "-"))
973 sign = -1.0F;
974 else if (Parse_String(parseState, "+"))
975 sign = +1.0F;
976
977 if (Parse_String(parseState, "|")) {
978 srcReg->Abs = GL_TRUE;
979 negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
980
981 if (Parse_String(parseState, "-"))
982 negateBase = NEGATE_XYZW;
983 else if (Parse_String(parseState, "+"))
984 negateBase = NEGATE_NONE;
985 else
986 negateBase = NEGATE_NONE;
987 }
988 else {
989 srcReg->Abs = GL_FALSE;
990 negateAbs = NEGATE_NONE;
991 negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
992 }
993
994 srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
995
996 /* This should be the real src vector/register name */
997 if (!Peek_Token(parseState, token))
998 RETURN_ERROR;
999
1000 /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
1001 * literal or vector literal.
1002 */
1003 if (token[0] == 'R' || token[0] == 'H') {
1004 srcReg->File = PROGRAM_TEMPORARY;
1005 if (!Parse_TempReg(parseState, &idx))
1006 RETURN_ERROR;
1007 srcReg->Index = idx;
1008 }
1009 else if (token[0] == 'f') {
1010 /* XXX this might be an identifier! */
1011 srcReg->File = PROGRAM_INPUT;
1012 if (!Parse_FragReg(parseState, &idx))
1013 RETURN_ERROR;
1014 srcReg->Index = idx;
1015 }
1016 else if (token[0] == 'p') {
1017 /* XXX this might be an identifier! */
1018 srcReg->File = PROGRAM_LOCAL_PARAM;
1019 if (!Parse_ProgramParamReg(parseState, &idx))
1020 RETURN_ERROR;
1021 srcReg->Index = idx;
1022 }
1023 else if (IsLetter(token[0])){
1024 GLubyte ident[100];
1025 GLint paramIndex;
1026 if (!Parse_Identifier(parseState, ident))
1027 RETURN_ERROR;
1028 paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1029 -1, (const char *) ident);
1030 if (paramIndex < 0) {
1031 RETURN_ERROR2("Undefined constant or parameter: ", ident);
1032 }
1033 srcReg->File = PROGRAM_NAMED_PARAM;
1034 srcReg->Index = paramIndex;
1035 }
1036 else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){
1037 /* literal scalar constant */
1038 GLfloat values[4];
1039 GLuint paramIndex;
1040 if (!Parse_ScalarConstant(parseState, values))
1041 RETURN_ERROR;
1042 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1043 (gl_constant_value *) values,
1044 4, NULL);
1045 srcReg->File = PROGRAM_NAMED_PARAM;
1046 srcReg->Index = paramIndex;
1047 }
1048 else if (token[0] == '{'){
1049 /* literal vector constant */
1050 GLfloat values[4];
1051 GLuint paramIndex;
1052 (void) Parse_String(parseState, "{");
1053 if (!Parse_VectorConstant(parseState, values))
1054 RETURN_ERROR;
1055 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1056 (gl_constant_value *) values,
1057 4, NULL);
1058 srcReg->File = PROGRAM_NAMED_PARAM;
1059 srcReg->Index = paramIndex;
1060 }
1061 else {
1062 RETURN_ERROR2("Invalid source register name", token);
1063 }
1064
1065 /* init swizzle fields */
1066 srcReg->Swizzle = SWIZZLE_NOOP;
1067
1068 /* Look for optional swizzle suffix */
1069 if (Parse_String(parseState, ".")) {
1070 GLuint swz[4];
1071
1072 if (!Parse_Token(parseState, token))
1073 RETURN_ERROR;
1074
1075 if (!Parse_SwizzleSuffix(token, swz))
1076 RETURN_ERROR1("Invalid swizzle suffix");
1077
1078 srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
1079 }
1080
1081 /* Finish absolute value */
1082 if (srcReg->Abs && !Parse_String(parseState, "|")) {
1083 RETURN_ERROR1("Expected |");
1084 }
1085
1086 return GL_TRUE;
1087 }
1088
1089
1090 static GLboolean
1091 Parse_ScalarSrcReg(struct parse_state *parseState,
1092 struct prog_src_register *srcReg)
1093 {
1094 GLubyte token[100];
1095 GLfloat sign = 1.0F;
1096 GLboolean needSuffix = GL_TRUE;
1097 GLint idx;
1098 GLuint negateBase, negateAbs;
1099
1100 /*
1101 * First, take care of +/- and absolute value stuff.
1102 */
1103 if (Parse_String(parseState, "-"))
1104 sign = -1.0F;
1105 else if (Parse_String(parseState, "+"))
1106 sign = +1.0F;
1107
1108 if (Parse_String(parseState, "|")) {
1109 srcReg->Abs = GL_TRUE;
1110 negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
1111
1112 if (Parse_String(parseState, "-"))
1113 negateBase = NEGATE_XYZW;
1114 else if (Parse_String(parseState, "+"))
1115 negateBase = NEGATE_NONE;
1116 else
1117 negateBase = NEGATE_NONE;
1118 }
1119 else {
1120 srcReg->Abs = GL_FALSE;
1121 negateAbs = NEGATE_NONE;
1122 negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
1123 }
1124
1125 srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
1126
1127 if (!Peek_Token(parseState, token))
1128 RETURN_ERROR;
1129
1130 /* Src reg can be R<n>, H<n> or a named fragment attrib */
1131 if (token[0] == 'R' || token[0] == 'H') {
1132 srcReg->File = PROGRAM_TEMPORARY;
1133 if (!Parse_TempReg(parseState, &idx))
1134 RETURN_ERROR;
1135 srcReg->Index = idx;
1136 }
1137 else if (token[0] == 'f') {
1138 srcReg->File = PROGRAM_INPUT;
1139 if (!Parse_FragReg(parseState, &idx))
1140 RETURN_ERROR;
1141 srcReg->Index = idx;
1142 }
1143 else if (token[0] == '{') {
1144 /* vector literal */
1145 GLfloat values[4];
1146 GLuint paramIndex;
1147 (void) Parse_String(parseState, "{");
1148 if (!Parse_VectorConstant(parseState, values))
1149 RETURN_ERROR;
1150 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1151 (gl_constant_value *) values,
1152 4, NULL);
1153 srcReg->File = PROGRAM_NAMED_PARAM;
1154 srcReg->Index = paramIndex;
1155 }
1156 else if (IsLetter(token[0])){
1157 /* named param/constant */
1158 GLubyte ident[100];
1159 GLint paramIndex;
1160 if (!Parse_Identifier(parseState, ident))
1161 RETURN_ERROR;
1162 paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1163 -1, (const char *) ident);
1164 if (paramIndex < 0) {
1165 RETURN_ERROR2("Undefined constant or parameter: ", ident);
1166 }
1167 srcReg->File = PROGRAM_NAMED_PARAM;
1168 srcReg->Index = paramIndex;
1169 }
1170 else if (IsDigit(token[0])) {
1171 /* scalar literal */
1172 GLfloat values[4];
1173 GLuint paramIndex;
1174 if (!Parse_ScalarConstant(parseState, values))
1175 RETURN_ERROR;
1176 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1177 (gl_constant_value *) values,
1178 4, NULL);
1179 srcReg->Index = paramIndex;
1180 srcReg->File = PROGRAM_NAMED_PARAM;
1181 needSuffix = GL_FALSE;
1182 }
1183 else {
1184 RETURN_ERROR2("Invalid scalar source argument", token);
1185 }
1186
1187 srcReg->Swizzle = 0;
1188 if (needSuffix) {
1189 /* parse .[xyzw] suffix */
1190 if (!Parse_String(parseState, "."))
1191 RETURN_ERROR1("Expected .");
1192
1193 if (!Parse_Token(parseState, token))
1194 RETURN_ERROR;
1195
1196 if (token[0] == 'x' && token[1] == 0) {
1197 srcReg->Swizzle = 0;
1198 }
1199 else if (token[0] == 'y' && token[1] == 0) {
1200 srcReg->Swizzle = 1;
1201 }
1202 else if (token[0] == 'z' && token[1] == 0) {
1203 srcReg->Swizzle = 2;
1204 }
1205 else if (token[0] == 'w' && token[1] == 0) {
1206 srcReg->Swizzle = 3;
1207 }
1208 else {
1209 RETURN_ERROR1("Invalid scalar source suffix");
1210 }
1211 }
1212
1213 /* Finish absolute value */
1214 if (srcReg->Abs && !Parse_String(parseState, "|")) {
1215 RETURN_ERROR1("Expected |");
1216 }
1217
1218 return GL_TRUE;
1219 }
1220
1221
1222 static GLboolean
1223 Parse_PrintInstruction(struct parse_state *parseState,
1224 struct prog_instruction *inst)
1225 {
1226 const GLubyte *str;
1227 GLubyte *msg;
1228 GLuint len;
1229 GLint idx;
1230
1231 /* The first argument is a literal string 'just like this' */
1232 if (!Parse_String(parseState, "'"))
1233 RETURN_ERROR1("Expected '");
1234
1235 str = parseState->pos;
1236 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1237 ;
1238 parseState->pos += len + 1;
1239 msg = malloc(len + 1);
1240
1241 memcpy(msg, str, len);
1242 msg[len] = 0;
1243 inst->Data = msg;
1244
1245 if (Parse_String(parseState, ",")) {
1246 /* got an optional register to print */
1247 GLubyte token[100];
1248 GetToken(parseState, token);
1249 if (token[0] == 'o') {
1250 /* dst reg */
1251 if (!Parse_OutputReg(parseState, &idx))
1252 RETURN_ERROR;
1253 inst->SrcReg[0].Index = idx;
1254 inst->SrcReg[0].File = PROGRAM_OUTPUT;
1255 }
1256 else {
1257 /* src reg */
1258 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1259 RETURN_ERROR;
1260 }
1261 }
1262 else {
1263 inst->SrcReg[0].File = PROGRAM_UNDEFINED;
1264 }
1265
1266 inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
1267 inst->SrcReg[0].Abs = GL_FALSE;
1268 inst->SrcReg[0].Negate = NEGATE_NONE;
1269
1270 return GL_TRUE;
1271 }
1272
1273
1274 static GLboolean
1275 Parse_InstructionSequence(struct parse_state *parseState,
1276 struct prog_instruction program[])
1277 {
1278 while (1) {
1279 struct prog_instruction *inst = program + parseState->numInst;
1280 struct instruction_pattern instMatch;
1281 GLubyte token[100];
1282
1283 /* Initialize the instruction */
1284 _mesa_init_instructions(inst, 1);
1285
1286 /* special instructions */
1287 if (Parse_String(parseState, "DEFINE")) {
1288 GLubyte id[100];
1289 GLfloat value[7]; /* yes, 7 to be safe */
1290 if (!Parse_Identifier(parseState, id))
1291 RETURN_ERROR;
1292 /* XXX make sure id is not a reserved identifer, like R9 */
1293 if (!Parse_String(parseState, "="))
1294 RETURN_ERROR1("Expected =");
1295 if (!Parse_VectorOrScalarConstant(parseState, value))
1296 RETURN_ERROR;
1297 if (!Parse_String(parseState, ";"))
1298 RETURN_ERROR1("Expected ;");
1299 if (_mesa_lookup_parameter_index(parseState->parameters,
1300 -1, (const char *) id) >= 0) {
1301 RETURN_ERROR2(id, "already defined");
1302 }
1303 _mesa_add_named_parameter(parseState->parameters,
1304 (const char *) id,
1305 (gl_constant_value *) value);
1306 }
1307 else if (Parse_String(parseState, "DECLARE")) {
1308 GLubyte id[100];
1309 GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */
1310 if (!Parse_Identifier(parseState, id))
1311 RETURN_ERROR;
1312 /* XXX make sure id is not a reserved identifer, like R9 */
1313 if (Parse_String(parseState, "=")) {
1314 if (!Parse_VectorOrScalarConstant(parseState, value))
1315 RETURN_ERROR;
1316 }
1317 if (!Parse_String(parseState, ";"))
1318 RETURN_ERROR1("Expected ;");
1319 if (_mesa_lookup_parameter_index(parseState->parameters,
1320 -1, (const char *) id) >= 0) {
1321 RETURN_ERROR2(id, "already declared");
1322 }
1323 _mesa_add_named_parameter(parseState->parameters,
1324 (const char *) id,
1325 (gl_constant_value *) value);
1326 }
1327 else if (Parse_String(parseState, "END")) {
1328 inst->Opcode = OPCODE_END;
1329 parseState->numInst++;
1330 if (Parse_Token(parseState, token)) {
1331 RETURN_ERROR1("Code after END opcode.");
1332 }
1333 break;
1334 }
1335 else {
1336 /* general/arithmetic instruction */
1337
1338 /* get token */
1339 if (!Parse_Token(parseState, token)) {
1340 RETURN_ERROR1("Missing END instruction.");
1341 }
1342
1343 /* try to find matching instuction */
1344 instMatch = MatchInstruction(token);
1345 if (instMatch.opcode >= MAX_OPCODE) {
1346 /* bad instruction name */
1347 RETURN_ERROR2("Unexpected token: ", token);
1348 }
1349
1350 inst->Opcode = instMatch.opcode;
1351 inst->Precision = instMatch.suffixes & (_R | _H | _X);
1352 inst->SaturateMode = (instMatch.suffixes & (_S))
1353 ? SATURATE_ZERO_ONE : SATURATE_OFF;
1354 inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
1355
1356 /*
1357 * parse the input and output operands
1358 */
1359 if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
1360 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
1361 RETURN_ERROR;
1362 if (!Parse_String(parseState, ","))
1363 RETURN_ERROR1("Expected ,");
1364 }
1365 else if (instMatch.outputs == OUTPUT_NONE) {
1366 if (instMatch.opcode == OPCODE_KIL_NV) {
1367 /* This is a little weird, the cond code info is in
1368 * the dest register.
1369 */
1370 if (!Parse_CondCodeMask(parseState, &inst->DstReg))
1371 RETURN_ERROR;
1372 }
1373 else {
1374 ASSERT(instMatch.opcode == OPCODE_PRINT);
1375 }
1376 }
1377
1378 if (instMatch.inputs == INPUT_1V) {
1379 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1380 RETURN_ERROR;
1381 }
1382 else if (instMatch.inputs == INPUT_2V) {
1383 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1384 RETURN_ERROR;
1385 if (!Parse_String(parseState, ","))
1386 RETURN_ERROR1("Expected ,");
1387 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1388 RETURN_ERROR;
1389 }
1390 else if (instMatch.inputs == INPUT_3V) {
1391 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1392 RETURN_ERROR;
1393 if (!Parse_String(parseState, ","))
1394 RETURN_ERROR1("Expected ,");
1395 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1396 RETURN_ERROR;
1397 if (!Parse_String(parseState, ","))
1398 RETURN_ERROR1("Expected ,");
1399 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1400 RETURN_ERROR;
1401 }
1402 else if (instMatch.inputs == INPUT_1S) {
1403 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1404 RETURN_ERROR;
1405 }
1406 else if (instMatch.inputs == INPUT_2S) {
1407 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1408 RETURN_ERROR;
1409 if (!Parse_String(parseState, ","))
1410 RETURN_ERROR1("Expected ,");
1411 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
1412 RETURN_ERROR;
1413 }
1414 else if (instMatch.inputs == INPUT_CC) {
1415 /* XXX to-do */
1416 }
1417 else if (instMatch.inputs == INPUT_1V_T) {
1418 GLubyte unit, idx;
1419 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1420 RETURN_ERROR;
1421 if (!Parse_String(parseState, ","))
1422 RETURN_ERROR1("Expected ,");
1423 if (!Parse_TextureImageId(parseState, &unit, &idx))
1424 RETURN_ERROR;
1425 inst->TexSrcUnit = unit;
1426 inst->TexSrcTarget = idx;
1427 }
1428 else if (instMatch.inputs == INPUT_3V_T) {
1429 GLubyte unit, idx;
1430 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1431 RETURN_ERROR;
1432 if (!Parse_String(parseState, ","))
1433 RETURN_ERROR1("Expected ,");
1434 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1435 RETURN_ERROR;
1436 if (!Parse_String(parseState, ","))
1437 RETURN_ERROR1("Expected ,");
1438 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1439 RETURN_ERROR;
1440 if (!Parse_String(parseState, ","))
1441 RETURN_ERROR1("Expected ,");
1442 if (!Parse_TextureImageId(parseState, &unit, &idx))
1443 RETURN_ERROR;
1444 inst->TexSrcUnit = unit;
1445 inst->TexSrcTarget = idx;
1446 }
1447 else if (instMatch.inputs == INPUT_1V_S) {
1448 if (!Parse_PrintInstruction(parseState, inst))
1449 RETURN_ERROR;
1450 }
1451
1452 /* end of statement semicolon */
1453 if (!Parse_String(parseState, ";"))
1454 RETURN_ERROR1("Expected ;");
1455
1456 parseState->numInst++;
1457
1458 if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
1459 RETURN_ERROR1("Program too long");
1460 }
1461 }
1462 return GL_TRUE;
1463 }
1464
1465
1466
1467 /**
1468 * Parse/compile the 'str' returning the compiled 'program'.
1469 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1470 * indicates the position of the error in 'str'.
1471 */
1472 void
1473 _mesa_parse_nv_fragment_program(struct gl_context *ctx, GLenum dstTarget,
1474 const GLubyte *str, GLsizei len,
1475 struct gl_fragment_program *program)
1476 {
1477 struct parse_state parseState;
1478 struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
1479 struct prog_instruction *newInst;
1480 GLenum target;
1481 GLubyte *programString;
1482
1483 /* Make a null-terminated copy of the program string */
1484 programString = malloc(len + 1);
1485 if (!programString) {
1486 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1487 return;
1488 }
1489 memcpy(programString, str, len);
1490 programString[len] = 0;
1491
1492 /* Get ready to parse */
1493 memset(&parseState, 0, sizeof(struct parse_state));
1494 parseState.ctx = ctx;
1495 parseState.start = programString;
1496 parseState.program = program;
1497 parseState.numInst = 0;
1498 parseState.curLine = programString;
1499 parseState.parameters = _mesa_new_parameter_list();
1500
1501 /* Reset error state */
1502 _mesa_set_program_error(ctx, -1, NULL);
1503
1504 /* check the program header */
1505 if (strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
1506 target = GL_FRAGMENT_PROGRAM_NV;
1507 parseState.pos = programString + 7;
1508 }
1509 else if (strncmp((const char *) programString, "!!FCP1.0", 8) == 0) {
1510 /* fragment / register combiner program - not supported */
1511 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1512 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1513 return;
1514 }
1515 else {
1516 /* invalid header */
1517 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1518 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1519 return;
1520 }
1521
1522 /* make sure target and header match */
1523 if (target != dstTarget) {
1524 _mesa_error(ctx, GL_INVALID_OPERATION,
1525 "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1526 target, dstTarget);
1527 return;
1528 }
1529
1530 if (Parse_InstructionSequence(&parseState, instBuffer)) {
1531 GLuint u;
1532 /* successful parse! */
1533
1534 if (parseState.outputsWritten == 0) {
1535 /* must write at least one output! */
1536 _mesa_error(ctx, GL_INVALID_OPERATION,
1537 "Invalid fragment program - no outputs written.");
1538 return;
1539 }
1540
1541 /* copy the compiled instructions */
1542 assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
1543 newInst = _mesa_alloc_instructions(parseState.numInst);
1544 if (!newInst) {
1545 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1546 return; /* out of memory */
1547 }
1548 _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
1549
1550 /* install the program */
1551 program->Base.Target = target;
1552 if (program->Base.String) {
1553 free(program->Base.String);
1554 }
1555 program->Base.String = programString;
1556 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
1557 if (program->Base.Instructions) {
1558 free(program->Base.Instructions);
1559 }
1560 program->Base.Instructions = newInst;
1561 program->Base.NumInstructions = parseState.numInst;
1562 program->Base.InputsRead = parseState.inputsRead;
1563 program->Base.OutputsWritten = parseState.outputsWritten;
1564 for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
1565 program->Base.TexturesUsed[u] = parseState.texturesUsed[u];
1566
1567 /* save program parameters */
1568 program->Base.Parameters = parseState.parameters;
1569
1570 /* allocate registers for declared program parameters */
1571 #if 00
1572 _mesa_assign_program_registers(&(program->SymbolTable));
1573 #endif
1574
1575 #ifdef DEBUG_foo
1576 printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
1577 _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
1578 printf("----------------------------------\n");
1579 #endif
1580 }
1581 else {
1582 /* Error! */
1583 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1584 /* NOTE: _mesa_set_program_error would have been called already */
1585 }
1586 }
1587
1588
1589 const char *
1590 _mesa_nv_fragment_input_register_name(GLuint i)
1591 {
1592 ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
1593 return InputRegisters[i];
1594 }
1595