blob: 35f18aa2fb7364510ab63358ec4d057d99a6c29f [file] [log] [blame]
Michal Krol2861e732004-03-29 11:09:34 +00001/*
2 * Mesa 3-D graphics library
Brian Paul7e807512005-11-05 17:10:45 +00003 * Version: 6.5
Michal Krol2861e732004-03-29 11:09:34 +00004 *
Brian Paul7e807512005-11-05 17:10:45 +00005 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
Michal Krol2861e732004-03-29 11:09:34 +00006 *
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
Brian Paulbbd28712008-09-18 12:26:54 -060040#include "main/glheader.h"
41#include "main/context.h"
42#include "main/imports.h"
43#include "main/macros.h"
44#include "program.h"
Brianc0551f02006-12-14 15:02:37 -070045#include "prog_parameter.h"
Brian Paulfe278f12009-04-14 19:53:37 -060046#include "prog_print.h"
Brianc0551f02006-12-14 15:02:37 -070047#include "prog_instruction.h"
Michal Krol2861e732004-03-29 11:09:34 +000048#include "nvfragparse.h"
Michal Krol2861e732004-03-29 11:09:34 +000049
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
Brian Paul2a5afe32004-12-18 16:18:00 +000060#define INPUT_1V_S 10 /* a string and a vector register */
Michal Krol2861e732004-03-29 11:09:34 +000061#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
79struct instruction_pattern {
80 const char *name;
Brian Paul7e807512005-11-05 17:10:45 +000081 enum prog_opcode opcode;
Michal Krol2861e732004-03-29 11:09:34 +000082 GLuint inputs;
83 GLuint outputs;
84 GLuint suffixes;
85};
86
87static const struct instruction_pattern Instructions[] = {
Brian Paul7e807512005-11-05 17:10:45 +000088 { "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 }
Michal Krol2861e732004-03-29 11:09:34 +0000135};
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 */
143struct parse_state {
144 GLcontext *ctx;
145 const GLubyte *start; /* start of program string */
146 const GLubyte *pos; /* current position */
147 const GLubyte *curLine;
Brian Paul122629f2006-07-20 16:49:57 +0000148 struct gl_fragment_program *program; /* current program */
Michal Krol2861e732004-03-29 11:09:34 +0000149
Brian Paul122629f2006-07-20 16:49:57 +0000150 struct gl_program_parameter_list *parameters;
Michal Krol2861e732004-03-29 11:09:34 +0000151
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 */
163static void
164record_error(struct parse_state *parseState, const char *msg, int lineNo)
165{
166#ifdef DEBUG
167 GLint line, column;
168 const GLubyte *lineStr;
169 lineStr = _mesa_find_line_column(parseState->start,
170 parseState->pos, &line, &column);
171 _mesa_debug(parseState->ctx,
172 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
173 lineNo, line, column, (char *) lineStr, msg);
174 _mesa_free((void *) lineStr);
175#else
176 (void) lineNo;
177#endif
178
179 /* Check that no error was already recorded. Only record the first one. */
180 if (parseState->ctx->Program.ErrorString[0] == 0) {
181 _mesa_set_program_error(parseState->ctx,
182 parseState->pos - parseState->start,
183 msg);
184 }
185}
186
187
188#define RETURN_ERROR \
189do { \
190 record_error(parseState, "Unexpected end of input.", __LINE__); \
191 return GL_FALSE; \
192} while(0)
193
194#define RETURN_ERROR1(msg) \
195do { \
196 record_error(parseState, msg, __LINE__); \
197 return GL_FALSE; \
198} while(0)
199
200#define RETURN_ERROR2(msg1, msg2) \
201do { \
202 char err[1000]; \
203 _mesa_sprintf(err, "%s %s", msg1, msg2); \
204 record_error(parseState, err, __LINE__); \
205 return GL_FALSE; \
206} while(0)
207
208
209
210
211/*
212 * Search a list of instruction structures for a match.
213 */
214static struct instruction_pattern
215MatchInstruction(const GLubyte *token)
216{
217 const struct instruction_pattern *inst;
218 struct instruction_pattern result;
219
Vinson Lee94fba492009-12-10 18:51:51 -0800220 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
Michal Krol2861e732004-03-29 11:09:34 +0000226 for (inst = Instructions; inst->name; inst++) {
Kenneth Graunke9d9afe92010-02-18 23:50:57 -0800227 if (strncmp((const char *) token, inst->name, 3) == 0) {
Michal Krol2861e732004-03-29 11:09:34 +0000228 /* 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 }
Vinson Lee94fba492009-12-10 18:51:51 -0800256
Michal Krol2861e732004-03-29 11:09:34 +0000257 return result;
258}
259
260
261
262
263/**********************************************************************/
264
265
266static GLboolean IsLetter(GLubyte b)
267{
268 return (b >= 'a' && b <= 'z') ||
269 (b >= 'A' && b <= 'Z') ||
270 (b == '_') ||
271 (b == '$');
272}
273
274
275static GLboolean IsDigit(GLubyte b)
276{
277 return b >= '0' && b <= '9';
278}
279
280
281static 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 */
292static GLint
293GetToken(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 */
355static GLboolean
356Parse_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 */
372static GLboolean
373Peek_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 }
Kenneth Graunke21d0c702010-02-18 23:50:55 -0800381 len = (GLint) strlen((const char *) token);
Michal Krol2861e732004-03-29 11:09:34 +0000382 parseState->pos += (i - len);
383 return GL_TRUE;
384}
385
386
387/**********************************************************************/
388
389static 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
Brian Paul8d475822009-02-28 11:49:46 -0700394
Michal Krol2861e732004-03-29 11:09:34 +0000395
Michal Krol2861e732004-03-29 11:09:34 +0000396/**********************************************************************/
397
398/**
399 * Try to match 'pattern' as the next token after any whitespace/comments.
400 */
401static GLboolean
402Parse_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
437static GLboolean
438Parse_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 */
454static GLboolean
455Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number)
456{
457 char *end = NULL;
458
459 *number = (GLfloat) _mesa_strtod((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 = _mesa_lookup_parameter_value(parseState->parameters,
476 -1, (const char *) ident);
477 /* XXX Check that it's a constant and not a parameter */
478 if (!constant) {
479 RETURN_ERROR1("Undefined symbol");
480 }
481 else {
482 COPY_4V(number, constant);
483 return GL_TRUE;
484 }
485 }
486}
487
488
489
490/**
491 * Parse a vector constant, one of:
492 * { float }
493 * { float, float }
494 * { float, float, float }
495 * { float, float, float, float }
496 */
497static GLboolean
498Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
499{
500 /* "{" was already consumed */
501
502 ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0);
503
504 if (!Parse_ScalarConstant(parseState, vec+0)) /* X */
505 return GL_FALSE;
506
507 if (Parse_String(parseState, "}")) {
508 return GL_TRUE;
509 }
510
511 if (!Parse_String(parseState, ","))
512 RETURN_ERROR1("Expected comma in vector constant");
513
514 if (!Parse_ScalarConstant(parseState, vec+1)) /* Y */
515 return GL_FALSE;
516
517 if (Parse_String(parseState, "}")) {
518 return GL_TRUE;
519 }
520
521 if (!Parse_String(parseState, ","))
522 RETURN_ERROR1("Expected comma in vector constant");
523
524 if (!Parse_ScalarConstant(parseState, vec+2)) /* Z */
525 return GL_FALSE;
526
527 if (Parse_String(parseState, "}")) {
528 return GL_TRUE;
529 }
530
531 if (!Parse_String(parseState, ","))
532 RETURN_ERROR1("Expected comma in vector constant");
533
534 if (!Parse_ScalarConstant(parseState, vec+3)) /* W */
535 return GL_FALSE;
536
537 if (!Parse_String(parseState, "}"))
538 RETURN_ERROR1("Expected closing brace in vector constant");
539
540 return GL_TRUE;
541}
542
543
544/**
545 * Parse <number>, <varname> or {a, b, c, d}.
546 * Return number of values in the vector or scalar, or zero if parse error.
547 */
548static GLuint
549Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec)
550{
551 if (Parse_String(parseState, "{")) {
552 return Parse_VectorConstant(parseState, vec);
553 }
554 else {
555 GLboolean b = Parse_ScalarConstant(parseState, vec);
556 if (b) {
557 vec[1] = vec[2] = vec[3] = vec[0];
558 }
559 return b;
560 }
561}
562
563
564/**
565 * Parse a texture image source:
566 * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
567 */
568static GLboolean
569Parse_TextureImageId(struct parse_state *parseState,
570 GLubyte *texUnit, GLubyte *texTargetBit)
571{
572 GLubyte imageSrc[100];
573 GLint unit;
574
575 if (!Parse_Token(parseState, imageSrc))
576 RETURN_ERROR;
577
578 if (imageSrc[0] != 'T' ||
579 imageSrc[1] != 'E' ||
580 imageSrc[2] != 'X') {
581 RETURN_ERROR1("Expected TEX# source");
582 }
Kenneth Graunke60b0cae2010-02-18 23:50:58 -0800583 unit = atoi((const char *) imageSrc + 3);
Michal Krol2861e732004-03-29 11:09:34 +0000584 if ((unit < 0 || unit > MAX_TEXTURE_IMAGE_UNITS) ||
585 (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) {
586 RETURN_ERROR1("Invalied TEX# source index");
587 }
588 *texUnit = unit;
589
590 if (!Parse_String(parseState, ","))
591 RETURN_ERROR1("Expected ,");
592
593 if (Parse_String(parseState, "1D")) {
594 *texTargetBit = TEXTURE_1D_BIT;
595 }
596 else if (Parse_String(parseState, "2D")) {
597 *texTargetBit = TEXTURE_2D_BIT;
598 }
599 else if (Parse_String(parseState, "3D")) {
600 *texTargetBit = TEXTURE_3D_BIT;
601 }
602 else if (Parse_String(parseState, "CUBE")) {
603 *texTargetBit = TEXTURE_CUBE_BIT;
604 }
605 else if (Parse_String(parseState, "RECT")) {
606 *texTargetBit = TEXTURE_RECT_BIT;
607 }
608 else {
609 RETURN_ERROR1("Invalid texture target token");
610 }
611
612 /* update record of referenced texture units */
613 parseState->texturesUsed[*texUnit] |= *texTargetBit;
614 if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) {
615 RETURN_ERROR1("Only one texture target can be used per texture unit.");
616 }
617
618 return GL_TRUE;
619}
620
621
622/**
623 * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
624 * like .wxyz, .xxyy, etc and return the swizzle indexes.
625 */
626static GLboolean
627Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4])
628{
629 if (token[1] == 0) {
630 /* single letter swizzle (scalar) */
631 if (token[0] == 'x')
632 ASSIGN_4V(swizzle, 0, 0, 0, 0);
633 else if (token[0] == 'y')
634 ASSIGN_4V(swizzle, 1, 1, 1, 1);
635 else if (token[0] == 'z')
636 ASSIGN_4V(swizzle, 2, 2, 2, 2);
637 else if (token[0] == 'w')
638 ASSIGN_4V(swizzle, 3, 3, 3, 3);
639 else
640 return GL_FALSE;
641 }
642 else {
643 /* 4-component swizzle (vector) */
644 GLint k;
Roel Kluin324568f2010-01-06 08:27:42 -0800645 for (k = 0; k < 4 && token[k]; k++) {
Michal Krol2861e732004-03-29 11:09:34 +0000646 if (token[k] == 'x')
647 swizzle[k] = 0;
648 else if (token[k] == 'y')
649 swizzle[k] = 1;
650 else if (token[k] == 'z')
651 swizzle[k] = 2;
652 else if (token[k] == 'w')
653 swizzle[k] = 3;
654 else
655 return GL_FALSE;
656 }
657 if (k != 4)
658 return GL_FALSE;
659 }
660 return GL_TRUE;
661}
662
663
664static GLboolean
665Parse_CondCodeMask(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000666 struct prog_dst_register *dstReg)
Michal Krol2861e732004-03-29 11:09:34 +0000667{
668 if (Parse_String(parseState, "EQ"))
669 dstReg->CondMask = COND_EQ;
670 else if (Parse_String(parseState, "GE"))
671 dstReg->CondMask = COND_GE;
672 else if (Parse_String(parseState, "GT"))
673 dstReg->CondMask = COND_GT;
674 else if (Parse_String(parseState, "LE"))
675 dstReg->CondMask = COND_LE;
676 else if (Parse_String(parseState, "LT"))
677 dstReg->CondMask = COND_LT;
678 else if (Parse_String(parseState, "NE"))
679 dstReg->CondMask = COND_NE;
680 else if (Parse_String(parseState, "TR"))
681 dstReg->CondMask = COND_TR;
682 else if (Parse_String(parseState, "FL"))
683 dstReg->CondMask = COND_FL;
684 else
685 RETURN_ERROR1("Invalid condition code mask");
686
687 /* look for optional .xyzw swizzle */
688 if (Parse_String(parseState, ".")) {
689 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000690 GLuint swz[4];
691
Michal Krol2861e732004-03-29 11:09:34 +0000692 if (!Parse_Token(parseState, token)) /* get xyzw suffix */
693 RETURN_ERROR;
694
Keith Whitwell7c26b612005-04-21 14:46:57 +0000695 if (!Parse_SwizzleSuffix(token, swz))
Michal Krol2861e732004-03-29 11:09:34 +0000696 RETURN_ERROR1("Invalid swizzle suffix");
Keith Whitwell7c26b612005-04-21 14:46:57 +0000697
Brian Paulfd4395b2005-11-05 03:02:28 +0000698 dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
Michal Krol2861e732004-03-29 11:09:34 +0000699 }
700
701 return GL_TRUE;
702}
703
704
705/**
706 * Parse a temporary register: Rnn or Hnn
707 */
708static GLboolean
709Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
710{
711 GLubyte token[100];
712
713 /* Should be 'R##' or 'H##' */
714 if (!Parse_Token(parseState, token))
715 RETURN_ERROR;
716 if (token[0] != 'R' && token[0] != 'H')
717 RETURN_ERROR1("Expected R## or H##");
718
719 if (IsDigit(token[1])) {
Kenneth Graunke60b0cae2010-02-18 23:50:58 -0800720 GLint reg = atoi((const char *) (token + 1));
Michal Krol2861e732004-03-29 11:09:34 +0000721 if (token[0] == 'H')
722 reg += 32;
723 if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS)
724 RETURN_ERROR1("Invalid temporary register name");
725 *tempRegNum = reg;
726 }
727 else {
728 RETURN_ERROR1("Invalid temporary register name");
729 }
730
731 return GL_TRUE;
732}
733
734
735/**
736 * Parse a write-only dummy register: RC or HC.
737 */
738static GLboolean
739Parse_DummyReg(struct parse_state *parseState, GLint *regNum)
740{
741 if (Parse_String(parseState, "RC")) {
742 *regNum = 0;
743 }
744 else if (Parse_String(parseState, "HC")) {
745 *regNum = 1;
746 }
747 else {
748 RETURN_ERROR1("Invalid write-only register name");
749 }
750
751 return GL_TRUE;
752}
753
754
755/**
756 * Parse a program local parameter register "p[##]"
757 */
758static GLboolean
759Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum)
760{
761 GLubyte token[100];
762
763 if (!Parse_String(parseState, "p["))
764 RETURN_ERROR1("Expected p[");
765
766 if (!Parse_Token(parseState, token))
767 RETURN_ERROR;
768
769 if (IsDigit(token[0])) {
770 /* a numbered program parameter register */
Kenneth Graunke60b0cae2010-02-18 23:50:58 -0800771 GLint reg = atoi((const char *) token);
Michal Krol2861e732004-03-29 11:09:34 +0000772 if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS)
773 RETURN_ERROR1("Invalid constant program number");
774 *regNum = reg;
775 }
776 else {
777 RETURN_ERROR;
778 }
779
780 if (!Parse_String(parseState, "]"))
781 RETURN_ERROR1("Expected ]");
782
783 return GL_TRUE;
784}
785
786
787/**
788 * Parse f[name] - fragment input register
789 */
790static GLboolean
791Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum)
792{
793 GLubyte token[100];
794 GLint j;
795
796 /* Match 'f[' */
797 if (!Parse_String(parseState, "f["))
798 RETURN_ERROR1("Expected f[");
799
800 /* get <name> and look for match */
801 if (!Parse_Token(parseState, token)) {
802 RETURN_ERROR;
803 }
804 for (j = 0; InputRegisters[j]; j++) {
Kenneth Graunke8d73aa62010-02-18 23:50:56 -0800805 if (strcmp((const char *) token, InputRegisters[j]) == 0) {
Michal Krol2861e732004-03-29 11:09:34 +0000806 *tempRegNum = j;
807 parseState->inputsRead |= (1 << j);
808 break;
809 }
810 }
811 if (!InputRegisters[j]) {
812 /* unknown input register label */
813 RETURN_ERROR2("Invalid register name", token);
814 }
815
816 /* Match '[' */
817 if (!Parse_String(parseState, "]"))
818 RETURN_ERROR1("Expected ]");
819
820 return GL_TRUE;
821}
822
823
824static GLboolean
825Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
826{
827 GLubyte token[100];
Michal Krol2861e732004-03-29 11:09:34 +0000828
829 /* Match "o[" */
830 if (!Parse_String(parseState, "o["))
831 RETURN_ERROR1("Expected o[");
832
833 /* Get output reg name */
834 if (!Parse_Token(parseState, token))
835 RETURN_ERROR;
836
837 /* try to match an output register name */
Kenneth Graunke8d73aa62010-02-18 23:50:56 -0800838 if (strcmp((char *) token, "COLR") == 0 ||
839 strcmp((char *) token, "COLH") == 0) {
Brian Paul8d475822009-02-28 11:49:46 -0700840 /* note that we don't distinguish between COLR and COLH */
841 *outputRegNum = FRAG_RESULT_COLOR;
842 parseState->outputsWritten |= (1 << FRAG_RESULT_COLOR);
Michal Krol2861e732004-03-29 11:09:34 +0000843 }
Kenneth Graunke8d73aa62010-02-18 23:50:56 -0800844 else if (strcmp((char *) token, "DEPR") == 0) {
Brian Paul8d475822009-02-28 11:49:46 -0700845 *outputRegNum = FRAG_RESULT_DEPTH;
846 parseState->outputsWritten |= (1 << FRAG_RESULT_DEPTH);
847 }
848 else {
Michal Krol2861e732004-03-29 11:09:34 +0000849 RETURN_ERROR1("Invalid output register name");
Brian Paul8d475822009-02-28 11:49:46 -0700850 }
Michal Krol2861e732004-03-29 11:09:34 +0000851
852 /* Match ']' */
853 if (!Parse_String(parseState, "]"))
854 RETURN_ERROR1("Expected ]");
855
856 return GL_TRUE;
857}
858
859
860static GLboolean
861Parse_MaskedDstReg(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000862 struct prog_dst_register *dstReg)
Michal Krol2861e732004-03-29 11:09:34 +0000863{
864 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000865 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000866
867 /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
868 if (!Peek_Token(parseState, token))
869 RETURN_ERROR;
870
Kenneth Graunke8d73aa62010-02-18 23:50:56 -0800871 if (strcmp((const char *) token, "RC") == 0 ||
872 strcmp((const char *) token, "HC") == 0) {
Michal Krol2861e732004-03-29 11:09:34 +0000873 /* a write-only register */
874 dstReg->File = PROGRAM_WRITE_ONLY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000875 if (!Parse_DummyReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000876 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000877 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000878 }
879 else if (token[0] == 'R' || token[0] == 'H') {
880 /* a temporary register */
881 dstReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000882 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000883 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000884 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000885 }
886 else if (token[0] == 'o') {
887 /* an output register */
888 dstReg->File = PROGRAM_OUTPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000889 if (!Parse_OutputReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000890 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000891 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000892 }
893 else {
894 RETURN_ERROR1("Invalid destination register name");
895 }
896
897 /* Parse optional write mask */
898 if (Parse_String(parseState, ".")) {
899 /* got a mask */
900 GLint k = 0;
901
902 if (!Parse_Token(parseState, token)) /* get xyzw writemask */
903 RETURN_ERROR;
904
Keith Whitwell7c26b612005-04-21 14:46:57 +0000905 dstReg->WriteMask = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000906
907 if (token[k] == 'x') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000908 dstReg->WriteMask |= WRITEMASK_X;
Michal Krol2861e732004-03-29 11:09:34 +0000909 k++;
910 }
911 if (token[k] == 'y') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000912 dstReg->WriteMask |= WRITEMASK_Y;
Michal Krol2861e732004-03-29 11:09:34 +0000913 k++;
914 }
915 if (token[k] == 'z') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000916 dstReg->WriteMask |= WRITEMASK_Z;
Michal Krol2861e732004-03-29 11:09:34 +0000917 k++;
918 }
919 if (token[k] == 'w') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000920 dstReg->WriteMask |= WRITEMASK_W;
Michal Krol2861e732004-03-29 11:09:34 +0000921 k++;
922 }
923 if (k == 0) {
924 RETURN_ERROR1("Invalid writemask character");
925 }
926
927 }
928 else {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000929 dstReg->WriteMask = WRITEMASK_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000930 }
931
932 /* optional condition code mask */
933 if (Parse_String(parseState, "(")) {
934 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
935 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
936 if (!Parse_CondCodeMask(parseState, dstReg))
937 RETURN_ERROR;
938
939 if (!Parse_String(parseState, ")")) /* consume ")" */
940 RETURN_ERROR1("Expected )");
941
942 return GL_TRUE;
943 }
944 else {
945 /* no cond code mask */
946 dstReg->CondMask = COND_TR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000947 dstReg->CondSwizzle = SWIZZLE_NOOP;
Michal Krol2861e732004-03-29 11:09:34 +0000948 return GL_TRUE;
949 }
950}
951
952
953/**
954 * Parse a vector source (register, constant, etc):
955 * <vectorSrc> ::= <absVectorSrc>
956 * | <baseVectorSrc>
957 * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
958 */
959static GLboolean
960Parse_VectorSrc(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000961 struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000962{
963 GLfloat sign = 1.0F;
964 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000965 GLint idx;
Brian Paul7db7ff82009-04-14 22:14:30 -0600966 GLuint negateBase, negateAbs;
Michal Krol2861e732004-03-29 11:09:34 +0000967
968 /*
969 * First, take care of +/- and absolute value stuff.
970 */
971 if (Parse_String(parseState, "-"))
972 sign = -1.0F;
973 else if (Parse_String(parseState, "+"))
974 sign = +1.0F;
975
976 if (Parse_String(parseState, "|")) {
977 srcReg->Abs = GL_TRUE;
Brian Paul7db7ff82009-04-14 22:14:30 -0600978 negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000979
980 if (Parse_String(parseState, "-"))
Brian Paul7db7ff82009-04-14 22:14:30 -0600981 negateBase = NEGATE_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000982 else if (Parse_String(parseState, "+"))
Brian Paul7db7ff82009-04-14 22:14:30 -0600983 negateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000984 else
Brian Paul7db7ff82009-04-14 22:14:30 -0600985 negateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000986 }
987 else {
988 srcReg->Abs = GL_FALSE;
Brian Paul7db7ff82009-04-14 22:14:30 -0600989 negateAbs = NEGATE_NONE;
990 negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000991 }
992
Brian Paul7db7ff82009-04-14 22:14:30 -0600993 srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
994
Michal Krol2861e732004-03-29 11:09:34 +0000995 /* This should be the real src vector/register name */
996 if (!Peek_Token(parseState, token))
997 RETURN_ERROR;
998
999 /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
1000 * literal or vector literal.
1001 */
1002 if (token[0] == 'R' || token[0] == 'H') {
1003 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001004 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001005 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001006 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001007 }
1008 else if (token[0] == 'f') {
Brian Paule6940f02006-08-24 23:08:01 +00001009 /* XXX this might be an identifier! */
Michal Krol2861e732004-03-29 11:09:34 +00001010 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001011 if (!Parse_FragReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001012 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001013 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001014 }
1015 else if (token[0] == 'p') {
Brian Paule6940f02006-08-24 23:08:01 +00001016 /* XXX this might be an identifier! */
Michal Krol2861e732004-03-29 11:09:34 +00001017 srcReg->File = PROGRAM_LOCAL_PARAM;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001018 if (!Parse_ProgramParamReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001019 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001020 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001021 }
1022 else if (IsLetter(token[0])){
1023 GLubyte ident[100];
1024 GLint paramIndex;
1025 if (!Parse_Identifier(parseState, ident))
1026 RETURN_ERROR;
1027 paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1028 -1, (const char *) ident);
1029 if (paramIndex < 0) {
1030 RETURN_ERROR2("Undefined constant or parameter: ", ident);
1031 }
1032 srcReg->File = PROGRAM_NAMED_PARAM;
1033 srcReg->Index = paramIndex;
1034 }
1035 else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){
1036 /* literal scalar constant */
1037 GLfloat values[4];
Brian257f79982007-04-20 11:54:30 -06001038 GLuint paramIndex;
Michal Krol2861e732004-03-29 11:09:34 +00001039 if (!Parse_ScalarConstant(parseState, values))
1040 RETURN_ERROR;
Brianfe1d01c2006-12-13 14:54:47 -07001041 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
Brian1bf81e32007-03-22 09:07:27 -06001042 values, 4, NULL);
Michal Krol2861e732004-03-29 11:09:34 +00001043 srcReg->File = PROGRAM_NAMED_PARAM;
1044 srcReg->Index = paramIndex;
1045 }
1046 else if (token[0] == '{'){
1047 /* literal vector constant */
1048 GLfloat values[4];
Brian257f79982007-04-20 11:54:30 -06001049 GLuint paramIndex;
Michal Krol2861e732004-03-29 11:09:34 +00001050 (void) Parse_String(parseState, "{");
1051 if (!Parse_VectorConstant(parseState, values))
1052 RETURN_ERROR;
Brianfe1d01c2006-12-13 14:54:47 -07001053 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
Brian1bf81e32007-03-22 09:07:27 -06001054 values, 4, NULL);
Michal Krol2861e732004-03-29 11:09:34 +00001055 srcReg->File = PROGRAM_NAMED_PARAM;
1056 srcReg->Index = paramIndex;
1057 }
1058 else {
1059 RETURN_ERROR2("Invalid source register name", token);
1060 }
1061
1062 /* init swizzle fields */
Keith Whitwell7c26b612005-04-21 14:46:57 +00001063 srcReg->Swizzle = SWIZZLE_NOOP;
Michal Krol2861e732004-03-29 11:09:34 +00001064
1065 /* Look for optional swizzle suffix */
1066 if (Parse_String(parseState, ".")) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001067 GLuint swz[4];
1068
Michal Krol2861e732004-03-29 11:09:34 +00001069 if (!Parse_Token(parseState, token))
1070 RETURN_ERROR;
1071
Keith Whitwell7c26b612005-04-21 14:46:57 +00001072 if (!Parse_SwizzleSuffix(token, swz))
Michal Krol2861e732004-03-29 11:09:34 +00001073 RETURN_ERROR1("Invalid swizzle suffix");
Keith Whitwell7c26b612005-04-21 14:46:57 +00001074
Brian Paulfd4395b2005-11-05 03:02:28 +00001075 srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
Michal Krol2861e732004-03-29 11:09:34 +00001076 }
1077
1078 /* Finish absolute value */
1079 if (srcReg->Abs && !Parse_String(parseState, "|")) {
1080 RETURN_ERROR1("Expected |");
1081 }
1082
1083 return GL_TRUE;
1084}
1085
1086
1087static GLboolean
1088Parse_ScalarSrcReg(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001089 struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +00001090{
1091 GLubyte token[100];
1092 GLfloat sign = 1.0F;
1093 GLboolean needSuffix = GL_TRUE;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001094 GLint idx;
Brian Paul7db7ff82009-04-14 22:14:30 -06001095 GLuint negateBase, negateAbs;
Michal Krol2861e732004-03-29 11:09:34 +00001096
1097 /*
1098 * First, take care of +/- and absolute value stuff.
1099 */
1100 if (Parse_String(parseState, "-"))
1101 sign = -1.0F;
1102 else if (Parse_String(parseState, "+"))
1103 sign = +1.0F;
1104
1105 if (Parse_String(parseState, "|")) {
1106 srcReg->Abs = GL_TRUE;
Brian Paul7db7ff82009-04-14 22:14:30 -06001107 negateAbs = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +00001108
1109 if (Parse_String(parseState, "-"))
Brian Paul7db7ff82009-04-14 22:14:30 -06001110 negateBase = NEGATE_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +00001111 else if (Parse_String(parseState, "+"))
Brian Paul7db7ff82009-04-14 22:14:30 -06001112 negateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +00001113 else
Brian Paul7db7ff82009-04-14 22:14:30 -06001114 negateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +00001115 }
1116 else {
1117 srcReg->Abs = GL_FALSE;
Brian Paul7db7ff82009-04-14 22:14:30 -06001118 negateAbs = NEGATE_NONE;
1119 negateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +00001120 }
1121
Brian Paul7db7ff82009-04-14 22:14:30 -06001122 srcReg->Negate = srcReg->Abs ? negateAbs : negateBase;
1123
Michal Krol2861e732004-03-29 11:09:34 +00001124 if (!Peek_Token(parseState, token))
1125 RETURN_ERROR;
1126
1127 /* Src reg can be R<n>, H<n> or a named fragment attrib */
1128 if (token[0] == 'R' || token[0] == 'H') {
1129 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001130 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001131 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001132 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001133 }
1134 else if (token[0] == 'f') {
1135 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001136 if (!Parse_FragReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001137 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001138 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001139 }
1140 else if (token[0] == '{') {
1141 /* vector literal */
1142 GLfloat values[4];
Brian81c4fee2007-04-20 11:53:48 -06001143 GLuint paramIndex;
Michal Krol2861e732004-03-29 11:09:34 +00001144 (void) Parse_String(parseState, "{");
1145 if (!Parse_VectorConstant(parseState, values))
1146 RETURN_ERROR;
Brianfe1d01c2006-12-13 14:54:47 -07001147 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
Brian1bf81e32007-03-22 09:07:27 -06001148 values, 4, NULL);
Michal Krol2861e732004-03-29 11:09:34 +00001149 srcReg->File = PROGRAM_NAMED_PARAM;
1150 srcReg->Index = paramIndex;
1151 }
Brian Paule6940f02006-08-24 23:08:01 +00001152 else if (IsLetter(token[0])){
1153 /* named param/constant */
1154 GLubyte ident[100];
1155 GLint paramIndex;
1156 if (!Parse_Identifier(parseState, ident))
1157 RETURN_ERROR;
1158 paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1159 -1, (const char *) ident);
1160 if (paramIndex < 0) {
1161 RETURN_ERROR2("Undefined constant or parameter: ", ident);
1162 }
1163 srcReg->File = PROGRAM_NAMED_PARAM;
1164 srcReg->Index = paramIndex;
1165 }
Michal Krol2861e732004-03-29 11:09:34 +00001166 else if (IsDigit(token[0])) {
1167 /* scalar literal */
1168 GLfloat values[4];
Brian81c4fee2007-04-20 11:53:48 -06001169 GLuint paramIndex;
Michal Krol2861e732004-03-29 11:09:34 +00001170 if (!Parse_ScalarConstant(parseState, values))
1171 RETURN_ERROR;
Brianfe1d01c2006-12-13 14:54:47 -07001172 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
Brian1bf81e32007-03-22 09:07:27 -06001173 values, 4, NULL);
Michal Krol2861e732004-03-29 11:09:34 +00001174 srcReg->Index = paramIndex;
1175 srcReg->File = PROGRAM_NAMED_PARAM;
1176 needSuffix = GL_FALSE;
1177 }
1178 else {
1179 RETURN_ERROR2("Invalid scalar source argument", token);
1180 }
1181
Keith Whitwell7c26b612005-04-21 14:46:57 +00001182 srcReg->Swizzle = 0;
Michal Krol2861e732004-03-29 11:09:34 +00001183 if (needSuffix) {
1184 /* parse .[xyzw] suffix */
1185 if (!Parse_String(parseState, "."))
1186 RETURN_ERROR1("Expected .");
1187
1188 if (!Parse_Token(parseState, token))
1189 RETURN_ERROR;
1190
1191 if (token[0] == 'x' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001192 srcReg->Swizzle = 0;
Michal Krol2861e732004-03-29 11:09:34 +00001193 }
1194 else if (token[0] == 'y' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001195 srcReg->Swizzle = 1;
Michal Krol2861e732004-03-29 11:09:34 +00001196 }
1197 else if (token[0] == 'z' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001198 srcReg->Swizzle = 2;
Michal Krol2861e732004-03-29 11:09:34 +00001199 }
1200 else if (token[0] == 'w' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001201 srcReg->Swizzle = 3;
Michal Krol2861e732004-03-29 11:09:34 +00001202 }
1203 else {
1204 RETURN_ERROR1("Invalid scalar source suffix");
1205 }
1206 }
Michal Krol2861e732004-03-29 11:09:34 +00001207
1208 /* Finish absolute value */
1209 if (srcReg->Abs && !Parse_String(parseState, "|")) {
1210 RETURN_ERROR1("Expected |");
1211 }
1212
1213 return GL_TRUE;
1214}
1215
1216
Brian Paul2a5afe32004-12-18 16:18:00 +00001217static GLboolean
1218Parse_PrintInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001219 struct prog_instruction *inst)
Brian Paul2a5afe32004-12-18 16:18:00 +00001220{
1221 const GLubyte *str;
1222 GLubyte *msg;
1223 GLuint len;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001224 GLint idx;
Brian Paul2a5afe32004-12-18 16:18:00 +00001225
1226 /* The first argument is a literal string 'just like this' */
1227 if (!Parse_String(parseState, "'"))
1228 RETURN_ERROR1("Expected '");
1229
1230 str = parseState->pos;
1231 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1232 ;
1233 parseState->pos += len + 1;
Brian Paul95801792005-12-06 15:41:43 +00001234 msg = (GLubyte*) _mesa_malloc(len + 1);
Brian Paul2a5afe32004-12-18 16:18:00 +00001235
Kenneth Graunkec7ac48622010-02-18 23:50:59 -08001236 memcpy(msg, str, len);
Brian Paul2a5afe32004-12-18 16:18:00 +00001237 msg[len] = 0;
1238 inst->Data = msg;
1239
1240 if (Parse_String(parseState, ",")) {
1241 /* got an optional register to print */
1242 GLubyte token[100];
1243 GetToken(parseState, token);
1244 if (token[0] == 'o') {
1245 /* dst reg */
Keith Whitwell7c26b612005-04-21 14:46:57 +00001246 if (!Parse_OutputReg(parseState, &idx))
Brian Paul2a5afe32004-12-18 16:18:00 +00001247 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001248 inst->SrcReg[0].Index = idx;
Brian Paul2a5afe32004-12-18 16:18:00 +00001249 inst->SrcReg[0].File = PROGRAM_OUTPUT;
1250 }
1251 else {
1252 /* src reg */
1253 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1254 RETURN_ERROR;
1255 }
1256 }
1257 else {
Brian Paul8cdf3722005-09-02 13:40:09 +00001258 inst->SrcReg[0].File = PROGRAM_UNDEFINED;
Brian Paul2a5afe32004-12-18 16:18:00 +00001259 }
1260
Keith Whitwell7c26b612005-04-21 14:46:57 +00001261 inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
Brian Paul2a5afe32004-12-18 16:18:00 +00001262 inst->SrcReg[0].Abs = GL_FALSE;
Brian Paul7db7ff82009-04-14 22:14:30 -06001263 inst->SrcReg[0].Negate = NEGATE_NONE;
Brian Paul2a5afe32004-12-18 16:18:00 +00001264
1265 return GL_TRUE;
1266}
1267
Michal Krol2861e732004-03-29 11:09:34 +00001268
1269static GLboolean
1270Parse_InstructionSequence(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001271 struct prog_instruction program[])
Michal Krol2861e732004-03-29 11:09:34 +00001272{
1273 while (1) {
Brian Paul7e807512005-11-05 17:10:45 +00001274 struct prog_instruction *inst = program + parseState->numInst;
Michal Krol2861e732004-03-29 11:09:34 +00001275 struct instruction_pattern instMatch;
1276 GLubyte token[100];
1277
1278 /* Initialize the instruction */
Brian Pauld6272e02006-10-29 18:03:16 +00001279 _mesa_init_instructions(inst, 1);
Michal Krol2861e732004-03-29 11:09:34 +00001280
1281 /* special instructions */
1282 if (Parse_String(parseState, "DEFINE")) {
1283 GLubyte id[100];
1284 GLfloat value[7]; /* yes, 7 to be safe */
1285 if (!Parse_Identifier(parseState, id))
1286 RETURN_ERROR;
1287 /* XXX make sure id is not a reserved identifer, like R9 */
1288 if (!Parse_String(parseState, "="))
1289 RETURN_ERROR1("Expected =");
1290 if (!Parse_VectorOrScalarConstant(parseState, value))
1291 RETURN_ERROR;
1292 if (!Parse_String(parseState, ";"))
1293 RETURN_ERROR1("Expected ;");
1294 if (_mesa_lookup_parameter_index(parseState->parameters,
1295 -1, (const char *) id) >= 0) {
1296 RETURN_ERROR2(id, "already defined");
1297 }
1298 _mesa_add_named_parameter(parseState->parameters,
1299 (const char *) id, value);
1300 }
1301 else if (Parse_String(parseState, "DECLARE")) {
1302 GLubyte id[100];
1303 GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */
1304 if (!Parse_Identifier(parseState, id))
1305 RETURN_ERROR;
1306 /* XXX make sure id is not a reserved identifer, like R9 */
1307 if (Parse_String(parseState, "=")) {
1308 if (!Parse_VectorOrScalarConstant(parseState, value))
1309 RETURN_ERROR;
1310 }
1311 if (!Parse_String(parseState, ";"))
1312 RETURN_ERROR1("Expected ;");
1313 if (_mesa_lookup_parameter_index(parseState->parameters,
1314 -1, (const char *) id) >= 0) {
1315 RETURN_ERROR2(id, "already declared");
1316 }
1317 _mesa_add_named_parameter(parseState->parameters,
1318 (const char *) id, value);
1319 }
1320 else if (Parse_String(parseState, "END")) {
Brian Paul7e807512005-11-05 17:10:45 +00001321 inst->Opcode = OPCODE_END;
Michal Krol2861e732004-03-29 11:09:34 +00001322 parseState->numInst++;
1323 if (Parse_Token(parseState, token)) {
1324 RETURN_ERROR1("Code after END opcode.");
1325 }
1326 break;
1327 }
1328 else {
1329 /* general/arithmetic instruction */
1330
1331 /* get token */
1332 if (!Parse_Token(parseState, token)) {
1333 RETURN_ERROR1("Missing END instruction.");
1334 }
1335
1336 /* try to find matching instuction */
1337 instMatch = MatchInstruction(token);
Brian Paul28b014e2006-04-05 03:05:17 +00001338 if (instMatch.opcode >= MAX_OPCODE) {
Michal Krol2861e732004-03-29 11:09:34 +00001339 /* bad instruction name */
1340 RETURN_ERROR2("Unexpected token: ", token);
1341 }
1342
1343 inst->Opcode = instMatch.opcode;
1344 inst->Precision = instMatch.suffixes & (_R | _H | _X);
Brian Paule31ac052005-11-20 17:52:40 +00001345 inst->SaturateMode = (instMatch.suffixes & (_S))
1346 ? SATURATE_ZERO_ONE : SATURATE_OFF;
Brian Paul7e807512005-11-05 17:10:45 +00001347 inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
Michal Krol2861e732004-03-29 11:09:34 +00001348
1349 /*
1350 * parse the input and output operands
1351 */
1352 if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
1353 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
1354 RETURN_ERROR;
1355 if (!Parse_String(parseState, ","))
1356 RETURN_ERROR1("Expected ,");
1357 }
1358 else if (instMatch.outputs == OUTPUT_NONE) {
Brian Paul7e807512005-11-05 17:10:45 +00001359 if (instMatch.opcode == OPCODE_KIL_NV) {
Brian Paul2a5afe32004-12-18 16:18:00 +00001360 /* This is a little weird, the cond code info is in
1361 * the dest register.
1362 */
1363 if (!Parse_CondCodeMask(parseState, &inst->DstReg))
1364 RETURN_ERROR;
1365 }
1366 else {
Brian Paul7e807512005-11-05 17:10:45 +00001367 ASSERT(instMatch.opcode == OPCODE_PRINT);
Brian Paul2a5afe32004-12-18 16:18:00 +00001368 }
Michal Krol2861e732004-03-29 11:09:34 +00001369 }
1370
1371 if (instMatch.inputs == INPUT_1V) {
1372 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1373 RETURN_ERROR;
1374 }
1375 else if (instMatch.inputs == INPUT_2V) {
1376 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1377 RETURN_ERROR;
1378 if (!Parse_String(parseState, ","))
1379 RETURN_ERROR1("Expected ,");
1380 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1381 RETURN_ERROR;
1382 }
1383 else if (instMatch.inputs == INPUT_3V) {
1384 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1385 RETURN_ERROR;
1386 if (!Parse_String(parseState, ","))
1387 RETURN_ERROR1("Expected ,");
1388 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1389 RETURN_ERROR;
1390 if (!Parse_String(parseState, ","))
1391 RETURN_ERROR1("Expected ,");
1392 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1393 RETURN_ERROR;
1394 }
1395 else if (instMatch.inputs == INPUT_1S) {
1396 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1397 RETURN_ERROR;
1398 }
1399 else if (instMatch.inputs == INPUT_2S) {
1400 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1401 RETURN_ERROR;
1402 if (!Parse_String(parseState, ","))
1403 RETURN_ERROR1("Expected ,");
1404 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
1405 RETURN_ERROR;
1406 }
1407 else if (instMatch.inputs == INPUT_CC) {
1408 /* XXX to-do */
1409 }
1410 else if (instMatch.inputs == INPUT_1V_T) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001411 GLubyte unit, idx;
Michal Krol2861e732004-03-29 11:09:34 +00001412 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1413 RETURN_ERROR;
1414 if (!Parse_String(parseState, ","))
1415 RETURN_ERROR1("Expected ,");
Keith Whitwell7c26b612005-04-21 14:46:57 +00001416 if (!Parse_TextureImageId(parseState, &unit, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001417 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001418 inst->TexSrcUnit = unit;
Brian Paul7e807512005-11-05 17:10:45 +00001419 inst->TexSrcTarget = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001420 }
1421 else if (instMatch.inputs == INPUT_3V_T) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001422 GLubyte unit, idx;
Michal Krol2861e732004-03-29 11:09:34 +00001423 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1424 RETURN_ERROR;
1425 if (!Parse_String(parseState, ","))
1426 RETURN_ERROR1("Expected ,");
1427 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1428 RETURN_ERROR;
1429 if (!Parse_String(parseState, ","))
1430 RETURN_ERROR1("Expected ,");
1431 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1432 RETURN_ERROR;
1433 if (!Parse_String(parseState, ","))
1434 RETURN_ERROR1("Expected ,");
Keith Whitwell7c26b612005-04-21 14:46:57 +00001435 if (!Parse_TextureImageId(parseState, &unit, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001436 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001437 inst->TexSrcUnit = unit;
Brian Paul7e807512005-11-05 17:10:45 +00001438 inst->TexSrcTarget = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001439 }
Brian Paul2a5afe32004-12-18 16:18:00 +00001440 else if (instMatch.inputs == INPUT_1V_S) {
1441 if (!Parse_PrintInstruction(parseState, inst))
1442 RETURN_ERROR;
1443 }
Michal Krol2861e732004-03-29 11:09:34 +00001444
1445 /* end of statement semicolon */
1446 if (!Parse_String(parseState, ";"))
1447 RETURN_ERROR1("Expected ;");
1448
1449 parseState->numInst++;
1450
1451 if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
1452 RETURN_ERROR1("Program too long");
1453 }
1454 }
1455 return GL_TRUE;
1456}
1457
1458
1459
1460/**
1461 * Parse/compile the 'str' returning the compiled 'program'.
1462 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1463 * indicates the position of the error in 'str'.
1464 */
1465void
1466_mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget,
1467 const GLubyte *str, GLsizei len,
Brian Paul122629f2006-07-20 16:49:57 +00001468 struct gl_fragment_program *program)
Michal Krol2861e732004-03-29 11:09:34 +00001469{
1470 struct parse_state parseState;
Brian Paul7e807512005-11-05 17:10:45 +00001471 struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
1472 struct prog_instruction *newInst;
Michal Krol2861e732004-03-29 11:09:34 +00001473 GLenum target;
1474 GLubyte *programString;
1475
1476 /* Make a null-terminated copy of the program string */
1477 programString = (GLubyte *) MALLOC(len + 1);
1478 if (!programString) {
1479 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1480 return;
1481 }
Brian Paule197de52010-02-19 08:09:01 -07001482 memcpy(programString, str, len);
Michal Krol2861e732004-03-29 11:09:34 +00001483 programString[len] = 0;
1484
1485 /* Get ready to parse */
1486 _mesa_bzero(&parseState, sizeof(struct parse_state));
1487 parseState.ctx = ctx;
1488 parseState.start = programString;
1489 parseState.program = program;
1490 parseState.numInst = 0;
1491 parseState.curLine = programString;
1492 parseState.parameters = _mesa_new_parameter_list();
1493
1494 /* Reset error state */
1495 _mesa_set_program_error(ctx, -1, NULL);
1496
1497 /* check the program header */
Kenneth Graunke9d9afe92010-02-18 23:50:57 -08001498 if (strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
Michal Krol2861e732004-03-29 11:09:34 +00001499 target = GL_FRAGMENT_PROGRAM_NV;
1500 parseState.pos = programString + 7;
1501 }
Kenneth Graunke9d9afe92010-02-18 23:50:57 -08001502 else if (strncmp((const char *) programString, "!!FCP1.0", 8) == 0) {
Michal Krol2861e732004-03-29 11:09:34 +00001503 /* fragment / register combiner program - not supported */
1504 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1505 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1506 return;
1507 }
1508 else {
1509 /* invalid header */
1510 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1511 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1512 return;
1513 }
1514
1515 /* make sure target and header match */
1516 if (target != dstTarget) {
1517 _mesa_error(ctx, GL_INVALID_OPERATION,
1518 "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1519 target, dstTarget);
1520 return;
1521 }
1522
1523 if (Parse_InstructionSequence(&parseState, instBuffer)) {
1524 GLuint u;
1525 /* successful parse! */
1526
1527 if (parseState.outputsWritten == 0) {
1528 /* must write at least one output! */
1529 _mesa_error(ctx, GL_INVALID_OPERATION,
1530 "Invalid fragment program - no outputs written.");
1531 return;
1532 }
1533
1534 /* copy the compiled instructions */
1535 assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
Brian Paul383c39e2006-08-25 15:14:25 +00001536 newInst = _mesa_alloc_instructions(parseState.numInst);
Michal Krol2861e732004-03-29 11:09:34 +00001537 if (!newInst) {
1538 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1539 return; /* out of memory */
1540 }
Brian12229f12007-03-22 09:11:26 -06001541 _mesa_copy_instructions(newInst, instBuffer, parseState.numInst);
Michal Krol2861e732004-03-29 11:09:34 +00001542
1543 /* install the program */
1544 program->Base.Target = target;
1545 if (program->Base.String) {
1546 FREE(program->Base.String);
1547 }
1548 program->Base.String = programString;
1549 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
Brian Paulde997602005-11-12 17:53:14 +00001550 if (program->Base.Instructions) {
1551 _mesa_free(program->Base.Instructions);
Michal Krol2861e732004-03-29 11:09:34 +00001552 }
Brian Paulde997602005-11-12 17:53:14 +00001553 program->Base.Instructions = newInst;
Brian Paulee40c4fb32006-02-15 15:59:37 +00001554 program->Base.NumInstructions = parseState.numInst;
Brian Paulde997602005-11-12 17:53:14 +00001555 program->Base.InputsRead = parseState.inputsRead;
1556 program->Base.OutputsWritten = parseState.outputsWritten;
Michal Krol2861e732004-03-29 11:09:34 +00001557 for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
Brianc9db2232007-01-04 17:22:19 -07001558 program->Base.TexturesUsed[u] = parseState.texturesUsed[u];
Michal Krol2861e732004-03-29 11:09:34 +00001559
1560 /* save program parameters */
Brian Paulde997602005-11-12 17:53:14 +00001561 program->Base.Parameters = parseState.parameters;
Michal Krol2861e732004-03-29 11:09:34 +00001562
1563 /* allocate registers for declared program parameters */
1564#if 00
1565 _mesa_assign_program_registers(&(program->SymbolTable));
1566#endif
1567
Brian Paulac33dd12004-06-29 00:00:29 +00001568#ifdef DEBUG_foo
Michal Krol2861e732004-03-29 11:09:34 +00001569 _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
Brian Paulfe278f12009-04-14 19:53:37 -06001570 _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0);
Michal Krol2861e732004-03-29 11:09:34 +00001571 _mesa_printf("----------------------------------\n");
1572#endif
1573 }
1574 else {
1575 /* Error! */
1576 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1577 /* NOTE: _mesa_set_program_error would have been called already */
1578 }
1579}
1580
1581
Michal Krol2861e732004-03-29 11:09:34 +00001582const char *
1583_mesa_nv_fragment_input_register_name(GLuint i)
1584{
1585 ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
1586 return InputRegisters[i];
1587}
1588