blob: 5f3a30b74164d84c097caaa4e487ef9486e41a37 [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"
Brian Paul7e807512005-11-05 17:10:45 +000046#include "program_instruction.h"
Michal Krol2861e732004-03-29 11:09:34 +000047#include "nvfragparse.h"
48#include "nvprogram.h"
49#include "program.h"
50
51
52#define INPUT_1V 1
53#define INPUT_2V 2
54#define INPUT_3V 3
55#define INPUT_1S 4
56#define INPUT_2S 5
57#define INPUT_CC 6
58#define INPUT_1V_T 7 /* one source vector, plus textureId */
59#define INPUT_3V_T 8 /* one source vector, plus textureId */
60#define INPUT_NONE 9
Brian Paul2a5afe32004-12-18 16:18:00 +000061#define INPUT_1V_S 10 /* a string and a vector register */
Michal Krol2861e732004-03-29 11:09:34 +000062#define OUTPUT_V 20
63#define OUTPUT_S 21
64#define OUTPUT_NONE 22
65
66/* IRIX defines some of these */
67#undef _R
68#undef _H
69#undef _X
70#undef _C
71#undef _S
72
73/* Optional suffixes */
74#define _R FLOAT32 /* float */
75#define _H FLOAT16 /* half-float */
76#define _X FIXED12 /* fixed */
77#define _C 0x08 /* set cond codes */
78#define _S 0x10 /* saturate, clamp result to [0,1] */
79
80struct instruction_pattern {
81 const char *name;
Brian Paul7e807512005-11-05 17:10:45 +000082 enum prog_opcode opcode;
Michal Krol2861e732004-03-29 11:09:34 +000083 GLuint inputs;
84 GLuint outputs;
85 GLuint suffixes;
86};
87
88static const struct instruction_pattern Instructions[] = {
Brian Paul7e807512005-11-05 17:10:45 +000089 { "ADD", OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
90 { "COS", OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
91 { "DDX", OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
92 { "DDY", OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
93 { "DP3", OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
94 { "DP4", OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
95 { "DST", OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H | _C | _S },
96 { "EX2", OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
97 { "FLR", OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
98 { "FRC", OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
99 { "KIL", OPCODE_KIL_NV, INPUT_CC, OUTPUT_NONE, 0 },
100 { "LG2", OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
101 { "LIT", OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
102 { "LRP", OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
103 { "MAD", OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
104 { "MAX", OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
105 { "MIN", OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
106 { "MOV", OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
107 { "MUL", OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
108 { "PK2H", OPCODE_PK2H, INPUT_1V, OUTPUT_S, 0 },
109 { "PK2US", OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0 },
110 { "PK4B", OPCODE_PK4B, INPUT_1V, OUTPUT_S, 0 },
111 { "PK4UB", OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0 },
112 { "POW", OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H | _C | _S },
113 { "RCP", OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
114 { "RFL", OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H | _C | _S },
115 { "RSQ", OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
116 { "SEQ", OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
117 { "SFL", OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
118 { "SGE", OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
119 { "SGT", OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
120 { "SIN", OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
121 { "SLE", OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
122 { "SLT", OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
123 { "SNE", OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
124 { "STR", OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
125 { "SUB", OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
126 { "TEX", OPCODE_TEX, INPUT_1V_T, OUTPUT_V, _C | _S },
127 { "TXD", OPCODE_TXD, INPUT_3V_T, OUTPUT_V, _C | _S },
128 { "TXP", OPCODE_TXP_NV, INPUT_1V_T, OUTPUT_V, _C | _S },
129 { "UP2H", OPCODE_UP2H, INPUT_1S, OUTPUT_V, _C | _S },
130 { "UP2US", OPCODE_UP2US, INPUT_1S, OUTPUT_V, _C | _S },
131 { "UP4B", OPCODE_UP4B, INPUT_1S, OUTPUT_V, _C | _S },
132 { "UP4UB", OPCODE_UP4UB, INPUT_1S, OUTPUT_V, _C | _S },
133 { "X2D", OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H | _C | _S },
134 { "PRINT", OPCODE_PRINT, INPUT_1V_S, OUTPUT_NONE, 0 },
135 { NULL, (enum prog_opcode) -1, 0, 0, 0 }
Michal Krol2861e732004-03-29 11:09:34 +0000136};
137
138
139/*
140 * Information needed or computed during parsing.
141 * Remember, we can't modify the target program object until we've
142 * _successfully_ parsed the program text.
143 */
144struct parse_state {
145 GLcontext *ctx;
146 const GLubyte *start; /* start of program string */
147 const GLubyte *pos; /* current position */
148 const GLubyte *curLine;
Brian Paul122629f2006-07-20 16:49:57 +0000149 struct gl_fragment_program *program; /* current program */
Michal Krol2861e732004-03-29 11:09:34 +0000150
Brian Paul122629f2006-07-20 16:49:57 +0000151 struct gl_program_parameter_list *parameters;
Michal Krol2861e732004-03-29 11:09:34 +0000152
153 GLuint numInst; /* number of instructions parsed */
154 GLuint inputsRead; /* bitmask of input registers used */
155 GLuint outputsWritten; /* bitmask of 1 << FRAG_OUTPUT_* bits */
156 GLuint texturesUsed[MAX_TEXTURE_IMAGE_UNITS];
157};
158
159
160
161/*
162 * Called whenever we find an error during parsing.
163 */
164static void
165record_error(struct parse_state *parseState, const char *msg, int lineNo)
166{
167#ifdef DEBUG
168 GLint line, column;
169 const GLubyte *lineStr;
170 lineStr = _mesa_find_line_column(parseState->start,
171 parseState->pos, &line, &column);
172 _mesa_debug(parseState->ctx,
173 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n",
174 lineNo, line, column, (char *) lineStr, msg);
175 _mesa_free((void *) lineStr);
176#else
177 (void) lineNo;
178#endif
179
180 /* Check that no error was already recorded. Only record the first one. */
181 if (parseState->ctx->Program.ErrorString[0] == 0) {
182 _mesa_set_program_error(parseState->ctx,
183 parseState->pos - parseState->start,
184 msg);
185 }
186}
187
188
189#define RETURN_ERROR \
190do { \
191 record_error(parseState, "Unexpected end of input.", __LINE__); \
192 return GL_FALSE; \
193} while(0)
194
195#define RETURN_ERROR1(msg) \
196do { \
197 record_error(parseState, msg, __LINE__); \
198 return GL_FALSE; \
199} while(0)
200
201#define RETURN_ERROR2(msg1, msg2) \
202do { \
203 char err[1000]; \
204 _mesa_sprintf(err, "%s %s", msg1, msg2); \
205 record_error(parseState, err, __LINE__); \
206 return GL_FALSE; \
207} while(0)
208
209
210
211
212/*
213 * Search a list of instruction structures for a match.
214 */
215static struct instruction_pattern
216MatchInstruction(const GLubyte *token)
217{
218 const struct instruction_pattern *inst;
219 struct instruction_pattern result;
220
221 for (inst = Instructions; inst->name; inst++) {
222 if (_mesa_strncmp((const char *) token, inst->name, 3) == 0) {
223 /* matched! */
224 int i = 3;
225 result = *inst;
226 result.suffixes = 0;
227 /* look at suffix */
228 if (token[i] == 'R') {
229 result.suffixes |= _R;
230 i++;
231 }
232 else if (token[i] == 'H') {
233 result.suffixes |= _H;
234 i++;
235 }
236 else if (token[i] == 'X') {
237 result.suffixes |= _X;
238 i++;
239 }
240 if (token[i] == 'C') {
241 result.suffixes |= _C;
242 i++;
243 }
244 if (token[i] == '_' && token[i+1] == 'S' &&
245 token[i+2] == 'A' && token[i+3] == 'T') {
246 result.suffixes |= _S;
247 }
248 return result;
249 }
250 }
Brian Paul28b014e2006-04-05 03:05:17 +0000251 result.opcode = MAX_OPCODE; /* i.e. invalid instruction */
Michal Krol2861e732004-03-29 11:09:34 +0000252 return result;
253}
254
255
256
257
258/**********************************************************************/
259
260
261static GLboolean IsLetter(GLubyte b)
262{
263 return (b >= 'a' && b <= 'z') ||
264 (b >= 'A' && b <= 'Z') ||
265 (b == '_') ||
266 (b == '$');
267}
268
269
270static GLboolean IsDigit(GLubyte b)
271{
272 return b >= '0' && b <= '9';
273}
274
275
276static GLboolean IsWhitespace(GLubyte b)
277{
278 return b == ' ' || b == '\t' || b == '\n' || b == '\r';
279}
280
281
282/**
283 * Starting at 'str' find the next token. A token can be an integer,
284 * an identifier or punctuation symbol.
285 * \return <= 0 we found an error, else, return number of characters parsed.
286 */
287static GLint
288GetToken(struct parse_state *parseState, GLubyte *token)
289{
290 const GLubyte *str = parseState->pos;
291 GLint i = 0, j = 0;
292
293 token[0] = 0;
294
295 /* skip whitespace and comments */
296 while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
297 if (str[i] == '#') {
298 /* skip comment */
299 while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
300 i++;
301 }
302 if (str[i] == '\n' || str[i] == '\r')
303 parseState->curLine = str + i + 1;
304 }
305 else {
306 /* skip whitespace */
307 if (str[i] == '\n' || str[i] == '\r')
308 parseState->curLine = str + i + 1;
309 i++;
310 }
311 }
312
313 if (str[i] == 0)
314 return -i;
315
316 /* try matching an integer */
317 while (str[i] && IsDigit(str[i])) {
318 token[j++] = str[i++];
319 }
320 if (j > 0 || !str[i]) {
321 token[j] = 0;
322 return i;
323 }
324
325 /* try matching an identifier */
326 if (IsLetter(str[i])) {
327 while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
328 token[j++] = str[i++];
329 }
330 token[j] = 0;
331 return i;
332 }
333
334 /* punctuation character */
335 if (str[i]) {
336 token[0] = str[i++];
337 token[1] = 0;
338 return i;
339 }
340
341 /* end of input */
342 token[0] = 0;
343 return i;
344}
345
346
347/**
348 * Get next token from input stream and increment stream pointer past token.
349 */
350static GLboolean
351Parse_Token(struct parse_state *parseState, GLubyte *token)
352{
353 GLint i;
354 i = GetToken(parseState, token);
355 if (i <= 0) {
356 parseState->pos += (-i);
357 return GL_FALSE;
358 }
359 parseState->pos += i;
360 return GL_TRUE;
361}
362
363
364/**
365 * Get next token from input stream but don't increment stream pointer.
366 */
367static GLboolean
368Peek_Token(struct parse_state *parseState, GLubyte *token)
369{
370 GLint i, len;
371 i = GetToken(parseState, token);
372 if (i <= 0) {
373 parseState->pos += (-i);
374 return GL_FALSE;
375 }
Karl Schultz6258b762005-05-05 21:08:07 +0000376 len = (GLint)_mesa_strlen((const char *) token);
Michal Krol2861e732004-03-29 11:09:34 +0000377 parseState->pos += (i - len);
378 return GL_TRUE;
379}
380
381
382/**********************************************************************/
383
384static const char *InputRegisters[MAX_NV_FRAGMENT_PROGRAM_INPUTS + 1] = {
385 "WPOS", "COL0", "COL1", "FOGC",
386 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
387};
388
389static const char *OutputRegisters[MAX_NV_FRAGMENT_PROGRAM_OUTPUTS + 1] = {
390 "COLR", "COLH",
391 /* These are only allows for register combiners */
392 /*
393 "TEX0", "TEX1", "TEX2", "TEX3",
394 */
395 "DEPR", NULL
396};
397
398
399
400
401/**********************************************************************/
402
403/**
404 * Try to match 'pattern' as the next token after any whitespace/comments.
405 */
406static GLboolean
407Parse_String(struct parse_state *parseState, const char *pattern)
408{
409 const GLubyte *m;
410 GLint i;
411
412 /* skip whitespace and comments */
413 while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') {
414 if (*parseState->pos == '#') {
415 while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) {
416 parseState->pos += 1;
417 }
418 if (*parseState->pos == '\n' || *parseState->pos == '\r')
419 parseState->curLine = parseState->pos + 1;
420 }
421 else {
422 /* skip whitespace */
423 if (*parseState->pos == '\n' || *parseState->pos == '\r')
424 parseState->curLine = parseState->pos + 1;
425 parseState->pos += 1;
426 }
427 }
428
429 /* Try to match the pattern */
430 m = parseState->pos;
431 for (i = 0; pattern[i]; i++) {
432 if (*m != (GLubyte) pattern[i])
433 return GL_FALSE;
434 m += 1;
435 }
436 parseState->pos = m;
437
438 return GL_TRUE; /* success */
439}
440
441
442static GLboolean
443Parse_Identifier(struct parse_state *parseState, GLubyte *ident)
444{
445 if (!Parse_Token(parseState, ident))
446 RETURN_ERROR;
447 if (IsLetter(ident[0]))
448 return GL_TRUE;
449 else
450 RETURN_ERROR1("Expected an identfier");
451}
452
453
454/**
455 * Parse a floating point constant, or a defined symbol name.
456 * [+/-]N[.N[eN]]
457 * Output: number[0 .. 3] will get the value.
458 */
459static GLboolean
460Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number)
461{
462 char *end = NULL;
463
464 *number = (GLfloat) _mesa_strtod((const char *) parseState->pos, &end);
465
466 if (end && end > (char *) parseState->pos) {
467 /* got a number */
468 parseState->pos = (GLubyte *) end;
469 number[1] = *number;
470 number[2] = *number;
471 number[3] = *number;
472 return GL_TRUE;
473 }
474 else {
475 /* should be an identifier */
476 GLubyte ident[100];
477 const GLfloat *constant;
478 if (!Parse_Identifier(parseState, ident))
479 RETURN_ERROR1("Expected an identifier");
480 constant = _mesa_lookup_parameter_value(parseState->parameters,
481 -1, (const char *) ident);
482 /* XXX Check that it's a constant and not a parameter */
483 if (!constant) {
484 RETURN_ERROR1("Undefined symbol");
485 }
486 else {
487 COPY_4V(number, constant);
488 return GL_TRUE;
489 }
490 }
491}
492
493
494
495/**
496 * Parse a vector constant, one of:
497 * { float }
498 * { float, float }
499 * { float, float, float }
500 * { float, float, float, float }
501 */
502static GLboolean
503Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec)
504{
505 /* "{" was already consumed */
506
507 ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0);
508
509 if (!Parse_ScalarConstant(parseState, vec+0)) /* X */
510 return GL_FALSE;
511
512 if (Parse_String(parseState, "}")) {
513 return GL_TRUE;
514 }
515
516 if (!Parse_String(parseState, ","))
517 RETURN_ERROR1("Expected comma in vector constant");
518
519 if (!Parse_ScalarConstant(parseState, vec+1)) /* Y */
520 return GL_FALSE;
521
522 if (Parse_String(parseState, "}")) {
523 return GL_TRUE;
524 }
525
526 if (!Parse_String(parseState, ","))
527 RETURN_ERROR1("Expected comma in vector constant");
528
529 if (!Parse_ScalarConstant(parseState, vec+2)) /* Z */
530 return GL_FALSE;
531
532 if (Parse_String(parseState, "}")) {
533 return GL_TRUE;
534 }
535
536 if (!Parse_String(parseState, ","))
537 RETURN_ERROR1("Expected comma in vector constant");
538
539 if (!Parse_ScalarConstant(parseState, vec+3)) /* W */
540 return GL_FALSE;
541
542 if (!Parse_String(parseState, "}"))
543 RETURN_ERROR1("Expected closing brace in vector constant");
544
545 return GL_TRUE;
546}
547
548
549/**
550 * Parse <number>, <varname> or {a, b, c, d}.
551 * Return number of values in the vector or scalar, or zero if parse error.
552 */
553static GLuint
554Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec)
555{
556 if (Parse_String(parseState, "{")) {
557 return Parse_VectorConstant(parseState, vec);
558 }
559 else {
560 GLboolean b = Parse_ScalarConstant(parseState, vec);
561 if (b) {
562 vec[1] = vec[2] = vec[3] = vec[0];
563 }
564 return b;
565 }
566}
567
568
569/**
570 * Parse a texture image source:
571 * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT]
572 */
573static GLboolean
574Parse_TextureImageId(struct parse_state *parseState,
575 GLubyte *texUnit, GLubyte *texTargetBit)
576{
577 GLubyte imageSrc[100];
578 GLint unit;
579
580 if (!Parse_Token(parseState, imageSrc))
581 RETURN_ERROR;
582
583 if (imageSrc[0] != 'T' ||
584 imageSrc[1] != 'E' ||
585 imageSrc[2] != 'X') {
586 RETURN_ERROR1("Expected TEX# source");
587 }
588 unit = _mesa_atoi((const char *) imageSrc + 3);
589 if ((unit < 0 || unit > MAX_TEXTURE_IMAGE_UNITS) ||
590 (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) {
591 RETURN_ERROR1("Invalied TEX# source index");
592 }
593 *texUnit = unit;
594
595 if (!Parse_String(parseState, ","))
596 RETURN_ERROR1("Expected ,");
597
598 if (Parse_String(parseState, "1D")) {
599 *texTargetBit = TEXTURE_1D_BIT;
600 }
601 else if (Parse_String(parseState, "2D")) {
602 *texTargetBit = TEXTURE_2D_BIT;
603 }
604 else if (Parse_String(parseState, "3D")) {
605 *texTargetBit = TEXTURE_3D_BIT;
606 }
607 else if (Parse_String(parseState, "CUBE")) {
608 *texTargetBit = TEXTURE_CUBE_BIT;
609 }
610 else if (Parse_String(parseState, "RECT")) {
611 *texTargetBit = TEXTURE_RECT_BIT;
612 }
613 else {
614 RETURN_ERROR1("Invalid texture target token");
615 }
616
617 /* update record of referenced texture units */
618 parseState->texturesUsed[*texUnit] |= *texTargetBit;
619 if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) {
620 RETURN_ERROR1("Only one texture target can be used per texture unit.");
621 }
622
623 return GL_TRUE;
624}
625
626
627/**
628 * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix
629 * like .wxyz, .xxyy, etc and return the swizzle indexes.
630 */
631static GLboolean
632Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4])
633{
634 if (token[1] == 0) {
635 /* single letter swizzle (scalar) */
636 if (token[0] == 'x')
637 ASSIGN_4V(swizzle, 0, 0, 0, 0);
638 else if (token[0] == 'y')
639 ASSIGN_4V(swizzle, 1, 1, 1, 1);
640 else if (token[0] == 'z')
641 ASSIGN_4V(swizzle, 2, 2, 2, 2);
642 else if (token[0] == 'w')
643 ASSIGN_4V(swizzle, 3, 3, 3, 3);
644 else
645 return GL_FALSE;
646 }
647 else {
648 /* 4-component swizzle (vector) */
649 GLint k;
650 for (k = 0; token[k] && k < 4; k++) {
651 if (token[k] == 'x')
652 swizzle[k] = 0;
653 else if (token[k] == 'y')
654 swizzle[k] = 1;
655 else if (token[k] == 'z')
656 swizzle[k] = 2;
657 else if (token[k] == 'w')
658 swizzle[k] = 3;
659 else
660 return GL_FALSE;
661 }
662 if (k != 4)
663 return GL_FALSE;
664 }
665 return GL_TRUE;
666}
667
668
669static GLboolean
670Parse_CondCodeMask(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000671 struct prog_dst_register *dstReg)
Michal Krol2861e732004-03-29 11:09:34 +0000672{
673 if (Parse_String(parseState, "EQ"))
674 dstReg->CondMask = COND_EQ;
675 else if (Parse_String(parseState, "GE"))
676 dstReg->CondMask = COND_GE;
677 else if (Parse_String(parseState, "GT"))
678 dstReg->CondMask = COND_GT;
679 else if (Parse_String(parseState, "LE"))
680 dstReg->CondMask = COND_LE;
681 else if (Parse_String(parseState, "LT"))
682 dstReg->CondMask = COND_LT;
683 else if (Parse_String(parseState, "NE"))
684 dstReg->CondMask = COND_NE;
685 else if (Parse_String(parseState, "TR"))
686 dstReg->CondMask = COND_TR;
687 else if (Parse_String(parseState, "FL"))
688 dstReg->CondMask = COND_FL;
689 else
690 RETURN_ERROR1("Invalid condition code mask");
691
692 /* look for optional .xyzw swizzle */
693 if (Parse_String(parseState, ".")) {
694 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000695 GLuint swz[4];
696
Michal Krol2861e732004-03-29 11:09:34 +0000697 if (!Parse_Token(parseState, token)) /* get xyzw suffix */
698 RETURN_ERROR;
699
Keith Whitwell7c26b612005-04-21 14:46:57 +0000700 if (!Parse_SwizzleSuffix(token, swz))
Michal Krol2861e732004-03-29 11:09:34 +0000701 RETURN_ERROR1("Invalid swizzle suffix");
Keith Whitwell7c26b612005-04-21 14:46:57 +0000702
Brian Paulfd4395b2005-11-05 03:02:28 +0000703 dstReg->CondSwizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
Michal Krol2861e732004-03-29 11:09:34 +0000704 }
705
706 return GL_TRUE;
707}
708
709
710/**
711 * Parse a temporary register: Rnn or Hnn
712 */
713static GLboolean
714Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum)
715{
716 GLubyte token[100];
717
718 /* Should be 'R##' or 'H##' */
719 if (!Parse_Token(parseState, token))
720 RETURN_ERROR;
721 if (token[0] != 'R' && token[0] != 'H')
722 RETURN_ERROR1("Expected R## or H##");
723
724 if (IsDigit(token[1])) {
725 GLint reg = _mesa_atoi((const char *) (token + 1));
726 if (token[0] == 'H')
727 reg += 32;
728 if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS)
729 RETURN_ERROR1("Invalid temporary register name");
730 *tempRegNum = reg;
731 }
732 else {
733 RETURN_ERROR1("Invalid temporary register name");
734 }
735
736 return GL_TRUE;
737}
738
739
740/**
741 * Parse a write-only dummy register: RC or HC.
742 */
743static GLboolean
744Parse_DummyReg(struct parse_state *parseState, GLint *regNum)
745{
746 if (Parse_String(parseState, "RC")) {
747 *regNum = 0;
748 }
749 else if (Parse_String(parseState, "HC")) {
750 *regNum = 1;
751 }
752 else {
753 RETURN_ERROR1("Invalid write-only register name");
754 }
755
756 return GL_TRUE;
757}
758
759
760/**
761 * Parse a program local parameter register "p[##]"
762 */
763static GLboolean
764Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum)
765{
766 GLubyte token[100];
767
768 if (!Parse_String(parseState, "p["))
769 RETURN_ERROR1("Expected p[");
770
771 if (!Parse_Token(parseState, token))
772 RETURN_ERROR;
773
774 if (IsDigit(token[0])) {
775 /* a numbered program parameter register */
776 GLint reg = _mesa_atoi((const char *) token);
777 if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS)
778 RETURN_ERROR1("Invalid constant program number");
779 *regNum = reg;
780 }
781 else {
782 RETURN_ERROR;
783 }
784
785 if (!Parse_String(parseState, "]"))
786 RETURN_ERROR1("Expected ]");
787
788 return GL_TRUE;
789}
790
791
792/**
793 * Parse f[name] - fragment input register
794 */
795static GLboolean
796Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum)
797{
798 GLubyte token[100];
799 GLint j;
800
801 /* Match 'f[' */
802 if (!Parse_String(parseState, "f["))
803 RETURN_ERROR1("Expected f[");
804
805 /* get <name> and look for match */
806 if (!Parse_Token(parseState, token)) {
807 RETURN_ERROR;
808 }
809 for (j = 0; InputRegisters[j]; j++) {
810 if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) {
811 *tempRegNum = j;
812 parseState->inputsRead |= (1 << j);
813 break;
814 }
815 }
816 if (!InputRegisters[j]) {
817 /* unknown input register label */
818 RETURN_ERROR2("Invalid register name", token);
819 }
820
821 /* Match '[' */
822 if (!Parse_String(parseState, "]"))
823 RETURN_ERROR1("Expected ]");
824
825 return GL_TRUE;
826}
827
828
829static GLboolean
830Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum)
831{
832 GLubyte token[100];
833 GLint j;
834
835 /* Match "o[" */
836 if (!Parse_String(parseState, "o["))
837 RETURN_ERROR1("Expected o[");
838
839 /* Get output reg name */
840 if (!Parse_Token(parseState, token))
841 RETURN_ERROR;
842
843 /* try to match an output register name */
844 for (j = 0; OutputRegisters[j]; j++) {
845 if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) {
Brian Paul90ebb582005-11-02 18:06:12 +0000846 static GLuint bothColors = (1 << FRAG_RESULT_COLR) | (1 << FRAG_RESULT_COLH);
Michal Krol2861e732004-03-29 11:09:34 +0000847 *outputRegNum = j;
848 parseState->outputsWritten |= (1 << j);
849 if ((parseState->outputsWritten & bothColors) == bothColors) {
850 RETURN_ERROR1("Illegal to write to both o[COLR] and o[COLH]");
851 }
852 break;
853 }
854 }
855 if (!OutputRegisters[j])
856 RETURN_ERROR1("Invalid output register name");
857
858 /* Match ']' */
859 if (!Parse_String(parseState, "]"))
860 RETURN_ERROR1("Expected ]");
861
862 return GL_TRUE;
863}
864
865
866static GLboolean
867Parse_MaskedDstReg(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000868 struct prog_dst_register *dstReg)
Michal Krol2861e732004-03-29 11:09:34 +0000869{
870 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000871 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000872
873 /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
874 if (!Peek_Token(parseState, token))
875 RETURN_ERROR;
876
877 if (_mesa_strcmp((const char *) token, "RC") == 0 ||
878 _mesa_strcmp((const char *) token, "HC") == 0) {
879 /* a write-only register */
880 dstReg->File = PROGRAM_WRITE_ONLY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000881 if (!Parse_DummyReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000882 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000883 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000884 }
885 else if (token[0] == 'R' || token[0] == 'H') {
886 /* a temporary register */
887 dstReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000888 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000889 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000890 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000891 }
892 else if (token[0] == 'o') {
893 /* an output register */
894 dstReg->File = PROGRAM_OUTPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000895 if (!Parse_OutputReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +0000896 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000897 dstReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +0000898 }
899 else {
900 RETURN_ERROR1("Invalid destination register name");
901 }
902
903 /* Parse optional write mask */
904 if (Parse_String(parseState, ".")) {
905 /* got a mask */
906 GLint k = 0;
907
908 if (!Parse_Token(parseState, token)) /* get xyzw writemask */
909 RETURN_ERROR;
910
Keith Whitwell7c26b612005-04-21 14:46:57 +0000911 dstReg->WriteMask = 0;
Michal Krol2861e732004-03-29 11:09:34 +0000912
913 if (token[k] == 'x') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000914 dstReg->WriteMask |= WRITEMASK_X;
Michal Krol2861e732004-03-29 11:09:34 +0000915 k++;
916 }
917 if (token[k] == 'y') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000918 dstReg->WriteMask |= WRITEMASK_Y;
Michal Krol2861e732004-03-29 11:09:34 +0000919 k++;
920 }
921 if (token[k] == 'z') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000922 dstReg->WriteMask |= WRITEMASK_Z;
Michal Krol2861e732004-03-29 11:09:34 +0000923 k++;
924 }
925 if (token[k] == 'w') {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000926 dstReg->WriteMask |= WRITEMASK_W;
Michal Krol2861e732004-03-29 11:09:34 +0000927 k++;
928 }
929 if (k == 0) {
930 RETURN_ERROR1("Invalid writemask character");
931 }
932
933 }
934 else {
Keith Whitwell7c26b612005-04-21 14:46:57 +0000935 dstReg->WriteMask = WRITEMASK_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000936 }
937
938 /* optional condition code mask */
939 if (Parse_String(parseState, "(")) {
940 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
941 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
942 if (!Parse_CondCodeMask(parseState, dstReg))
943 RETURN_ERROR;
944
945 if (!Parse_String(parseState, ")")) /* consume ")" */
946 RETURN_ERROR1("Expected )");
947
948 return GL_TRUE;
949 }
950 else {
951 /* no cond code mask */
952 dstReg->CondMask = COND_TR;
Keith Whitwell7c26b612005-04-21 14:46:57 +0000953 dstReg->CondSwizzle = SWIZZLE_NOOP;
Michal Krol2861e732004-03-29 11:09:34 +0000954 return GL_TRUE;
955 }
956}
957
958
959/**
960 * Parse a vector source (register, constant, etc):
961 * <vectorSrc> ::= <absVectorSrc>
962 * | <baseVectorSrc>
963 * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|"
964 */
965static GLboolean
966Parse_VectorSrc(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +0000967 struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +0000968{
969 GLfloat sign = 1.0F;
970 GLubyte token[100];
Keith Whitwell7c26b612005-04-21 14:46:57 +0000971 GLint idx;
Michal Krol2861e732004-03-29 11:09:34 +0000972
973 /*
974 * First, take care of +/- and absolute value stuff.
975 */
976 if (Parse_String(parseState, "-"))
977 sign = -1.0F;
978 else if (Parse_String(parseState, "+"))
979 sign = +1.0F;
980
981 if (Parse_String(parseState, "|")) {
982 srcReg->Abs = GL_TRUE;
983 srcReg->NegateAbs = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
984
985 if (Parse_String(parseState, "-"))
Brian Paula8c42422006-05-30 22:17:35 +0000986 srcReg->NegateBase = NEGATE_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +0000987 else if (Parse_String(parseState, "+"))
Brian Paula8c42422006-05-30 22:17:35 +0000988 srcReg->NegateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000989 else
Brian Paula8c42422006-05-30 22:17:35 +0000990 srcReg->NegateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000991 }
992 else {
993 srcReg->Abs = GL_FALSE;
994 srcReg->NegateAbs = GL_FALSE;
Brian Paula8c42422006-05-30 22:17:35 +0000995 srcReg->NegateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +0000996 }
997
998 /* This should be the real src vector/register name */
999 if (!Peek_Token(parseState, token))
1000 RETURN_ERROR;
1001
1002 /* Src reg can be Rn, Hn, f[n], p[n], a named parameter, a scalar
1003 * literal or vector literal.
1004 */
1005 if (token[0] == 'R' || token[0] == 'H') {
1006 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001007 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001008 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001009 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001010 }
1011 else if (token[0] == 'f') {
Brian Paule6940f02006-08-24 23:08:01 +00001012 /* XXX this might be an identifier! */
Michal Krol2861e732004-03-29 11:09:34 +00001013 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001014 if (!Parse_FragReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001015 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001016 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001017 }
1018 else if (token[0] == 'p') {
Brian Paule6940f02006-08-24 23:08:01 +00001019 /* XXX this might be an identifier! */
Michal Krol2861e732004-03-29 11:09:34 +00001020 srcReg->File = PROGRAM_LOCAL_PARAM;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001021 if (!Parse_ProgramParamReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001022 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001023 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001024 }
1025 else if (IsLetter(token[0])){
1026 GLubyte ident[100];
1027 GLint paramIndex;
1028 if (!Parse_Identifier(parseState, ident))
1029 RETURN_ERROR;
1030 paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1031 -1, (const char *) ident);
1032 if (paramIndex < 0) {
1033 RETURN_ERROR2("Undefined constant or parameter: ", ident);
1034 }
1035 srcReg->File = PROGRAM_NAMED_PARAM;
1036 srcReg->Index = paramIndex;
1037 }
1038 else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){
1039 /* literal scalar constant */
1040 GLfloat values[4];
1041 GLuint paramIndex;
1042 if (!Parse_ScalarConstant(parseState, values))
1043 RETURN_ERROR;
1044 paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
1045 srcReg->File = PROGRAM_NAMED_PARAM;
1046 srcReg->Index = paramIndex;
1047 }
1048 else if (token[0] == '{'){
1049 /* literal vector constant */
1050 GLfloat values[4];
1051 GLuint paramIndex;
1052 (void) Parse_String(parseState, "{");
1053 if (!Parse_VectorConstant(parseState, values))
1054 RETURN_ERROR;
1055 paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
1056 srcReg->File = PROGRAM_NAMED_PARAM;
1057 srcReg->Index = paramIndex;
1058 }
1059 else {
1060 RETURN_ERROR2("Invalid source register name", token);
1061 }
1062
1063 /* init swizzle fields */
Keith Whitwell7c26b612005-04-21 14:46:57 +00001064 srcReg->Swizzle = SWIZZLE_NOOP;
Michal Krol2861e732004-03-29 11:09:34 +00001065
1066 /* Look for optional swizzle suffix */
1067 if (Parse_String(parseState, ".")) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001068 GLuint swz[4];
1069
Michal Krol2861e732004-03-29 11:09:34 +00001070 if (!Parse_Token(parseState, token))
1071 RETURN_ERROR;
1072
Keith Whitwell7c26b612005-04-21 14:46:57 +00001073 if (!Parse_SwizzleSuffix(token, swz))
Michal Krol2861e732004-03-29 11:09:34 +00001074 RETURN_ERROR1("Invalid swizzle suffix");
Keith Whitwell7c26b612005-04-21 14:46:57 +00001075
Brian Paulfd4395b2005-11-05 03:02:28 +00001076 srcReg->Swizzle = MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
Michal Krol2861e732004-03-29 11:09:34 +00001077 }
1078
1079 /* Finish absolute value */
1080 if (srcReg->Abs && !Parse_String(parseState, "|")) {
1081 RETURN_ERROR1("Expected |");
1082 }
1083
1084 return GL_TRUE;
1085}
1086
1087
1088static GLboolean
1089Parse_ScalarSrcReg(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001090 struct prog_src_register *srcReg)
Michal Krol2861e732004-03-29 11:09:34 +00001091{
1092 GLubyte token[100];
1093 GLfloat sign = 1.0F;
1094 GLboolean needSuffix = GL_TRUE;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001095 GLint idx;
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;
1107 srcReg->NegateAbs = (sign < 0.0F) ? GL_TRUE : GL_FALSE;
1108
1109 if (Parse_String(parseState, "-"))
Brian Paula8c42422006-05-30 22:17:35 +00001110 srcReg->NegateBase = NEGATE_XYZW;
Michal Krol2861e732004-03-29 11:09:34 +00001111 else if (Parse_String(parseState, "+"))
Brian Paula8c42422006-05-30 22:17:35 +00001112 srcReg->NegateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +00001113 else
Brian Paula8c42422006-05-30 22:17:35 +00001114 srcReg->NegateBase = NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +00001115 }
1116 else {
1117 srcReg->Abs = GL_FALSE;
1118 srcReg->NegateAbs = GL_FALSE;
Brian Paula8c42422006-05-30 22:17:35 +00001119 srcReg->NegateBase = (sign < 0.0F) ? NEGATE_XYZW : NEGATE_NONE;
Michal Krol2861e732004-03-29 11:09:34 +00001120 }
1121
1122 if (!Peek_Token(parseState, token))
1123 RETURN_ERROR;
1124
1125 /* Src reg can be R<n>, H<n> or a named fragment attrib */
1126 if (token[0] == 'R' || token[0] == 'H') {
1127 srcReg->File = PROGRAM_TEMPORARY;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001128 if (!Parse_TempReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001129 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001130 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001131 }
1132 else if (token[0] == 'f') {
1133 srcReg->File = PROGRAM_INPUT;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001134 if (!Parse_FragReg(parseState, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001135 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001136 srcReg->Index = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001137 }
1138 else if (token[0] == '{') {
1139 /* vector literal */
1140 GLfloat values[4];
1141 GLuint paramIndex;
1142 (void) Parse_String(parseState, "{");
1143 if (!Parse_VectorConstant(parseState, values))
1144 RETURN_ERROR;
1145 paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
1146 srcReg->File = PROGRAM_NAMED_PARAM;
1147 srcReg->Index = paramIndex;
1148 }
Brian Paule6940f02006-08-24 23:08:01 +00001149 else if (IsLetter(token[0])){
1150 /* named param/constant */
1151 GLubyte ident[100];
1152 GLint paramIndex;
1153 if (!Parse_Identifier(parseState, ident))
1154 RETURN_ERROR;
1155 paramIndex = _mesa_lookup_parameter_index(parseState->parameters,
1156 -1, (const char *) ident);
1157 if (paramIndex < 0) {
1158 RETURN_ERROR2("Undefined constant or parameter: ", ident);
1159 }
1160 srcReg->File = PROGRAM_NAMED_PARAM;
1161 srcReg->Index = paramIndex;
1162 }
Michal Krol2861e732004-03-29 11:09:34 +00001163 else if (IsDigit(token[0])) {
1164 /* scalar literal */
1165 GLfloat values[4];
1166 GLuint paramIndex;
1167 if (!Parse_ScalarConstant(parseState, values))
1168 RETURN_ERROR;
1169 paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values);
1170 srcReg->Index = paramIndex;
1171 srcReg->File = PROGRAM_NAMED_PARAM;
1172 needSuffix = GL_FALSE;
1173 }
1174 else {
1175 RETURN_ERROR2("Invalid scalar source argument", token);
1176 }
1177
Keith Whitwell7c26b612005-04-21 14:46:57 +00001178 srcReg->Swizzle = 0;
Michal Krol2861e732004-03-29 11:09:34 +00001179 if (needSuffix) {
1180 /* parse .[xyzw] suffix */
1181 if (!Parse_String(parseState, "."))
1182 RETURN_ERROR1("Expected .");
1183
1184 if (!Parse_Token(parseState, token))
1185 RETURN_ERROR;
1186
1187 if (token[0] == 'x' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001188 srcReg->Swizzle = 0;
Michal Krol2861e732004-03-29 11:09:34 +00001189 }
1190 else if (token[0] == 'y' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001191 srcReg->Swizzle = 1;
Michal Krol2861e732004-03-29 11:09:34 +00001192 }
1193 else if (token[0] == 'z' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001194 srcReg->Swizzle = 2;
Michal Krol2861e732004-03-29 11:09:34 +00001195 }
1196 else if (token[0] == 'w' && token[1] == 0) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001197 srcReg->Swizzle = 3;
Michal Krol2861e732004-03-29 11:09:34 +00001198 }
1199 else {
1200 RETURN_ERROR1("Invalid scalar source suffix");
1201 }
1202 }
Michal Krol2861e732004-03-29 11:09:34 +00001203
1204 /* Finish absolute value */
1205 if (srcReg->Abs && !Parse_String(parseState, "|")) {
1206 RETURN_ERROR1("Expected |");
1207 }
1208
1209 return GL_TRUE;
1210}
1211
1212
Brian Paul2a5afe32004-12-18 16:18:00 +00001213static GLboolean
1214Parse_PrintInstruction(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001215 struct prog_instruction *inst)
Brian Paul2a5afe32004-12-18 16:18:00 +00001216{
1217 const GLubyte *str;
1218 GLubyte *msg;
1219 GLuint len;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001220 GLint idx;
Brian Paul2a5afe32004-12-18 16:18:00 +00001221
1222 /* The first argument is a literal string 'just like this' */
1223 if (!Parse_String(parseState, "'"))
1224 RETURN_ERROR1("Expected '");
1225
1226 str = parseState->pos;
1227 for (len = 0; str[len] != '\''; len++) /* find closing quote */
1228 ;
1229 parseState->pos += len + 1;
Brian Paul95801792005-12-06 15:41:43 +00001230 msg = (GLubyte*) _mesa_malloc(len + 1);
Brian Paul2a5afe32004-12-18 16:18:00 +00001231
1232 _mesa_memcpy(msg, str, len);
1233 msg[len] = 0;
1234 inst->Data = msg;
1235
1236 if (Parse_String(parseState, ",")) {
1237 /* got an optional register to print */
1238 GLubyte token[100];
1239 GetToken(parseState, token);
1240 if (token[0] == 'o') {
1241 /* dst reg */
Keith Whitwell7c26b612005-04-21 14:46:57 +00001242 if (!Parse_OutputReg(parseState, &idx))
Brian Paul2a5afe32004-12-18 16:18:00 +00001243 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001244 inst->SrcReg[0].Index = idx;
Brian Paul2a5afe32004-12-18 16:18:00 +00001245 inst->SrcReg[0].File = PROGRAM_OUTPUT;
1246 }
1247 else {
1248 /* src reg */
1249 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1250 RETURN_ERROR;
1251 }
1252 }
1253 else {
Brian Paul8cdf3722005-09-02 13:40:09 +00001254 inst->SrcReg[0].File = PROGRAM_UNDEFINED;
Brian Paul2a5afe32004-12-18 16:18:00 +00001255 }
1256
Keith Whitwell7c26b612005-04-21 14:46:57 +00001257 inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
Brian Paula8c42422006-05-30 22:17:35 +00001258 inst->SrcReg[0].NegateBase = NEGATE_NONE;
Brian Paul2a5afe32004-12-18 16:18:00 +00001259 inst->SrcReg[0].Abs = GL_FALSE;
1260 inst->SrcReg[0].NegateAbs = GL_FALSE;
1261
1262 return GL_TRUE;
1263}
1264
Michal Krol2861e732004-03-29 11:09:34 +00001265
1266static GLboolean
1267Parse_InstructionSequence(struct parse_state *parseState,
Brian Paul7e807512005-11-05 17:10:45 +00001268 struct prog_instruction program[])
Michal Krol2861e732004-03-29 11:09:34 +00001269{
1270 while (1) {
Brian Paul7e807512005-11-05 17:10:45 +00001271 struct prog_instruction *inst = program + parseState->numInst;
Michal Krol2861e732004-03-29 11:09:34 +00001272 struct instruction_pattern instMatch;
1273 GLubyte token[100];
1274
1275 /* Initialize the instruction */
Brian Pauld6272e02006-10-29 18:03:16 +00001276 _mesa_init_instructions(inst, 1);
Michal Krol2861e732004-03-29 11:09:34 +00001277
1278 /* special instructions */
1279 if (Parse_String(parseState, "DEFINE")) {
1280 GLubyte id[100];
1281 GLfloat value[7]; /* yes, 7 to be safe */
1282 if (!Parse_Identifier(parseState, id))
1283 RETURN_ERROR;
1284 /* XXX make sure id is not a reserved identifer, like R9 */
1285 if (!Parse_String(parseState, "="))
1286 RETURN_ERROR1("Expected =");
1287 if (!Parse_VectorOrScalarConstant(parseState, value))
1288 RETURN_ERROR;
1289 if (!Parse_String(parseState, ";"))
1290 RETURN_ERROR1("Expected ;");
1291 if (_mesa_lookup_parameter_index(parseState->parameters,
1292 -1, (const char *) id) >= 0) {
1293 RETURN_ERROR2(id, "already defined");
1294 }
1295 _mesa_add_named_parameter(parseState->parameters,
1296 (const char *) id, value);
1297 }
1298 else if (Parse_String(parseState, "DECLARE")) {
1299 GLubyte id[100];
1300 GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */
1301 if (!Parse_Identifier(parseState, id))
1302 RETURN_ERROR;
1303 /* XXX make sure id is not a reserved identifer, like R9 */
1304 if (Parse_String(parseState, "=")) {
1305 if (!Parse_VectorOrScalarConstant(parseState, value))
1306 RETURN_ERROR;
1307 }
1308 if (!Parse_String(parseState, ";"))
1309 RETURN_ERROR1("Expected ;");
1310 if (_mesa_lookup_parameter_index(parseState->parameters,
1311 -1, (const char *) id) >= 0) {
1312 RETURN_ERROR2(id, "already declared");
1313 }
1314 _mesa_add_named_parameter(parseState->parameters,
1315 (const char *) id, value);
1316 }
1317 else if (Parse_String(parseState, "END")) {
Brian Paul7e807512005-11-05 17:10:45 +00001318 inst->Opcode = OPCODE_END;
Michal Krol2861e732004-03-29 11:09:34 +00001319 inst->StringPos = parseState->curLine - parseState->start;
1320 assert(inst->StringPos >= 0);
1321 parseState->numInst++;
1322 if (Parse_Token(parseState, token)) {
1323 RETURN_ERROR1("Code after END opcode.");
1324 }
1325 break;
1326 }
1327 else {
1328 /* general/arithmetic instruction */
1329
1330 /* get token */
1331 if (!Parse_Token(parseState, token)) {
1332 RETURN_ERROR1("Missing END instruction.");
1333 }
1334
1335 /* try to find matching instuction */
1336 instMatch = MatchInstruction(token);
Brian Paul28b014e2006-04-05 03:05:17 +00001337 if (instMatch.opcode >= MAX_OPCODE) {
Michal Krol2861e732004-03-29 11:09:34 +00001338 /* bad instruction name */
1339 RETURN_ERROR2("Unexpected token: ", token);
1340 }
1341
1342 inst->Opcode = instMatch.opcode;
1343 inst->Precision = instMatch.suffixes & (_R | _H | _X);
Brian Paule31ac052005-11-20 17:52:40 +00001344 inst->SaturateMode = (instMatch.suffixes & (_S))
1345 ? SATURATE_ZERO_ONE : SATURATE_OFF;
Brian Paul7e807512005-11-05 17:10:45 +00001346 inst->CondUpdate = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
Michal Krol2861e732004-03-29 11:09:34 +00001347 inst->StringPos = parseState->curLine - parseState->start;
1348 assert(inst->StringPos >= 0);
1349
1350 /*
1351 * parse the input and output operands
1352 */
1353 if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
1354 if (!Parse_MaskedDstReg(parseState, &inst->DstReg))
1355 RETURN_ERROR;
1356 if (!Parse_String(parseState, ","))
1357 RETURN_ERROR1("Expected ,");
1358 }
1359 else if (instMatch.outputs == OUTPUT_NONE) {
Brian Paul7e807512005-11-05 17:10:45 +00001360 if (instMatch.opcode == OPCODE_KIL_NV) {
Brian Paul2a5afe32004-12-18 16:18:00 +00001361 /* This is a little weird, the cond code info is in
1362 * the dest register.
1363 */
1364 if (!Parse_CondCodeMask(parseState, &inst->DstReg))
1365 RETURN_ERROR;
1366 }
1367 else {
Brian Paul7e807512005-11-05 17:10:45 +00001368 ASSERT(instMatch.opcode == OPCODE_PRINT);
Brian Paul2a5afe32004-12-18 16:18:00 +00001369 }
Michal Krol2861e732004-03-29 11:09:34 +00001370 }
1371
1372 if (instMatch.inputs == INPUT_1V) {
1373 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1374 RETURN_ERROR;
1375 }
1376 else if (instMatch.inputs == INPUT_2V) {
1377 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1378 RETURN_ERROR;
1379 if (!Parse_String(parseState, ","))
1380 RETURN_ERROR1("Expected ,");
1381 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1382 RETURN_ERROR;
1383 }
1384 else if (instMatch.inputs == INPUT_3V) {
1385 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1386 RETURN_ERROR;
1387 if (!Parse_String(parseState, ","))
1388 RETURN_ERROR1("Expected ,");
1389 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1390 RETURN_ERROR;
1391 if (!Parse_String(parseState, ","))
1392 RETURN_ERROR1("Expected ,");
1393 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1394 RETURN_ERROR;
1395 }
1396 else if (instMatch.inputs == INPUT_1S) {
1397 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1398 RETURN_ERROR;
1399 }
1400 else if (instMatch.inputs == INPUT_2S) {
1401 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0]))
1402 RETURN_ERROR;
1403 if (!Parse_String(parseState, ","))
1404 RETURN_ERROR1("Expected ,");
1405 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1]))
1406 RETURN_ERROR;
1407 }
1408 else if (instMatch.inputs == INPUT_CC) {
1409 /* XXX to-do */
1410 }
1411 else if (instMatch.inputs == INPUT_1V_T) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001412 GLubyte unit, idx;
Michal Krol2861e732004-03-29 11:09:34 +00001413 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1414 RETURN_ERROR;
1415 if (!Parse_String(parseState, ","))
1416 RETURN_ERROR1("Expected ,");
Keith Whitwell7c26b612005-04-21 14:46:57 +00001417 if (!Parse_TextureImageId(parseState, &unit, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001418 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001419 inst->TexSrcUnit = unit;
Brian Paul7e807512005-11-05 17:10:45 +00001420 inst->TexSrcTarget = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001421 }
1422 else if (instMatch.inputs == INPUT_3V_T) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001423 GLubyte unit, idx;
Michal Krol2861e732004-03-29 11:09:34 +00001424 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0]))
1425 RETURN_ERROR;
1426 if (!Parse_String(parseState, ","))
1427 RETURN_ERROR1("Expected ,");
1428 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1]))
1429 RETURN_ERROR;
1430 if (!Parse_String(parseState, ","))
1431 RETURN_ERROR1("Expected ,");
1432 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2]))
1433 RETURN_ERROR;
1434 if (!Parse_String(parseState, ","))
1435 RETURN_ERROR1("Expected ,");
Keith Whitwell7c26b612005-04-21 14:46:57 +00001436 if (!Parse_TextureImageId(parseState, &unit, &idx))
Michal Krol2861e732004-03-29 11:09:34 +00001437 RETURN_ERROR;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001438 inst->TexSrcUnit = unit;
Brian Paul7e807512005-11-05 17:10:45 +00001439 inst->TexSrcTarget = idx;
Michal Krol2861e732004-03-29 11:09:34 +00001440 }
Brian Paul2a5afe32004-12-18 16:18:00 +00001441 else if (instMatch.inputs == INPUT_1V_S) {
1442 if (!Parse_PrintInstruction(parseState, inst))
1443 RETURN_ERROR;
1444 }
Michal Krol2861e732004-03-29 11:09:34 +00001445
1446 /* end of statement semicolon */
1447 if (!Parse_String(parseState, ";"))
1448 RETURN_ERROR1("Expected ;");
1449
1450 parseState->numInst++;
1451
1452 if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
1453 RETURN_ERROR1("Program too long");
1454 }
1455 }
1456 return GL_TRUE;
1457}
1458
1459
1460
1461/**
1462 * Parse/compile the 'str' returning the compiled 'program'.
1463 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1464 * indicates the position of the error in 'str'.
1465 */
1466void
1467_mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget,
1468 const GLubyte *str, GLsizei len,
Brian Paul122629f2006-07-20 16:49:57 +00001469 struct gl_fragment_program *program)
Michal Krol2861e732004-03-29 11:09:34 +00001470{
1471 struct parse_state parseState;
Brian Paul7e807512005-11-05 17:10:45 +00001472 struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
1473 struct prog_instruction *newInst;
Michal Krol2861e732004-03-29 11:09:34 +00001474 GLenum target;
1475 GLubyte *programString;
1476
1477 /* Make a null-terminated copy of the program string */
1478 programString = (GLubyte *) MALLOC(len + 1);
1479 if (!programString) {
1480 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1481 return;
1482 }
1483 MEMCPY(programString, str, len);
1484 programString[len] = 0;
1485
1486 /* Get ready to parse */
1487 _mesa_bzero(&parseState, sizeof(struct parse_state));
1488 parseState.ctx = ctx;
1489 parseState.start = programString;
1490 parseState.program = program;
1491 parseState.numInst = 0;
1492 parseState.curLine = programString;
1493 parseState.parameters = _mesa_new_parameter_list();
1494
1495 /* Reset error state */
1496 _mesa_set_program_error(ctx, -1, NULL);
1497
1498 /* check the program header */
1499 if (_mesa_strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
1500 target = GL_FRAGMENT_PROGRAM_NV;
1501 parseState.pos = programString + 7;
1502 }
1503 else if (_mesa_strncmp((const char *) programString, "!!FCP1.0", 8) == 0) {
1504 /* fragment / register combiner program - not supported */
1505 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1506 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1507 return;
1508 }
1509 else {
1510 /* invalid header */
1511 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1512 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1513 return;
1514 }
1515
1516 /* make sure target and header match */
1517 if (target != dstTarget) {
1518 _mesa_error(ctx, GL_INVALID_OPERATION,
1519 "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1520 target, dstTarget);
1521 return;
1522 }
1523
1524 if (Parse_InstructionSequence(&parseState, instBuffer)) {
1525 GLuint u;
1526 /* successful parse! */
1527
1528 if (parseState.outputsWritten == 0) {
1529 /* must write at least one output! */
1530 _mesa_error(ctx, GL_INVALID_OPERATION,
1531 "Invalid fragment program - no outputs written.");
1532 return;
1533 }
1534
1535 /* copy the compiled instructions */
1536 assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
Brian Paul383c39e2006-08-25 15:14:25 +00001537 newInst = _mesa_alloc_instructions(parseState.numInst);
Michal Krol2861e732004-03-29 11:09:34 +00001538 if (!newInst) {
1539 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1540 return; /* out of memory */
1541 }
Brian Paul383c39e2006-08-25 15:14:25 +00001542 _mesa_memcpy(newInst, instBuffer,
1543 parseState.numInst * sizeof(struct prog_instruction));
Michal Krol2861e732004-03-29 11:09:34 +00001544
1545 /* install the program */
1546 program->Base.Target = target;
1547 if (program->Base.String) {
1548 FREE(program->Base.String);
1549 }
1550 program->Base.String = programString;
1551 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB;
Brian Paulde997602005-11-12 17:53:14 +00001552 if (program->Base.Instructions) {
1553 _mesa_free(program->Base.Instructions);
Michal Krol2861e732004-03-29 11:09:34 +00001554 }
Brian Paulde997602005-11-12 17:53:14 +00001555 program->Base.Instructions = newInst;
Brian Paulee40c4fb32006-02-15 15:59:37 +00001556 program->Base.NumInstructions = parseState.numInst;
Brian Paulde997602005-11-12 17:53:14 +00001557 program->Base.InputsRead = parseState.inputsRead;
1558 program->Base.OutputsWritten = parseState.outputsWritten;
Michal Krol2861e732004-03-29 11:09:34 +00001559 for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++)
1560 program->TexturesUsed[u] = parseState.texturesUsed[u];
1561
1562 /* save program parameters */
Brian Paulde997602005-11-12 17:53:14 +00001563 program->Base.Parameters = parseState.parameters;
Michal Krol2861e732004-03-29 11:09:34 +00001564
1565 /* allocate registers for declared program parameters */
1566#if 00
1567 _mesa_assign_program_registers(&(program->SymbolTable));
1568#endif
1569
Brian Paulac33dd12004-06-29 00:00:29 +00001570#ifdef DEBUG_foo
Michal Krol2861e732004-03-29 11:09:34 +00001571 _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id);
1572 _mesa_print_nv_fragment_program(program);
1573 _mesa_printf("----------------------------------\n");
1574#endif
1575 }
1576 else {
1577 /* Error! */
1578 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1579 /* NOTE: _mesa_set_program_error would have been called already */
1580 }
1581}
1582
1583
1584static void
Brian Paul122629f2006-07-20 16:49:57 +00001585PrintSrcReg(const struct gl_fragment_program *program,
Brian Paul7e807512005-11-05 17:10:45 +00001586 const struct prog_src_register *src)
Michal Krol2861e732004-03-29 11:09:34 +00001587{
1588 static const char comps[5] = "xyzw";
1589
1590 if (src->NegateAbs) {
1591 _mesa_printf("-");
1592 }
1593 if (src->Abs) {
1594 _mesa_printf("|");
1595 }
1596 if (src->NegateBase) {
1597 _mesa_printf("-");
1598 }
1599 if (src->File == PROGRAM_NAMED_PARAM) {
Brian Paulde997602005-11-12 17:53:14 +00001600 if (program->Base.Parameters->Parameters[src->Index].Type
1601 == PROGRAM_CONSTANT) {
1602 const GLfloat *v;
1603 v = program->Base.Parameters->ParameterValues[src->Index];
1604 _mesa_printf("{%g, %g, %g, %g}", v[0], v[1], v[2], v[3]);
Michal Krol2861e732004-03-29 11:09:34 +00001605 }
1606 else {
Brian Paulbed83632005-11-12 17:56:18 +00001607 ASSERT(program->Base.Parameters->Parameters[src->Index].Type
Brian Paul613e1ad2005-11-05 02:15:21 +00001608 == PROGRAM_NAMED_PARAM);
Brian Paulde997602005-11-12 17:53:14 +00001609 _mesa_printf("%s", program->Base.Parameters->Parameters[src->Index].Name);
Michal Krol2861e732004-03-29 11:09:34 +00001610 }
1611 }
1612 else if (src->File == PROGRAM_OUTPUT) {
1613 _mesa_printf("o[%s]", OutputRegisters[src->Index]);
1614 }
1615 else if (src->File == PROGRAM_INPUT) {
1616 _mesa_printf("f[%s]", InputRegisters[src->Index]);
1617 }
1618 else if (src->File == PROGRAM_LOCAL_PARAM) {
1619 _mesa_printf("p[%d]", src->Index);
1620 }
1621 else if (src->File == PROGRAM_TEMPORARY) {
1622 if (src->Index >= 32)
1623 _mesa_printf("H%d", src->Index);
1624 else
1625 _mesa_printf("R%d", src->Index);
1626 }
1627 else if (src->File == PROGRAM_WRITE_ONLY) {
1628 _mesa_printf("%cC", "HR"[src->Index]);
1629 }
1630 else {
1631 _mesa_problem(NULL, "Invalid fragment register %d", src->Index);
1632 return;
1633 }
Keith Whitwell7c26b612005-04-21 14:46:57 +00001634 if (GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 1) &&
1635 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 2) &&
1636 GET_SWZ(src->Swizzle, 0) == GET_SWZ(src->Swizzle, 3)) {
1637 _mesa_printf(".%c", comps[GET_SWZ(src->Swizzle, 0)]);
Michal Krol2861e732004-03-29 11:09:34 +00001638 }
Keith Whitwell7c26b612005-04-21 14:46:57 +00001639 else if (src->Swizzle != SWIZZLE_NOOP) {
Michal Krol2861e732004-03-29 11:09:34 +00001640 _mesa_printf(".%c%c%c%c",
Keith Whitwell7c26b612005-04-21 14:46:57 +00001641 comps[GET_SWZ(src->Swizzle, 0)],
1642 comps[GET_SWZ(src->Swizzle, 1)],
1643 comps[GET_SWZ(src->Swizzle, 2)],
1644 comps[GET_SWZ(src->Swizzle, 3)]);
Michal Krol2861e732004-03-29 11:09:34 +00001645 }
1646 if (src->Abs) {
1647 _mesa_printf("|");
1648 }
1649}
1650
1651static void
Brian Paul7e807512005-11-05 17:10:45 +00001652PrintTextureSrc(const struct prog_instruction *inst)
Michal Krol2861e732004-03-29 11:09:34 +00001653{
1654 _mesa_printf("TEX%d, ", inst->TexSrcUnit);
Brian Paul7e807512005-11-05 17:10:45 +00001655 switch (inst->TexSrcTarget) {
Keith Whitwell7c26b612005-04-21 14:46:57 +00001656 case TEXTURE_1D_INDEX:
Michal Krol2861e732004-03-29 11:09:34 +00001657 _mesa_printf("1D");
1658 break;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001659 case TEXTURE_2D_INDEX:
Michal Krol2861e732004-03-29 11:09:34 +00001660 _mesa_printf("2D");
1661 break;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001662 case TEXTURE_3D_INDEX:
Michal Krol2861e732004-03-29 11:09:34 +00001663 _mesa_printf("3D");
1664 break;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001665 case TEXTURE_RECT_INDEX:
Michal Krol2861e732004-03-29 11:09:34 +00001666 _mesa_printf("RECT");
1667 break;
Keith Whitwell7c26b612005-04-21 14:46:57 +00001668 case TEXTURE_CUBE_INDEX:
Michal Krol2861e732004-03-29 11:09:34 +00001669 _mesa_printf("CUBE");
1670 break;
1671 default:
1672 _mesa_problem(NULL, "Invalid textue target in PrintTextureSrc");
1673 }
1674}
1675
1676static void
Brian Paul7e807512005-11-05 17:10:45 +00001677PrintCondCode(const struct prog_dst_register *dst)
Michal Krol2861e732004-03-29 11:09:34 +00001678{
1679 static const char *comps = "xyzw";
1680 static const char *ccString[] = {
1681 "??", "GT", "EQ", "LT", "UN", "GE", "LE", "NE", "TR", "FL", "??"
1682 };
1683
1684 _mesa_printf("%s", ccString[dst->CondMask]);
Keith Whitwell7c26b612005-04-21 14:46:57 +00001685 if (GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 1) &&
1686 GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 2) &&
1687 GET_SWZ(dst->CondSwizzle, 0) == GET_SWZ(dst->CondSwizzle, 3)) {
1688 _mesa_printf(".%c", comps[GET_SWZ(dst->CondSwizzle, 0)]);
Michal Krol2861e732004-03-29 11:09:34 +00001689 }
Keith Whitwell7c26b612005-04-21 14:46:57 +00001690 else if (dst->CondSwizzle != SWIZZLE_NOOP) {
Michal Krol2861e732004-03-29 11:09:34 +00001691 _mesa_printf(".%c%c%c%c",
Keith Whitwell7c26b612005-04-21 14:46:57 +00001692 comps[GET_SWZ(dst->CondSwizzle, 0)],
1693 comps[GET_SWZ(dst->CondSwizzle, 1)],
1694 comps[GET_SWZ(dst->CondSwizzle, 2)],
1695 comps[GET_SWZ(dst->CondSwizzle, 3)]);
Michal Krol2861e732004-03-29 11:09:34 +00001696 }
1697}
1698
1699
1700static void
Brian Paul7e807512005-11-05 17:10:45 +00001701PrintDstReg(const struct prog_dst_register *dst)
Michal Krol2861e732004-03-29 11:09:34 +00001702{
Michal Krol2861e732004-03-29 11:09:34 +00001703 if (dst->File == PROGRAM_OUTPUT) {
1704 _mesa_printf("o[%s]", OutputRegisters[dst->Index]);
1705 }
1706 else if (dst->File == PROGRAM_TEMPORARY) {
1707 if (dst->Index >= 32)
1708 _mesa_printf("H%d", dst->Index);
1709 else
1710 _mesa_printf("R%d", dst->Index);
1711 }
1712 else if (dst->File == PROGRAM_LOCAL_PARAM) {
1713 _mesa_printf("p[%d]", dst->Index);
1714 }
1715 else if (dst->File == PROGRAM_WRITE_ONLY) {
1716 _mesa_printf("%cC", "HR"[dst->Index]);
1717 }
1718 else {
1719 _mesa_printf("???");
1720 }
1721
Brian Paulccfe3d42005-11-03 02:35:15 +00001722 if (dst->WriteMask != 0 && dst->WriteMask != WRITEMASK_XYZW) {
Michal Krol2861e732004-03-29 11:09:34 +00001723 _mesa_printf(".");
Brian Paulccfe3d42005-11-03 02:35:15 +00001724 if (dst->WriteMask & WRITEMASK_X)
Michal Krol2861e732004-03-29 11:09:34 +00001725 _mesa_printf("x");
Brian Paulccfe3d42005-11-03 02:35:15 +00001726 if (dst->WriteMask & WRITEMASK_Y)
Michal Krol2861e732004-03-29 11:09:34 +00001727 _mesa_printf("y");
Brian Paulccfe3d42005-11-03 02:35:15 +00001728 if (dst->WriteMask & WRITEMASK_Z)
Michal Krol2861e732004-03-29 11:09:34 +00001729 _mesa_printf("z");
Brian Paulccfe3d42005-11-03 02:35:15 +00001730 if (dst->WriteMask & WRITEMASK_W)
Michal Krol2861e732004-03-29 11:09:34 +00001731 _mesa_printf("w");
1732 }
1733
1734 if (dst->CondMask != COND_TR ||
Keith Whitwell7c26b612005-04-21 14:46:57 +00001735 dst->CondSwizzle != SWIZZLE_NOOP) {
Michal Krol2861e732004-03-29 11:09:34 +00001736 _mesa_printf(" (");
1737 PrintCondCode(dst);
1738 _mesa_printf(")");
1739 }
1740}
1741
1742
1743/**
1744 * Print (unparse) the given vertex program. Just for debugging.
1745 */
1746void
Brian Paul122629f2006-07-20 16:49:57 +00001747_mesa_print_nv_fragment_program(const struct gl_fragment_program *program)
Michal Krol2861e732004-03-29 11:09:34 +00001748{
Brian Paul7e807512005-11-05 17:10:45 +00001749 const struct prog_instruction *inst;
Michal Krol2861e732004-03-29 11:09:34 +00001750
Brian Paulde997602005-11-12 17:53:14 +00001751 for (inst = program->Base.Instructions; inst->Opcode != OPCODE_END; inst++) {
Michal Krol2861e732004-03-29 11:09:34 +00001752 int i;
1753 for (i = 0; Instructions[i].name; i++) {
1754 if (inst->Opcode == Instructions[i].opcode) {
1755 /* print instruction name */
1756 _mesa_printf("%s", Instructions[i].name);
1757 if (inst->Precision == FLOAT16)
1758 _mesa_printf("H");
1759 else if (inst->Precision == FIXED12)
1760 _mesa_printf("X");
Brian Paul7e807512005-11-05 17:10:45 +00001761 if (inst->CondUpdate)
Michal Krol2861e732004-03-29 11:09:34 +00001762 _mesa_printf("C");
Brian Paule31ac052005-11-20 17:52:40 +00001763 if (inst->SaturateMode == SATURATE_ZERO_ONE)
Michal Krol2861e732004-03-29 11:09:34 +00001764 _mesa_printf("_SAT");
1765 _mesa_printf(" ");
1766
1767 if (Instructions[i].inputs == INPUT_CC) {
1768 PrintCondCode(&inst->DstReg);
1769 }
1770 else if (Instructions[i].outputs == OUTPUT_V ||
1771 Instructions[i].outputs == OUTPUT_S) {
1772 /* print dest register */
1773 PrintDstReg(&inst->DstReg);
1774 _mesa_printf(", ");
1775 }
1776
1777 /* print source register(s) */
1778 if (Instructions[i].inputs == INPUT_1V ||
1779 Instructions[i].inputs == INPUT_1S) {
1780 PrintSrcReg(program, &inst->SrcReg[0]);
1781 }
1782 else if (Instructions[i].inputs == INPUT_2V ||
1783 Instructions[i].inputs == INPUT_2S) {
1784 PrintSrcReg(program, &inst->SrcReg[0]);
1785 _mesa_printf(", ");
1786 PrintSrcReg(program, &inst->SrcReg[1]);
1787 }
1788 else if (Instructions[i].inputs == INPUT_3V) {
1789 PrintSrcReg(program, &inst->SrcReg[0]);
1790 _mesa_printf(", ");
1791 PrintSrcReg(program, &inst->SrcReg[1]);
1792 _mesa_printf(", ");
1793 PrintSrcReg(program, &inst->SrcReg[2]);
1794 }
1795 else if (Instructions[i].inputs == INPUT_1V_T) {
1796 PrintSrcReg(program, &inst->SrcReg[0]);
1797 _mesa_printf(", ");
1798 PrintTextureSrc(inst);
1799 }
1800 else if (Instructions[i].inputs == INPUT_3V_T) {
1801 PrintSrcReg(program, &inst->SrcReg[0]);
1802 _mesa_printf(", ");
1803 PrintSrcReg(program, &inst->SrcReg[1]);
1804 _mesa_printf(", ");
1805 PrintSrcReg(program, &inst->SrcReg[2]);
1806 _mesa_printf(", ");
1807 PrintTextureSrc(inst);
1808 }
1809 _mesa_printf(";\n");
1810 break;
1811 }
1812 }
1813 if (!Instructions[i].name) {
1814 _mesa_printf("Invalid opcode %d\n", inst->Opcode);
1815 }
1816 }
1817 _mesa_printf("END\n");
1818}
1819
1820
1821const char *
1822_mesa_nv_fragment_input_register_name(GLuint i)
1823{
1824 ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS);
1825 return InputRegisters[i];
1826}
1827
1828
1829const char *
1830_mesa_nv_fragment_output_register_name(GLuint i)
1831{
1832 ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_OUTPUTS);
1833 return OutputRegisters[i];
1834}