new X86 CPU detection code (Petr Sebor)
[mesa.git] / src / mesa / main / nvfragparse.c
1 /* $Id: nvfragparse.c,v 1.2 2003/01/19 15:27:37 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 5.1
6 *
7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28 /**
29 * \file nvfragparse.c
30 * \brief NVIDIA fragment program parser.
31 * \author Brian Paul
32 */
33
34 #include "glheader.h"
35 #include "context.h"
36 #include "hash.h"
37 #include "imports.h"
38 #include "macros.h"
39 #include "mmath.h"
40 #include "mtypes.h"
41 #include "nvfragprog.h"
42 #include "nvfragparse.h"
43 #include "nvprogram.h"
44
45
46 #define FRAG_ATTRIB_WPOS 0
47 #define FRAG_ATTRIB_COL0 1
48 #define FRAG_ATTRIB_COL1 2
49 #define FRAG_ATTRIB_FOGC 3
50 #define FRAG_ATTRIB_TEX0 4
51 #define FRAG_ATTRIB_TEX1 5
52 #define FRAG_ATTRIB_TEX2 6
53 #define FRAG_ATTRIB_TEX3 7
54 #define FRAG_ATTRIB_TEX4 8
55 #define FRAG_ATTRIB_TEX5 9
56 #define FRAG_ATTRIB_TEX6 10
57 #define FRAG_ATTRIB_TEX7 11
58
59
60 #define INPUT_1V 1
61 #define INPUT_2V 2
62 #define INPUT_3V 3
63 #define INPUT_1S 4
64 #define INPUT_2S 5
65 #define INPUT_CC 6
66 #define INPUT_1V_T 7 /* one source vector, plus textureId */
67 #define INPUT_3V_T 8 /* one source vector, plus textureId */
68 #define INPUT_NONE 9
69 #define OUTPUT_V 20
70 #define OUTPUT_S 21
71 #define OUTPUT_NONE 22
72
73 /* Optional suffixes */
74 #define _R 0x01 /* real */
75 #define _H 0x02 /* half */
76 #define _X 0x04 /* fixed */
77 #define _C 0x08 /* set cond codes */
78 #define _S 0x10 /* saturate */
79
80 #define SINGLE _R
81 #define HALF _H
82 #define FIXED _X
83
84 struct instruction_pattern {
85 const char *name;
86 enum fp_opcode opcode;
87 GLuint inputs;
88 GLuint outputs;
89 GLuint suffixes;
90 };
91
92 static const struct instruction_pattern Instructions[] = {
93 { "ADD", FP_OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
94 { "COS", FP_OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
95 { "DDX", FP_OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
96 { "DDY", FP_OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
97 { "DP3", FP_OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
98 { "DP4", FP_OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S },
99 { "DST", FP_OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H | _C | _S },
100 { "EX2", FP_OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
101 { "FLR", FP_OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
102 { "FRC", FP_OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
103 { "KIL", FP_OPCODE_KIL, INPUT_CC, OUTPUT_NONE, 0 },
104 { "LG2", FP_OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
105 { "LIT", FP_OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H | _C | _S },
106 { "LRP", FP_OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
107 { "MAD", FP_OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S },
108 { "MAX", FP_OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
109 { "MIN", FP_OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
110 { "MOV", FP_OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S },
111 { "MUL", FP_OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
112 { "PK2H", FP_OPCODE_PK2H, INPUT_1V, OUTPUT_S, 0 },
113 { "PK2US", FP_OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0 },
114 { "PK4B", FP_OPCODE_PK4B, INPUT_1V, OUTPUT_S, 0 },
115 { "PK2UB", FP_OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0 },
116 { "POW", FP_OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H | _C | _S },
117 { "RCP", FP_OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
118 { "RFL", FP_OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H | _C | _S },
119 { "RSQ", FP_OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
120 { "SEQ", FP_OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
121 { "SFL", FP_OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
122 { "SGE", FP_OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
123 { "SGT", FP_OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
124 { "SIN", FP_OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H | _C | _S },
125 { "SLE", FP_OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
126 { "SLT", FP_OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
127 { "SNE", FP_OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
128 { "STR", FP_OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
129 { "SUB", FP_OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S },
130 { "TEX", FP_OPCODE_SUB, INPUT_1V_T, OUTPUT_V, _C | _S },
131 { "TXD", FP_OPCODE_SUB, INPUT_3V_T, OUTPUT_V, _C | _S },
132 { "TXP", FP_OPCODE_SUB, INPUT_1V_T, OUTPUT_V, _C | _S },
133 { "UP2H", FP_OPCODE_UP2H, INPUT_1S, OUTPUT_V, _C | _S },
134 { "UP2US", FP_OPCODE_UP2US, INPUT_1S, OUTPUT_V, _C | _S },
135 { "UP4B", FP_OPCODE_UP4B, INPUT_1S, OUTPUT_V, _C | _S },
136 { "UP4UB", FP_OPCODE_UP4UB, INPUT_1S, OUTPUT_V, _C | _S },
137 { "X2D", FP_OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H | _C | _S },
138 { NULL, -1, 0, 0, 0 }
139 };
140
141
142 /**********************************************************************/
143
144
145 struct parse_state {
146 const GLubyte *start; /* start of program */
147 const GLubyte *end; /* one char past end of the program */
148 const GLubyte *s; /* current position */
149 GLboolean IsStateProgram;
150 GLboolean IsVersion1_1;
151 };
152
153
154
155 /*
156 * Search a list of instruction structures for a match.
157 */
158 static struct instruction_pattern
159 MatchInstruction(const char *token)
160 {
161 const struct instruction_pattern *inst;
162 struct instruction_pattern result;
163
164 for (inst = Instructions; inst->name; inst++) {
165 if (_mesa_strncmp(token, inst->name, 3) == 0) {
166 /* matched! */
167 int i = 3;
168 result = *inst;
169 result.suffixes = 0;
170 /* look at suffix */
171 if (token[i] == 'R') {
172 result.suffixes |= _R;
173 i++;
174 }
175 else if (token[i] == 'H') {
176 result.suffixes |= _H;
177 i++;
178 }
179 else if (token[i] == 'X') {
180 result.suffixes |= _X;
181 i++;
182 }
183 if (token[i] == 'C') {
184 result.suffixes |= _C;
185 i++;
186 }
187 if (token[i] == '_' && token[i+1] == 'S' &&
188 token[i+2] == 'A' && token[i+3] == 'T') {
189 result.suffixes |= _S;
190 }
191 return result;
192 }
193 }
194 result.opcode = (enum fp_opcode) -1;
195 return result;
196 }
197
198
199
200
201 /**********************************************************************/
202
203
204 static GLboolean IsLetter(char b)
205 {
206 return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b == '_');
207 }
208
209
210 static GLboolean IsDigit(char b)
211 {
212 return b >= '0' && b <= '9';
213 }
214
215
216 static GLboolean IsWhitespace(char b)
217 {
218 return b == ' ' || b == '\t' || b == '\n' || b == '\r';
219 }
220
221
222 /**
223 * Starting at 'str' find the next token. A token can be an integer,
224 * an identifier or punctuation symbol.
225 * \return <= 0 we found an error, else, return number of characters parsed.
226 */
227 static GLint
228 GetToken(const char *str, char *token)
229 {
230 GLint i = 0, j = 0;
231
232 token[0] = 0;
233
234 /* skip whitespace and comments */
235 while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) {
236 if (str[i] == '#') {
237 /* skip comment */
238 while (str[i] && (str[i] != '\n' && str[i] != '\r')) {
239 i++;
240 }
241 }
242 else {
243 /* skip whitespace */
244 i++;
245 }
246 }
247
248 if (str[i] == 0)
249 return -i;
250
251 /* try matching an integer */
252 while (str[i] && IsDigit(str[i])) {
253 token[j++] = str[i++];
254 }
255 if (j > 0 || !str[i]) {
256 token[j] = 0;
257 return i;
258 }
259
260 /* try matching an identifier */
261 if (IsLetter(str[i])) {
262 while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) {
263 token[j++] = str[i++];
264 }
265 token[j] = 0;
266 return i;
267 }
268
269 /* punctuation */
270 if (str[i]) {
271 token[0] = str[i++];
272 token[1] = 0;
273 return i;
274 }
275
276 /* end of input */
277 token[0] = 0;
278 return i;
279 }
280
281
282 /**
283 * Get next token from input stream and increment stream pointer past token.
284 */
285 static GLboolean
286 Parse_Token(const char **s, char *token)
287 {
288 GLint i;
289 i = GetToken(*s, token);
290 if (i <= 0) {
291 *s += (-i);
292 return GL_FALSE;
293 }
294 *s += i;
295 return GL_TRUE;
296 }
297
298
299 /**
300 * Get next token from input stream but don't increment stream pointer.
301 */
302 static GLboolean
303 Peek_Token(const char **s, char *token)
304 {
305 GLint i, len;
306 i = GetToken(*s, token);
307 if (i <= 0) {
308 *s += (-i);
309 return GL_FALSE;
310 }
311 len = _mesa_strlen(token);
312 *s += (i - len);
313 return GL_TRUE;
314 }
315
316
317 /**
318 * String equality test
319 */
320 static GLboolean
321 StrEq(const char *a, const char *b)
322 {
323 GLint i;
324 for (i = 0; a[i] && b[i] && a[i] == (char) b[i]; i++)
325 ;
326 if (a[i] == 0 && b[i] == 0)
327 return GL_TRUE;
328 else
329 return GL_FALSE;
330 }
331
332
333
334 /**********************************************************************/
335
336 static const char *InputRegisters[] = {
337 "WPOS", "COL0", "COL1", "FOGC",
338 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
339 };
340
341 static const char *OutputRegisters[] = {
342 "COLR", "COLH", "TEX0", "TEX1", "TEX2", "TEX3", "DEPR", NULL
343 };
344
345
346 #ifdef DEBUG
347
348 #define PARSE_ERROR \
349 do { \
350 _mesa_printf("fpparse.c error at %d: parse error\n", __LINE__); \
351 return GL_FALSE; \
352 } while(0)
353
354 #define PARSE_ERROR1(msg) \
355 do { \
356 _mesa_printf("fpparse.c error at %d: %s\n", __LINE__, msg); \
357 return GL_FALSE; \
358 } while(0)
359
360 #define PARSE_ERROR2(msg1, msg2) \
361 do { \
362 _mesa_printf("fpparse.c error at %d: %s %s\n", __LINE__, msg1, msg2);\
363 return GL_FALSE; \
364 } while(0)
365
366 #else
367
368 #define PARSE_ERROR return GL_FALSE
369 #define PARSE_ERROR1(msg1) return GL_FALSE
370 #define PARSE_ERROR2(msg1, msg2) return GL_FALSE
371
372 #endif
373
374
375 static GLint
376 TempRegisterNumber(GLuint r)
377 {
378 if (r >= FP_TEMP_REG_START && r <= FP_TEMP_REG_END)
379 return r - FP_TEMP_REG_START;
380 else
381 return -1;
382 }
383
384 static GLint
385 HalfTempRegisterNumber(GLuint r)
386 {
387 if (r >= FP_TEMP_REG_START + 32 && r <= FP_TEMP_REG_END)
388 return r - FP_TEMP_REG_START - 32;
389 else
390 return -1;
391 }
392
393 static GLint
394 InputRegisterNumber(GLuint r)
395 {
396 if (r >= FP_INPUT_REG_START && r <= FP_INPUT_REG_END)
397 return r - FP_INPUT_REG_START;
398 else
399 return -1;
400 }
401
402 static GLint
403 OutputRegisterNumber(GLuint r)
404 {
405 if (r >= FP_OUTPUT_REG_START && r <= FP_OUTPUT_REG_END)
406 return r - FP_OUTPUT_REG_START;
407 else
408 return -1;
409 }
410
411 static GLint
412 ProgramRegisterNumber(GLuint r)
413 {
414 if (r >= FP_PROG_REG_START && r <= FP_PROG_REG_END)
415 return r - FP_PROG_REG_START;
416 else
417 return -1;
418 }
419
420 static GLint
421 DummyRegisterNumber(GLuint r)
422 {
423 if (r >= FP_DUMMY_REG_START && r <= FP_DUMMY_REG_END)
424 return r - FP_DUMMY_REG_START;
425 else
426 return -1;
427 }
428
429
430
431 /**********************************************************************/
432
433
434 /**
435 * Try to match 'pattern' as the next token after any whitespace/comments.
436 */
437 static GLboolean
438 Parse_String(const char **s, const char *pattern)
439 {
440 GLint i;
441
442 /* skip whitespace and comments */
443 while (IsWhitespace(**s) || **s == '#') {
444 if (**s == '#') {
445 while (**s && (**s != '\n' && **s != '\r')) {
446 *s += 1;
447 }
448 }
449 else {
450 /* skip whitespace */
451 *s += 1;
452 }
453 }
454
455 /* Try to match the pattern */
456 for (i = 0; pattern[i]; i++) {
457 if (**s != pattern[i])
458 PARSE_ERROR2("failed to match", pattern); /* failure */
459 *s += 1;
460 }
461
462 return GL_TRUE; /* success */
463 }
464
465
466 static GLboolean
467 Parse_Identifier(const char **s, char *ident)
468 {
469 if (!Parse_Token(s, ident))
470 PARSE_ERROR;
471 if (IsLetter(ident[0]))
472 return GL_TRUE;
473 else
474 PARSE_ERROR1("Expected an identfier");
475 }
476
477
478 /**
479 * Parse a floating point constant.
480 * [+/-]N[.N[eN]]
481 */
482 static GLboolean
483 Parse_ScalarConstant(const char **s, GLfloat *number)
484 {
485 char *end;
486
487 *number = _mesa_strtof(*s, &end);
488
489 if (end && end > *s) {
490 /* got a number */
491 *s = end;
492 return GL_TRUE;
493 }
494 else {
495 /* should be an identifier */
496 char ident[100];
497 if (!Parse_Identifier(s, ident))
498 PARSE_ERROR1("Expected an identifier");
499 /* XXX Look up the value in the symbol table */
500 *number = -999;
501 return GL_TRUE;
502 }
503 }
504
505
506
507 /**
508 * Parse a vector constant, one of:
509 * { float }
510 * { float, float }
511 * { float, float, float }
512 * { float, float, float, float }
513 */
514 static GLboolean
515 Parse_VectorConstant(const char **s, GLfloat *vec)
516 {
517 char token[100];
518
519 if (!Parse_String(s, "{"))
520 return GL_FALSE;
521
522 if (!Parse_ScalarConstant(s, vec+0)) /* X */
523 return GL_FALSE;
524
525 if (!Parse_Token(s, token)) /* , or } */
526 return GL_FALSE;
527
528 if (token[0] == '}') {
529 vec[1] = vec[2] = vec[3] = vec[0];
530 return GL_TRUE;
531 }
532
533 if (token[0] != ',')
534 PARSE_ERROR1("Expected comma in vector constant");
535
536 if (!Parse_ScalarConstant(s, vec+1)) /* Y */
537 return GL_FALSE;
538
539 if (!Parse_Token(s, token)) /* , or } */
540 return GL_FALSE;
541
542 if (token[0] == '}') {
543 vec[2] = vec[3] = vec[1];
544 return GL_TRUE;
545 }
546
547 if (token[0] != ',')
548 PARSE_ERROR1("Expected comma in vector constant");
549
550 if (!Parse_ScalarConstant(s, vec+2)) /* Z */
551 return GL_FALSE;
552
553 if (!Parse_Token(s, token)) /* , or } */
554 return GL_FALSE;
555
556 if (token[0] == '}') {
557 vec[3] = vec[2];
558 return GL_TRUE;
559 }
560
561 if (token[0] != ',')
562 PARSE_ERROR1("Expected comma in vector constant");
563
564 if (!Parse_ScalarConstant(s, vec+3)) /* W */
565 return GL_FALSE;
566
567 if (!Parse_String(s, "}"))
568 PARSE_ERROR1("Expected closing brace in vector constant");
569
570 return GL_TRUE;
571 }
572
573
574 static GLboolean
575 Parse_VectorOrScalarConstant(const char **s, GLfloat *vec)
576 {
577 char token[100];
578 if (!Peek_Token(s, token))
579 PARSE_ERROR;
580 if (token[0] == '{') {
581 return Parse_VectorConstant(s, vec);
582 }
583 else {
584 GLboolean b = Parse_ScalarConstant(s, vec);
585 if (b) {
586 vec[1] = vec[2] = vec[3] = vec[0];
587 }
588 return b;
589 }
590 }
591
592
593 /**
594 * Parse a texture image source:
595 * [TEX0 | TEX1 | .. | TEX15]
596 * [TEX0 | TEX1 | .. | TEX15] . [1D | 2D | 3D | CUBE | RECT]
597 */
598 static GLboolean
599 Parse_TextureImageId(const char **s, GLuint *unit, GLenum *target)
600 {
601 return GL_TRUE;
602 }
603
604
605 /**
606 * Parse a swizzle suffix like .x or .z or .wxyz or .xxyy etc and return
607 * the swizzle indexes.
608 */
609 static GLboolean
610 Parse_SwizzleSuffix(const char *token, GLuint swizzle[4])
611 {
612 if (token[1] == 0) {
613 /* single letter swizzle (scalar) */
614 if (token[0] == 'x')
615 ASSIGN_4V(swizzle, 0, 0, 0, 0);
616 else if (token[0] == 'y')
617 ASSIGN_4V(swizzle, 1, 1, 1, 1);
618 else if (token[0] == 'z')
619 ASSIGN_4V(swizzle, 2, 2, 2, 2);
620 else if (token[0] == 'w')
621 ASSIGN_4V(swizzle, 3, 3, 3, 3);
622 else
623 return GL_FALSE;
624 }
625 else {
626 /* 4-component swizzle (vector) */
627 GLint k;
628 for (k = 0; token[k] && k < 4; k++) {
629 if (token[k] == 'x')
630 swizzle[k] = 0;
631 else if (token[k] == 'y')
632 swizzle[k] = 1;
633 else if (token[k] == 'z')
634 swizzle[k] = 2;
635 else if (token[k] == 'w')
636 swizzle[k] = 3;
637 else
638 return GL_FALSE;
639 }
640 if (k != 4)
641 return GL_FALSE;
642 }
643 return GL_TRUE;
644 }
645
646
647 static GLboolean
648 Parse_CondCodeMask(const char **s, struct fp_dst_register *dstReg)
649 {
650 char token[100];
651
652 if (!Parse_Token(s, token))
653 PARSE_ERROR;
654
655 if (StrEq(token, "EQ"))
656 dstReg->CondMask = COND_EQ;
657 else if (StrEq(token, "GE"))
658 dstReg->CondMask = COND_GE;
659 else if (StrEq(token, "GT"))
660 dstReg->CondMask = COND_GT;
661 else if (StrEq(token, "LE"))
662 dstReg->CondMask = COND_LE;
663 else if (StrEq(token, "LT"))
664 dstReg->CondMask = COND_LT;
665 else if (StrEq(token, "NE"))
666 dstReg->CondMask = COND_NE;
667 else if (StrEq(token, "TR"))
668 dstReg->CondMask = COND_TR;
669 else if (StrEq(token, "FL"))
670 dstReg->CondMask = COND_FL;
671 else
672 PARSE_ERROR1("Invalid condition code mask");
673
674 /* look for optional .xyzw swizzle */
675 if (!Peek_Token(s, token))
676 PARSE_ERROR;
677
678 if (token[0] == '.') {
679 Parse_String(s, "."); /* consume '.' */
680 if (!Parse_Token(s, token)) /* get xyzw suffix */
681 PARSE_ERROR;
682
683 if (!Parse_SwizzleSuffix(token, dstReg->CondSwizzle))
684 PARSE_ERROR1("Bad swizzle suffix");
685 }
686
687 return GL_TRUE;
688 }
689
690
691 /**
692 * Parse a temporary register: Rnn or Hnn
693 */
694 static GLboolean
695 Parse_TempReg(const char **s, GLint *tempRegNum)
696 {
697 char token[100];
698
699 /* Should be 'R##' or 'H##' */
700 if (!Parse_Token(s, token))
701 PARSE_ERROR;
702 if (token[0] != 'R' && token[0] != 'H')
703 PARSE_ERROR1("Expected R## or H##");
704
705 if (IsDigit(token[1])) {
706 GLint reg = _mesa_atoi((token + 1));
707 if (token[0] == 'H')
708 reg += 32;
709 if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS)
710 PARSE_ERROR1("Bad temporary register name");
711 *tempRegNum = FP_TEMP_REG_START + reg;
712 }
713 else {
714 PARSE_ERROR1("Bad temporary register name");
715 }
716
717 return GL_TRUE;
718 }
719
720
721 static GLboolean
722 Parse_DummyReg(const char **s, GLint *regNum)
723 {
724 char token[100];
725
726 /* Should be 'RC' or 'HC' */
727 if (!Parse_Token(s, token))
728 PARSE_ERROR;
729
730 if (_mesa_strcmp(token, "RC")) {
731 *regNum = FP_DUMMY_REG_START;
732 }
733 else if (_mesa_strcmp(token, "HC")) {
734 *regNum = FP_DUMMY_REG_START + 1;
735 }
736 else {
737 PARSE_ERROR1("Bad write-only register name");
738 }
739
740 return GL_TRUE;
741 }
742
743
744 /**
745 * Parse a program local parameter register "p[##]"
746 */
747 static GLboolean
748 Parse_ProgramParamReg(const char **s, GLint *regNum)
749 {
750 char token[100];
751
752 if (!Parse_String(s, "p"))
753 PARSE_ERROR;
754
755 if (!Parse_String(s, "["))
756 PARSE_ERROR;
757
758 if (!Parse_Token(s, token))
759 PARSE_ERROR;
760
761 if (IsDigit(token[0])) {
762 /* a numbered program parameter register */
763 GLint reg = _mesa_atoi(token);
764 if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS)
765 PARSE_ERROR1("Bad constant program number");
766 *regNum = FP_PROG_REG_START + reg;
767 }
768 else {
769 PARSE_ERROR;
770 }
771
772 if (!Parse_String(s, "]"))
773 PARSE_ERROR;
774
775 return GL_TRUE;
776 }
777
778
779 /**
780 * Parse f[name] - fragment input register
781 */
782 static GLboolean
783 Parse_AttribReg(const char **s, GLint *tempRegNum)
784 {
785 char token[100];
786 GLint j;
787
788 /* Match 'f' */
789 if (!Parse_String(s, "f"))
790 PARSE_ERROR;
791
792 /* Match '[' */
793 if (!Parse_String(s, "["))
794 PARSE_ERROR;
795
796 /* get <name> and look for match */
797 if (!Parse_Token(s, token)) {
798 PARSE_ERROR;
799 }
800 for (j = 0; InputRegisters[j]; j++) {
801 if (StrEq(token, InputRegisters[j])) {
802 *tempRegNum = FP_INPUT_REG_START + j;
803 break;
804 }
805 }
806 if (!InputRegisters[j]) {
807 /* unknown input register label */
808 PARSE_ERROR2("Bad register name", token);
809 }
810
811 /* Match '[' */
812 if (!Parse_String(s, "]"))
813 PARSE_ERROR;
814
815 return GL_TRUE;
816 }
817
818
819 static GLboolean
820 Parse_OutputReg(const char **s, GLint *outputRegNum)
821 {
822 char token[100];
823 GLint j;
824
825 /* Match 'o' */
826 if (!Parse_String(s, "o"))
827 PARSE_ERROR;
828
829 /* Match '[' */
830 if (!Parse_String(s, "["))
831 PARSE_ERROR;
832
833 /* Get output reg name */
834 if (!Parse_Token(s, token))
835 PARSE_ERROR;
836
837 /* try to match an output register name */
838 for (j = 0; OutputRegisters[j]; j++) {
839 if (StrEq(token, OutputRegisters[j])) {
840 *outputRegNum = FP_OUTPUT_REG_START + j;
841 break;
842 }
843 }
844 if (!OutputRegisters[j])
845 PARSE_ERROR1("Unrecognized output register name");
846
847 /* Match ']' */
848 if (!Parse_String(s, "]"))
849 PARSE_ERROR1("Expected ]");
850
851 return GL_TRUE;
852 }
853
854
855 static GLboolean
856 Parse_MaskedDstReg(const char **s, struct fp_dst_register *dstReg)
857 {
858 char token[100];
859
860 /* Dst reg can be R<n>, H<n>, o[n], RC or HC */
861 if (!Peek_Token(s, token))
862 PARSE_ERROR;
863
864 if (_mesa_strcmp(token, "RC") == 0 ||
865 _mesa_strcmp(token, "HC") == 0) {
866 /* a write-only register */
867 if (!Parse_DummyReg(s, &dstReg->Register))
868 PARSE_ERROR;
869 }
870 else if (token[0] == 'R' || token[0] == 'H') {
871 /* a temporary register */
872 if (!Parse_TempReg(s, &dstReg->Register))
873 PARSE_ERROR;
874 }
875 else if (token[0] == 'o') {
876 /* an output register */
877 if (!Parse_OutputReg(s, &dstReg->Register))
878 PARSE_ERROR;
879 }
880 else {
881 PARSE_ERROR1("Bad destination register name");
882 }
883
884 /* Parse optional write mask */
885 if (!Peek_Token(s, token))
886 PARSE_ERROR;
887
888 if (token[0] == '.') {
889 /* got a mask */
890 GLint k = 0;
891
892 if (!Parse_String(s, "."))
893 PARSE_ERROR;
894
895 if (!Parse_Token(s, token)) /* get xyzw writemask */
896 PARSE_ERROR;
897
898 dstReg->WriteMask[0] = GL_FALSE;
899 dstReg->WriteMask[1] = GL_FALSE;
900 dstReg->WriteMask[2] = GL_FALSE;
901 dstReg->WriteMask[3] = GL_FALSE;
902
903 if (token[k] == 'x') {
904 dstReg->WriteMask[0] = GL_TRUE;
905 k++;
906 }
907 if (token[k] == 'y') {
908 dstReg->WriteMask[1] = GL_TRUE;
909 k++;
910 }
911 if (token[k] == 'z') {
912 dstReg->WriteMask[2] = GL_TRUE;
913 k++;
914 }
915 if (token[k] == 'w') {
916 dstReg->WriteMask[3] = GL_TRUE;
917 k++;
918 }
919 if (k == 0) {
920 PARSE_ERROR1("Bad writemask character");
921 }
922
923 /* peek optional cc mask */
924 if (!Peek_Token(s, token))
925 PARSE_ERROR;
926 }
927 else {
928 dstReg->WriteMask[0] = GL_TRUE;
929 dstReg->WriteMask[1] = GL_TRUE;
930 dstReg->WriteMask[2] = GL_TRUE;
931 dstReg->WriteMask[3] = GL_TRUE;
932 }
933
934 /* optional condition code mask */
935 if (token[0] == '(') {
936 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */
937 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */
938 Parse_String(s, "(");
939
940 if (!Parse_CondCodeMask(s, dstReg))
941 PARSE_ERROR;
942
943 if (!Parse_String(s, ")")) /* consume ")" */
944 PARSE_ERROR;
945
946 return GL_TRUE;
947 }
948 else {
949 /* no cond code mask */
950 dstReg->CondMask = COND_TR;
951 dstReg->CondSwizzle[0] = 0;
952 dstReg->CondSwizzle[1] = 1;
953 dstReg->CondSwizzle[2] = 2;
954 dstReg->CondSwizzle[3] = 3;
955 return GL_TRUE;
956 }
957 }
958
959
960 static GLboolean
961 Parse_SwizzleSrcReg(const char **s, struct fp_src_register *srcReg)
962 {
963 char token[100];
964
965 /* XXX need to parse absolute value and another negation ***/
966 srcReg->NegateBase = GL_FALSE;
967 srcReg->Abs = GL_FALSE;
968 srcReg->NegateAbs = GL_FALSE;
969
970 /* check for '-' */
971 if (!Peek_Token(s, token))
972 PARSE_ERROR;
973 if (token[0] == '-') {
974 (void) Parse_String(s, "-");
975 srcReg->NegateBase = GL_TRUE;
976 if (!Peek_Token(s, token))
977 PARSE_ERROR;
978 }
979 else {
980 srcReg->NegateBase = GL_FALSE;
981 }
982
983 /* Src reg can be R<n>, H<n> or a named fragment attrib */
984 if (token[0] == 'R' || token[0] == 'H') {
985 if (!Parse_TempReg(s, &srcReg->Register))
986 PARSE_ERROR;
987 }
988 else if (token[0] == 'f') {
989 if (!Parse_AttribReg(s, &srcReg->Register))
990 PARSE_ERROR;
991 }
992 else if (token[0] == 'p') {
993 if (!Parse_ProgramParamReg(s, &srcReg->Register))
994 PARSE_ERROR;
995 }
996 else {
997 /* Also parse defined/declared constant or vector literal */
998 PARSE_ERROR2("Bad source register name", token);
999 }
1000
1001 /* init swizzle fields */
1002 srcReg->Swizzle[0] = 0;
1003 srcReg->Swizzle[1] = 1;
1004 srcReg->Swizzle[2] = 2;
1005 srcReg->Swizzle[3] = 3;
1006
1007 /* Look for optional swizzle suffix */
1008 if (!Peek_Token(s, token))
1009 PARSE_ERROR;
1010 if (token[0] == '.') {
1011 (void) Parse_String(s, "."); /* consume . */
1012
1013 if (!Parse_Token(s, token))
1014 PARSE_ERROR;
1015
1016 if (!Parse_SwizzleSuffix(token, srcReg->Swizzle))
1017 PARSE_ERROR1("Bad swizzle suffix");
1018 }
1019
1020 return GL_TRUE;
1021 }
1022
1023
1024 static GLboolean
1025 Parse_ScalarSrcReg(const char **s, struct fp_src_register *srcReg)
1026 {
1027 char token[100];
1028
1029 /* check for '-' */
1030 if (!Peek_Token(s, token))
1031 PARSE_ERROR;
1032 if (token[0] == '-') {
1033 srcReg->NegateBase = GL_TRUE;
1034 (void) Parse_String(s, "-"); /* consume '-' */
1035 if (!Peek_Token(s, token))
1036 PARSE_ERROR;
1037 }
1038 else {
1039 srcReg->NegateBase = GL_FALSE;
1040 }
1041
1042 /* Src reg can be R<n>, H<n> or a named fragment attrib */
1043 if (token[0] == 'R' || token[0] == 'H') {
1044 if (!Parse_TempReg(s, &srcReg->Register))
1045 PARSE_ERROR;
1046 }
1047 else if (token[0] == 'f') {
1048 if (!Parse_AttribReg(s, &srcReg->Register))
1049 PARSE_ERROR;
1050 }
1051 else {
1052 PARSE_ERROR2("Bad source register name", token);
1053 }
1054
1055 /* Look for .[xyzw] suffix */
1056 if (!Parse_String(s, "."))
1057 PARSE_ERROR;
1058
1059 if (!Parse_Token(s, token))
1060 PARSE_ERROR;
1061
1062 if (token[0] == 'x' && token[1] == 0) {
1063 srcReg->Swizzle[0] = 0;
1064 }
1065 else if (token[0] == 'y' && token[1] == 0) {
1066 srcReg->Swizzle[0] = 1;
1067 }
1068 else if (token[0] == 'z' && token[1] == 0) {
1069 srcReg->Swizzle[0] = 2;
1070 }
1071 else if (token[0] == 'w' && token[1] == 0) {
1072 srcReg->Swizzle[0] = 3;
1073 }
1074 else {
1075 PARSE_ERROR1("Bad scalar source suffix");
1076 }
1077 srcReg->Swizzle[1] = srcReg->Swizzle[2] = srcReg->Swizzle[3] = 0;
1078
1079 return GL_TRUE;
1080 }
1081
1082
1083
1084 static GLboolean
1085 Parse_InstructionSequence(const char **s, struct fp_instruction program[])
1086 {
1087 char token[100];
1088 GLint count = 0;
1089
1090 while (1) {
1091 struct fp_instruction *inst = program + count;
1092 struct instruction_pattern instMatch;
1093
1094 /* Initialize the instruction */
1095 inst->SrcReg[0].Register = -1;
1096 inst->SrcReg[1].Register = -1;
1097 inst->SrcReg[2].Register = -1;
1098 inst->DstReg.Register = -1;
1099
1100 /* get token */
1101 if (!Parse_Token(s, token)) {
1102 inst->Opcode = FP_OPCODE_END;
1103 printf("END OF PROGRAM %d\n", count);
1104 break;
1105 }
1106
1107 /* special instructions */
1108 if (StrEq(token, "DEFINE")) {
1109 char id[100];
1110 GLfloat value[4];
1111 if (!Parse_Identifier(s, id))
1112 PARSE_ERROR;
1113 if (!Parse_String(s, "="))
1114 PARSE_ERROR1("Expected = symbol");
1115 if (!Parse_VectorOrScalarConstant(s, value))
1116 PARSE_ERROR;
1117 printf("Parsed DEFINE %s = %f %f %f %f\n", id, value[0], value[1],
1118 value[2], value[3]);
1119 }
1120 else if (StrEq(token, "DECLARE")) {
1121 char id[100];
1122 GLfloat value[4];
1123 if (!Parse_Identifier(s, id))
1124 PARSE_ERROR;
1125 if (!Peek_Token(s, token))
1126 PARSE_ERROR;
1127 if (token[0] == '=') {
1128 Parse_String(s, "=");
1129 if (!Parse_VectorOrScalarConstant(s, value))
1130 PARSE_ERROR;
1131 printf("Parsed DECLARE %s = %f %f %f %f\n", id, value[0], value[1],
1132 value[2], value[3]);
1133 }
1134 else {
1135 printf("Parsed DECLARE %s\n", id);
1136 }
1137 }
1138
1139 /* try to find matching instuction */
1140 instMatch = MatchInstruction(token);
1141 if (instMatch.opcode < 0) {
1142 /* bad instruction name */
1143 PARSE_ERROR2("Unexpected token: ", token);
1144 }
1145
1146 inst->Opcode = instMatch.opcode;
1147 inst->Precision = instMatch.suffixes & (_R | _H | _X);
1148 inst->Saturate = (instMatch.suffixes & (_S)) ? GL_TRUE : GL_FALSE;
1149 inst->UpdateCondRegister = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE;
1150
1151 /*
1152 * parse the input and output operands
1153 */
1154 if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) {
1155 if (!Parse_MaskedDstReg(s, &inst->DstReg))
1156 PARSE_ERROR;
1157 if (!Parse_String(s, ","))
1158 PARSE_ERROR;
1159 }
1160 else if (instMatch.outputs == OUTPUT_NONE) {
1161 ASSERT(instMatch.opcode == FP_OPCODE_KIL);
1162 /* This is a little weird, the cond code info is in the dest register */
1163 if (!Parse_CondCodeMask(s, &inst->DstReg))
1164 PARSE_ERROR;
1165 }
1166
1167 if (instMatch.inputs == INPUT_1V) {
1168 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
1169 PARSE_ERROR;
1170 }
1171 else if (instMatch.inputs == INPUT_2V) {
1172 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
1173 PARSE_ERROR;
1174 if (!Parse_String(s, ","))
1175 PARSE_ERROR;
1176 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
1177 PARSE_ERROR;
1178 }
1179 else if (instMatch.inputs == INPUT_3V) {
1180 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
1181 PARSE_ERROR;
1182 if (!Parse_String(s, ","))
1183 PARSE_ERROR;
1184 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
1185 PARSE_ERROR;
1186 if (!Parse_String(s, ","))
1187 PARSE_ERROR;
1188 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
1189 PARSE_ERROR;
1190 }
1191 else if (instMatch.inputs == INPUT_1S) {
1192 if (!Parse_ScalarSrcReg(s, &inst->SrcReg[1]))
1193 PARSE_ERROR;
1194 }
1195 else if (instMatch.inputs == INPUT_2S) {
1196 if (!Parse_ScalarSrcReg(s, &inst->SrcReg[0]))
1197 PARSE_ERROR;
1198 if (!Parse_String(s, ","))
1199 PARSE_ERROR;
1200 if (!Parse_ScalarSrcReg(s, &inst->SrcReg[1]))
1201 PARSE_ERROR;
1202 }
1203 else if (instMatch.inputs == INPUT_CC) {
1204 #if 00
1205 if (!ParseCondCodeSrc(s, &inst->srcReg[0]))
1206 PARSE_ERROR;
1207 #endif
1208 }
1209 else if (instMatch.inputs == INPUT_1V_T) {
1210 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
1211 PARSE_ERROR;
1212 if (!Parse_String(s, ","))
1213 PARSE_ERROR;
1214 if (!Parse_TextureImageId(s, &inst->TexSrcUnit, &inst->TexSrcTarget))
1215 PARSE_ERROR;
1216 }
1217 else if (instMatch.inputs == INPUT_1V_T) {
1218 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[0]))
1219 PARSE_ERROR;
1220 if (!Parse_String(s, ","))
1221 PARSE_ERROR;
1222 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[1]))
1223 PARSE_ERROR;
1224 if (!Parse_String(s, ","))
1225 PARSE_ERROR;
1226 if (!Parse_SwizzleSrcReg(s, &inst->SrcReg[2]))
1227 PARSE_ERROR;
1228 if (!Parse_String(s, ","))
1229 PARSE_ERROR;
1230 if (!Parse_TextureImageId(s, &inst->TexSrcUnit, &inst->TexSrcTarget))
1231 PARSE_ERROR;
1232 }
1233
1234 /* end of statement semicolon */
1235 if (!Parse_String(s, ";"))
1236 PARSE_ERROR;
1237
1238 count++;
1239 if (count >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS)
1240 PARSE_ERROR1("Program too long");
1241 }
1242 return GL_TRUE;
1243 }
1244
1245
1246 static GLboolean
1247 Parse_Program(const char **s, struct fp_instruction instBuffer[])
1248 {
1249 return Parse_InstructionSequence(s, instBuffer);
1250 }
1251
1252
1253 /**
1254 * Parse/compile the 'str' returning the compiled 'program'.
1255 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos
1256 * indicates the position of the error in 'str'.
1257 */
1258 void
1259 _mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget,
1260 const GLubyte *str, GLsizei len,
1261 struct fragment_program *program)
1262 {
1263 const char *s;
1264 struct fp_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS];
1265 GLubyte *newString;
1266 struct fp_instruction *newInst;
1267 GLenum target;
1268 GLubyte *programString;
1269
1270 /* Make a null-terminated copy of the program string */
1271 programString = (GLubyte *) MALLOC(len + 1);
1272 if (!programString) {
1273 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1274 return;
1275 }
1276 MEMCPY(programString, str, len);
1277 programString[len] = 0;
1278
1279
1280 /* check the program header */
1281 if (_mesa_strncmp((const char *) programString, "!!FP1.0", 7) == 0) {
1282 target = GL_FRAGMENT_PROGRAM_NV;
1283 s = (const char *) programString + 7;
1284 }
1285 else {
1286 /* invalid header */
1287 _mesa_set_program_error(ctx, 0, "Invalid fragment program header");
1288 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)");
1289 return;
1290 }
1291
1292 /* make sure target and header match */
1293 if (target != dstTarget) {
1294 _mesa_error(ctx, GL_INVALID_OPERATION,
1295 "glLoadProgramNV(target mismatch 0x%x != 0x%x)",
1296 target, dstTarget);
1297 return;
1298 }
1299
1300 if (Parse_Program(&s, instBuffer)) {
1301 GLuint numInst;
1302 GLuint strLen;
1303 GLuint inputsRead = 0;
1304 GLuint outputsWritten = 0;
1305 /**GLuint progRegsWritten = 0;**/
1306
1307 /* Find length of the program and compute bitmasks to indicate which
1308 * vertex input registers are read, which vertex result registers are
1309 * written to, and which program registers are written to.
1310 * We could actually do this while we parse the program.
1311 */
1312 for (numInst = 0; instBuffer[numInst].Opcode != FP_OPCODE_END; numInst++) {
1313 #if 0
1314 const GLint srcReg0 = instBuffer[numInst].SrcReg[0].Register;
1315 const GLint srcReg1 = instBuffer[numInst].SrcReg[1].Register;
1316 const GLint srcReg2 = instBuffer[numInst].SrcReg[2].Register;
1317 const GLint dstReg = instBuffer[numInst].DstReg.Register;
1318
1319 if ((r = OutputRegisterNumber(dstReg)) >= 0)
1320 outputsWritten |= (1 << r);
1321 else if (IsProgRegister(dstReg))
1322 progRegsWritten |= (1 << (dstReg - FP_PROG_REG_START));
1323 if ((r = InputRegisterNumber(srcReg0)) >= 0
1324 && !instBuffer[numInst].SrcReg[0].RelAddr)
1325 inputsRead |= (1 << r);
1326 if ((r = InputRegisterNumber(srcReg1) >= 0
1327 && !instBuffer[numInst].SrcReg[1].RelAddr)
1328 inputsRead |= (1 << r);
1329 if ((r = InputRegisterNumber(srcReg2) >= 0
1330 && !instBuffer[numInst].SrcReg[2].RelAddr)
1331 inputsRead |= (1 << r);
1332 #endif
1333 }
1334 numInst++;
1335 printf("numInst %d\n", numInst);
1336
1337 program->InputsRead = inputsRead;
1338 program->OutputsWritten = outputsWritten;
1339
1340 /* make copy of the input program string */
1341 strLen = _mesa_strlen((const char *) str);
1342 newString = (GLubyte *) MALLOC(strLen + 1);
1343 if (!newString) {
1344 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1345 return;
1346 }
1347 MEMCPY(newString, str, strLen);
1348 newString[strLen] = 0; /* terminate */
1349
1350 /* copy the compiled instructions */
1351 assert(numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS);
1352 newInst = (struct fp_instruction *) MALLOC(numInst * sizeof(struct fp_instruction));
1353 if (!newInst) {
1354 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
1355 return; /* out of memory */
1356 }
1357 MEMCPY(newInst, instBuffer, numInst * sizeof(struct fp_instruction));
1358
1359 /* install the program */
1360 program->Base.Target = target;
1361 if (program->Base.String) {
1362 FREE(program->Base.String);
1363 }
1364 program->Base.String = newString;
1365 if (program->Instructions) {
1366 FREE(program->Instructions);
1367 }
1368 program->Instructions = newInst;
1369
1370 #ifdef DEBUG
1371 _mesa_printf("--- glLoadProgramNV result ---\n");
1372 _mesa_print_nv_fragment_program(program);
1373 _mesa_printf("------------------------------\n");
1374 #endif
1375 }
1376 else {
1377 /* Error! */
1378 #ifdef DEBUG
1379 /* print a message showing the program line containing the error */
1380 ctx->Program.ErrorPos = (GLubyte *) s - str;
1381 {
1382 const GLubyte *p = str, *line = str;
1383 int lineNum = 1, statementNum = 1, column = 0;
1384 char errorLine[1000];
1385 int i;
1386 while (*p && p < (const GLubyte *) s) { /* s is the error position */
1387 if (*p == '\n') {
1388 line = p + 1;
1389 lineNum++;
1390 column = 0;
1391 }
1392 else if (*p == ';') {
1393 statementNum++;
1394 }
1395 else
1396 column++;
1397 p++;
1398 }
1399 if (p) {
1400 /* Copy the line with the error into errorLine so we can null-
1401 * terminate it.
1402 */
1403 for (i = 0; line[i] != '\n' && line[i]; i++)
1404 errorLine[i] = (char) line[i];
1405 errorLine[i] = 0;
1406 }
1407 /*
1408 _mesa_debug("Error pos = %d (%c) col %d\n",
1409 ctx->Program.ErrorPos, *s, column);
1410 */
1411 _mesa_debug(ctx, "Fragment program error on line %2d: %s\n", lineNum, errorLine);
1412 _mesa_debug(ctx, " (statement %2d) near column %2d: ", statementNum, column+1);
1413 for (i = 0; i < column; i++)
1414 _mesa_debug(ctx, " ");
1415 _mesa_debug(ctx, "^\n");
1416 }
1417 #endif
1418 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV");
1419 }
1420 }
1421
1422
1423 static void
1424 PrintSrcReg(const struct fp_src_register *src)
1425 {
1426 static const char comps[5] = "xyzw";
1427 GLint r;
1428
1429 if (src->NegateAbs) {
1430 _mesa_printf("-");
1431 }
1432 if (src->Abs) {
1433 _mesa_printf("|");
1434 }
1435 if (src->NegateBase) {
1436 _mesa_printf("-");
1437 }
1438 if ((r = OutputRegisterNumber(src->Register)) >= 0) {
1439 _mesa_printf("o[%s]", OutputRegisters[r]);
1440 }
1441 else if ((r = InputRegisterNumber(src->Register)) >= 0) {
1442 _mesa_printf("f[%s]", InputRegisters[r]);
1443 }
1444 else if ((r = ProgramRegisterNumber(src->Register)) >= 0) {
1445 _mesa_printf("p[%d]", r);
1446 }
1447 else if ((r = HalfTempRegisterNumber(src->Register)) >= 0) {
1448 _mesa_printf("H%d", r);
1449 }
1450 else if ((r = TempRegisterNumber(src->Register)) >= 0) {
1451 _mesa_printf("R%d", r);
1452 }
1453 else if ((r = DummyRegisterNumber(src->Register)) >= 0) {
1454 _mesa_printf("%cC", "HR"[r]);
1455 }
1456 else {
1457 _mesa_problem(NULL, "Bad fragment register");
1458 return;
1459 }
1460 if (src->Swizzle[0] == src->Swizzle[1] &&
1461 src->Swizzle[0] == src->Swizzle[2] &&
1462 src->Swizzle[0] == src->Swizzle[3]) {
1463 _mesa_printf(".%c", comps[src->Swizzle[0]]);
1464 }
1465 else if (src->Swizzle[0] != 0 ||
1466 src->Swizzle[1] != 1 ||
1467 src->Swizzle[2] != 2 ||
1468 src->Swizzle[3] != 3) {
1469 _mesa_printf(".%c%c%c%c",
1470 comps[src->Swizzle[0]],
1471 comps[src->Swizzle[1]],
1472 comps[src->Swizzle[2]],
1473 comps[src->Swizzle[3]]);
1474 }
1475 if (src->Abs) {
1476 _mesa_printf("|");
1477 }
1478 }
1479
1480 static void
1481 PrintCondCode(const struct fp_dst_register *dst)
1482 {
1483 static const char *comps = "xyzw";
1484 static const char *ccString[] = {
1485 "??", "GT", "EQ", "LT", "UN", "GE", "LE", "NE", "TR", "FL", "??"
1486 };
1487
1488 _mesa_printf("%s", ccString[dst->CondMask]);
1489 if (dst->CondSwizzle[0] == dst->CondSwizzle[1] &&
1490 dst->CondSwizzle[0] == dst->CondSwizzle[2] &&
1491 dst->CondSwizzle[0] == dst->CondSwizzle[3]) {
1492 _mesa_printf(".%c", comps[dst->CondSwizzle[0]]);
1493 }
1494 else if (dst->CondSwizzle[0] != 0 ||
1495 dst->CondSwizzle[1] != 1 ||
1496 dst->CondSwizzle[2] != 2 ||
1497 dst->CondSwizzle[3] != 3) {
1498 _mesa_printf(".%c%c%c%c",
1499 comps[dst->CondSwizzle[0]],
1500 comps[dst->CondSwizzle[1]],
1501 comps[dst->CondSwizzle[2]],
1502 comps[dst->CondSwizzle[3]]);
1503 }
1504 }
1505
1506
1507 static void
1508 PrintDstReg(const struct fp_dst_register *dst)
1509 {
1510 GLint w = dst->WriteMask[0] + dst->WriteMask[1]
1511 + dst->WriteMask[2] + dst->WriteMask[3];
1512 GLint r;
1513
1514 if ((r = OutputRegisterNumber(dst->Register)) >= 0) {
1515 _mesa_printf("o[%s]", OutputRegisters[r]);
1516 }
1517 else if ((r = HalfTempRegisterNumber(dst->Register)) >= 0) {
1518 _mesa_printf("H[%s]", InputRegisters[r]);
1519 }
1520 else if ((r = TempRegisterNumber(dst->Register)) >= 0) {
1521 _mesa_printf("R[%s]", InputRegisters[r]);
1522 }
1523 else if ((r = ProgramRegisterNumber(dst->Register)) >= 0) {
1524 _mesa_printf("p[%d]", r);
1525 }
1526 else if ((r = DummyRegisterNumber(dst->Register)) >= 0) {
1527 _mesa_printf("%cC", "HR"[r]);
1528 }
1529 else {
1530 _mesa_printf("???");
1531 }
1532
1533 if (w != 0 && w != 4) {
1534 _mesa_printf(".");
1535 if (dst->WriteMask[0])
1536 _mesa_printf("x");
1537 if (dst->WriteMask[1])
1538 _mesa_printf("y");
1539 if (dst->WriteMask[2])
1540 _mesa_printf("z");
1541 if (dst->WriteMask[3])
1542 _mesa_printf("w");
1543 }
1544
1545 if (dst->CondMask != COND_TR ||
1546 dst->CondSwizzle[0] != 0 ||
1547 dst->CondSwizzle[1] != 1 ||
1548 dst->CondSwizzle[2] != 2 ||
1549 dst->CondSwizzle[3] != 3) {
1550 _mesa_printf(" (");
1551 PrintCondCode(dst);
1552 _mesa_printf(")");
1553 }
1554 }
1555
1556
1557 /**
1558 * Print (unparse) the given vertex program. Just for debugging.
1559 */
1560 void
1561 _mesa_print_nv_fragment_program(const struct fragment_program *program)
1562 {
1563 const struct fp_instruction *inst;
1564
1565 for (inst = program->Instructions; inst->Opcode != FP_OPCODE_END; inst++) {
1566 int i;
1567 for (i = 0; Instructions[i].name; i++) {
1568 if (inst->Opcode == Instructions[i].opcode) {
1569 /* print instruction name */
1570 _mesa_printf("%s", Instructions[i].name);
1571 if (inst->Precision == HALF)
1572 _mesa_printf("H");
1573 else if (inst->Precision == FIXED)
1574 _mesa_printf("X");
1575 if (inst->UpdateCondRegister)
1576 _mesa_printf("C");
1577 if (inst->Saturate)
1578 _mesa_printf("_SAT");
1579 _mesa_printf(" ");
1580
1581 if (Instructions[i].inputs == INPUT_CC) {
1582 PrintCondCode(&inst->DstReg);
1583 }
1584 else if (Instructions[i].outputs == OUTPUT_V ||
1585 Instructions[i].outputs == OUTPUT_S) {
1586 /* print dest register */
1587 PrintDstReg(&inst->DstReg);
1588 _mesa_printf(", ");
1589 }
1590
1591 /* print source register(s) */
1592 if (Instructions[i].inputs == INPUT_1V ||
1593 Instructions[i].inputs == INPUT_1S) {
1594 PrintSrcReg(&inst->SrcReg[0]);
1595 }
1596 else if (Instructions[i].inputs == INPUT_2V ||
1597 Instructions[i].inputs == INPUT_2S) {
1598 PrintSrcReg(&inst->SrcReg[0]);
1599 _mesa_printf(", ");
1600 PrintSrcReg(&inst->SrcReg[1]);
1601 }
1602 else if (Instructions[i].inputs == INPUT_3V) {
1603 PrintSrcReg(&inst->SrcReg[0]);
1604 _mesa_printf(", ");
1605 PrintSrcReg(&inst->SrcReg[1]);
1606 _mesa_printf(", ");
1607 PrintSrcReg(&inst->SrcReg[2]);
1608 }
1609
1610 _mesa_printf(";\n");
1611 break;
1612 }
1613 }
1614 if (!Instructions[i].name) {
1615 _mesa_printf("Bad opcode %d\n", inst->Opcode);
1616 }
1617 }
1618 }
1619