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