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