1 /* 2 * Mesa 3-D graphics library 3 * Version: 6.5.2 4 * 5 * Copyright (C) 1999-2006 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 nvvertparse.c 27 * NVIDIA vertex program parser. 28 * \author Brian Paul 29 */ 30 31 /* 32 * Regarding GL_NV_vertex_program, GL_NV_vertex_program1_1: 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/nvprogram.h" 44 #include "nvvertparse.h" 45 #include "prog_instruction.h" 46 #include "prog_parameter.h" 47 #include "prog_print.h" 48 #include "program.h" 49 50 51 /** 52 * Current parsing state. This structure is passed among the parsing 53 * functions and keeps track of the current parser position and various 54 * program attributes. 55 */ 56 struct parse_state { 57 struct gl_context *ctx; 58 const GLubyte *start; 59 const GLubyte *pos; 60 const GLubyte *curLine; 61 GLboolean isStateProgram; 62 GLboolean isPositionInvariant; 63 GLboolean isVersion1_1; 64 GLbitfield inputsRead; 65 GLbitfield outputsWritten; 66 GLboolean anyProgRegsWritten; 67 GLboolean indirectRegisterFiles; 68 GLuint numInst; /* number of instructions parsed */ 69 }; 70 71 72 /* 73 * Called whenever we find an error during parsing. 74 */ 75 static void 76 record_error(struct parse_state *parseState, const char *msg, int lineNo) 77 { 78 #ifdef DEBUG 79 GLint line, column; 80 const GLubyte *lineStr; 81 lineStr = _mesa_find_line_column(parseState->start, 82 parseState->pos, &line, &column); 83 _mesa_debug(parseState->ctx, 84 "nvfragparse.c(%d): line %d, column %d:%s (%s)\n", 85 lineNo, line, column, (char *) lineStr, msg); 86 free((void *) lineStr); 87 #else 88 (void) lineNo; 89 #endif 90 91 /* Check that no error was already recorded. Only record the first one. */ 92 if (parseState->ctx->Program.ErrorString[0] == 0) { 93 _mesa_set_program_error(parseState->ctx, 94 parseState->pos - parseState->start, 95 msg); 96 } 97 } 98 99 100 #define RETURN_ERROR \ 101 do { \ 102 record_error(parseState, "Unexpected end of input.", __LINE__); \ 103 return GL_FALSE; \ 104 } while(0) 105 106 #define RETURN_ERROR1(msg) \ 107 do { \ 108 record_error(parseState, msg, __LINE__); \ 109 return GL_FALSE; \ 110 } while(0) 111 112 #define RETURN_ERROR2(msg1, msg2) \ 113 do { \ 114 char err[1000]; \ 115 sprintf(err, "%s %s", msg1, msg2); \ 116 record_error(parseState, err, __LINE__); \ 117 return GL_FALSE; \ 118 } while(0) 119 120 121 122 123 124 static GLboolean IsLetter(GLubyte b) 125 { 126 return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z'); 127 } 128 129 130 static GLboolean IsDigit(GLubyte b) 131 { 132 return b >= '0' && b <= '9'; 133 } 134 135 136 static GLboolean IsWhitespace(GLubyte b) 137 { 138 return b == ' ' || b == '\t' || b == '\n' || b == '\r'; 139 } 140 141 142 /** 143 * Starting at 'str' find the next token. A token can be an integer, 144 * an identifier or punctuation symbol. 145 * \return <= 0 we found an error, else, return number of characters parsed. 146 */ 147 static GLint 148 GetToken(struct parse_state *parseState, GLubyte *token) 149 { 150 const GLubyte *str = parseState->pos; 151 GLint i = 0, j = 0; 152 153 token[0] = 0; 154 155 /* skip whitespace and comments */ 156 while (str[i] && (IsWhitespace(str[i]) || str[i] == '#')) { 157 if (str[i] == '#') { 158 /* skip comment */ 159 while (str[i] && (str[i] != '\n' && str[i] != '\r')) { 160 i++; 161 } 162 if (str[i] == '\n' || str[i] == '\r') 163 parseState->curLine = str + i + 1; 164 } 165 else { 166 /* skip whitespace */ 167 if (str[i] == '\n' || str[i] == '\r') 168 parseState->curLine = str + i + 1; 169 i++; 170 } 171 } 172 173 if (str[i] == 0) 174 return -i; 175 176 /* try matching an integer */ 177 while (str[i] && IsDigit(str[i])) { 178 token[j++] = str[i++]; 179 } 180 if (j > 0 || !str[i]) { 181 token[j] = 0; 182 return i; 183 } 184 185 /* try matching an identifier */ 186 if (IsLetter(str[i])) { 187 while (str[i] && (IsLetter(str[i]) || IsDigit(str[i]))) { 188 token[j++] = str[i++]; 189 } 190 token[j] = 0; 191 return i; 192 } 193 194 /* punctuation character */ 195 if (str[i]) { 196 token[0] = str[i++]; 197 token[1] = 0; 198 return i; 199 } 200 201 /* end of input */ 202 token[0] = 0; 203 return i; 204 } 205 206 207 /** 208 * Get next token from input stream and increment stream pointer past token. 209 */ 210 static GLboolean 211 Parse_Token(struct parse_state *parseState, GLubyte *token) 212 { 213 GLint i; 214 i = GetToken(parseState, token); 215 if (i <= 0) { 216 parseState->pos += (-i); 217 return GL_FALSE; 218 } 219 parseState->pos += i; 220 return GL_TRUE; 221 } 222 223 224 /** 225 * Get next token from input stream but don't increment stream pointer. 226 */ 227 static GLboolean 228 Peek_Token(struct parse_state *parseState, GLubyte *token) 229 { 230 GLint i, len; 231 i = GetToken(parseState, token); 232 if (i <= 0) { 233 parseState->pos += (-i); 234 return GL_FALSE; 235 } 236 len = (GLint) strlen((const char *) token); 237 parseState->pos += (i - len); 238 return GL_TRUE; 239 } 240 241 242 /** 243 * Try to match 'pattern' as the next token after any whitespace/comments. 244 * Advance the current parsing position only if we match the pattern. 245 * \return GL_TRUE if pattern is matched, GL_FALSE otherwise. 246 */ 247 static GLboolean 248 Parse_String(struct parse_state *parseState, const char *pattern) 249 { 250 const GLubyte *m; 251 GLint i; 252 253 /* skip whitespace and comments */ 254 while (IsWhitespace(*parseState->pos) || *parseState->pos == '#') { 255 if (*parseState->pos == '#') { 256 while (*parseState->pos && (*parseState->pos != '\n' && *parseState->pos != '\r')) { 257 parseState->pos += 1; 258 } 259 if (*parseState->pos == '\n' || *parseState->pos == '\r') 260 parseState->curLine = parseState->pos + 1; 261 } 262 else { 263 /* skip whitespace */ 264 if (*parseState->pos == '\n' || *parseState->pos == '\r') 265 parseState->curLine = parseState->pos + 1; 266 parseState->pos += 1; 267 } 268 } 269 270 /* Try to match the pattern */ 271 m = parseState->pos; 272 for (i = 0; pattern[i]; i++) { 273 if (*m != (GLubyte) pattern[i]) 274 return GL_FALSE; 275 m += 1; 276 } 277 parseState->pos = m; 278 279 return GL_TRUE; /* success */ 280 } 281 282 283 /**********************************************************************/ 284 285 static const char *InputRegisters[MAX_NV_VERTEX_PROGRAM_INPUTS + 1] = { 286 "OPOS", "WGHT", "NRML", "COL0", "COL1", "FOGC", "6", "7", 287 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL 288 }; 289 290 static const char *OutputRegisters[MAX_NV_VERTEX_PROGRAM_OUTPUTS + 1] = { 291 "HPOS", "COL0", "COL1", "FOGC", 292 "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", 293 "PSIZ", "BFC0", "BFC1", NULL 294 }; 295 296 297 298 /** 299 * Parse a temporary register: Rnn 300 */ 301 static GLboolean 302 Parse_TempReg(struct parse_state *parseState, GLint *tempRegNum) 303 { 304 GLubyte token[100]; 305 306 /* Should be 'R##' */ 307 if (!Parse_Token(parseState, token)) 308 RETURN_ERROR; 309 if (token[0] != 'R') 310 RETURN_ERROR1("Expected R##"); 311 312 if (IsDigit(token[1])) { 313 GLint reg = atoi((char *) (token + 1)); 314 if (reg >= MAX_NV_VERTEX_PROGRAM_TEMPS) 315 RETURN_ERROR1("Bad temporary register name"); 316 *tempRegNum = reg; 317 } 318 else { 319 RETURN_ERROR1("Bad temporary register name"); 320 } 321 322 return GL_TRUE; 323 } 324 325 326 /** 327 * Parse address register "A0.x" 328 */ 329 static GLboolean 330 Parse_AddrReg(struct parse_state *parseState) 331 { 332 /* match 'A0' */ 333 if (!Parse_String(parseState, "A0")) 334 RETURN_ERROR; 335 336 /* match '.' */ 337 if (!Parse_String(parseState, ".")) 338 RETURN_ERROR; 339 340 /* match 'x' */ 341 if (!Parse_String(parseState, "x")) 342 RETURN_ERROR; 343 344 return GL_TRUE; 345 } 346 347 348 /** 349 * Parse absolute program parameter register "c[##]" 350 */ 351 static GLboolean 352 Parse_AbsParamReg(struct parse_state *parseState, GLint *regNum) 353 { 354 GLubyte token[100]; 355 356 if (!Parse_String(parseState, "c")) 357 RETURN_ERROR; 358 359 if (!Parse_String(parseState, "[")) 360 RETURN_ERROR; 361 362 if (!Parse_Token(parseState, token)) 363 RETURN_ERROR; 364 365 if (IsDigit(token[0])) { 366 /* a numbered program parameter register */ 367 GLint reg = atoi((char *) token); 368 if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS) 369 RETURN_ERROR1("Bad program parameter number"); 370 *regNum = reg; 371 } 372 else { 373 RETURN_ERROR; 374 } 375 376 if (!Parse_String(parseState, "]")) 377 RETURN_ERROR; 378 379 return GL_TRUE; 380 } 381 382 383 static GLboolean 384 Parse_ParamReg(struct parse_state *parseState, struct prog_src_register *srcReg) 385 { 386 GLubyte token[100]; 387 388 if (!Parse_String(parseState, "c")) 389 RETURN_ERROR; 390 391 if (!Parse_String(parseState, "[")) 392 RETURN_ERROR; 393 394 if (!Peek_Token(parseState, token)) 395 RETURN_ERROR; 396 397 if (IsDigit(token[0])) { 398 /* a numbered program parameter register */ 399 GLint reg; 400 (void) Parse_Token(parseState, token); 401 reg = atoi((char *) token); 402 if (reg >= MAX_NV_VERTEX_PROGRAM_PARAMS) 403 RETURN_ERROR1("Bad program parameter number"); 404 srcReg->File = PROGRAM_ENV_PARAM; 405 srcReg->Index = reg; 406 } 407 else if (strcmp((const char *) token, "A0") == 0) { 408 /* address register "A0.x" */ 409 if (!Parse_AddrReg(parseState)) 410 RETURN_ERROR; 411 412 srcReg->RelAddr = GL_TRUE; 413 srcReg->File = PROGRAM_ENV_PARAM; 414 parseState->indirectRegisterFiles |= (1 << srcReg->File); 415 /* Look for +/-N offset */ 416 if (!Peek_Token(parseState, token)) 417 RETURN_ERROR; 418 419 if (token[0] == '-' || token[0] == '+') { 420 const GLubyte sign = token[0]; 421 (void) Parse_Token(parseState, token); /* consume +/- */ 422 423 /* an integer should be next */ 424 if (!Parse_Token(parseState, token)) 425 RETURN_ERROR; 426 427 if (IsDigit(token[0])) { 428 const GLint k = atoi((char *) token); 429 if (sign == '-') { 430 if (k > 64) 431 RETURN_ERROR1("Bad address offset"); 432 srcReg->Index = -k; 433 } 434 else { 435 if (k > 63) 436 RETURN_ERROR1("Bad address offset"); 437 srcReg->Index = k; 438 } 439 } 440 else { 441 RETURN_ERROR; 442 } 443 } 444 else { 445 /* probably got a ']', catch it below */ 446 } 447 } 448 else { 449 RETURN_ERROR; 450 } 451 452 /* Match closing ']' */ 453 if (!Parse_String(parseState, "]")) 454 RETURN_ERROR; 455 456 return GL_TRUE; 457 } 458 459 460 /** 461 * Parse v[#] or v[<name>] 462 */ 463 static GLboolean 464 Parse_AttribReg(struct parse_state *parseState, GLint *tempRegNum) 465 { 466 GLubyte token[100]; 467 GLint j; 468 469 /* Match 'v' */ 470 if (!Parse_String(parseState, "v")) 471 RETURN_ERROR; 472 473 /* Match '[' */ 474 if (!Parse_String(parseState, "[")) 475 RETURN_ERROR; 476 477 /* match number or named register */ 478 if (!Parse_Token(parseState, token)) 479 RETURN_ERROR; 480 481 if (parseState->isStateProgram && token[0] != '0') 482 RETURN_ERROR1("Only v[0] accessible in vertex state programs"); 483 484 if (IsDigit(token[0])) { 485 GLint reg = atoi((char *) token); 486 if (reg >= MAX_NV_VERTEX_PROGRAM_INPUTS) 487 RETURN_ERROR1("Bad vertex attribute register name"); 488 *tempRegNum = reg; 489 } 490 else { 491 for (j = 0; InputRegisters[j]; j++) { 492 if (strcmp((const char *) token, InputRegisters[j]) == 0) { 493 *tempRegNum = j; 494 break; 495 } 496 } 497 if (!InputRegisters[j]) { 498 /* unknown input register label */ 499 RETURN_ERROR2("Bad register name", token); 500 } 501 } 502 503 /* Match '[' */ 504 if (!Parse_String(parseState, "]")) 505 RETURN_ERROR; 506 507 return GL_TRUE; 508 } 509 510 511 static GLboolean 512 Parse_OutputReg(struct parse_state *parseState, GLint *outputRegNum) 513 { 514 GLubyte token[100]; 515 GLint start, j; 516 517 /* Match 'o' */ 518 if (!Parse_String(parseState, "o")) 519 RETURN_ERROR; 520 521 /* Match '[' */ 522 if (!Parse_String(parseState, "[")) 523 RETURN_ERROR; 524 525 /* Get output reg name */ 526 if (!Parse_Token(parseState, token)) 527 RETURN_ERROR; 528 529 if (parseState->isPositionInvariant) 530 start = 1; /* skip HPOS register name */ 531 else 532 start = 0; 533 534 /* try to match an output register name */ 535 for (j = start; OutputRegisters[j]; j++) { 536 if (strcmp((const char *) token, OutputRegisters[j]) == 0) { 537 *outputRegNum = j; 538 break; 539 } 540 } 541 if (!OutputRegisters[j]) 542 RETURN_ERROR1("Unrecognized output register name"); 543 544 /* Match ']' */ 545 if (!Parse_String(parseState, "]")) 546 RETURN_ERROR1("Expected ]"); 547 548 return GL_TRUE; 549 } 550 551 552 static GLboolean 553 Parse_MaskedDstReg(struct parse_state *parseState, struct prog_dst_register *dstReg) 554 { 555 GLubyte token[100]; 556 GLint idx; 557 558 /* Dst reg can be R<n> or o[n] */ 559 if (!Peek_Token(parseState, token)) 560 RETURN_ERROR; 561 562 if (token[0] == 'R') { 563 /* a temporary register */ 564 dstReg->File = PROGRAM_TEMPORARY; 565 if (!Parse_TempReg(parseState, &idx)) 566 RETURN_ERROR; 567 dstReg->Index = idx; 568 } 569 else if (!parseState->isStateProgram && token[0] == 'o') { 570 /* an output register */ 571 dstReg->File = PROGRAM_OUTPUT; 572 if (!Parse_OutputReg(parseState, &idx)) 573 RETURN_ERROR; 574 dstReg->Index = idx; 575 } 576 else if (parseState->isStateProgram && token[0] == 'c' && 577 parseState->isStateProgram) { 578 /* absolute program parameter register */ 579 /* Only valid for vertex state programs */ 580 dstReg->File = PROGRAM_ENV_PARAM; 581 if (!Parse_AbsParamReg(parseState, &idx)) 582 RETURN_ERROR; 583 dstReg->Index = idx; 584 } 585 else { 586 RETURN_ERROR1("Bad destination register name"); 587 } 588 589 /* Parse optional write mask */ 590 if (!Peek_Token(parseState, token)) 591 RETURN_ERROR; 592 593 if (token[0] == '.') { 594 /* got a mask */ 595 GLint k = 0; 596 597 if (!Parse_String(parseState, ".")) 598 RETURN_ERROR; 599 600 if (!Parse_Token(parseState, token)) 601 RETURN_ERROR; 602 603 dstReg->WriteMask = 0; 604 605 if (token[k] == 'x') { 606 dstReg->WriteMask |= WRITEMASK_X; 607 k++; 608 } 609 if (token[k] == 'y') { 610 dstReg->WriteMask |= WRITEMASK_Y; 611 k++; 612 } 613 if (token[k] == 'z') { 614 dstReg->WriteMask |= WRITEMASK_Z; 615 k++; 616 } 617 if (token[k] == 'w') { 618 dstReg->WriteMask |= WRITEMASK_W; 619 k++; 620 } 621 if (k == 0) { 622 RETURN_ERROR1("Bad writemask character"); 623 } 624 return GL_TRUE; 625 } 626 else { 627 dstReg->WriteMask = WRITEMASK_XYZW; 628 return GL_TRUE; 629 } 630 } 631 632 633 static GLboolean 634 Parse_SwizzleSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg) 635 { 636 GLubyte token[100]; 637 GLint idx; 638 639 srcReg->RelAddr = GL_FALSE; 640 641 /* check for '-' */ 642 if (!Peek_Token(parseState, token)) 643 RETURN_ERROR; 644 if (token[0] == '-') { 645 (void) Parse_String(parseState, "-"); 646 srcReg->Negate = NEGATE_XYZW; 647 if (!Peek_Token(parseState, token)) 648 RETURN_ERROR; 649 } 650 else { 651 srcReg->Negate = NEGATE_NONE; 652 } 653 654 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */ 655 if (token[0] == 'R') { 656 srcReg->File = PROGRAM_TEMPORARY; 657 if (!Parse_TempReg(parseState, &idx)) 658 RETURN_ERROR; 659 srcReg->Index = idx; 660 } 661 else if (token[0] == 'c') { 662 if (!Parse_ParamReg(parseState, srcReg)) 663 RETURN_ERROR; 664 } 665 else if (token[0] == 'v') { 666 srcReg->File = PROGRAM_INPUT; 667 if (!Parse_AttribReg(parseState, &idx)) 668 RETURN_ERROR; 669 srcReg->Index = idx; 670 } 671 else { 672 RETURN_ERROR2("Bad source register name", token); 673 } 674 675 /* init swizzle fields */ 676 srcReg->Swizzle = SWIZZLE_NOOP; 677 678 /* Look for optional swizzle suffix */ 679 if (!Peek_Token(parseState, token)) 680 RETURN_ERROR; 681 if (token[0] == '.') { 682 (void) Parse_String(parseState, "."); /* consume . */ 683 684 if (!Parse_Token(parseState, token)) 685 RETURN_ERROR; 686 687 if (token[1] == 0) { 688 /* single letter swizzle */ 689 if (token[0] == 'x') 690 srcReg->Swizzle = SWIZZLE_XXXX; 691 else if (token[0] == 'y') 692 srcReg->Swizzle = SWIZZLE_YYYY; 693 else if (token[0] == 'z') 694 srcReg->Swizzle = SWIZZLE_ZZZZ; 695 else if (token[0] == 'w') 696 srcReg->Swizzle = SWIZZLE_WWWW; 697 else 698 RETURN_ERROR1("Expected x, y, z, or w"); 699 } 700 else { 701 /* 2, 3 or 4-component swizzle */ 702 GLint k; 703 704 srcReg->Swizzle = 0; 705 706 for (k = 0; token[k] && k < 5; k++) { 707 if (token[k] == 'x') 708 srcReg->Swizzle |= 0 << (k*3); 709 else if (token[k] == 'y') 710 srcReg->Swizzle |= 1 << (k*3); 711 else if (token[k] == 'z') 712 srcReg->Swizzle |= 2 << (k*3); 713 else if (token[k] == 'w') 714 srcReg->Swizzle |= 3 << (k*3); 715 else 716 RETURN_ERROR; 717 } 718 if (k >= 5) 719 RETURN_ERROR; 720 } 721 } 722 723 return GL_TRUE; 724 } 725 726 727 static GLboolean 728 Parse_ScalarSrcReg(struct parse_state *parseState, struct prog_src_register *srcReg) 729 { 730 GLubyte token[100]; 731 GLint idx; 732 733 srcReg->RelAddr = GL_FALSE; 734 735 /* check for '-' */ 736 if (!Peek_Token(parseState, token)) 737 RETURN_ERROR; 738 if (token[0] == '-') { 739 srcReg->Negate = NEGATE_XYZW; 740 (void) Parse_String(parseState, "-"); /* consume '-' */ 741 if (!Peek_Token(parseState, token)) 742 RETURN_ERROR; 743 } 744 else { 745 srcReg->Negate = NEGATE_NONE; 746 } 747 748 /* Src reg can be R<n>, c[n], c[n +/- offset], or a named vertex attrib */ 749 if (token[0] == 'R') { 750 srcReg->File = PROGRAM_TEMPORARY; 751 if (!Parse_TempReg(parseState, &idx)) 752 RETURN_ERROR; 753 srcReg->Index = idx; 754 } 755 else if (token[0] == 'c') { 756 if (!Parse_ParamReg(parseState, srcReg)) 757 RETURN_ERROR; 758 } 759 else if (token[0] == 'v') { 760 srcReg->File = PROGRAM_INPUT; 761 if (!Parse_AttribReg(parseState, &idx)) 762 RETURN_ERROR; 763 srcReg->Index = idx; 764 } 765 else { 766 RETURN_ERROR2("Bad source register name", token); 767 } 768 769 /* Look for .[xyzw] suffix */ 770 if (!Parse_String(parseState, ".")) 771 RETURN_ERROR; 772 773 if (!Parse_Token(parseState, token)) 774 RETURN_ERROR; 775 776 if (token[0] == 'x' && token[1] == 0) { 777 srcReg->Swizzle = 0; 778 } 779 else if (token[0] == 'y' && token[1] == 0) { 780 srcReg->Swizzle = 1; 781 } 782 else if (token[0] == 'z' && token[1] == 0) { 783 srcReg->Swizzle = 2; 784 } 785 else if (token[0] == 'w' && token[1] == 0) { 786 srcReg->Swizzle = 3; 787 } 788 else { 789 RETURN_ERROR1("Bad scalar source suffix"); 790 } 791 792 return GL_TRUE; 793 } 794 795 796 static GLint 797 Parse_UnaryOpInstruction(struct parse_state *parseState, 798 struct prog_instruction *inst, 799 enum prog_opcode opcode) 800 { 801 if (opcode == OPCODE_ABS && !parseState->isVersion1_1) 802 RETURN_ERROR1("ABS illegal for vertex program 1.0"); 803 804 inst->Opcode = opcode; 805 806 /* dest reg */ 807 if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) 808 RETURN_ERROR; 809 810 /* comma */ 811 if (!Parse_String(parseState, ",")) 812 RETURN_ERROR; 813 814 /* src arg */ 815 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0])) 816 RETURN_ERROR; 817 818 /* semicolon */ 819 if (!Parse_String(parseState, ";")) 820 RETURN_ERROR; 821 822 return GL_TRUE; 823 } 824 825 826 static GLboolean 827 Parse_BiOpInstruction(struct parse_state *parseState, 828 struct prog_instruction *inst, 829 enum prog_opcode opcode) 830 { 831 if (opcode == OPCODE_DPH && !parseState->isVersion1_1) 832 RETURN_ERROR1("DPH illegal for vertex program 1.0"); 833 if (opcode == OPCODE_SUB && !parseState->isVersion1_1) 834 RETURN_ERROR1("SUB illegal for vertex program 1.0"); 835 836 inst->Opcode = opcode; 837 838 /* dest reg */ 839 if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) 840 RETURN_ERROR; 841 842 /* comma */ 843 if (!Parse_String(parseState, ",")) 844 RETURN_ERROR; 845 846 /* first src arg */ 847 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0])) 848 RETURN_ERROR; 849 850 /* comma */ 851 if (!Parse_String(parseState, ",")) 852 RETURN_ERROR; 853 854 /* second src arg */ 855 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1])) 856 RETURN_ERROR; 857 858 /* semicolon */ 859 if (!Parse_String(parseState, ";")) 860 RETURN_ERROR; 861 862 /* make sure we don't reference more than one program parameter register */ 863 if (inst->SrcReg[0].File == PROGRAM_ENV_PARAM && 864 inst->SrcReg[1].File == PROGRAM_ENV_PARAM && 865 inst->SrcReg[0].Index != inst->SrcReg[1].Index) 866 RETURN_ERROR1("Can't reference two program parameter registers"); 867 868 /* make sure we don't reference more than one vertex attribute register */ 869 if (inst->SrcReg[0].File == PROGRAM_INPUT && 870 inst->SrcReg[1].File == PROGRAM_INPUT && 871 inst->SrcReg[0].Index != inst->SrcReg[1].Index) 872 RETURN_ERROR1("Can't reference two vertex attribute registers"); 873 874 return GL_TRUE; 875 } 876 877 878 static GLboolean 879 Parse_TriOpInstruction(struct parse_state *parseState, 880 struct prog_instruction *inst, 881 enum prog_opcode opcode) 882 { 883 inst->Opcode = opcode; 884 885 /* dest reg */ 886 if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) 887 RETURN_ERROR; 888 889 /* comma */ 890 if (!Parse_String(parseState, ",")) 891 RETURN_ERROR; 892 893 /* first src arg */ 894 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[0])) 895 RETURN_ERROR; 896 897 /* comma */ 898 if (!Parse_String(parseState, ",")) 899 RETURN_ERROR; 900 901 /* second src arg */ 902 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[1])) 903 RETURN_ERROR; 904 905 /* comma */ 906 if (!Parse_String(parseState, ",")) 907 RETURN_ERROR; 908 909 /* third src arg */ 910 if (!Parse_SwizzleSrcReg(parseState, &inst->SrcReg[2])) 911 RETURN_ERROR; 912 913 /* semicolon */ 914 if (!Parse_String(parseState, ";")) 915 RETURN_ERROR; 916 917 /* make sure we don't reference more than one program parameter register */ 918 if ((inst->SrcReg[0].File == PROGRAM_ENV_PARAM && 919 inst->SrcReg[1].File == PROGRAM_ENV_PARAM && 920 inst->SrcReg[0].Index != inst->SrcReg[1].Index) || 921 (inst->SrcReg[0].File == PROGRAM_ENV_PARAM && 922 inst->SrcReg[2].File == PROGRAM_ENV_PARAM && 923 inst->SrcReg[0].Index != inst->SrcReg[2].Index) || 924 (inst->SrcReg[1].File == PROGRAM_ENV_PARAM && 925 inst->SrcReg[2].File == PROGRAM_ENV_PARAM && 926 inst->SrcReg[1].Index != inst->SrcReg[2].Index)) 927 RETURN_ERROR1("Can only reference one program register"); 928 929 /* make sure we don't reference more than one vertex attribute register */ 930 if ((inst->SrcReg[0].File == PROGRAM_INPUT && 931 inst->SrcReg[1].File == PROGRAM_INPUT && 932 inst->SrcReg[0].Index != inst->SrcReg[1].Index) || 933 (inst->SrcReg[0].File == PROGRAM_INPUT && 934 inst->SrcReg[2].File == PROGRAM_INPUT && 935 inst->SrcReg[0].Index != inst->SrcReg[2].Index) || 936 (inst->SrcReg[1].File == PROGRAM_INPUT && 937 inst->SrcReg[2].File == PROGRAM_INPUT && 938 inst->SrcReg[1].Index != inst->SrcReg[2].Index)) 939 RETURN_ERROR1("Can only reference one input register"); 940 941 return GL_TRUE; 942 } 943 944 945 static GLboolean 946 Parse_ScalarInstruction(struct parse_state *parseState, 947 struct prog_instruction *inst, 948 enum prog_opcode opcode) 949 { 950 if (opcode == OPCODE_RCC && !parseState->isVersion1_1) 951 RETURN_ERROR1("RCC illegal for vertex program 1.0"); 952 953 inst->Opcode = opcode; 954 955 /* dest reg */ 956 if (!Parse_MaskedDstReg(parseState, &inst->DstReg)) 957 RETURN_ERROR; 958 959 /* comma */ 960 if (!Parse_String(parseState, ",")) 961 RETURN_ERROR; 962 963 /* first src arg */ 964 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) 965 RETURN_ERROR; 966 967 /* semicolon */ 968 if (!Parse_String(parseState, ";")) 969 RETURN_ERROR; 970 971 return GL_TRUE; 972 } 973 974 975 static GLboolean 976 Parse_AddressInstruction(struct parse_state *parseState, struct prog_instruction *inst) 977 { 978 inst->Opcode = OPCODE_ARL; 979 980 /* Make ARB_vp backends happy */ 981 inst->DstReg.File = PROGRAM_ADDRESS; 982 inst->DstReg.WriteMask = WRITEMASK_X; 983 inst->DstReg.Index = 0; 984 985 /* dest A0 reg */ 986 if (!Parse_AddrReg(parseState)) 987 RETURN_ERROR; 988 989 /* comma */ 990 if (!Parse_String(parseState, ",")) 991 RETURN_ERROR; 992 993 /* parse src reg */ 994 if (!Parse_ScalarSrcReg(parseState, &inst->SrcReg[0])) 995 RETURN_ERROR; 996 997 /* semicolon */ 998 if (!Parse_String(parseState, ";")) 999 RETURN_ERROR; 1000 1001 return GL_TRUE; 1002 } 1003 1004 1005 static GLboolean 1006 Parse_EndInstruction(struct parse_state *parseState, struct prog_instruction *inst) 1007 { 1008 GLubyte token[100]; 1009 1010 inst->Opcode = OPCODE_END; 1011 1012 /* this should fail! */ 1013 if (Parse_Token(parseState, token)) 1014 RETURN_ERROR2("Unexpected token after END:", token); 1015 else 1016 return GL_TRUE; 1017 } 1018 1019 1020 /** 1021 * The PRINT instruction is Mesa-specific and is meant as a debugging aid for 1022 * the vertex program developer. 1023 * The NV_vertex_program extension grammar is modified as follows: 1024 * 1025 * <instruction> ::= <ARL-instruction> 1026 * | ... 1027 * | <PRINT-instruction> 1028 * 1029 * <PRINT-instruction> ::= "PRINT" <string literal> 1030 * | "PRINT" <string literal> "," <srcReg> 1031 * | "PRINT" <string literal> "," <dstReg> 1032 */ 1033 static GLboolean 1034 Parse_PrintInstruction(struct parse_state *parseState, struct prog_instruction *inst) 1035 { 1036 const GLubyte *str; 1037 GLubyte *msg; 1038 GLuint len; 1039 GLubyte token[100]; 1040 struct prog_src_register *srcReg = &inst->SrcReg[0]; 1041 GLint idx; 1042 1043 inst->Opcode = OPCODE_PRINT; 1044 1045 /* The first argument is a literal string 'just like this' */ 1046 if (!Parse_String(parseState, "'")) 1047 RETURN_ERROR; 1048 1049 str = parseState->pos; 1050 for (len = 0; str[len] != '\''; len++) /* find closing quote */ 1051 ; 1052 parseState->pos += len + 1; 1053 msg = (GLubyte*) malloc(len + 1); 1054 1055 memcpy(msg, str, len); 1056 msg[len] = 0; 1057 inst->Data = msg; 1058 1059 /* comma */ 1060 if (Parse_String(parseState, ",")) { 1061 1062 /* The second argument is a register name */ 1063 if (!Peek_Token(parseState, token)) 1064 RETURN_ERROR; 1065 1066 srcReg->RelAddr = GL_FALSE; 1067 srcReg->Negate = NEGATE_NONE; 1068 srcReg->Swizzle = SWIZZLE_NOOP; 1069 1070 /* Register can be R<n>, c[n], c[n +/- offset], a named vertex attrib, 1071 * or an o[n] output register. 1072 */ 1073 if (token[0] == 'R') { 1074 srcReg->File = PROGRAM_TEMPORARY; 1075 if (!Parse_TempReg(parseState, &idx)) 1076 RETURN_ERROR; 1077 srcReg->Index = idx; 1078 } 1079 else if (token[0] == 'c') { 1080 srcReg->File = PROGRAM_ENV_PARAM; 1081 if (!Parse_ParamReg(parseState, srcReg)) 1082 RETURN_ERROR; 1083 } 1084 else if (token[0] == 'v') { 1085 srcReg->File = PROGRAM_INPUT; 1086 if (!Parse_AttribReg(parseState, &idx)) 1087 RETURN_ERROR; 1088 srcReg->Index = idx; 1089 } 1090 else if (token[0] == 'o') { 1091 srcReg->File = PROGRAM_OUTPUT; 1092 if (!Parse_OutputReg(parseState, &idx)) 1093 RETURN_ERROR; 1094 srcReg->Index = idx; 1095 } 1096 else { 1097 RETURN_ERROR2("Bad source register name", token); 1098 } 1099 } 1100 else { 1101 srcReg->File = PROGRAM_UNDEFINED; 1102 } 1103 1104 /* semicolon */ 1105 if (!Parse_String(parseState, ";")) 1106 RETURN_ERROR; 1107 1108 return GL_TRUE; 1109 } 1110 1111 1112 static GLboolean 1113 Parse_OptionSequence(struct parse_state *parseState, 1114 struct prog_instruction program[]) 1115 { 1116 (void) program; 1117 while (1) { 1118 if (!Parse_String(parseState, "OPTION")) 1119 return GL_TRUE; /* ok, not an OPTION statement */ 1120 if (Parse_String(parseState, "NV_position_invariant")) { 1121 parseState->isPositionInvariant = GL_TRUE; 1122 } 1123 else { 1124 RETURN_ERROR1("unexpected OPTION statement"); 1125 } 1126 if (!Parse_String(parseState, ";")) 1127 return GL_FALSE; 1128 } 1129 } 1130 1131 1132 static GLboolean 1133 Parse_InstructionSequence(struct parse_state *parseState, 1134 struct prog_instruction program[]) 1135 { 1136 while (1) { 1137 struct prog_instruction *inst = program + parseState->numInst; 1138 1139 /* Initialize the instruction */ 1140 _mesa_init_instructions(inst, 1); 1141 1142 if (Parse_String(parseState, "MOV")) { 1143 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_MOV)) 1144 RETURN_ERROR; 1145 } 1146 else if (Parse_String(parseState, "LIT")) { 1147 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_LIT)) 1148 RETURN_ERROR; 1149 } 1150 else if (Parse_String(parseState, "ABS")) { 1151 if (!Parse_UnaryOpInstruction(parseState, inst, OPCODE_ABS)) 1152 RETURN_ERROR; 1153 } 1154 else if (Parse_String(parseState, "MUL")) { 1155 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MUL)) 1156 RETURN_ERROR; 1157 } 1158 else if (Parse_String(parseState, "ADD")) { 1159 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_ADD)) 1160 RETURN_ERROR; 1161 } 1162 else if (Parse_String(parseState, "DP3")) { 1163 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP3)) 1164 RETURN_ERROR; 1165 } 1166 else if (Parse_String(parseState, "DP4")) { 1167 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DP4)) 1168 RETURN_ERROR; 1169 } 1170 else if (Parse_String(parseState, "DST")) { 1171 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DST)) 1172 RETURN_ERROR; 1173 } 1174 else if (Parse_String(parseState, "MIN")) { 1175 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MIN)) 1176 RETURN_ERROR; 1177 } 1178 else if (Parse_String(parseState, "MAX")) { 1179 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_MAX)) 1180 RETURN_ERROR; 1181 } 1182 else if (Parse_String(parseState, "SLT")) { 1183 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SLT)) 1184 RETURN_ERROR; 1185 } 1186 else if (Parse_String(parseState, "SGE")) { 1187 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SGE)) 1188 RETURN_ERROR; 1189 } 1190 else if (Parse_String(parseState, "DPH")) { 1191 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_DPH)) 1192 RETURN_ERROR; 1193 } 1194 else if (Parse_String(parseState, "SUB")) { 1195 if (!Parse_BiOpInstruction(parseState, inst, OPCODE_SUB)) 1196 RETURN_ERROR; 1197 } 1198 else if (Parse_String(parseState, "MAD")) { 1199 if (!Parse_TriOpInstruction(parseState, inst, OPCODE_MAD)) 1200 RETURN_ERROR; 1201 } 1202 else if (Parse_String(parseState, "RCP")) { 1203 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCP)) 1204 RETURN_ERROR; 1205 } 1206 else if (Parse_String(parseState, "RSQ")) { 1207 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RSQ)) 1208 RETURN_ERROR; 1209 } 1210 else if (Parse_String(parseState, "EXP")) { 1211 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_EXP)) 1212 RETURN_ERROR; 1213 } 1214 else if (Parse_String(parseState, "LOG")) { 1215 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_LOG)) 1216 RETURN_ERROR; 1217 } 1218 else if (Parse_String(parseState, "RCC")) { 1219 if (!Parse_ScalarInstruction(parseState, inst, OPCODE_RCC)) 1220 RETURN_ERROR; 1221 } 1222 else if (Parse_String(parseState, "ARL")) { 1223 if (!Parse_AddressInstruction(parseState, inst)) 1224 RETURN_ERROR; 1225 } 1226 else if (Parse_String(parseState, "PRINT")) { 1227 if (!Parse_PrintInstruction(parseState, inst)) 1228 RETURN_ERROR; 1229 } 1230 else if (Parse_String(parseState, "END")) { 1231 if (!Parse_EndInstruction(parseState, inst)) 1232 RETURN_ERROR; 1233 else { 1234 parseState->numInst++; 1235 return GL_TRUE; /* all done */ 1236 } 1237 } 1238 else { 1239 /* bad instruction name */ 1240 RETURN_ERROR1("Unexpected token"); 1241 } 1242 1243 /* examine input/output registers */ 1244 if (inst->DstReg.File == PROGRAM_OUTPUT) 1245 parseState->outputsWritten |= (1 << inst->DstReg.Index); 1246 else if (inst->DstReg.File == PROGRAM_ENV_PARAM) 1247 parseState->anyProgRegsWritten = GL_TRUE; 1248 1249 if (inst->SrcReg[0].File == PROGRAM_INPUT) 1250 parseState->inputsRead |= (1 << inst->SrcReg[0].Index); 1251 if (inst->SrcReg[1].File == PROGRAM_INPUT) 1252 parseState->inputsRead |= (1 << inst->SrcReg[1].Index); 1253 if (inst->SrcReg[2].File == PROGRAM_INPUT) 1254 parseState->inputsRead |= (1 << inst->SrcReg[2].Index); 1255 1256 parseState->numInst++; 1257 1258 if (parseState->numInst >= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS) 1259 RETURN_ERROR1("Program too long"); 1260 } 1261 1262 RETURN_ERROR; 1263 } 1264 1265 1266 static GLboolean 1267 Parse_Program(struct parse_state *parseState, 1268 struct prog_instruction instBuffer[]) 1269 { 1270 if (parseState->isVersion1_1) { 1271 if (!Parse_OptionSequence(parseState, instBuffer)) { 1272 return GL_FALSE; 1273 } 1274 } 1275 return Parse_InstructionSequence(parseState, instBuffer); 1276 } 1277 1278 1279 /** 1280 * Parse/compile the 'str' returning the compiled 'program'. 1281 * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos 1282 * indicates the position of the error in 'str'. 1283 */ 1284 void 1285 _mesa_parse_nv_vertex_program(struct gl_context *ctx, GLenum dstTarget, 1286 const GLubyte *str, GLsizei len, 1287 struct gl_vertex_program *program) 1288 { 1289 struct parse_state parseState; 1290 struct prog_instruction instBuffer[MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS]; 1291 struct prog_instruction *newInst; 1292 GLenum target; 1293 GLubyte *programString; 1294 1295 /* Make a null-terminated copy of the program string */ 1296 programString = (GLubyte *) MALLOC(len + 1); 1297 if (!programString) { 1298 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); 1299 return; 1300 } 1301 memcpy(programString, str, len); 1302 programString[len] = 0; 1303 1304 /* Get ready to parse */ 1305 parseState.ctx = ctx; 1306 parseState.start = programString; 1307 parseState.isPositionInvariant = GL_FALSE; 1308 parseState.isVersion1_1 = GL_FALSE; 1309 parseState.numInst = 0; 1310 parseState.inputsRead = 0; 1311 parseState.outputsWritten = 0; 1312 parseState.anyProgRegsWritten = GL_FALSE; 1313 parseState.indirectRegisterFiles = 0x0; 1314 1315 /* Reset error state */ 1316 _mesa_set_program_error(ctx, -1, NULL); 1317 1318 /* check the program header */ 1319 if (strncmp((const char *) programString, "!!VP1.0", 7) == 0) { 1320 target = GL_VERTEX_PROGRAM_NV; 1321 parseState.pos = programString + 7; 1322 parseState.isStateProgram = GL_FALSE; 1323 } 1324 else if (strncmp((const char *) programString, "!!VP1.1", 7) == 0) { 1325 target = GL_VERTEX_PROGRAM_NV; 1326 parseState.pos = programString + 7; 1327 parseState.isStateProgram = GL_FALSE; 1328 parseState.isVersion1_1 = GL_TRUE; 1329 } 1330 else if (strncmp((const char *) programString, "!!VSP1.0", 8) == 0) { 1331 target = GL_VERTEX_STATE_PROGRAM_NV; 1332 parseState.pos = programString + 8; 1333 parseState.isStateProgram = GL_TRUE; 1334 } 1335 else { 1336 /* invalid header */ 1337 ctx->Program.ErrorPos = 0; 1338 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); 1339 return; 1340 } 1341 1342 /* make sure target and header match */ 1343 if (target != dstTarget) { 1344 _mesa_error(ctx, GL_INVALID_OPERATION, 1345 "glLoadProgramNV(target mismatch)"); 1346 return; 1347 } 1348 1349 1350 if (Parse_Program(&parseState, instBuffer)) { 1351 gl_state_index state_tokens[STATE_LENGTH] = {0, 0, 0, 0, 0}; 1352 int i; 1353 1354 /* successful parse! */ 1355 1356 if (parseState.isStateProgram) { 1357 if (!parseState.anyProgRegsWritten) { 1358 _mesa_error(ctx, GL_INVALID_OPERATION, 1359 "glLoadProgramNV(c[#] not written)"); 1360 return; 1361 } 1362 } 1363 else { 1364 if (!parseState.isPositionInvariant && 1365 !(parseState.outputsWritten & (1 << VERT_RESULT_HPOS))) { 1366 /* bit 1 = HPOS register */ 1367 _mesa_error(ctx, GL_INVALID_OPERATION, 1368 "glLoadProgramNV(HPOS not written)"); 1369 return; 1370 } 1371 } 1372 1373 /* copy the compiled instructions */ 1374 assert(parseState.numInst <= MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS); 1375 newInst = _mesa_alloc_instructions(parseState.numInst); 1376 if (!newInst) { 1377 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); 1378 free(programString); 1379 return; /* out of memory */ 1380 } 1381 _mesa_copy_instructions(newInst, instBuffer, parseState.numInst); 1382 1383 /* install the program */ 1384 program->Base.Target = target; 1385 if (program->Base.String) { 1386 free(program->Base.String); 1387 } 1388 program->Base.String = programString; 1389 program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB; 1390 if (program->Base.Instructions) { 1391 free(program->Base.Instructions); 1392 } 1393 program->Base.Instructions = newInst; 1394 program->Base.InputsRead = parseState.inputsRead; 1395 if (parseState.isPositionInvariant) 1396 program->Base.InputsRead |= VERT_BIT_POS; 1397 program->Base.NumInstructions = parseState.numInst; 1398 program->Base.OutputsWritten = parseState.outputsWritten; 1399 program->IsPositionInvariant = parseState.isPositionInvariant; 1400 program->IsNVProgram = GL_TRUE; 1401 1402 #ifdef DEBUG_foo 1403 printf("--- glLoadProgramNV result ---\n"); 1404 _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0); 1405 printf("------------------------------\n"); 1406 #endif 1407 1408 if (program->Base.Parameters) 1409 _mesa_free_parameter_list(program->Base.Parameters); 1410 1411 program->Base.Parameters = _mesa_new_parameter_list (); 1412 program->Base.NumParameters = 0; 1413 1414 program->Base.IndirectRegisterFiles = parseState.indirectRegisterFiles; 1415 1416 state_tokens[0] = STATE_VERTEX_PROGRAM; 1417 state_tokens[1] = STATE_ENV; 1418 /* Add refs to all of the potential params, in order. If we want to not 1419 * upload everything, _mesa_layout_parameters is the answer. 1420 */ 1421 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS; i++) { 1422 GLint index; 1423 state_tokens[2] = i; 1424 index = _mesa_add_state_reference(program->Base.Parameters, 1425 state_tokens); 1426 assert(index == i); 1427 (void)index; 1428 } 1429 program->Base.NumParameters = program->Base.Parameters->NumParameters; 1430 1431 _mesa_setup_nv_temporary_count(&program->Base); 1432 _mesa_emit_nv_temp_initialization(ctx, &program->Base); 1433 } 1434 else { 1435 /* Error! */ 1436 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV"); 1437 /* NOTE: _mesa_set_program_error would have been called already */ 1438 /* GL_NV_vertex_program isn't supposed to set the error string 1439 * so we reset it here. 1440 */ 1441 _mesa_set_program_error(ctx, ctx->Program.ErrorPos, NULL); 1442 } 1443 } 1444 1445 1446 const char * 1447 _mesa_nv_vertex_input_register_name(GLuint i) 1448 { 1449 ASSERT(i < MAX_NV_VERTEX_PROGRAM_INPUTS); 1450 return InputRegisters[i]; 1451 } 1452 1453 1454 const char * 1455 _mesa_nv_vertex_output_register_name(GLuint i) 1456 { 1457 ASSERT(i < MAX_NV_VERTEX_PROGRAM_OUTPUTS); 1458 return OutputRegisters[i]; 1459 } 1460 1461