blob: 6690c9a85142a01e25cfabe6800ffcdfb17accf3 [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
40#include "glheader.h"
41#include "context.h"
42#include "hash.h"
43#include "imports.h"
44#include "macros.h"
45#include "mtypes.h"
Brianc0551f02006-12-14 15:02:37 -070046#include "prog_parameter.h"
47#include "prog_instruction.h"
Michal Krol2861e732004-03-29 11:09:34 +000048#include "nvfragparse.h"
49#include "nvprogram.h"
50#include "program.h"
51
52
53#define INPUT_1V 1
54#define INPUT_2V 2
55#define INPUT_3V 3
56#define INPUT_1S 4
57#define INPUT_2S 5
58#define INPUT_CC 6
59#define INPUT_1V_T 7 /* one source vector, plus textureId */
60#define INPUT_3V_T 8 /* one source vector, plus textureId */
61#define INPUT_NONE 9
Brian Paul2a5afe32004-12-18 16:18:00 +000062#define INPUT_1V_S 10 /* a string and a vector register */
Michal Krol2861e732004-03-29 11:09:34 +000063#define OUTPUT_V 20
64#define OUTPUT_S 21
65#define OUTPUT_NONE 22
66
67/* IRIX defines some of these */
68#undef _R
69#undef _H
70#undef _X
71#undef _C
72#undef _S
73
74/* Optional suffixes */
75#define _R FLOAT32 /* float */
76#define _H FLOAT16 /* half-float */
77#define _X FIXED12 /* fixed */
78#define _C 0x08 /* set cond codes */
79#define _S 0x10 /* saturate, clamp result to [0,1] */
80
81struct instruction_pattern {
82 const char *name;
Brian Paul7e807512005-11-05 17:10:45 +000083 enum prog_opcode opcode;
Michal Krol2861e732004-03-29 11:09:34 +000084 GLuint inputs;
85 GLuint outputs;
86 GLuint suffixes;
87};
88
89static const struct instruction_pattern Instructions[] = {
Brian Paul7e807512005-11-05 17:10:45 +000090 { "ADD", OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
91 { "COS", OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
92 { "DDX", OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
93 { "DDY", OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
94 { "DP3", OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
95 { "DP4", OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
96 { "DST", OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H | _C | _S },
97 { "EX2", OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
98 { "FLR", OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
99 { "FRC", OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
100 { "KIL", OPCODE_KIL_NV, INPUT_CC, OUTPUT_NONE, 0 },
101 { "LG2", OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
102 { "LIT", OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
103 { "LRP", OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
104 { "MAD", OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
105 { "MAX", OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
106 { "MIN", OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
107 { "MOV", OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
108 { "MUL", OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
109 { "PK2H", OPCODE_PK2H, INPUT_1V, OUTPUT_S, 0 },
110 { "PK2US", OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0 },
111 { "PK4B", OPCODE_PK4B, INPUT_1V, OUTPUT_S, 0 },
112 { "PK4UB", OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0 },
113 { "POW", OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H | _C | _S },
114 { "RCP", OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
115 { "RFL", OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H | _C | _S },
116 { "RSQ", OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
117 { "SEQ", OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
118 { "SFL", OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
119 { "SGE", OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
120 { "SGT", OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
121 { "SIN", OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
122 { "SLE", OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
123 { "SLT", OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
124 { "SNE", OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
125 { "STR", OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
126 { "SUB", OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
127 { "TEX", OPCODE_TEX, INPUT_1V_T, OUTPUT_V, _C | _S },
128 { "TXD", OPCODE_TXD, INPUT_3V_T, OUTPUT_V, _C | _S },
129 { "TXP", OPCODE_TXP_NV, INPUT_1V_T, OUTPUT_V, _C | _S },
130 { "UP2H", OPCODE_UP2H, INPUT_1S, OUTPUT_V, _C | _S },
131 { "UP2US", OPCODE_UP2US, INPUT_1S, OUTPUT_V, _C | _S },
132 { "UP4B", OPCODE_UP4B, INPUT_1S, OUTPUT_V, _C | _S },
133 { "UP4UB", OPCODE_UP4UB, INPUT_1S, OUTPUT_V, _C | _S },
134 { "X2D", OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H | _C | _S },
135 { "PRINT", OPCODE_PRINT, INPUT_1V_S, OUTPUT_NONE, 0 },
136 { NULL, (enum prog_opcode) -1, 0, 0, 0 }
Michal Krol2861e732004-03-29 11:09:34 +0000137};
138
139
140/*
141 * Information needed or computed during parsing.
142 * Remember, we can't modify the target program object until we've
143 * _successfully_ parsed the program text.
144 */
145struct parse_state {
146 GLcontext *ctx;
147 const GLubyte *start; /* start of program string */
148 const GLubyte *pos; /* current position */
149 const GLubyte *curLine;
Brian Paul122629f2006-07-20 16:49:57 +0000150 struct gl_fragment_program *program; /* current program */
Michal Krol2861e732004-03-29 11:09:34 +0000151
Brian Paul122629f2006-07-20 16:49:57 +0000152 struct gl_program_parameter_list *parameters;
Michal Krol2861e732004-03-29 11:09:34 +0000153
154 GLuint numInst; /* number of instructions parsed */
155 GLuint inputsRead; /* bitmask of input registers used */
156 GLuint outputsWritten; /* bitmask of 1 << FRAG_OUTPUT_* bits */
157 GLuint texturesUsed[MAX_TEXTURE_IMAGE_UNITS];
158};
159
160
161
162/*
163 * Called whenever we find an error during parsing.
164 */
165static void
166record_error(struct parse_state *parseState, const char *msg, int lineNo)
167{
168#ifdef DEBUG
169 GLint line, column;
170 const GLubyte *lineStr;
171 lineStr = _mesa_find_line_column(parseState->start,
172 parseState->pos, &line, &column);
173 _mesa_debug(parseState->ctx,
174 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
175 lineNo, line, column, (char *) lineStr, msg);
176 _mesa_free((void *) lineStr);
177#else
178 (void) lineNo;
179#endif
180
181 /* Check that no error was already recorded. Only record the first one. */
182 if (parseState->ctx->Program.ErrorString[0] == 0) {
183 _mesa_set_program_error(parseState->ctx,
184 parseState->pos - parseState->start,
185 msg);
186 }
187}
188
189
190#define RETURN_ERROR \
191do { \
192 record_error(parseState, "Unexpected end of input.", __LINE__); \
193 return GL_FALSE; \
194} while(0)
195
196#define RETURN_ERROR1(msg) \
197do { \
198 record_error(parseState, msg, __LINE__); \
199 return GL_FALSE; \
200} while(0)
201
202#define RETURN_ERROR2(msg1, msg2) \
203do { \
204 char err[1000]; \
205 _mesa_sprintf(err, "%s %s", msg1, msg2); \
206 record_error(parseState, err, __LINE__); \
207 return GL_FALSE; \
208} while(0)
209
210
211
212
213/*
214 * Search a list of instruction structures for a match.
215 */
216static struct instruction_pattern
217MatchInstruction(const GLubyte *token)
218{
219 const struct instruction_pattern *inst;
220 struct instruction_pattern result;
221
222 for (inst = Instructions; inst->name; inst++) {
223 if (_mesa_strncmp((const char *) token, inst->name, 3) == 0) {
224 /* matched! */
225 int i = 3;
226 result = *inst;
227 result.suffixes = 0;
228 /* look at suffix */
229 if (token[i] == 'R') {
230 result.suffixes |= _R;
231 i++;
232 }
233 else if (token[i] == 'H') {
234 result.suffixes |= _H;
235 i++;
236 }
237 else if (token[i] == 'X') {
238 result.suffixes |= _X;
239 i++;
240 }
241 if (token[i] == 'C') {
242 result.suffixes |= _C;
243 i++;
244 }
245 if (token[i] == '_' && token[i+1] == 'S' &&
246 token[i+2] == 'A' && token[i+3] == 'T') {
247 result.suffixes |= _S;
248 }
249 return result;
250 }
251 }
Brian Paul28b014e2006-04-05 03:05:17 +0000252 result.opcode = MAX_OPCODE; /* i.e. invalid instruction */
Michal Krol2861e732004-03-29 11:09:34 +0000253 return result;
254}
255
256
257
258
259/**********************************************************************/
260
261
262static GLboolean IsLetter(GLubyte b)
263{
264 return (b >= 'a' && b <= 'z') ||
265 (b >= 'A' && b <= 'Z') ||
266 (b == '_') ||
267 (b == '$');
268}
269
270
271static GLboolean IsDigit(GLubyte b)
272{
273 return b >= '0' && b <= '9';
274}
275
276
277static GLboolean IsWhitespace(GLubyte b)
278{
279 return b == ' ' || b == '\t' || b == '\n' || b == '\r';
280}
281
282
283/**
284 * Starting at 'str' find the next token. A token can be an integer,
285 * an identifier or punctuation symbol.
286 * \return <= 0 we found an error, else, return number of characters parsed.
287 */
288static GLint
289GetToken(struct parse_state *parseState, GLubyte *token)
290{
291 const GLubyte *str = parseState->pos;
292 GLint i = 0, j = 0;
293
294 token[0] = 0;
295
296 /* skip whitespace and comments */
297 while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
298 if (str[i] == '#') {
299 /* skip comment */
300 while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
301 i++;
302 }
303 if (str[i] == '\n' || str[i] == '\r')
304 parseState->curLine = str + i + 1;
305 }
306 else {
307 /* skip whitespace */
308 if (str[i] == '\n' || str[i] == '\r')
309 parseState->curLine = str + i + 1;
310 i++;
311 }
312 }
313
314 if (str[i] == 0)
315 return -i;
316
317 /* try matching an integer */
318 while (str[i] && IsDigit(str[i])) {
319 token[j++] = str[i++];
320 }
321 if (j > 0 || !str[i]) {
322 token[j] = 0;
323 return i;
324 }
325
326 /* try matching an identifier */
327 if (IsLetter(str[i])) {
328 while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
329 token[j++] = str[i++];
330 }
331 token[j] = 0;
332 return i;
333 }
334
335 /* punctuation character */
336 if (str[i]) {
337 token[0] = str[i++];
338 token[1] = 0;
339 return i;
340 }
341
342 /* end of input */
343 token[0] = 0;
344 return i;
345}
346
347
348/**
349 * Get next token from input stream and increment stream pointer past token.
350 */
351static GLboolean
352Parse_Token(struct parse_state *parseState, GLubyte *token)
353{
354 GLint i;
355 i = GetToken(parseState, token);
356 if (i <= 0) {
357 parseState->pos += (-i);
358 return GL_FALSE;
359 }
360 parseState->pos += i;
361 return GL_TRUE;
362}
363
364
365/**
366 * Get next token from input stream but don't increment stream pointer.
367 */
368static GLboolean
369Peek_Token(struct parse_state *parseState, GLubyte *token)
370{
371 GLint i, len;
372 i = GetToken(parseState, token);
373 if (i <= 0) {
374 parseState->pos += (-i);
375 return GL_FALSE;
376 }
Karl Schultz6258b762005-05-05 21:08:07 +0000377 len = (GLint)_mesa_strlen((const char *) token);
Michal Krol2861e732004-03-29 11:09:34 +0000378 parseState->pos += (i - len);
379 return GL_TRUE;
380}
381
382
383/**********************************************************************/
384
385static const char *InputRegisters[MAX_NV_FRAGMENT_PROGRAM_INPUTS + 1] = {
386 "WPOS", "COL0", "COL1", "FOGC",
387 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
388};
389
390static const char *OutputRegisters[MAX_NV_FRAGMENT_PROGRAM_OUTPUTS + 1] = {
391 "COLR", "COLH",
392 /* These are only allows for register combiners */
393 /*
394 "TEX0", "TEX1", "TEX2", "TEX3",
395 */
396 "DEPR", NULL
397};
398
399
400
401
402/**********************************************************************/
403
404/**
405 * Try to match 'pattern' as the next token after any whitespace/comments.
406 */
407static GLboolean
408Parse_String(struct parse_state *parseState, const char *pattern)
409{
410 const GLubyte *m;
411 GLint i;
412
413 /* skip whitespace and comments */
414 while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
415 if (*parseState->pos == '#') {
416 while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
417 parseState->pos += 1;
418 }
419 if (*parseState->pos == '\n' || *parseState->pos == '\r')
420 parseState->curLine = parseState->pos + 1;
421 }
422 else {
423 /* skip whitespace */
424 if (*parseState->pos == '\n' || *parseState->pos == '\r')
425 parseState->curLine = parseState->pos + 1;
426 parseState->pos += 1;
427 }
428 }
429
430 /* Try to match the pattern */
431 m = parseState->pos;
432 for (i = 0; pattern[i]; i++) {
433 if (*m != (GLubyte) pattern[i])
434 return GL_FALSE;
435 m += 1;
436 }
437 parseState->pos = m;
438
439 return GL_TRUE; /* success */
440}
441
442
443static GLboolean
444Parse_Identifier(struct parse_state *parseState, GLubyte *ident)
445{
446 if (!Parse_Token(parseState, ident))
447 RETURN_ERROR;
448 if (IsLetter(ident[0]))
449 return GL_TRUE;
450 else
451 RETURN_ERROR1("Expected an identfier");
452}
453
454
455/**
456 * Parse a floating point constant, or a defined symbol name.
457 * [+/-]N[.N[eN]]
458 * Output: number[0 .. 3] will get the value.
459 */
460static GLboolean
461Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number)
462{
463 char *end = NULL;
464
465 *number = (GLfloat) _mesa_strtod((const char *) parseState->pos, &end);
466
467 if (end && end > (char *) parseState->pos) {
468 /* got a number */
469 parseState->pos = (GLubyte *) end;
470 number[1] = *number;
471 number[2] = *number;
472 number[3] = *number;
473 return GL_TRUE;
474 }
475 else {
476 /* should be an identifier */
477 GLubyte ident[100];
478 const GLfloat *constant;
479 if (!Parse_Identifier(parseState, ident))
480 RETURN_ERROR1("Expected an identifier");
481 constant = _mesa_lookup_parameter_value(parseState->parameters,
482 -1, (const char *) ident);
483 /* XXX Check that it's a constant and not a parameter */
484 if (!constant) {
485 RETURN_ERROR1("Undefined symbol");
486 }
487 else {
488 COPY_4V(number, constant);
489 return GL_TRUE;
490 }
491 }
492}
493
494
495
496/**
497 * Parse a vector constant, one of:
498 * { float }
499 * { float, float }
500 * { float, float, float }
501 * { float, float, float, float }
502 */
503static GLboolean
504Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
505{
506 /* "{" was already consumed */
507
508 ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0);
509
510 if (!Parse_ScalarConstant(parseState, vec+0)) /* X */
511 return GL_FALSE;
512
513 if (Parse_String(parseState, "}")) {
514 return GL_TRUE;
515 }
516
517 if (!Parse_String(parseState, ","))
518 RETURN_ERROR1("Expected comma in vector constant");
519
520 if (!Parse_ScalarConstant(parseState, vec+1)) /* Y */
521 return GL_FALSE;
522
523 if (Parse_String(parseState, "}")) {
524 return GL_TRUE;
525 }
526
527 if (!Parse_String(parseState, ","))
528 RETURN_ERROR1("Expected comma in vector constant");
529
530 if (!Parse_ScalarConstant(parseState, vec+2)) /* Z */
531 return GL_FALSE;
532
533 if (Parse_String(parseState, "}")) {
534 return GL_TRUE;
535 }
536
537 if (!Parse_String(parseState, ","))
538 RETURN_ERROR1("Expected comma in vector constant");
539
540 if (!Parse_ScalarConstant(parseState, vec+3)) /* W */
541 return GL_FALSE;
542
543 if (!Parse_String(parseState, "}"))
544 RETURN_ERROR1("Expected closing brace in vector constant");
545
546 return GL_TRUE;
547}
548
549
550/**
551 * Parse <number>, <varname> or {a, b, c, d}.
552 * Return number of values in the vector or scalar, or zero if parse error.
553 */
554static GLuint
555Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec)
556{
557 if (Parse_String(parseState, "{")) {
558 return Parse_VectorConstant(parseState, vec);
559 }
560 else {
561 GLboolean b = Parse_ScalarConstant(parseState, vec);
562 if (b) {
563 vec[1] = vec[2] = vec[3] = vec[0];
564 }
565 return b;
566 }
567}
568
569
570/**
571 * Parse a texture image source:
572 * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
573 */
574static GLboolean
575Parse_TextureImageId(struct parse_state *parseState,
576 GLubyte *texUnit, GLubyte *texTargetBit)
577{
578 GLubyte imageSrc[100];
579 GLint unit;
580
581 if (!Parse_Token(parseState, imageSrc))
582 RETURN_ERROR;
583
584 if (imageSrc[0] != 'T' ||
585 imageSrc[1] != 'E' ||
586 imageSrc[2] != 'X') {
587 RETURN_ERROR1("Expected TEX# source");
588 }
589 unit = _mesa_atoi((const char *) imageSrc + 3);
590 if ((unit < 0 || unit > MAX_TEXTURE_IMAGE_UNITS) ||
591 (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) {
592 RETURN_ERROR1("Invalied TEX# source index");
593 }
594 *texUnit = unit;
595
596 if (!Parse_String(parseState, ","))
597 RETURN_ERROR1("Expected ,");
598
599 if (Parse_String(parseState, "1D")) {
600 *texTargetBit = TEXTURE_1D_BIT;
601 }
602 else if (Parse_String(parseState, "2D")) {
603 *texTargetBit = TEXTURE_2D_BIT;
604 }
605 else if (Parse_String(parseState, "3D")) {
606 *texTargetBit = TEXTURE_3D_BIT;
607 }
608 else if (Parse_String(parseState, "CUBE")) {
609 *texTargetBit = TEXTURE_CUBE_BIT;
610 }
611 else if (Parse_String(parseState, "RECT")) {
612 *texTargetBit = TEXTURE_RECT_BIT;
613 }
614 else {
615 RETURN_ERROR1("Invalid texture target token");
616 }
617
618 /* update record of referenced texture units */
619 parseState->texturesUsed[*texUnit] |= *texTargetBit;
620 if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) {
621 RETURN_ERROR1("Only one texture target can be used per texture unit.");
622 }
623
624 return GL_TRUE;
625}
626
627
628/**
629 * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
630 * like .wxyz, .xxyy, etc and return the swizzle indexes.
631 */
632static GLboolean
633Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4])
634{
635 if (token[1] == 0) {
636 /* single letter swizzle (scalar) */
637 if (token[0] == 'x')
638 ASSIGN_4V(swizzle, 0, 0, 0, 0);
639 else if (token[0] == 'y')
640 ASSIGN_4V(swizzle, 1, 1, 1, 1);
641 else if (token[0] == 'z')
642 ASSIGN_4V(swizzle, 2, 2, 2, 2);
643 else if (token[0] == 'w')
644 ASSIGN_4V(swizzle, 3, 3, 3, 3);
645 else
646 return GL_FALSE;
647 }
648 else {
649 /* 4-component swizzle (vector) */
650 GLint k;
651 for (k = 0; token[k] && k < 4; k++) {
652 if (token[k] == 'x')
653 swizzle[k] = 0;
654 else if (token[k] == 'y')
655 swizzle[k] = 1;
656 else if (token[k] == 'z')
657 swizzle[k] = 2;
658 else if (token[k] == 'w')
659 swizzle[k] = 3;
660 else
661 return GL_FALSE;
662 }
663 if (k != 4)
664 return GL_FALSE;
665 }
666 return GL_TRUE;
667}
668
669
670static GLboolean
671Parse_CondCodeMask(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000672 struct prog_dst_register *dstReg)
Michal Krol2861e732004-03-29 11:09:34 +0000673{
674 if (Parse_String(parseState, "EQ"))
675 dstReg->CondMask = COND_EQ;
676 else if (Parse_String(parseState, "GE"))
677 dstReg->CondMask = COND_GE;
678 else if (Parse_String(parseState, "GT"))
679 dstReg->CondMask = COND_GT;
680 else if (Parse_String(parseState, "LE"))
681 dstReg->CondMask = COND_LE;
682 else if (Parse_String(parseState, "LT"))
683 dstReg->CondMask = COND_LT;
684 else if (Parse_String(parseState, "NE"))
685 dstReg->CondMask = COND_NE;
686 else if (Parse_String(parseState, "TR"))
687 dstReg->CondMask = COND_TR;
688 else if (Parse_String(parseState, "FL"))
689 dstReg->CondMask = COND_FL;
690 else
691 RETURN_ERROR1("Invalid condition code mask");
692
693 /* look for optional .xyzw swizzle */
694 if (Parse_String(parseState, ".")) {
695 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000696 GLuint swz[4];
697
Michal Krol2861e732004-03-29 11:09:34 +0000698 if (!Parse_Token(parseState, token)) /* get xyzw suffix */
699 RETURN_ERROR;
700
Keith Whitwell7c26b612005-04-21 14:46:57 +0000701 if (!Parse_SwizzleSuffix(token, swz))
Michal Krol2861e732004-03-29 11:09:34 +0000702 RETURN_ERROR1("Invalid swizzle suffix");
Keith Whitwell7c26b612005-04-21 14:46:57 +0000703
Brian Paulfd4395b2005-11-05 03:02:28 +0000704 dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
Michal Krol2861e732004-03-29 11:09:34 +0000705 }
706
707 return GL_TRUE;
708}
709
710
711/**
712 * Parse a temporary register: Rnn or Hnn
713 */
714static GLboolean
715Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
716{
717 GLubyte token[100];
718
719 /* Should be 'R##' or 'H##' */
720 if (!Parse_Token(parseState, token))
721 RETURN_ERROR;
722 if (token[0] != 'R' && token[0] != 'H')
723 RETURN_ERROR1("Expected R## or H##");
724
725 if (IsDigit(token[1])) {
726 GLint reg = _mesa_atoi((const char *) (token + 1));
727 if (token[0] == 'H')
728 reg += 32;
729 if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS)
730 RETURN_ERROR1("Invalid temporary register name");
731 *tempRegNum = reg;
732 }
733 else {
734 RETURN_ERROR1("Invalid temporary register name");
735 }
736
737 return GL_TRUE;
738}
739
740
741/**
742 * Parse a write-only dummy register: RC or HC.
743 */
744static GLboolean
745Parse_DummyReg(struct parse_state *parseState, GLint *regNum)
746{
747 if (Parse_String(parseState, "RC")) {
748 *regNum = 0;
749 }
750 else if (Parse_String(parseState, "HC")) {
751 *regNum = 1;
752 }
753 else {
754 RETURN_ERROR1("Invalid write-only register name");
755 }
756
757 return GL_TRUE;
758}
759
760
761/**
762 * Parse a program local parameter register "p[##]"
763 */
764static GLboolean
765Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum)
766{
767 GLubyte token[100];
768
769 if (!Parse_String(parseState, "p["))
770 RETURN_ERROR1("Expected p[");
771
772 if (!Parse_Token(parseState, token))
773 RETURN_ERROR;
774
775 if (IsDigit(token[0])) {
776 /* a numbered program parameter register */
777 GLint reg = _mesa_atoi((const char *) token);
778 if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS)
779 RETURN_ERROR1("Invalid constant program number");
780 *regNum = reg;
781 }
782 else {
783 RETURN_ERROR;
784 }
785
786 if (!Parse_String(parseState, "]"))
787 RETURN_ERROR1("Expected ]");
788
789 return GL_TRUE;
790}
791
792
793/**
794 * Parse f[name] - fragment input register
795 */
796static GLboolean
797Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum)
798{
799 GLubyte token[100];
800 GLint j;
801
802 /* Match 'f[' */
803 if (!Parse_String(parseState, "f["))
804 RETURN_ERROR1("Expected f[");
805
806 /* get <name> and look for match */
807 if (!Parse_Token(parseState, token)) {
808 RETURN_ERROR;
809 }
810 for (j = 0; InputRegisters[j]; j++) {
811 if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
812 *tempRegNum = j;
813 parseState->inputsRead |= (1 << j);
814 break;
815 }
816 }
817 if (!InputRegisters[j]) {
818 /* unknown input register label */
819 RETURN_ERROR2("Invalid register name", token);
820 }
821
822 /* Match '[' */
823 if (!Parse_String(parseState, "]"))
824 RETURN_ERROR1("Expected ]");
825
826 return GL_TRUE;
827}
828
829
830static GLboolean
831Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
832{
833 GLubyte token[100];
834 GLint j;
835
836 /* Match "o[" */
837 if (!Parse_String(parseState, "o["))
838 RETURN_ERROR1("Expected o[");
839
840 /* Get output reg name */
841 if (!Parse_Token(parseState, token))
842 RETURN_ERROR;
843
844 /* try to match an output register name */
845 for (j = 0; OutputRegisters[j]; j++) {
846 if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) {
Brian Paul90ebb582005-11-02 18:06:12 +0000847 static GLuint bothColors = (1 << FRAG_RESULT_COLR) | (1 << FRAG_RESULT_COLH);
Michal Krol2861e732004-03-29 11:09:34 +0000848 *outputRegNum = j;
849 parseState->outputsWritten |= (1 << j);
850 if ((parseState->outputsWritten & bothColors) == bothColors) {
851 RETURN_ERROR1("Illegal to write to both o[COLR] and o[COLH]");
852 }
853 break;
854 }
855 }
856 if (!OutputRegisters[j])
857 RETURN_ERROR1("Invalid output register name");
858
859 /* Match ']' */
860 if (!Parse_String(parseState, "]"))
861 RETURN_ERROR1("Expected ]");
862
863 return GL_TRUE;
864}
865
866
867static GLboolean
868Parse_MaskedDstReg(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000869 struct prog_dst_register *dstReg)
Michal Krol2861e732004-03-29 11:09:34 +0000870{
871 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000872 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000873
874 /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
875 if (!Peek_Token(parseState, token))
876 RETURN_ERROR;
877
878 if (_mesa_strcmp((const char *) token, "RC") == 0 ||
879 _mesa_strcmp((const char *) token, "HC") == 0) {
880 /* a write-only register */
881 dstReg->File = PROGRAM_WRITE_ONLY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000882 if (!Parse_DummyReg(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] == 'R' || token[0] == 'H') {
887 /* a temporary register */
888 dstReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000889 if (!Parse_TempReg(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 if (token[0] == 'o') {
894 /* an output register */
895 dstReg->File = PROGRAM_OUTPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000896 if (!Parse_OutputReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000897 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000898 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000899 }
900 else {
901 RETURN_ERROR1("Invalid destination register name");
902 }
903
904 /* Parse optional write mask */
905 if (Parse_String(parseState, ".")) {
906 /* got a mask */
907 GLint k = 0;
908
909 if (!Parse_Token(parseState, token)) /* get xyzw writemask */
910 RETURN_ERROR;
911
Keith Whitwell7c26b612005-04-21 14:46:57 +0000912 dstReg->WriteMask = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000913
914 if (token[k] == 'x') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000915 dstReg->WriteMask |= WRITEMASK_X;
Michal Krol2861e732004-03-29 11:09:34 +0000916 k++;
917 }
918 if (token[k] == 'y') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000919 dstReg->WriteMask |= WRITEMASK_Y;
Michal Krol2861e732004-03-29 11:09:34 +0000920 k++;
921 }
922 if (token[k] == 'z') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000923 dstReg->WriteMask |= WRITEMASK_Z;
Michal Krol2861e732004-03-29 11:09:34 +0000924 k++;
925 }
926 if (token[k] == 'w') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000927 dstReg->WriteMask |= WRITEMASK_W;
Michal Krol2861e732004-03-29 11:09:34 +0000928 k++;
929 }
930 if (k == 0) {
931 RETURN_ERROR1("Invalid writemask character");
932 }
933
934 }
935 else {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000936 dstReg->WriteMask = WRITEMASK_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000937 }
938
939 /* optional condition code mask */
940 if (Parse_String(parseState, "(")) {
941 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
942 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
943 if (!Parse_CondCodeMask(parseState, dstReg))
944 RETURN_ERROR;
945
946 if (!Parse_String(parseState, ")")) /* consume ")" */
947 RETURN_ERROR1("Expected )");
948
949 return GL_TRUE;
950 }
951 else {
952 /* no cond code mask */
953 dstReg->CondMask = COND_TR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000954 dstReg->CondSwizzle = SWIZZLE_NOOP;
Michal Krol2861e732004-03-29 11:09:34 +0000955 return GL_TRUE;
956 }
957}
958
959
960/**
961 * Parse a vector source (register, constant, etc):
962 * <vectorSrc> ::= <absVectorSrc>
963 * | <baseVectorSrc>
964 * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
965 */
966static GLboolean
967Parse_VectorSrc(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000968 struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000969{
970 GLfloat sign = 1.0F;
971 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000972 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000973
974 /*
975 * First, take care of +/- and absolute value stuff.
976 */
977 if (Parse_String(parseState, "-"))
978 sign = -1.0F;
979 else if (Parse_String(parseState, "+"))
980 sign = +1.0F;
981
982 if (Parse_String(parseState, "|")) {
983 srcReg->Abs = GL_TRUE;
984 srcReg->NegateAbs = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
985
986 if (Parse_String(parseState, "-"))
Brian Paula8c42422006-05-30 22:17:35 +0000987 srcReg->NegateBase = NEGATE_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000988 else if (Parse_String(parseState, "+"))
Brian Paula8c42422006-05-30 22:17:35 +0000989 srcReg->NegateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000990 else
Brian Paula8c42422006-05-30 22:17:35 +0000991 srcReg->NegateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000992 }
993 else {
994 srcReg->Abs = GL_FALSE;
995 srcReg->NegateAbs = GL_FALSE;
Brian Paula8c42422006-05-30 22:17:35 +0000996 srcReg->NegateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000997 }
998
999 /* This should be the real src vector/register name */
1000 if (!Peek_Token(parseState, token))
1001 RETURN_ERROR;
1002
1003 /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
1004 * literal or vector literal.
1005 */
1006 if (token[0] == 'R' || token[0] == 'H') {
1007 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001008 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001009 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001010 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001011 }
1012 else if (token[0] == 'f') {
Brian Paule6940f02006-08-24 23:08:01 +00001013 /* XXX this might be an identifier! */
Michal Krol2861e732004-03-29 11:09:34 +00001014 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001015 if (!Parse_FragReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001016 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001017 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001018 }
1019 else if (token[0] == 'p') {
Brian Paule6940f02006-08-24 23:08:01 +00001020 /* XXX this might be an identifier! */
Michal Krol2861e732004-03-29 11:09:34 +00001021 srcReg->File = PROGRAM_LOCAL_PARAM;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001022 if (!Parse_ProgramParamReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001023 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001024 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001025 }
1026 else if (IsLetter(token[0])){
1027 GLubyte ident[100];
1028 GLint paramIndex;
1029 if (!Parse_Identifier(parseState, ident))
1030 RETURN_ERROR;
1031 paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1032 -1, (const char *) ident);
1033 if (paramIndex < 0) {
1034 RETURN_ERROR2("Undefined constant or parameter: ", ident);
1035 }
1036 srcReg->File = PROGRAM_NAMED_PARAM;
1037 srcReg->Index = paramIndex;
1038 }
1039 else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){
1040 /* literal scalar constant */
1041 GLfloat values[4];
Brianfe1d01c2006-12-13 14:54:47 -07001042 GLuint paramIndex, swizzle;
Michal Krol2861e732004-03-29 11:09:34 +00001043 if (!Parse_ScalarConstant(parseState, values))
1044 RETURN_ERROR;
Brianfe1d01c2006-12-13 14:54:47 -07001045 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1046 values, 4, &swizzle);
1047 ASSERT(swizzle == SWIZZLE_NOOP);
Michal Krol2861e732004-03-29 11:09:34 +00001048 srcReg->File = PROGRAM_NAMED_PARAM;
1049 srcReg->Index = paramIndex;
1050 }
1051 else if (token[0] == '{'){
1052 /* literal vector constant */
1053 GLfloat values[4];
Brianfe1d01c2006-12-13 14:54:47 -07001054 GLuint paramIndex, swizzle;
Michal Krol2861e732004-03-29 11:09:34 +00001055 (void) Parse_String(parseState, "{");
1056 if (!Parse_VectorConstant(parseState, values))
1057 RETURN_ERROR;
Brianfe1d01c2006-12-13 14:54:47 -07001058 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1059 values, 4, &swizzle);
1060 ASSERT(swizzle == SWIZZLE_NOOP);
Michal Krol2861e732004-03-29 11:09:34 +00001061 srcReg->File = PROGRAM_NAMED_PARAM;
1062 srcReg->Index = paramIndex;
1063 }
1064 else {
1065 RETURN_ERROR2("Invalid source register name", token);
1066 }
1067
1068 /* init swizzle fields */
Keith Whitwell7c26b612005-04-21 14:46:57 +00001069 srcReg->Swizzle = SWIZZLE_NOOP;
Michal Krol2861e732004-03-29 11:09:34 +00001070
1071 /* Look for optional swizzle suffix */
1072 if (Parse_String(parseState, ".")) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001073 GLuint swz[4];
1074
Michal Krol2861e732004-03-29 11:09:34 +00001075 if (!Parse_Token(parseState, token))
1076 RETURN_ERROR;
1077
Keith Whitwell7c26b612005-04-21 14:46:57 +00001078 if (!Parse_SwizzleSuffix(token, swz))
Michal Krol2861e732004-03-29 11:09:34 +00001079 RETURN_ERROR1("Invalid swizzle suffix");
Keith Whitwell7c26b612005-04-21 14:46:57 +00001080
Brian Paulfd4395b2005-11-05 03:02:28 +00001081 srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
Michal Krol2861e732004-03-29 11:09:34 +00001082 }
1083
1084 /* Finish absolute value */
1085 if (srcReg->Abs && !Parse_String(parseState, "|")) {
1086 RETURN_ERROR1("Expected |");
1087 }
1088
1089 return GL_TRUE;
1090}
1091
1092
1093static GLboolean
1094Parse_ScalarSrcReg(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001095 struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +00001096{
1097 GLubyte token[100];
1098 GLfloat sign = 1.0F;
1099 GLboolean needSuffix = GL_TRUE;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001100 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +00001101
1102 /*
1103 * First, take care of +/- and absolute value stuff.
1104 */
1105 if (Parse_String(parseState, "-"))
1106 sign = -1.0F;
1107 else if (Parse_String(parseState, "+"))
1108 sign = +1.0F;
1109
1110 if (Parse_String(parseState, "|")) {
1111 srcReg->Abs = GL_TRUE;
1112 srcReg->NegateAbs = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
1113
1114 if (Parse_String(parseState, "-"))
Brian Paula8c42422006-05-30 22:17:35 +00001115 srcReg->NegateBase = NEGATE_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +00001116 else if (Parse_String(parseState, "+"))
Brian Paula8c42422006-05-30 22:17:35 +00001117 srcReg->NegateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +00001118 else
Brian Paula8c42422006-05-30 22:17:35 +00001119 srcReg->NegateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +00001120 }
1121 else {
1122 srcReg->Abs = GL_FALSE;
1123 srcReg->NegateAbs = GL_FALSE;
Brian Paula8c42422006-05-30 22:17:35 +00001124 srcReg->NegateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +00001125 }
1126
1127 if (!Peek_Token(parseState, token))
1128 RETURN_ERROR;
1129
1130 /* Src reg can be R<n>, H<n> or a named fragment attrib */
1131 if (token[0] == 'R' || token[0] == 'H') {
1132 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001133 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001134 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001135 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001136 }
1137 else if (token[0] == 'f') {
1138 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001139 if (!Parse_FragReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001140 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001141 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001142 }
1143 else if (token[0] == '{') {
1144 /* vector literal */
1145 GLfloat values[4];
Brianfe1d01c2006-12-13 14:54:47 -07001146 GLuint paramIndex, swizzle;
Michal Krol2861e732004-03-29 11:09:34 +00001147 (void) Parse_String(parseState, "{");
1148 if (!Parse_VectorConstant(parseState, values))
1149 RETURN_ERROR;
Brianfe1d01c2006-12-13 14:54:47 -07001150 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1151 values, 4, &swizzle);
1152 ASSERT(swizzle == SWIZZLE_NOOP);
Michal Krol2861e732004-03-29 11:09:34 +00001153 srcReg->File = PROGRAM_NAMED_PARAM;
1154 srcReg->Index = paramIndex;
1155 }
Brian Paule6940f02006-08-24 23:08:01 +00001156 else if (IsLetter(token[0])){
1157 /* named param/constant */
1158 GLubyte ident[100];
1159 GLint paramIndex;
1160 if (!Parse_Identifier(parseState, ident))
1161 RETURN_ERROR;
1162 paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1163 -1, (const char *) ident);
1164 if (paramIndex < 0) {
1165 RETURN_ERROR2("Undefined constant or parameter: ", ident);
1166 }
1167 srcReg->File = PROGRAM_NAMED_PARAM;
1168 srcReg->Index = paramIndex;
1169 }
Michal Krol2861e732004-03-29 11:09:34 +00001170 else if (IsDigit(token[0])) {
1171 /* scalar literal */
1172 GLfloat values[4];
Brianfe1d01c2006-12-13 14:54:47 -07001173 GLuint paramIndex, swizzle;
Michal Krol2861e732004-03-29 11:09:34 +00001174 if (!Parse_ScalarConstant(parseState, values))
1175 RETURN_ERROR;
Brianfe1d01c2006-12-13 14:54:47 -07001176 paramIndex = _mesa_add_unnamed_constant(parseState->parameters,
1177 values, 4, &swizzle);
1178 ASSERT(swizzle == SWIZZLE_NOOP);
Michal Krol2861e732004-03-29 11:09:34 +00001179 srcReg->Index = paramIndex;
1180 srcReg->File = PROGRAM_NAMED_PARAM;
1181 needSuffix = GL_FALSE;
1182 }
1183 else {
1184 RETURN_ERROR2("Invalid scalar source argument", token);
1185 }
1186
Keith Whitwell7c26b612005-04-21 14:46:57 +00001187 srcReg->Swizzle = 0;
Michal Krol2861e732004-03-29 11:09:34 +00001188 if (needSuffix) {
1189 /* parse .[xyzw] suffix */
1190 if (!Parse_String(parseState, "."))
1191 RETURN_ERROR1("Expected .");
1192
1193 if (!Parse_Token(parseState, token))
1194 RETURN_ERROR;
1195
1196 if (token[0] == 'x' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001197 srcReg->Swizzle = 0;
Michal Krol2861e732004-03-29 11:09:34 +00001198 }
1199 else if (token[0] == 'y' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001200 srcReg->Swizzle = 1;
Michal Krol2861e732004-03-29 11:09:34 +00001201 }
1202 else if (token[0] == 'z' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001203 srcReg->Swizzle = 2;
Michal Krol2861e732004-03-29 11:09:34 +00001204 }
1205 else if (token[0] == 'w' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001206 srcReg->Swizzle = 3;
Michal Krol2861e732004-03-29 11:09:34 +00001207 }
1208 else {
1209 RETURN_ERROR1("Invalid scalar source suffix");
1210 }
1211 }
Michal Krol2861e732004-03-29 11:09:34 +00001212
1213 /* Finish absolute value */
1214 if (srcReg->Abs && !Parse_String(parseState, "|")) {
1215 RETURN_ERROR1("Expected |");
1216 }
1217
1218 return GL_TRUE;
1219}
1220
1221
Brian Paul2a5afe32004-12-18 16:18:00 +00001222static GLboolean
1223Parse_PrintInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001224 struct prog_instruction *inst)
Brian Paul2a5afe32004-12-18 16:18:00 +00001225{
1226 const GLubyte *str;
1227 GLubyte *msg;
1228 GLuint len;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001229 GLint idx;
Brian Paul2a5afe32004-12-18 16:18:00 +00001230
1231 /* The first argument is a literal string 'just like this' */
1232 if (!Parse_String(parseState, "'"))
1233 RETURN_ERROR1("Expected '");
1234
1235 str = parseState->pos;
1236 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1237 ;
1238 parseState->pos += len + 1;
Brian Paul95801792005-12-06 15:41:43 +00001239 msg = (GLubyte*) _mesa_malloc(len + 1);
Brian Paul2a5afe32004-12-18 16:18:00 +00001240
1241 _mesa_memcpy(msg, str, len);
1242 msg[len] = 0;
1243 inst->Data = msg;
1244
1245 if (Parse_String(parseState, ",")) {
1246 /* got an optional register to print */
1247 GLubyte token[100];
1248 GetToken(parseState, token);
1249 if (token[0] == 'o') {
1250 /* dst reg */
Keith Whitwell7c26b612005-04-21 14:46:57 +00001251 if (!Parse_OutputReg(parseState, &idx))
Brian Paul2a5afe32004-12-18 16:18:00 +00001252 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001253 inst->SrcReg[0].Index = idx;
Brian Paul2a5afe32004-12-18 16:18:00 +00001254 inst->SrcReg[0].File = PROGRAM_OUTPUT;
1255 }
1256 else {
1257 /* src reg */
1258 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1259 RETURN_ERROR;
1260 }
1261 }
1262 else {
Brian Paul8cdf3722005-09-02 13:40:09 +00001263 inst->SrcReg[0].File = PROGRAM_UNDEFINED;
Brian Paul2a5afe32004-12-18 16:18:00 +00001264 }
1265
Keith Whitwell7c26b612005-04-21 14:46:57 +00001266 inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
Brian Paula8c42422006-05-30 22:17:35 +00001267 inst->SrcReg[0].NegateBase = NEGATE_NONE;
Brian Paul2a5afe32004-12-18 16:18:00 +00001268 inst->SrcReg[0].Abs = GL_FALSE;
1269 inst->SrcReg[0].NegateAbs = GL_FALSE;
1270
1271 return GL_TRUE;
1272}
1273
Michal Krol2861e732004-03-29 11:09:34 +00001274
1275static GLboolean
1276Parse_InstructionSequence(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001277 struct prog_instruction program[])
Michal Krol2861e732004-03-29 11:09:34 +00001278{
1279 while (1) {
Brian Paul7e807512005-11-05 17:10:45 +00001280 struct prog_instruction *inst = program + parseState->numInst;
Michal Krol2861e732004-03-29 11:09:34 +00001281 struct instruction_pattern instMatch;
1282 GLubyte token[100];
1283
1284 /* Initialize the instruction */
Brian Pauld6272e02006-10-29 18:03:16 +00001285 _mesa_init_instructions(inst, 1);
Michal Krol2861e732004-03-29 11:09:34 +00001286
1287 /* special instructions */
1288 if (Parse_String(parseState, "DEFINE")) {
1289 GLubyte id[100];
1290 GLfloat value[7]; /* yes, 7 to be safe */
1291 if (!Parse_Identifier(parseState, id))
1292 RETURN_ERROR;
1293 /* XXX make sure id is not a reserved identifer, like R9 */
1294 if (!Parse_String(parseState, "="))
1295 RETURN_ERROR1("Expected =");
1296 if (!Parse_VectorOrScalarConstant(parseState, value))
1297 RETURN_ERROR;
1298 if (!Parse_String(parseState, ";"))
1299 RETURN_ERROR1("Expected ;");
1300 if (_mesa_lookup_parameter_index(parseState->parameters,
1301 -1, (const char *) id) >= 0) {
1302 RETURN_ERROR2(id, "already defined");
1303 }
1304 _mesa_add_named_parameter(parseState->parameters,
1305 (const char *) id, value);
1306 }
1307 else if (Parse_String(parseState, "DECLARE")) {
1308 GLubyte id[100];
1309 GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */
1310 if (!Parse_Identifier(parseState, id))
1311 RETURN_ERROR;
1312 /* XXX make sure id is not a reserved identifer, like R9 */
1313 if (Parse_String(parseState, "=")) {
1314 if (!Parse_VectorOrScalarConstant(parseState, value))
1315 RETURN_ERROR;
1316 }
1317 if (!Parse_String(parseState, ";"))
1318 RETURN_ERROR1("Expected ;");
1319 if (_mesa_lookup_parameter_index(parseState->parameters,
1320 -1, (const char *) id) >= 0) {
1321 RETURN_ERROR2(id, "already declared");
1322 }
1323 _mesa_add_named_parameter(parseState->parameters,
1324 (const char *) id, value);
1325 }
1326 else if (Parse_String(parseState, "END")) {
Brian Paul7e807512005-11-05 17:10:45 +00001327 inst->Opcode = OPCODE_END;
Michal Krol2861e732004-03-29 11:09:34 +00001328 inst->StringPos = parseState->curLine - parseState->start;
1329 assert(inst->StringPos >= 0);
1330 parseState->numInst++;
1331 if (Parse_Token(parseState, token)) {
1332 RETURN_ERROR1("Code after END opcode.");
1333 }
1334 break;
1335 }
1336 else {
1337 /* general/arithmetic instruction */
1338
1339 /* get token */
1340 if (!Parse_Token(parseState, token)) {
1341 RETURN_ERROR1("Missing END instruction.");
1342 }
1343
1344 /* try to find matching instuction */
1345 instMatch = MatchInstruction(token);
Brian Paul28b014e2006-04-05 03:05:17 +00001346 if (instMatch.opcode >= MAX_OPCODE) {
Michal Krol2861e732004-03-29 11:09:34 +00001347 /* bad instruction name */
1348 RETURN_ERROR2("Unexpected token: ", token);
1349 }
1350
1351 inst->Opcode = instMatch.opcode;
1352 inst->Precision = instMatch.suffixes & (_R | _H | _X);
Brian Paule31ac052005-11-20 17:52:40 +00001353 inst->SaturateMode = (instMatch.suffixes & (_S))
1354 ? SATURATE_ZERO_ONE : SATURATE_OFF;
Brian Paul7e807512005-11-05 17:10:45 +00001355 inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
Michal Krol2861e732004-03-29 11:09:34 +00001356 inst->StringPos = parseState->curLine - parseState->start;
1357 assert(inst->StringPos >= 0);
1358
1359 /*
1360 * parse the input and output operands
1361 */
1362 if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
1363 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
1364 RETURN_ERROR;
1365 if (!Parse_String(parseState, ","))
1366 RETURN_ERROR1("Expected ,");
1367 }
1368 else if (instMatch.outputs == OUTPUT_NONE) {
Brian Paul7e807512005-11-05 17:10:45 +00001369 if (instMatch.opcode == OPCODE_KIL_NV) {
Brian Paul2a5afe32004-12-18 16:18:00 +00001370 /* This is a little weird, the cond code info is in
1371 * the dest register.
1372 */
1373 if (!Parse_CondCodeMask(parseState, &inst->DstReg))
1374 RETURN_ERROR;
1375 }
1376 else {
Brian Paul7e807512005-11-05 17:10:45 +00001377 ASSERT(instMatch.opcode == OPCODE_PRINT);
Brian Paul2a5afe32004-12-18 16:18:00 +00001378 }
Michal Krol2861e732004-03-29 11:09:34 +00001379 }
1380
1381 if (instMatch.inputs == INPUT_1V) {
1382 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1383 RETURN_ERROR;
1384 }
1385 else if (instMatch.inputs == INPUT_2V) {
1386 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1387 RETURN_ERROR;
1388 if (!Parse_String(parseState, ","))
1389 RETURN_ERROR1("Expected ,");
1390 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1391 RETURN_ERROR;
1392 }
1393 else if (instMatch.inputs == INPUT_3V) {
1394 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1395 RETURN_ERROR;
1396 if (!Parse_String(parseState, ","))
1397 RETURN_ERROR1("Expected ,");
1398 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1399 RETURN_ERROR;
1400 if (!Parse_String(parseState, ","))
1401 RETURN_ERROR1("Expected ,");
1402 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1403 RETURN_ERROR;
1404 }
1405 else if (instMatch.inputs == INPUT_1S) {
1406 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1407 RETURN_ERROR;
1408 }
1409 else if (instMatch.inputs == INPUT_2S) {
1410 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1411 RETURN_ERROR;
1412 if (!Parse_String(parseState, ","))
1413 RETURN_ERROR1("Expected ,");
1414 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
1415 RETURN_ERROR;
1416 }
1417 else if (instMatch.inputs == INPUT_CC) {
1418 /* XXX to-do */
1419 }
1420 else if (instMatch.inputs == INPUT_1V_T) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001421 GLubyte unit, idx;
Michal Krol2861e732004-03-29 11:09:34 +00001422 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1423 RETURN_ERROR;
1424 if (!Parse_String(parseState, ","))
1425 RETURN_ERROR1("Expected ,");
Keith Whitwell7c26b612005-04-21 14:46:57 +00001426 if (!Parse_TextureImageId(parseState, &unit, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001427 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001428 inst->TexSrcUnit = unit;
Brian Paul7e807512005-11-05 17:10:45 +00001429 inst->TexSrcTarget = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001430 }
1431 else if (instMatch.inputs == INPUT_3V_T) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001432 GLubyte unit, idx;
Michal Krol2861e732004-03-29 11:09:34 +00001433 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1434 RETURN_ERROR;
1435 if (!Parse_String(parseState, ","))
1436 RETURN_ERROR1("Expected ,");
1437 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1438 RETURN_ERROR;
1439 if (!Parse_String(parseState, ","))
1440 RETURN_ERROR1("Expected ,");
1441 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1442 RETURN_ERROR;
1443 if (!Parse_String(parseState, ","))
1444 RETURN_ERROR1("Expected ,");
Keith Whitwell7c26b612005-04-21 14:46:57 +00001445 if (!Parse_TextureImageId(parseState, &unit, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001446 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001447 inst->TexSrcUnit = unit;
Brian Paul7e807512005-11-05 17:10:45 +00001448 inst->TexSrcTarget = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001449 }
Brian Paul2a5afe32004-12-18 16:18:00 +00001450 else if (instMatch.inputs == INPUT_1V_S) {
1451 if (!Parse_PrintInstruction(parseState, inst))
1452 RETURN_ERROR;
1453 }
Michal Krol2861e732004-03-29 11:09:34 +00001454
1455 /* end of statement semicolon */
1456 if (!Parse_String(parseState, ";"))
1457 RETURN_ERROR1("Expected ;");
1458
1459 parseState->numInst++;
1460
1461 if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
1462 RETURN_ERROR1("Program too long");
1463 }
1464 }
1465 return GL_TRUE;
1466}
1467
1468
1469
1470/**
1471 * Parse/compile the 'str' returning the compiled 'program'.
1472 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1473 * indicates the position of the error in 'str'.
1474 */
1475void
1476_mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget,
1477 const GLubyte *str, GLsizei len,
Brian Paul122629f2006-07-20 16:49:57 +00001478 struct gl_fragment_program *program)
Michal Krol2861e732004-03-29 11:09:34 +00001479{
1480 struct parse_state parseState;
Brian Paul7e807512005-11-05 17:10:45 +00001481 struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
1482 struct prog_instruction *newInst;
Michal Krol2861e732004-03-29 11:09:34 +00001483 GLenum target;
1484 GLubyte *programString;
1485
1486 /* Make a null-terminated copy of the program string */
1487 programString = (GLubyte *) MALLOC(len + 1);
1488 if (!programString) {
1489 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1490 return;
1491 }
1492 MEMCPY(programString, str, len);
1493 programString[len] = 0;
1494
1495 /* Get ready to parse */
1496 _mesa_bzero(&parseState, sizeof(struct parse_state));
1497 parseState.ctx = ctx;
1498 parseState.start = programString;
1499 parseState.program = program;
1500 parseState.numInst = 0;
1501 parseState.curLine = programString;
1502 parseState.parameters = _mesa_new_parameter_list();
1503
1504 /* Reset error state */
1505 _mesa_set_program_error(ctx, -1, NULL);
1506
1507 /* check the program header */
1508 if (_mesa_strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
1509 target = GL_FRAGMENT_PROGRAM_NV;
1510 parseState.pos = programString + 7;
1511 }
1512 else if (_mesa_strncmp((const char *) programString, "!!FCP1.0", 8) == 0) {
1513 /* fragment / register combiner program - not supported */
1514 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1515 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1516 return;
1517 }
1518 else {
1519 /* invalid header */
1520 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1521 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1522 return;
1523 }
1524
1525 /* make sure target and header match */
1526 if (target != dstTarget) {
1527 _mesa_error(ctx, GL_INVALID_OPERATION,
1528 "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1529 target, dstTarget);
1530 return;
1531 }
1532
1533 if (Parse_InstructionSequence(&parseState, instBuffer)) {
1534 GLuint u;
1535 /* successful parse! */
1536
1537 if (parseState.outputsWritten == 0) {
1538 /* must write at least one output! */
1539 _mesa_error(ctx, GL_INVALID_OPERATION,
1540 "Invalid fragment program - no outputs written.");
1541 return;
1542 }
1543
1544 /* copy the compiled instructions */
1545 assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
Brian Paul383c39e2006-08-25 15:14:25 +00001546 newInst = _mesa_alloc_instructions(parseState.numInst);
Michal Krol2861e732004-03-29 11:09:34 +00001547 if (!newInst) {
1548 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1549 return; /* out of memory */
1550 }
Brian Paul383c39e2006-08-25 15:14:25 +00001551 _mesa_memcpy(newInst, instBuffer,
1552 parseState.numInst * sizeof(struct prog_instruction));
Michal Krol2861e732004-03-29 11:09:34 +00001553
1554 /* install the program */
1555 program->Base.Target = target;
1556 if (program->Base.String) {
1557 FREE(program->Base.String);
1558 }
1559 program->Base.String = programString;
1560 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
Brian Paulde997602005-11-12 17:53:14 +00001561 if (program->Base.Instructions) {
1562 _mesa_free(program->Base.Instructions);
Michal Krol2861e732004-03-29 11:09:34 +00001563 }
Brian Paulde997602005-11-12 17:53:14 +00001564 program->Base.Instructions = newInst;
Brian Paulee40c4fb32006-02-15 15:59:37 +00001565 program->Base.NumInstructions = parseState.numInst;
Brian Paulde997602005-11-12 17:53:14 +00001566 program->Base.InputsRead = parseState.inputsRead;
1567 program->Base.OutputsWritten = parseState.outputsWritten;
Michal Krol2861e732004-03-29 11:09:34 +00001568 for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
1569 program->TexturesUsed[u] = parseState.texturesUsed[u];
1570
1571 /* save program parameters */
Brian Paulde997602005-11-12 17:53:14 +00001572 program->Base.Parameters = parseState.parameters;
Michal Krol2861e732004-03-29 11:09:34 +00001573
1574 /* allocate registers for declared program parameters */
1575#if 00
1576 _mesa_assign_program_registers(&(program->SymbolTable));
1577#endif
1578
Brian Paulac33dd12004-06-29 00:00:29 +00001579#ifdef DEBUG_foo
Michal Krol2861e732004-03-29 11:09:34 +00001580 _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
1581 _mesa_print_nv_fragment_program(program);
1582 _mesa_printf("----------------------------------\n");
1583#endif
1584 }
1585 else {
1586 /* Error! */
1587 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1588 /* NOTE: _mesa_set_program_error would have been called already */
1589 }
1590}
1591
1592
1593static void
Brian Paul122629f2006-07-20 16:49:57 +00001594PrintSrcReg(const struct gl_fragment_program *program,
Brian Paul7e807512005-11-05 17:10:45 +00001595 const struct prog_src_register *src)
Michal Krol2861e732004-03-29 11:09:34 +00001596{
1597 static const char comps[5] = "xyzw";
1598
1599 if (src->NegateAbs) {
1600 _mesa_printf("-");
1601 }
1602 if (src->Abs) {
1603 _mesa_printf("|");
1604 }
1605 if (src->NegateBase) {
1606 _mesa_printf("-");
1607 }
1608 if (src->File == PROGRAM_NAMED_PARAM) {
Brian Paulde997602005-11-12 17:53:14 +00001609 if (program->Base.Parameters->Parameters[src->Index].Type
1610 == PROGRAM_CONSTANT) {
1611 const GLfloat *v;
1612 v = program->Base.Parameters->ParameterValues[src->Index];
1613 _mesa_printf("{%g, %g, %g, %g}", v[0], v[1], v[2], v[3]);
Michal Krol2861e732004-03-29 11:09:34 +00001614 }
1615 else {
Brian Paulbed83632005-11-12 17:56:18 +00001616 ASSERT(program->Base.Parameters->Parameters[src->Index].Type
Brian Paul613e1ad2005-11-05 02:15:21 +00001617 == PROGRAM_NAMED_PARAM);
Brian Paulde997602005-11-12 17:53:14 +00001618 _mesa_printf("%s", program->Base.Parameters->Parameters[src->Index].Name);
Michal Krol2861e732004-03-29 11:09:34 +00001619 }
1620 }
1621 else if (src->File == PROGRAM_OUTPUT) {
1622 _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1623 }
1624 else if (src->File == PROGRAM_INPUT) {
1625 _mesa_printf("f[%s]", InputRegisters[src->Index]);
1626 }
1627 else if (src->File == PROGRAM_LOCAL_PARAM) {
1628 _mesa_printf("p[%d]", src->Index);
1629 }
1630 else if (src->File == PROGRAM_TEMPORARY) {
1631 if (src->Index >= 32)
1632 _mesa_printf("H%d", src->Index);
1633 else
1634 _mesa_printf("R%d", src->Index);
1635 }
1636 else if (src->File == PROGRAM_WRITE_ONLY) {
1637 _mesa_printf("%cC", "HR"[src->Index]);
1638 }
1639 else {
1640 _mesa_problem(NULL, "Invalid fragment register %d", src->Index);
1641 return;
1642 }
Keith Whitwell7c26b612005-04-21 14:46:57 +00001643 if (GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 1) &&
1644 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 2) &&
1645 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 3)) {
1646 _mesa_printf(".%c", comps[GET_SWZ(src->Swizzle, 0)]);
Michal Krol2861e732004-03-29 11:09:34 +00001647 }
Keith Whitwell7c26b612005-04-21 14:46:57 +00001648 else if (src->Swizzle != SWIZZLE_NOOP) {
Michal Krol2861e732004-03-29 11:09:34 +00001649 _mesa_printf(".%c%c%c%c",
Keith Whitwell7c26b612005-04-21 14:46:57 +00001650 comps[GET_SWZ(src->Swizzle, 0)],
1651 comps[GET_SWZ(src->Swizzle, 1)],
1652 comps[GET_SWZ(src->Swizzle, 2)],
1653 comps[GET_SWZ(src->Swizzle, 3)]);
Michal Krol2861e732004-03-29 11:09:34 +00001654 }
1655 if (src->Abs) {
1656 _mesa_printf("|");
1657 }
1658}
1659
1660static void
Brian Paul7e807512005-11-05 17:10:45 +00001661PrintTextureSrc(const struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +00001662{
1663 _mesa_printf("TEX%d, ", inst->TexSrcUnit);
Brian Paul7e807512005-11-05 17:10:45 +00001664 switch (inst->TexSrcTarget) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001665 case TEXTURE_1D_INDEX:
Michal Krol2861e732004-03-29 11:09:34 +00001666 _mesa_printf("1D");
1667 break;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001668 case TEXTURE_2D_INDEX:
Michal Krol2861e732004-03-29 11:09:34 +00001669 _mesa_printf("2D");
1670 break;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001671 case TEXTURE_3D_INDEX:
Michal Krol2861e732004-03-29 11:09:34 +00001672 _mesa_printf("3D");
1673 break;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001674 case TEXTURE_RECT_INDEX:
Michal Krol2861e732004-03-29 11:09:34 +00001675 _mesa_printf("RECT");
1676 break;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001677 case TEXTURE_CUBE_INDEX:
Michal Krol2861e732004-03-29 11:09:34 +00001678 _mesa_printf("CUBE");
1679 break;
1680 default:
1681 _mesa_problem(NULL, "Invalid textue target in PrintTextureSrc");
1682 }
1683}
1684
1685static void
Brian Paul7e807512005-11-05 17:10:45 +00001686PrintCondCode(const struct prog_dst_register *dst)
Michal Krol2861e732004-03-29 11:09:34 +00001687{
1688 static const char *comps = "xyzw";
1689 static const char *ccString[] = {
1690 "??", "GT", "EQ", "LT", "UN", "GE", "LE", "NE", "TR", "FL", "??"
1691 };
1692
1693 _mesa_printf("%s", ccString[dst->CondMask]);
Keith Whitwell7c26b612005-04-21 14:46:57 +00001694 if (GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 1) &&
1695 GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 2) &&
1696 GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 3)) {
1697 _mesa_printf(".%c", comps[GET_SWZ(dst->CondSwizzle, 0)]);
Michal Krol2861e732004-03-29 11:09:34 +00001698 }
Keith Whitwell7c26b612005-04-21 14:46:57 +00001699 else if (dst->CondSwizzle != SWIZZLE_NOOP) {
Michal Krol2861e732004-03-29 11:09:34 +00001700 _mesa_printf(".%c%c%c%c",
Keith Whitwell7c26b612005-04-21 14:46:57 +00001701 comps[GET_SWZ(dst->CondSwizzle, 0)],
1702 comps[GET_SWZ(dst->CondSwizzle, 1)],
1703 comps[GET_SWZ(dst->CondSwizzle, 2)],
1704 comps[GET_SWZ(dst->CondSwizzle, 3)]);
Michal Krol2861e732004-03-29 11:09:34 +00001705 }
1706}
1707
1708
1709static void
Brian Paul7e807512005-11-05 17:10:45 +00001710PrintDstReg(const struct prog_dst_register *dst)
Michal Krol2861e732004-03-29 11:09:34 +00001711{
Michal Krol2861e732004-03-29 11:09:34 +00001712 if (dst->File == PROGRAM_OUTPUT) {
1713 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1714 }
1715 else if (dst->File == PROGRAM_TEMPORARY) {
1716 if (dst->Index >= 32)
1717 _mesa_printf("H%d", dst->Index);
1718 else
1719 _mesa_printf("R%d", dst->Index);
1720 }
1721 else if (dst->File == PROGRAM_LOCAL_PARAM) {
1722 _mesa_printf("p[%d]", dst->Index);
1723 }
1724 else if (dst->File == PROGRAM_WRITE_ONLY) {
1725 _mesa_printf("%cC", "HR"[dst->Index]);
1726 }
1727 else {
1728 _mesa_printf("???");
1729 }
1730
Brian Paulccfe3d42005-11-03 02:35:15 +00001731 if (dst->WriteMask != 0 && dst->WriteMask != WRITEMASK_XYZW) {
Michal Krol2861e732004-03-29 11:09:34 +00001732 _mesa_printf(".");
Brian Paulccfe3d42005-11-03 02:35:15 +00001733 if (dst->WriteMask & WRITEMASK_X)
Michal Krol2861e732004-03-29 11:09:34 +00001734 _mesa_printf("x");
Brian Paulccfe3d42005-11-03 02:35:15 +00001735 if (dst->WriteMask & WRITEMASK_Y)
Michal Krol2861e732004-03-29 11:09:34 +00001736 _mesa_printf("y");
Brian Paulccfe3d42005-11-03 02:35:15 +00001737 if (dst->WriteMask & WRITEMASK_Z)
Michal Krol2861e732004-03-29 11:09:34 +00001738 _mesa_printf("z");
Brian Paulccfe3d42005-11-03 02:35:15 +00001739 if (dst->WriteMask & WRITEMASK_W)
Michal Krol2861e732004-03-29 11:09:34 +00001740 _mesa_printf("w");
1741 }
1742
1743 if (dst->CondMask != COND_TR ||
Keith Whitwell7c26b612005-04-21 14:46:57 +00001744 dst->CondSwizzle != SWIZZLE_NOOP) {
Michal Krol2861e732004-03-29 11:09:34 +00001745 _mesa_printf(" (");
1746 PrintCondCode(dst);
1747 _mesa_printf(")");
1748 }
1749}
1750
1751
1752/**
1753 * Print (unparse) the given vertex program. Just for debugging.
1754 */
1755void
Brian Paul122629f2006-07-20 16:49:57 +00001756_mesa_print_nv_fragment_program(const struct gl_fragment_program *program)
Michal Krol2861e732004-03-29 11:09:34 +00001757{
Brian Paul7e807512005-11-05 17:10:45 +00001758 const struct prog_instruction *inst;
Michal Krol2861e732004-03-29 11:09:34 +00001759
Brian Paulde997602005-11-12 17:53:14 +00001760 for (inst = program->Base.Instructions; inst->Opcode != OPCODE_END; inst++) {
Michal Krol2861e732004-03-29 11:09:34 +00001761 int i;
1762 for (i = 0; Instructions[i].name; i++) {
1763 if (inst->Opcode == Instructions[i].opcode) {
1764 /* print instruction name */
1765 _mesa_printf("%s", Instructions[i].name);
1766 if (inst->Precision == FLOAT16)
1767 _mesa_printf("H");
1768 else if (inst->Precision == FIXED12)
1769 _mesa_printf("X");
Brian Paul7e807512005-11-05 17:10:45 +00001770 if (inst->CondUpdate)
Michal Krol2861e732004-03-29 11:09:34 +00001771 _mesa_printf("C");
Brian Paule31ac052005-11-20 17:52:40 +00001772 if (inst->SaturateMode == SATURATE_ZERO_ONE)
Michal Krol2861e732004-03-29 11:09:34 +00001773 _mesa_printf("_SAT");
1774 _mesa_printf(" ");
1775
1776 if (Instructions[i].inputs == INPUT_CC) {
1777 PrintCondCode(&inst->DstReg);
1778 }
1779 else if (Instructions[i].outputs == OUTPUT_V ||
1780 Instructions[i].outputs == OUTPUT_S) {
1781 /* print dest register */
1782 PrintDstReg(&inst->DstReg);
1783 _mesa_printf(", ");
1784 }
1785
1786 /* print source register(s) */
1787 if (Instructions[i].inputs == INPUT_1V ||
1788 Instructions[i].inputs == INPUT_1S) {
1789 PrintSrcReg(program, &inst->SrcReg[0]);
1790 }
1791 else if (Instructions[i].inputs == INPUT_2V ||
1792 Instructions[i].inputs == INPUT_2S) {
1793 PrintSrcReg(program, &inst->SrcReg[0]);
1794 _mesa_printf(", ");
1795 PrintSrcReg(program, &inst->SrcReg[1]);
1796 }
1797 else if (Instructions[i].inputs == INPUT_3V) {
1798 PrintSrcReg(program, &inst->SrcReg[0]);
1799 _mesa_printf(", ");
1800 PrintSrcReg(program, &inst->SrcReg[1]);
1801 _mesa_printf(", ");
1802 PrintSrcReg(program, &inst->SrcReg[2]);
1803 }
1804 else if (Instructions[i].inputs == INPUT_1V_T) {
1805 PrintSrcReg(program, &inst->SrcReg[0]);
1806 _mesa_printf(", ");
1807 PrintTextureSrc(inst);
1808 }
1809 else if (Instructions[i].inputs == INPUT_3V_T) {
1810 PrintSrcReg(program, &inst->SrcReg[0]);
1811 _mesa_printf(", ");
1812 PrintSrcReg(program, &inst->SrcReg[1]);
1813 _mesa_printf(", ");
1814 PrintSrcReg(program, &inst->SrcReg[2]);
1815 _mesa_printf(", ");
1816 PrintTextureSrc(inst);
1817 }
1818 _mesa_printf(";\n");
1819 break;
1820 }
1821 }
1822 if (!Instructions[i].name) {
1823 _mesa_printf("Invalid opcode %d\n", inst->Opcode);
1824 }
1825 }
1826 _mesa_printf("END\n");
1827}
1828
1829
1830const char *
1831_mesa_nv_fragment_input_register_name(GLuint i)
1832{
1833 ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
1834 return InputRegisters[i];
1835}
1836
1837
1838const char *
1839_mesa_nv_fragment_output_register_name(GLuint i)
1840{
1841 ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_OUTPUTS);
1842 return OutputRegisters[i];
1843}