nvfragparse.c revision 2861e737e84e4884109b9526ac645194ba892a74
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.0 4 * 5 * Copyright (C) 1999-2004 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 "glheader.h" 41#include "context.h" 42#include "hash.h" 43#include "imports.h" 44#include "macros.h" 45#include "mtypes.h" 46#include "nvfragprog.h" 47#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 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 fp_opcode opcode; 82 GLuint inputs; 83 GLuint outputs; 84 GLuint suffixes; 85}; 86 87static const struct instruction_pattern Instructions[] = { 88 { "ADD", FP_OPCODE_ADD, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, 89 { "COS", FP_OPCODE_COS, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, 90 { "DDX", FP_OPCODE_DDX, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, 91 { "DDY", FP_OPCODE_DDY, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, 92 { "DP3", FP_OPCODE_DP3, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S }, 93 { "DP4", FP_OPCODE_DP4, INPUT_2V, OUTPUT_S, _R | _H | _X | _C | _S }, 94 { "DST", FP_OPCODE_DP4, INPUT_2V, OUTPUT_V, _R | _H | _C | _S }, 95 { "EX2", FP_OPCODE_DP4, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, 96 { "FLR", FP_OPCODE_FLR, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, 97 { "FRC", FP_OPCODE_FRC, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, 98 { "KIL", FP_OPCODE_KIL, INPUT_CC, OUTPUT_NONE, 0 }, 99 { "LG2", FP_OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, 100 { "LIT", FP_OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, 101 { "LRP", FP_OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S }, 102 { "MAD", FP_OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S }, 103 { "MAX", FP_OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, 104 { "MIN", FP_OPCODE_MIN, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, 105 { "MOV", FP_OPCODE_MOV, INPUT_1V, OUTPUT_V, _R | _H | _X | _C | _S }, 106 { "MUL", FP_OPCODE_MUL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, 107 { "PK2H", FP_OPCODE_PK2H, INPUT_1V, OUTPUT_S, 0 }, 108 { "PK2US", FP_OPCODE_PK2US, INPUT_1V, OUTPUT_S, 0 }, 109 { "PK4B", FP_OPCODE_PK4B, INPUT_1V, OUTPUT_S, 0 }, 110 { "PK4UB", FP_OPCODE_PK4UB, INPUT_1V, OUTPUT_S, 0 }, 111 { "POW", FP_OPCODE_POW, INPUT_2S, OUTPUT_S, _R | _H | _C | _S }, 112 { "RCP", FP_OPCODE_RCP, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, 113 { "RFL", FP_OPCODE_RFL, INPUT_2V, OUTPUT_V, _R | _H | _C | _S }, 114 { "RSQ", FP_OPCODE_RSQ, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, 115 { "SEQ", FP_OPCODE_SEQ, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, 116 { "SFL", FP_OPCODE_SFL, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, 117 { "SGE", FP_OPCODE_SGE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, 118 { "SGT", FP_OPCODE_SGT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, 119 { "SIN", FP_OPCODE_SIN, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, 120 { "SLE", FP_OPCODE_SLE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, 121 { "SLT", FP_OPCODE_SLT, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, 122 { "SNE", FP_OPCODE_SNE, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, 123 { "STR", FP_OPCODE_STR, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, 124 { "SUB", FP_OPCODE_SUB, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, 125 { "TEX", FP_OPCODE_TEX, INPUT_1V_T, OUTPUT_V, _C | _S }, 126 { "TXD", FP_OPCODE_TXD, INPUT_3V_T, OUTPUT_V, _C | _S }, 127 { "TXP", FP_OPCODE_TXP, INPUT_1V_T, OUTPUT_V, _C | _S }, 128 { "UP2H", FP_OPCODE_UP2H, INPUT_1S, OUTPUT_V, _C | _S }, 129 { "UP2US", FP_OPCODE_UP2US, INPUT_1S, OUTPUT_V, _C | _S }, 130 { "UP4B", FP_OPCODE_UP4B, INPUT_1S, OUTPUT_V, _C | _S }, 131 { "UP4UB", FP_OPCODE_UP4UB, INPUT_1S, OUTPUT_V, _C | _S }, 132 { "X2D", FP_OPCODE_X2D, INPUT_3V, OUTPUT_V, _R | _H | _C | _S }, 133 { NULL, (enum fp_opcode) -1, 0, 0, 0 } 134}; 135 136 137/* 138 * Information needed or computed during parsing. 139 * Remember, we can't modify the target program object until we've 140 * _successfully_ parsed the program text. 141 */ 142struct parse_state { 143 GLcontext *ctx; 144 const GLubyte *start; /* start of program string */ 145 const GLubyte *pos; /* current position */ 146 const GLubyte *curLine; 147 struct fragment_program *program; /* current program */ 148 149 struct program_parameter_list *parameters; 150 151 GLuint numInst; /* number of instructions parsed */ 152 GLuint inputsRead; /* bitmask of input registers used */ 153 GLuint outputsWritten; /* bitmask of 1 << FRAG_OUTPUT_* bits */ 154 GLuint texturesUsed[MAX_TEXTURE_IMAGE_UNITS]; 155}; 156 157 158 159/* 160 * Called whenever we find an error during parsing. 161 */ 162static void 163record_error(struct parse_state *parseState, const char *msg, int lineNo) 164{ 165#ifdef DEBUG 166 GLint line, column; 167 const GLubyte *lineStr; 168 lineStr = _mesa_find_line_column(parseState->start, 169 parseState->pos, &line, &column); 170 _mesa_debug(parseState->ctx, 171 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n", 172 lineNo, line, column, (char *) lineStr, msg); 173 _mesa_free((void *) lineStr); 174#else 175 (void) lineNo; 176#endif 177 178 /* Check that no error was already recorded. Only record the first one. */ 179 if (parseState->ctx->Program.ErrorString[0] == 0) { 180 _mesa_set_program_error(parseState->ctx, 181 parseState->pos - parseState->start, 182 msg); 183 } 184} 185 186 187#define RETURN_ERROR \ 188do { \ 189 record_error(parseState, "Unexpected end of input.", __LINE__); \ 190 return GL_FALSE; \ 191} while(0) 192 193#define RETURN_ERROR1(msg) \ 194do { \ 195 record_error(parseState, msg, __LINE__); \ 196 return GL_FALSE; \ 197} while(0) 198 199#define RETURN_ERROR2(msg1, msg2) \ 200do { \ 201 char err[1000]; \ 202 _mesa_sprintf(err, "%s %s", msg1, msg2); \ 203 record_error(parseState, err, __LINE__); \ 204 return GL_FALSE; \ 205} while(0) 206 207 208 209 210/* 211 * Search a list of instruction structures for a match. 212 */ 213static struct instruction_pattern 214MatchInstruction(const GLubyte *token) 215{ 216 const struct instruction_pattern *inst; 217 struct instruction_pattern result; 218 219 for (inst = Instructions; inst->name; inst++) { 220 if (_mesa_strncmp((const char *) token, inst->name, 3) == 0) { 221 /* matched! */ 222 int i = 3; 223 result = *inst; 224 result.suffixes = 0; 225 /* look at suffix */ 226 if (token[i] == 'R') { 227 result.suffixes |= _R; 228 i++; 229 } 230 else if (token[i] == 'H') { 231 result.suffixes |= _H; 232 i++; 233 } 234 else if (token[i] == 'X') { 235 result.suffixes |= _X; 236 i++; 237 } 238 if (token[i] == 'C') { 239 result.suffixes |= _C; 240 i++; 241 } 242 if (token[i] == '_' && token[i+1] == 'S' && 243 token[i+2] == 'A' && token[i+3] == 'T') { 244 result.suffixes |= _S; 245 } 246 return result; 247 } 248 } 249 result.opcode = (enum fp_opcode) -1; 250 return result; 251} 252 253 254 255 256/**********************************************************************/ 257 258 259static GLboolean IsLetter(GLubyte b) 260{ 261 return (b >= 'a' && b <= 'z') || 262 (b >= 'A' && b <= 'Z') || 263 (b == '_') || 264 (b == '$'); 265} 266 267 268static GLboolean IsDigit(GLubyte b) 269{ 270 return b >= '0' && b <= '9'; 271} 272 273 274static GLboolean IsWhitespace(GLubyte b) 275{ 276 return b == ' ' || b == '\t' || b == '\n' || b == '\r'; 277} 278 279 280/** 281 * Starting at 'str' find the next token. A token can be an integer, 282 * an identifier or punctuation symbol. 283 * \return <= 0 we found an error, else, return number of characters parsed. 284 */ 285static GLint 286GetToken(struct parse_state *parseState, GLubyte *token) 287{ 288 const GLubyte *str = parseState->pos; 289 GLint i = 0, j = 0; 290 291 token[0] = 0; 292 293 /* skip whitespace and comments */ 294 while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) { 295 if (str[i] == '#') { 296 /* skip comment */ 297 while (str[i] && (str[i] != '\n' && str[i] != '\r')) { 298 i++; 299 } 300 if (str[i] == '\n' || str[i] == '\r') 301 parseState->curLine = str + i + 1; 302 } 303 else { 304 /* skip whitespace */ 305 if (str[i] == '\n' || str[i] == '\r') 306 parseState->curLine = str + i + 1; 307 i++; 308 } 309 } 310 311 if (str[i] == 0) 312 return -i; 313 314 /* try matching an integer */ 315 while (str[i] && IsDigit(str[i])) { 316 token[j++] = str[i++]; 317 } 318 if (j > 0 || !str[i]) { 319 token[j] = 0; 320 return i; 321 } 322 323 /* try matching an identifier */ 324 if (IsLetter(str[i])) { 325 while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) { 326 token[j++] = str[i++]; 327 } 328 token[j] = 0; 329 return i; 330 } 331 332 /* punctuation character */ 333 if (str[i]) { 334 token[0] = str[i++]; 335 token[1] = 0; 336 return i; 337 } 338 339 /* end of input */ 340 token[0] = 0; 341 return i; 342} 343 344 345/** 346 * Get next token from input stream and increment stream pointer past token. 347 */ 348static GLboolean 349Parse_Token(struct parse_state *parseState, GLubyte *token) 350{ 351 GLint i; 352 i = GetToken(parseState, token); 353 if (i <= 0) { 354 parseState->pos += (-i); 355 return GL_FALSE; 356 } 357 parseState->pos += i; 358 return GL_TRUE; 359} 360 361 362/** 363 * Get next token from input stream but don't increment stream pointer. 364 */ 365static GLboolean 366Peek_Token(struct parse_state *parseState, GLubyte *token) 367{ 368 GLint i, len; 369 i = GetToken(parseState, token); 370 if (i <= 0) { 371 parseState->pos += (-i); 372 return GL_FALSE; 373 } 374 len = _mesa_strlen((const char *) token); 375 parseState->pos += (i - len); 376 return GL_TRUE; 377} 378 379 380/**********************************************************************/ 381 382static const char *InputRegisters[MAX_NV_FRAGMENT_PROGRAM_INPUTS + 1] = { 383 "WPOS", "COL0", "COL1", "FOGC", 384 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL 385}; 386 387static const char *OutputRegisters[MAX_NV_FRAGMENT_PROGRAM_OUTPUTS + 1] = { 388 "COLR", "COLH", 389 /* These are only allows for register combiners */ 390 /* 391 "TEX0", "TEX1", "TEX2", "TEX3", 392 */ 393 "DEPR", NULL 394}; 395 396 397 398 399/**********************************************************************/ 400 401/** 402 * Try to match 'pattern' as the next token after any whitespace/comments. 403 */ 404static GLboolean 405Parse_String(struct parse_state *parseState, const char *pattern) 406{ 407 const GLubyte *m; 408 GLint i; 409 410 /* skip whitespace and comments */ 411 while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') { 412 if (*parseState->pos == '#') { 413 while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) { 414 parseState->pos += 1; 415 } 416 if (*parseState->pos == '\n' || *parseState->pos == '\r') 417 parseState->curLine = parseState->pos + 1; 418 } 419 else { 420 /* skip whitespace */ 421 if (*parseState->pos == '\n' || *parseState->pos == '\r') 422 parseState->curLine = parseState->pos + 1; 423 parseState->pos += 1; 424 } 425 } 426 427 /* Try to match the pattern */ 428 m = parseState->pos; 429 for (i = 0; pattern[i]; i++) { 430 if (*m != (GLubyte) pattern[i]) 431 return GL_FALSE; 432 m += 1; 433 } 434 parseState->pos = m; 435 436 return GL_TRUE; /* success */ 437} 438 439 440static GLboolean 441Parse_Identifier(struct parse_state *parseState, GLubyte *ident) 442{ 443 if (!Parse_Token(parseState, ident)) 444 RETURN_ERROR; 445 if (IsLetter(ident[0])) 446 return GL_TRUE; 447 else 448 RETURN_ERROR1("Expected an identfier"); 449} 450 451 452/** 453 * Parse a floating point constant, or a defined symbol name. 454 * [+/-]N[.N[eN]] 455 * Output: number[0 .. 3] will get the value. 456 */ 457static GLboolean 458Parse_ScalarConstant(struct parse_state *parseState, GLfloat *number) 459{ 460 char *end = NULL; 461 462 *number = (GLfloat) _mesa_strtod((const char *) parseState->pos, &end); 463 464 if (end && end > (char *) parseState->pos) { 465 /* got a number */ 466 parseState->pos = (GLubyte *) end; 467 number[1] = *number; 468 number[2] = *number; 469 number[3] = *number; 470 return GL_TRUE; 471 } 472 else { 473 /* should be an identifier */ 474 GLubyte ident[100]; 475 const GLfloat *constant; 476 if (!Parse_Identifier(parseState, ident)) 477 RETURN_ERROR1("Expected an identifier"); 478 constant = _mesa_lookup_parameter_value(parseState->parameters, 479 -1, (const char *) ident); 480 /* XXX Check that it's a constant and not a parameter */ 481 if (!constant) { 482 RETURN_ERROR1("Undefined symbol"); 483 } 484 else { 485 COPY_4V(number, constant); 486 return GL_TRUE; 487 } 488 } 489} 490 491 492 493/** 494 * Parse a vector constant, one of: 495 * { float } 496 * { float, float } 497 * { float, float, float } 498 * { float, float, float, float } 499 */ 500static GLboolean 501Parse_VectorConstant(struct parse_state *parseState, GLfloat *vec) 502{ 503 /* "{" was already consumed */ 504 505 ASSIGN_4V(vec, 0.0, 0.0, 0.0, 1.0); 506 507 if (!Parse_ScalarConstant(parseState, vec+0)) /* X */ 508 return GL_FALSE; 509 510 if (Parse_String(parseState, "}")) { 511 return GL_TRUE; 512 } 513 514 if (!Parse_String(parseState, ",")) 515 RETURN_ERROR1("Expected comma in vector constant"); 516 517 if (!Parse_ScalarConstant(parseState, vec+1)) /* Y */ 518 return GL_FALSE; 519 520 if (Parse_String(parseState, "}")) { 521 return GL_TRUE; 522 } 523 524 if (!Parse_String(parseState, ",")) 525 RETURN_ERROR1("Expected comma in vector constant"); 526 527 if (!Parse_ScalarConstant(parseState, vec+2)) /* Z */ 528 return GL_FALSE; 529 530 if (Parse_String(parseState, "}")) { 531 return GL_TRUE; 532 } 533 534 if (!Parse_String(parseState, ",")) 535 RETURN_ERROR1("Expected comma in vector constant"); 536 537 if (!Parse_ScalarConstant(parseState, vec+3)) /* W */ 538 return GL_FALSE; 539 540 if (!Parse_String(parseState, "}")) 541 RETURN_ERROR1("Expected closing brace in vector constant"); 542 543 return GL_TRUE; 544} 545 546 547/** 548 * Parse <number>, <varname> or {a, b, c, d}. 549 * Return number of values in the vector or scalar, or zero if parse error. 550 */ 551static GLuint 552Parse_VectorOrScalarConstant(struct parse_state *parseState, GLfloat *vec) 553{ 554 if (Parse_String(parseState, "{")) { 555 return Parse_VectorConstant(parseState, vec); 556 } 557 else { 558 GLboolean b = Parse_ScalarConstant(parseState, vec); 559 if (b) { 560 vec[1] = vec[2] = vec[3] = vec[0]; 561 } 562 return b; 563 } 564} 565 566 567/** 568 * Parse a texture image source: 569 * [TEX0 | TEX1 | .. | TEX15] , [1D | 2D | 3D | CUBE | RECT] 570 */ 571static GLboolean 572Parse_TextureImageId(struct parse_state *parseState, 573 GLubyte *texUnit, GLubyte *texTargetBit) 574{ 575 GLubyte imageSrc[100]; 576 GLint unit; 577 578 if (!Parse_Token(parseState, imageSrc)) 579 RETURN_ERROR; 580 581 if (imageSrc[0] != 'T' || 582 imageSrc[1] != 'E' || 583 imageSrc[2] != 'X') { 584 RETURN_ERROR1("Expected TEX# source"); 585 } 586 unit = _mesa_atoi((const char *) imageSrc + 3); 587 if ((unit < 0 || unit > MAX_TEXTURE_IMAGE_UNITS) || 588 (unit == 0 && (imageSrc[3] != '0' || imageSrc[4] != 0))) { 589 RETURN_ERROR1("Invalied TEX# source index"); 590 } 591 *texUnit = unit; 592 593 if (!Parse_String(parseState, ",")) 594 RETURN_ERROR1("Expected ,"); 595 596 if (Parse_String(parseState, "1D")) { 597 *texTargetBit = TEXTURE_1D_BIT; 598 } 599 else if (Parse_String(parseState, "2D")) { 600 *texTargetBit = TEXTURE_2D_BIT; 601 } 602 else if (Parse_String(parseState, "3D")) { 603 *texTargetBit = TEXTURE_3D_BIT; 604 } 605 else if (Parse_String(parseState, "CUBE")) { 606 *texTargetBit = TEXTURE_CUBE_BIT; 607 } 608 else if (Parse_String(parseState, "RECT")) { 609 *texTargetBit = TEXTURE_RECT_BIT; 610 } 611 else { 612 RETURN_ERROR1("Invalid texture target token"); 613 } 614 615 /* update record of referenced texture units */ 616 parseState->texturesUsed[*texUnit] |= *texTargetBit; 617 if (_mesa_bitcount(parseState->texturesUsed[*texUnit]) > 1) { 618 RETURN_ERROR1("Only one texture target can be used per texture unit."); 619 } 620 621 return GL_TRUE; 622} 623 624 625/** 626 * Parse a scalar suffix like .x, .y, .z or .w or parse a swizzle suffix 627 * like .wxyz, .xxyy, etc and return the swizzle indexes. 628 */ 629static GLboolean 630Parse_SwizzleSuffix(const GLubyte *token, GLuint swizzle[4]) 631{ 632 if (token[1] == 0) { 633 /* single letter swizzle (scalar) */ 634 if (token[0] == 'x') 635 ASSIGN_4V(swizzle, 0, 0, 0, 0); 636 else if (token[0] == 'y') 637 ASSIGN_4V(swizzle, 1, 1, 1, 1); 638 else if (token[0] == 'z') 639 ASSIGN_4V(swizzle, 2, 2, 2, 2); 640 else if (token[0] == 'w') 641 ASSIGN_4V(swizzle, 3, 3, 3, 3); 642 else 643 return GL_FALSE; 644 } 645 else { 646 /* 4-component swizzle (vector) */ 647 GLint k; 648 for (k = 0; token[k] && k < 4; k++) { 649 if (token[k] == 'x') 650 swizzle[k] = 0; 651 else if (token[k] == 'y') 652 swizzle[k] = 1; 653 else if (token[k] == 'z') 654 swizzle[k] = 2; 655 else if (token[k] == 'w') 656 swizzle[k] = 3; 657 else 658 return GL_FALSE; 659 } 660 if (k != 4) 661 return GL_FALSE; 662 } 663 return GL_TRUE; 664} 665 666 667static GLboolean 668Parse_CondCodeMask(struct parse_state *parseState, 669 struct fp_dst_register *dstReg) 670{ 671 if (Parse_String(parseState, "EQ")) 672 dstReg->CondMask = COND_EQ; 673 else if (Parse_String(parseState, "GE")) 674 dstReg->CondMask = COND_GE; 675 else if (Parse_String(parseState, "GT")) 676 dstReg->CondMask = COND_GT; 677 else if (Parse_String(parseState, "LE")) 678 dstReg->CondMask = COND_LE; 679 else if (Parse_String(parseState, "LT")) 680 dstReg->CondMask = COND_LT; 681 else if (Parse_String(parseState, "NE")) 682 dstReg->CondMask = COND_NE; 683 else if (Parse_String(parseState, "TR")) 684 dstReg->CondMask = COND_TR; 685 else if (Parse_String(parseState, "FL")) 686 dstReg->CondMask = COND_FL; 687 else 688 RETURN_ERROR1("Invalid condition code mask"); 689 690 /* look for optional .xyzw swizzle */ 691 if (Parse_String(parseState, ".")) { 692 GLubyte token[100]; 693 if (!Parse_Token(parseState, token)) /* get xyzw suffix */ 694 RETURN_ERROR; 695 696 if (!Parse_SwizzleSuffix(token, dstReg->CondSwizzle)) 697 RETURN_ERROR1("Invalid swizzle suffix"); 698 } 699 700 return GL_TRUE; 701} 702 703 704/** 705 * Parse a temporary register: Rnn or Hnn 706 */ 707static GLboolean 708Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum) 709{ 710 GLubyte token[100]; 711 712 /* Should be 'R##' or 'H##' */ 713 if (!Parse_Token(parseState, token)) 714 RETURN_ERROR; 715 if (token[0] != 'R' && token[0] != 'H') 716 RETURN_ERROR1("Expected R## or H##"); 717 718 if (IsDigit(token[1])) { 719 GLint reg = _mesa_atoi((const char *) (token + 1)); 720 if (token[0] == 'H') 721 reg += 32; 722 if (reg >= MAX_NV_FRAGMENT_PROGRAM_TEMPS) 723 RETURN_ERROR1("Invalid temporary register name"); 724 *tempRegNum = reg; 725 } 726 else { 727 RETURN_ERROR1("Invalid temporary register name"); 728 } 729 730 return GL_TRUE; 731} 732 733 734/** 735 * Parse a write-only dummy register: RC or HC. 736 */ 737static GLboolean 738Parse_DummyReg(struct parse_state *parseState, GLint *regNum) 739{ 740 if (Parse_String(parseState, "RC")) { 741 *regNum = 0; 742 } 743 else if (Parse_String(parseState, "HC")) { 744 *regNum = 1; 745 } 746 else { 747 RETURN_ERROR1("Invalid write-only register name"); 748 } 749 750 return GL_TRUE; 751} 752 753 754/** 755 * Parse a program local parameter register "p[##]" 756 */ 757static GLboolean 758Parse_ProgramParamReg(struct parse_state *parseState, GLint *regNum) 759{ 760 GLubyte token[100]; 761 762 if (!Parse_String(parseState, "p[")) 763 RETURN_ERROR1("Expected p["); 764 765 if (!Parse_Token(parseState, token)) 766 RETURN_ERROR; 767 768 if (IsDigit(token[0])) { 769 /* a numbered program parameter register */ 770 GLint reg = _mesa_atoi((const char *) token); 771 if (reg >= MAX_NV_FRAGMENT_PROGRAM_PARAMS) 772 RETURN_ERROR1("Invalid constant program number"); 773 *regNum = reg; 774 } 775 else { 776 RETURN_ERROR; 777 } 778 779 if (!Parse_String(parseState, "]")) 780 RETURN_ERROR1("Expected ]"); 781 782 return GL_TRUE; 783} 784 785 786/** 787 * Parse f[name] - fragment input register 788 */ 789static GLboolean 790Parse_FragReg(struct parse_state *parseState, GLint *tempRegNum) 791{ 792 GLubyte token[100]; 793 GLint j; 794 795 /* Match 'f[' */ 796 if (!Parse_String(parseState, "f[")) 797 RETURN_ERROR1("Expected f["); 798 799 /* get <name> and look for match */ 800 if (!Parse_Token(parseState, token)) { 801 RETURN_ERROR; 802 } 803 for (j = 0; InputRegisters[j]; j++) { 804 if (_mesa_strcmp((const char *) token, InputRegisters[j]) == 0) { 805 *tempRegNum = j; 806 parseState->inputsRead |= (1 << j); 807 break; 808 } 809 } 810 if (!InputRegisters[j]) { 811 /* unknown input register label */ 812 RETURN_ERROR2("Invalid register name", token); 813 } 814 815 /* Match '[' */ 816 if (!Parse_String(parseState, "]")) 817 RETURN_ERROR1("Expected ]"); 818 819 return GL_TRUE; 820} 821 822 823static GLboolean 824Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum) 825{ 826 GLubyte token[100]; 827 GLint j; 828 829 /* Match "o[" */ 830 if (!Parse_String(parseState, "o[")) 831 RETURN_ERROR1("Expected o["); 832 833 /* Get output reg name */ 834 if (!Parse_Token(parseState, token)) 835 RETURN_ERROR; 836 837 /* try to match an output register name */ 838 for (j = 0; OutputRegisters[j]; j++) { 839 if (_mesa_strcmp((const char *) token, OutputRegisters[j]) == 0) { 840 static GLuint bothColors = (1 << FRAG_OUTPUT_COLR) | (1 << FRAG_OUTPUT_COLH); 841 *outputRegNum = j; 842 parseState->outputsWritten |= (1 << j); 843 if ((parseState->outputsWritten & bothColors) == bothColors) { 844 RETURN_ERROR1("Illegal to write to both o[COLR] and o[COLH]"); 845 } 846 break; 847 } 848 } 849 if (!OutputRegisters[j]) 850 RETURN_ERROR1("Invalid output register name"); 851 852 /* Match ']' */ 853 if (!Parse_String(parseState, "]")) 854 RETURN_ERROR1("Expected ]"); 855 856 return GL_TRUE; 857} 858 859 860static GLboolean 861Parse_MaskedDstReg(struct parse_state *parseState, 862 struct fp_dst_register *dstReg) 863{ 864 GLubyte token[100]; 865 866 /* Dst reg can be R<n>, H<n>, o[n], RC or HC */ 867 if (!Peek_Token(parseState, token)) 868 RETURN_ERROR; 869 870 if (_mesa_strcmp((const char *) token, "RC") == 0 || 871 _mesa_strcmp((const char *) token, "HC") == 0) { 872 /* a write-only register */ 873 dstReg->File = PROGRAM_WRITE_ONLY; 874 if (!Parse_DummyReg(parseState, &dstReg->Index)) 875 RETURN_ERROR; 876 } 877 else if (token[0] == 'R' || token[0] == 'H') { 878 /* a temporary register */ 879 dstReg->File = PROGRAM_TEMPORARY; 880 if (!Parse_TempReg(parseState, &dstReg->Index)) 881 RETURN_ERROR; 882 } 883 else if (token[0] == 'o') { 884 /* an output register */ 885 dstReg->File = PROGRAM_OUTPUT; 886 if (!Parse_OutputReg(parseState, &dstReg->Index)) 887 RETURN_ERROR; 888 } 889 else { 890 RETURN_ERROR1("Invalid destination register name"); 891 } 892 893 /* Parse optional write mask */ 894 if (Parse_String(parseState, ".")) { 895 /* got a mask */ 896 GLint k = 0; 897 898 if (!Parse_Token(parseState, token)) /* get xyzw writemask */ 899 RETURN_ERROR; 900 901 dstReg->WriteMask[0] = GL_FALSE; 902 dstReg->WriteMask[1] = GL_FALSE; 903 dstReg->WriteMask[2] = GL_FALSE; 904 dstReg->WriteMask[3] = GL_FALSE; 905 906 if (token[k] == 'x') { 907 dstReg->WriteMask[0] = GL_TRUE; 908 k++; 909 } 910 if (token[k] == 'y') { 911 dstReg->WriteMask[1] = GL_TRUE; 912 k++; 913 } 914 if (token[k] == 'z') { 915 dstReg->WriteMask[2] = GL_TRUE; 916 k++; 917 } 918 if (token[k] == 'w') { 919 dstReg->WriteMask[3] = GL_TRUE; 920 k++; 921 } 922 if (k == 0) { 923 RETURN_ERROR1("Invalid writemask character"); 924 } 925 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 (Parse_String(parseState, "(")) { 936 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".x|y|z|w) */ 937 /* ("EQ" | "GE" | "GT" | "LE" | "LT" | "NE" | "TR" | "FL".[xyzw]) */ 938 if (!Parse_CondCodeMask(parseState, dstReg)) 939 RETURN_ERROR; 940 941 if (!Parse_String(parseState, ")")) /* consume ")" */ 942 RETURN_ERROR1("Expected )"); 943 944 return GL_TRUE; 945 } 946 else { 947 /* no cond code mask */ 948 dstReg->CondMask = COND_TR; 949 dstReg->CondSwizzle[0] = 0; 950 dstReg->CondSwizzle[1] = 1; 951 dstReg->CondSwizzle[2] = 2; 952 dstReg->CondSwizzle[3] = 3; 953 return GL_TRUE; 954 } 955} 956 957 958/** 959 * Parse a vector source (register, constant, etc): 960 * <vectorSrc> ::= <absVectorSrc> 961 * | <baseVectorSrc> 962 * <absVectorSrc> ::= <negate> "|" <baseVectorSrc> "|" 963 */ 964static GLboolean 965Parse_VectorSrc(struct parse_state *parseState, 966 struct fp_src_register *srcReg) 967{ 968 GLfloat sign = 1.0F; 969 GLubyte token[100]; 970 971 /* 972 * First, take care of +/- and absolute value stuff. 973 */ 974 if (Parse_String(parseState, "-")) 975 sign = -1.0F; 976 else if (Parse_String(parseState, "+")) 977 sign = +1.0F; 978 979 if (Parse_String(parseState, "|")) { 980 srcReg->Abs = GL_TRUE; 981 srcReg->NegateAbs = (sign < 0.0F) ? GL_TRUE : GL_FALSE; 982 983 if (Parse_String(parseState, "-")) 984 srcReg->NegateBase = GL_TRUE; 985 else if (Parse_String(parseState, "+")) 986 srcReg->NegateBase = GL_FALSE; 987 else 988 srcReg->NegateBase = GL_FALSE; 989 } 990 else { 991 srcReg->Abs = GL_FALSE; 992 srcReg->NegateAbs = GL_FALSE; 993 srcReg->NegateBase = (sign < 0.0F) ? GL_TRUE : GL_FALSE; 994 } 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, &srcReg->Index)) 1006 RETURN_ERROR; 1007 } 1008 else if (token[0] == 'f') { 1009 /* XXX this might be an identier! */ 1010 srcReg->File = PROGRAM_INPUT; 1011 if (!Parse_FragReg(parseState, &srcReg->Index)) 1012 RETURN_ERROR; 1013 } 1014 else if (token[0] == 'p') { 1015 /* XXX this might be an identier! */ 1016 srcReg->File = PROGRAM_LOCAL_PARAM; 1017 if (!Parse_ProgramParamReg(parseState, &srcReg->Index)) 1018 RETURN_ERROR; 1019 } 1020 else if (IsLetter(token[0])){ 1021 GLubyte ident[100]; 1022 GLint paramIndex; 1023 if (!Parse_Identifier(parseState, ident)) 1024 RETURN_ERROR; 1025 paramIndex = _mesa_lookup_parameter_index(parseState->parameters, 1026 -1, (const char *) ident); 1027 if (paramIndex < 0) { 1028 RETURN_ERROR2("Undefined constant or parameter: ", ident); 1029 } 1030 srcReg->File = PROGRAM_NAMED_PARAM; 1031 srcReg->Index = paramIndex; 1032 } 1033 else if (IsDigit(token[0]) || token[0] == '-' || token[0] == '+' || token[0] == '.'){ 1034 /* literal scalar constant */ 1035 GLfloat values[4]; 1036 GLuint paramIndex; 1037 if (!Parse_ScalarConstant(parseState, values)) 1038 RETURN_ERROR; 1039 paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values); 1040 srcReg->File = PROGRAM_NAMED_PARAM; 1041 srcReg->Index = paramIndex; 1042 } 1043 else if (token[0] == '{'){ 1044 /* literal vector constant */ 1045 GLfloat values[4]; 1046 GLuint paramIndex; 1047 (void) Parse_String(parseState, "{"); 1048 if (!Parse_VectorConstant(parseState, values)) 1049 RETURN_ERROR; 1050 paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values); 1051 srcReg->File = PROGRAM_NAMED_PARAM; 1052 srcReg->Index = paramIndex; 1053 } 1054 else { 1055 RETURN_ERROR2("Invalid source register name", token); 1056 } 1057 1058 /* init swizzle fields */ 1059 srcReg->Swizzle[0] = 0; 1060 srcReg->Swizzle[1] = 1; 1061 srcReg->Swizzle[2] = 2; 1062 srcReg->Swizzle[3] = 3; 1063 1064 /* Look for optional swizzle suffix */ 1065 if (Parse_String(parseState, ".")) { 1066 if (!Parse_Token(parseState, token)) 1067 RETURN_ERROR; 1068 1069 if (!Parse_SwizzleSuffix(token, srcReg->Swizzle)) 1070 RETURN_ERROR1("Invalid swizzle suffix"); 1071 } 1072 1073 /* Finish absolute value */ 1074 if (srcReg->Abs && !Parse_String(parseState, "|")) { 1075 RETURN_ERROR1("Expected |"); 1076 } 1077 1078 return GL_TRUE; 1079} 1080 1081 1082static GLboolean 1083Parse_ScalarSrcReg(struct parse_state *parseState, 1084 struct fp_src_register *srcReg) 1085{ 1086 GLubyte token[100]; 1087 GLfloat sign = 1.0F; 1088 GLboolean needSuffix = GL_TRUE; 1089 1090 /* 1091 * First, take care of +/- and absolute value stuff. 1092 */ 1093 if (Parse_String(parseState, "-")) 1094 sign = -1.0F; 1095 else if (Parse_String(parseState, "+")) 1096 sign = +1.0F; 1097 1098 if (Parse_String(parseState, "|")) { 1099 srcReg->Abs = GL_TRUE; 1100 srcReg->NegateAbs = (sign < 0.0F) ? GL_TRUE : GL_FALSE; 1101 1102 if (Parse_String(parseState, "-")) 1103 srcReg->NegateBase = GL_TRUE; 1104 else if (Parse_String(parseState, "+")) 1105 srcReg->NegateBase = GL_FALSE; 1106 else 1107 srcReg->NegateBase = GL_FALSE; 1108 } 1109 else { 1110 srcReg->Abs = GL_FALSE; 1111 srcReg->NegateAbs = GL_FALSE; 1112 srcReg->NegateBase = (sign < 0.0F) ? GL_TRUE : GL_FALSE; 1113 } 1114 1115 if (!Peek_Token(parseState, token)) 1116 RETURN_ERROR; 1117 1118 /* Src reg can be R<n>, H<n> or a named fragment attrib */ 1119 if (token[0] == 'R' || token[0] == 'H') { 1120 srcReg->File = PROGRAM_TEMPORARY; 1121 if (!Parse_TempReg(parseState, &srcReg->Index)) 1122 RETURN_ERROR; 1123 } 1124 else if (token[0] == 'f') { 1125 srcReg->File = PROGRAM_INPUT; 1126 if (!Parse_FragReg(parseState, &srcReg->Index)) 1127 RETURN_ERROR; 1128 } 1129 else if (token[0] == '{') { 1130 /* vector literal */ 1131 GLfloat values[4]; 1132 GLuint paramIndex; 1133 (void) Parse_String(parseState, "{"); 1134 if (!Parse_VectorConstant(parseState, values)) 1135 RETURN_ERROR; 1136 paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values); 1137 srcReg->File = PROGRAM_NAMED_PARAM; 1138 srcReg->Index = paramIndex; 1139 } 1140 else if (IsDigit(token[0])) { 1141 /* scalar literal */ 1142 GLfloat values[4]; 1143 GLuint paramIndex; 1144 if (!Parse_ScalarConstant(parseState, values)) 1145 RETURN_ERROR; 1146 paramIndex = _mesa_add_unnamed_constant(parseState->parameters, values); 1147 srcReg->Index = paramIndex; 1148 srcReg->File = PROGRAM_NAMED_PARAM; 1149 needSuffix = GL_FALSE; 1150 } 1151 else { 1152 RETURN_ERROR2("Invalid scalar source argument", token); 1153 } 1154 1155 if (needSuffix) { 1156 /* parse .[xyzw] suffix */ 1157 if (!Parse_String(parseState, ".")) 1158 RETURN_ERROR1("Expected ."); 1159 1160 if (!Parse_Token(parseState, token)) 1161 RETURN_ERROR; 1162 1163 if (token[0] == 'x' && token[1] == 0) { 1164 srcReg->Swizzle[0] = 0; 1165 } 1166 else if (token[0] == 'y' && token[1] == 0) { 1167 srcReg->Swizzle[0] = 1; 1168 } 1169 else if (token[0] == 'z' && token[1] == 0) { 1170 srcReg->Swizzle[0] = 2; 1171 } 1172 else if (token[0] == 'w' && token[1] == 0) { 1173 srcReg->Swizzle[0] = 3; 1174 } 1175 else { 1176 RETURN_ERROR1("Invalid scalar source suffix"); 1177 } 1178 } 1179 else { 1180 srcReg->Swizzle[0] = 0; 1181 } 1182 srcReg->Swizzle[1] = srcReg->Swizzle[2] = srcReg->Swizzle[3] = 0; 1183 1184 /* Finish absolute value */ 1185 if (srcReg->Abs && !Parse_String(parseState, "|")) { 1186 RETURN_ERROR1("Expected |"); 1187 } 1188 1189 return GL_TRUE; 1190} 1191 1192 1193 1194static GLboolean 1195Parse_InstructionSequence(struct parse_state *parseState, 1196 struct fp_instruction program[]) 1197{ 1198 while (1) { 1199 struct fp_instruction *inst = program + parseState->numInst; 1200 struct instruction_pattern instMatch; 1201 GLubyte token[100]; 1202 1203 /* Initialize the instruction */ 1204 inst->SrcReg[0].File = (enum register_file) -1; 1205 inst->SrcReg[1].File = (enum register_file) -1; 1206 inst->SrcReg[2].File = (enum register_file) -1; 1207 inst->DstReg.File = (enum register_file) -1; 1208 inst->DstReg.CondSwizzle[0] = 0; 1209 inst->DstReg.CondSwizzle[1] = 1; 1210 inst->DstReg.CondSwizzle[2] = 2; 1211 inst->DstReg.CondSwizzle[3] = 3; 1212 1213 /* special instructions */ 1214 if (Parse_String(parseState, "DEFINE")) { 1215 GLubyte id[100]; 1216 GLfloat value[7]; /* yes, 7 to be safe */ 1217 if (!Parse_Identifier(parseState, id)) 1218 RETURN_ERROR; 1219 /* XXX make sure id is not a reserved identifer, like R9 */ 1220 if (!Parse_String(parseState, "=")) 1221 RETURN_ERROR1("Expected ="); 1222 if (!Parse_VectorOrScalarConstant(parseState, value)) 1223 RETURN_ERROR; 1224 if (!Parse_String(parseState, ";")) 1225 RETURN_ERROR1("Expected ;"); 1226 if (_mesa_lookup_parameter_index(parseState->parameters, 1227 -1, (const char *) id) >= 0) { 1228 RETURN_ERROR2(id, "already defined"); 1229 } 1230 _mesa_add_named_parameter(parseState->parameters, 1231 (const char *) id, value); 1232 } 1233 else if (Parse_String(parseState, "DECLARE")) { 1234 GLubyte id[100]; 1235 GLfloat value[7] = {0, 0, 0, 0, 0, 0, 0}; /* yes, to be safe */ 1236 if (!Parse_Identifier(parseState, id)) 1237 RETURN_ERROR; 1238 /* XXX make sure id is not a reserved identifer, like R9 */ 1239 if (Parse_String(parseState, "=")) { 1240 if (!Parse_VectorOrScalarConstant(parseState, value)) 1241 RETURN_ERROR; 1242 } 1243 if (!Parse_String(parseState, ";")) 1244 RETURN_ERROR1("Expected ;"); 1245 if (_mesa_lookup_parameter_index(parseState->parameters, 1246 -1, (const char *) id) >= 0) { 1247 RETURN_ERROR2(id, "already declared"); 1248 } 1249 _mesa_add_named_parameter(parseState->parameters, 1250 (const char *) id, value); 1251 } 1252 else if (Parse_String(parseState, "END")) { 1253 inst->Opcode = FP_OPCODE_END; 1254 inst->StringPos = parseState->curLine - parseState->start; 1255 assert(inst->StringPos >= 0); 1256 parseState->numInst++; 1257 if (Parse_Token(parseState, token)) { 1258 RETURN_ERROR1("Code after END opcode."); 1259 } 1260 break; 1261 } 1262 else { 1263 /* general/arithmetic instruction */ 1264 1265 /* get token */ 1266 if (!Parse_Token(parseState, token)) { 1267 RETURN_ERROR1("Missing END instruction."); 1268 } 1269 1270 /* try to find matching instuction */ 1271 instMatch = MatchInstruction(token); 1272 if (instMatch.opcode < 0) { 1273 /* bad instruction name */ 1274 RETURN_ERROR2("Unexpected token: ", token); 1275 } 1276 1277 inst->Opcode = instMatch.opcode; 1278 inst->Precision = instMatch.suffixes & (_R | _H | _X); 1279 inst->Saturate = (instMatch.suffixes & (_S)) ? GL_TRUE : GL_FALSE; 1280 inst->UpdateCondRegister = (instMatch.suffixes & (_C)) ? GL_TRUE : GL_FALSE; 1281 inst->StringPos = parseState->curLine - parseState->start; 1282 assert(inst->StringPos >= 0); 1283 1284 /* 1285 * parse the input and output operands 1286 */ 1287 if (instMatch.outputs == OUTPUT_S || instMatch.outputs == OUTPUT_V) { 1288 if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) 1289 RETURN_ERROR; 1290 if (!Parse_String(parseState, ",")) 1291 RETURN_ERROR1("Expected ,"); 1292 } 1293 else if (instMatch.outputs == OUTPUT_NONE) { 1294 ASSERT(instMatch.opcode == FP_OPCODE_KIL); 1295 /* This is a little weird, the cond code info is in the dest register */ 1296 if (!Parse_CondCodeMask(parseState, &inst->DstReg)) 1297 RETURN_ERROR; 1298 } 1299 1300 if (instMatch.inputs == INPUT_1V) { 1301 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) 1302 RETURN_ERROR; 1303 } 1304 else if (instMatch.inputs == INPUT_2V) { 1305 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) 1306 RETURN_ERROR; 1307 if (!Parse_String(parseState, ",")) 1308 RETURN_ERROR1("Expected ,"); 1309 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) 1310 RETURN_ERROR; 1311 } 1312 else if (instMatch.inputs == INPUT_3V) { 1313 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) 1314 RETURN_ERROR; 1315 if (!Parse_String(parseState, ",")) 1316 RETURN_ERROR1("Expected ,"); 1317 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) 1318 RETURN_ERROR; 1319 if (!Parse_String(parseState, ",")) 1320 RETURN_ERROR1("Expected ,"); 1321 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2])) 1322 RETURN_ERROR; 1323 } 1324 else if (instMatch.inputs == INPUT_1S) { 1325 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) 1326 RETURN_ERROR; 1327 } 1328 else if (instMatch.inputs == INPUT_2S) { 1329 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) 1330 RETURN_ERROR; 1331 if (!Parse_String(parseState, ",")) 1332 RETURN_ERROR1("Expected ,"); 1333 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[1])) 1334 RETURN_ERROR; 1335 } 1336 else if (instMatch.inputs == INPUT_CC) { 1337 /* XXX to-do */ 1338 } 1339 else if (instMatch.inputs == INPUT_1V_T) { 1340 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) 1341 RETURN_ERROR; 1342 if (!Parse_String(parseState, ",")) 1343 RETURN_ERROR1("Expected ,"); 1344 if (!Parse_TextureImageId(parseState, &inst->TexSrcUnit, 1345 &inst->TexSrcBit)) 1346 RETURN_ERROR; 1347 } 1348 else if (instMatch.inputs == INPUT_3V_T) { 1349 if (!Parse_VectorSrc(parseState, &inst->SrcReg[0])) 1350 RETURN_ERROR; 1351 if (!Parse_String(parseState, ",")) 1352 RETURN_ERROR1("Expected ,"); 1353 if (!Parse_VectorSrc(parseState, &inst->SrcReg[1])) 1354 RETURN_ERROR; 1355 if (!Parse_String(parseState, ",")) 1356 RETURN_ERROR1("Expected ,"); 1357 if (!Parse_VectorSrc(parseState, &inst->SrcReg[2])) 1358 RETURN_ERROR; 1359 if (!Parse_String(parseState, ",")) 1360 RETURN_ERROR1("Expected ,"); 1361 if (!Parse_TextureImageId(parseState, &inst->TexSrcUnit, 1362 &inst->TexSrcBit)) 1363 RETURN_ERROR; 1364 } 1365 1366 /* end of statement semicolon */ 1367 if (!Parse_String(parseState, ";")) 1368 RETURN_ERROR1("Expected ;"); 1369 1370 parseState->numInst++; 1371 1372 if (parseState->numInst >= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS) 1373 RETURN_ERROR1("Program too long"); 1374 } 1375 } 1376 return GL_TRUE; 1377} 1378 1379 1380 1381/** 1382 * Parse/compile the 'str' returning the compiled 'program'. 1383 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos 1384 * indicates the position of the error in 'str'. 1385 */ 1386void 1387_mesa_parse_nv_fragment_program(GLcontext *ctx, GLenum dstTarget, 1388 const GLubyte *str, GLsizei len, 1389 struct fragment_program *program) 1390{ 1391 struct parse_state parseState; 1392 struct fp_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS]; 1393 struct fp_instruction *newInst; 1394 GLenum target; 1395 GLubyte *programString; 1396 1397 /* Make a null-terminated copy of the program string */ 1398 programString = (GLubyte *) MALLOC(len + 1); 1399 if (!programString) { 1400 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); 1401 return; 1402 } 1403 MEMCPY(programString, str, len); 1404 programString[len] = 0; 1405 1406 /* Get ready to parse */ 1407 _mesa_bzero(&parseState, sizeof(struct parse_state)); 1408 parseState.ctx = ctx; 1409 parseState.start = programString; 1410 parseState.program = program; 1411 parseState.numInst = 0; 1412 parseState.curLine = programString; 1413 parseState.parameters = _mesa_new_parameter_list(); 1414 1415 /* Reset error state */ 1416 _mesa_set_program_error(ctx, -1, NULL); 1417 1418 /* check the program header */ 1419 if (_mesa_strncmp((const char *) programString, "!!FP1.0", 7) == 0) { 1420 target = GL_FRAGMENT_PROGRAM_NV; 1421 parseState.pos = programString + 7; 1422 } 1423 else if (_mesa_strncmp((const char *) programString, "!!FCP1.0", 8) == 0) { 1424 /* fragment / register combiner program - not supported */ 1425 _mesa_set_program_error(ctx, 0, "Invalid fragment program header"); 1426 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); 1427 return; 1428 } 1429 else { 1430 /* invalid header */ 1431 _mesa_set_program_error(ctx, 0, "Invalid fragment program header"); 1432 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); 1433 return; 1434 } 1435 1436 /* make sure target and header match */ 1437 if (target != dstTarget) { 1438 _mesa_error(ctx, GL_INVALID_OPERATION, 1439 "glLoadProgramNV(target mismatch 0x%x != 0x%x)", 1440 target, dstTarget); 1441 return; 1442 } 1443 1444 if (Parse_InstructionSequence(&parseState, instBuffer)) { 1445 GLuint u; 1446 /* successful parse! */ 1447 1448 if (parseState.outputsWritten == 0) { 1449 /* must write at least one output! */ 1450 _mesa_error(ctx, GL_INVALID_OPERATION, 1451 "Invalid fragment program - no outputs written."); 1452 return; 1453 } 1454 1455 /* copy the compiled instructions */ 1456 assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS); 1457 newInst = (struct fp_instruction *) 1458 MALLOC(parseState.numInst * sizeof(struct fp_instruction)); 1459 if (!newInst) { 1460 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); 1461 return; /* out of memory */ 1462 } 1463 MEMCPY(newInst, instBuffer, 1464 parseState.numInst * sizeof(struct fp_instruction)); 1465 1466 /* install the program */ 1467 program->Base.Target = target; 1468 if (program->Base.String) { 1469 FREE(program->Base.String); 1470 } 1471 program->Base.String = programString; 1472 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB; 1473 if (program->Instructions) { 1474 FREE(program->Instructions); 1475 } 1476 program->Instructions = newInst; 1477 program->InputsRead = parseState.inputsRead; 1478 program->OutputsWritten = parseState.outputsWritten; 1479 for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++) 1480 program->TexturesUsed[u] = parseState.texturesUsed[u]; 1481 1482 /* save program parameters */ 1483 program->Parameters = parseState.parameters; 1484 1485 /* allocate registers for declared program parameters */ 1486#if 00 1487 _mesa_assign_program_registers(&(program->SymbolTable)); 1488#endif 1489 1490#ifdef DEBUG 1491 _mesa_printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id); 1492 _mesa_print_nv_fragment_program(program); 1493 _mesa_printf("----------------------------------\n"); 1494#endif 1495 } 1496 else { 1497 /* Error! */ 1498 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV"); 1499 /* NOTE: _mesa_set_program_error would have been called already */ 1500 } 1501} 1502 1503 1504static void 1505PrintSrcReg(const struct fragment_program *program, 1506 const struct fp_src_register *src) 1507{ 1508 static const char comps[5] = "xyzw"; 1509 1510 if (src->NegateAbs) { 1511 _mesa_printf("-"); 1512 } 1513 if (src->Abs) { 1514 _mesa_printf("|"); 1515 } 1516 if (src->NegateBase) { 1517 _mesa_printf("-"); 1518 } 1519 if (src->File == PROGRAM_NAMED_PARAM) { 1520 if (program->Parameters->Parameters[src->Index].Type == CONSTANT) { 1521 printf("{%g, %g, %g, %g}", 1522 program->Parameters->Parameters[src->Index].Values[0], 1523 program->Parameters->Parameters[src->Index].Values[1], 1524 program->Parameters->Parameters[src->Index].Values[2], 1525 program->Parameters->Parameters[src->Index].Values[3]); 1526 } 1527 else { 1528 ASSERT(program->Parameters->Parameters[src->Index].Type 1529 == NAMED_PARAMETER); 1530 printf("%s", program->Parameters->Parameters[src->Index].Name); 1531 } 1532 } 1533 else if (src->File == PROGRAM_OUTPUT) { 1534 _mesa_printf("o[%s]", OutputRegisters[src->Index]); 1535 } 1536 else if (src->File == PROGRAM_INPUT) { 1537 _mesa_printf("f[%s]", InputRegisters[src->Index]); 1538 } 1539 else if (src->File == PROGRAM_LOCAL_PARAM) { 1540 _mesa_printf("p[%d]", src->Index); 1541 } 1542 else if (src->File == PROGRAM_TEMPORARY) { 1543 if (src->Index >= 32) 1544 _mesa_printf("H%d", src->Index); 1545 else 1546 _mesa_printf("R%d", src->Index); 1547 } 1548 else if (src->File == PROGRAM_WRITE_ONLY) { 1549 _mesa_printf("%cC", "HR"[src->Index]); 1550 } 1551 else { 1552 _mesa_problem(NULL, "Invalid fragment register %d", src->Index); 1553 return; 1554 } 1555 if (src->Swizzle[0] == src->Swizzle[1] && 1556 src->Swizzle[0] == src->Swizzle[2] && 1557 src->Swizzle[0] == src->Swizzle[3]) { 1558 _mesa_printf(".%c", comps[src->Swizzle[0]]); 1559 } 1560 else if (src->Swizzle[0] != 0 || 1561 src->Swizzle[1] != 1 || 1562 src->Swizzle[2] != 2 || 1563 src->Swizzle[3] != 3) { 1564 _mesa_printf(".%c%c%c%c", 1565 comps[src->Swizzle[0]], 1566 comps[src->Swizzle[1]], 1567 comps[src->Swizzle[2]], 1568 comps[src->Swizzle[3]]); 1569 } 1570 if (src->Abs) { 1571 _mesa_printf("|"); 1572 } 1573} 1574 1575static void 1576PrintTextureSrc(const struct fp_instruction *inst) 1577{ 1578 _mesa_printf("TEX%d, ", inst->TexSrcUnit); 1579 switch (inst->TexSrcBit) { 1580 case TEXTURE_1D_BIT: 1581 _mesa_printf("1D"); 1582 break; 1583 case TEXTURE_2D_BIT: 1584 _mesa_printf("2D"); 1585 break; 1586 case TEXTURE_3D_BIT: 1587 _mesa_printf("3D"); 1588 break; 1589 case TEXTURE_RECT_BIT: 1590 _mesa_printf("RECT"); 1591 break; 1592 case TEXTURE_CUBE_BIT: 1593 _mesa_printf("CUBE"); 1594 break; 1595 default: 1596 _mesa_problem(NULL, "Invalid textue target in PrintTextureSrc"); 1597 } 1598} 1599 1600static void 1601PrintCondCode(const struct fp_dst_register *dst) 1602{ 1603 static const char *comps = "xyzw"; 1604 static const char *ccString[] = { 1605 "??", "GT", "EQ", "LT", "UN", "GE", "LE", "NE", "TR", "FL", "??" 1606 }; 1607 1608 _mesa_printf("%s", ccString[dst->CondMask]); 1609 if (dst->CondSwizzle[0] == dst->CondSwizzle[1] && 1610 dst->CondSwizzle[0] == dst->CondSwizzle[2] && 1611 dst->CondSwizzle[0] == dst->CondSwizzle[3]) { 1612 _mesa_printf(".%c", comps[dst->CondSwizzle[0]]); 1613 } 1614 else if (dst->CondSwizzle[0] != 0 || 1615 dst->CondSwizzle[1] != 1 || 1616 dst->CondSwizzle[2] != 2 || 1617 dst->CondSwizzle[3] != 3) { 1618 _mesa_printf(".%c%c%c%c", 1619 comps[dst->CondSwizzle[0]], 1620 comps[dst->CondSwizzle[1]], 1621 comps[dst->CondSwizzle[2]], 1622 comps[dst->CondSwizzle[3]]); 1623 } 1624} 1625 1626 1627static void 1628PrintDstReg(const struct fp_dst_register *dst) 1629{ 1630 GLint w = dst->WriteMask[0] + dst->WriteMask[1] 1631 + dst->WriteMask[2] + dst->WriteMask[3]; 1632 1633 if (dst->File == PROGRAM_OUTPUT) { 1634 _mesa_printf("o[%s]", OutputRegisters[dst->Index]); 1635 } 1636 else if (dst->File == PROGRAM_TEMPORARY) { 1637 if (dst->Index >= 32) 1638 _mesa_printf("H%d", dst->Index); 1639 else 1640 _mesa_printf("R%d", dst->Index); 1641 } 1642 else if (dst->File == PROGRAM_LOCAL_PARAM) { 1643 _mesa_printf("p[%d]", dst->Index); 1644 } 1645 else if (dst->File == PROGRAM_WRITE_ONLY) { 1646 _mesa_printf("%cC", "HR"[dst->Index]); 1647 } 1648 else { 1649 _mesa_printf("???"); 1650 } 1651 1652 if (w != 0 && w != 4) { 1653 _mesa_printf("."); 1654 if (dst->WriteMask[0]) 1655 _mesa_printf("x"); 1656 if (dst->WriteMask[1]) 1657 _mesa_printf("y"); 1658 if (dst->WriteMask[2]) 1659 _mesa_printf("z"); 1660 if (dst->WriteMask[3]) 1661 _mesa_printf("w"); 1662 } 1663 1664 if (dst->CondMask != COND_TR || 1665 dst->CondSwizzle[0] != 0 || 1666 dst->CondSwizzle[1] != 1 || 1667 dst->CondSwizzle[2] != 2 || 1668 dst->CondSwizzle[3] != 3) { 1669 _mesa_printf(" ("); 1670 PrintCondCode(dst); 1671 _mesa_printf(")"); 1672 } 1673} 1674 1675 1676/** 1677 * Print (unparse) the given vertex program. Just for debugging. 1678 */ 1679void 1680_mesa_print_nv_fragment_program(const struct fragment_program *program) 1681{ 1682 const struct fp_instruction *inst; 1683 1684 for (inst = program->Instructions; inst->Opcode != FP_OPCODE_END; inst++) { 1685 int i; 1686 for (i = 0; Instructions[i].name; i++) { 1687 if (inst->Opcode == Instructions[i].opcode) { 1688 /* print instruction name */ 1689 _mesa_printf("%s", Instructions[i].name); 1690 if (inst->Precision == FLOAT16) 1691 _mesa_printf("H"); 1692 else if (inst->Precision == FIXED12) 1693 _mesa_printf("X"); 1694 if (inst->UpdateCondRegister) 1695 _mesa_printf("C"); 1696 if (inst->Saturate) 1697 _mesa_printf("_SAT"); 1698 _mesa_printf(" "); 1699 1700 if (Instructions[i].inputs == INPUT_CC) { 1701 PrintCondCode(&inst->DstReg); 1702 } 1703 else if (Instructions[i].outputs == OUTPUT_V || 1704 Instructions[i].outputs == OUTPUT_S) { 1705 /* print dest register */ 1706 PrintDstReg(&inst->DstReg); 1707 _mesa_printf(", "); 1708 } 1709 1710 /* print source register(s) */ 1711 if (Instructions[i].inputs == INPUT_1V || 1712 Instructions[i].inputs == INPUT_1S) { 1713 PrintSrcReg(program, &inst->SrcReg[0]); 1714 } 1715 else if (Instructions[i].inputs == INPUT_2V || 1716 Instructions[i].inputs == INPUT_2S) { 1717 PrintSrcReg(program, &inst->SrcReg[0]); 1718 _mesa_printf(", "); 1719 PrintSrcReg(program, &inst->SrcReg[1]); 1720 } 1721 else if (Instructions[i].inputs == INPUT_3V) { 1722 PrintSrcReg(program, &inst->SrcReg[0]); 1723 _mesa_printf(", "); 1724 PrintSrcReg(program, &inst->SrcReg[1]); 1725 _mesa_printf(", "); 1726 PrintSrcReg(program, &inst->SrcReg[2]); 1727 } 1728 else if (Instructions[i].inputs == INPUT_1V_T) { 1729 PrintSrcReg(program, &inst->SrcReg[0]); 1730 _mesa_printf(", "); 1731 PrintTextureSrc(inst); 1732 } 1733 else if (Instructions[i].inputs == INPUT_3V_T) { 1734 PrintSrcReg(program, &inst->SrcReg[0]); 1735 _mesa_printf(", "); 1736 PrintSrcReg(program, &inst->SrcReg[1]); 1737 _mesa_printf(", "); 1738 PrintSrcReg(program, &inst->SrcReg[2]); 1739 _mesa_printf(", "); 1740 PrintTextureSrc(inst); 1741 } 1742 _mesa_printf(";\n"); 1743 break; 1744 } 1745 } 1746 if (!Instructions[i].name) { 1747 _mesa_printf("Invalid opcode %d\n", inst->Opcode); 1748 } 1749 } 1750 _mesa_printf("END\n"); 1751} 1752 1753 1754const char * 1755_mesa_nv_fragment_input_register_name(GLuint i) 1756{ 1757 ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_INPUTS); 1758 return InputRegisters[i]; 1759} 1760 1761 1762const char * 1763_mesa_nv_fragment_output_register_name(GLuint i) 1764{ 1765 ASSERT(i < MAX_NV_FRAGMENT_PROGRAM_OUTPUTS); 1766 return OutputRegisters[i]; 1767} 1768