program.c revision 4d203a01e20dedcfaab09c18922e8ed9dcb39729
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5.3 4 * 5 * Copyright (C) 1999-2007 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 program.c 27 * Vertex and fragment program support functions. 28 * \author Brian Paul 29 */ 30 31 32#include "main/glheader.h" 33#include "main/context.h" 34#include "main/hash.h" 35#include "main/mfeatures.h" 36#include "program.h" 37#include "prog_cache.h" 38#include "prog_parameter.h" 39#include "prog_instruction.h" 40 41 42/** 43 * A pointer to this dummy program is put into the hash table when 44 * glGenPrograms is called. 45 */ 46struct gl_program _mesa_DummyProgram; 47 48 49/** 50 * Init context's vertex/fragment program state 51 */ 52void 53_mesa_init_program(struct gl_context *ctx) 54{ 55 GLuint i; 56 57 /* 58 * If this assertion fails, we need to increase the field 59 * size for register indexes (see INST_INDEX_BITS). 60 */ 61 ASSERT(ctx->Const.VertexProgram.MaxUniformComponents / 4 62 <= (1 << INST_INDEX_BITS)); 63 ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents / 4 64 <= (1 << INST_INDEX_BITS)); 65 66 ASSERT(ctx->Const.VertexProgram.MaxTemps <= (1 << INST_INDEX_BITS)); 67 ASSERT(ctx->Const.VertexProgram.MaxLocalParams <= (1 << INST_INDEX_BITS)); 68 ASSERT(ctx->Const.FragmentProgram.MaxTemps <= (1 << INST_INDEX_BITS)); 69 ASSERT(ctx->Const.FragmentProgram.MaxLocalParams <= (1 << INST_INDEX_BITS)); 70 71 ASSERT(ctx->Const.VertexProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS); 72 ASSERT(ctx->Const.FragmentProgram.MaxUniformComponents <= 4 * MAX_UNIFORMS); 73 74 ASSERT(ctx->Const.VertexProgram.MaxAddressOffset <= (1 << INST_INDEX_BITS)); 75 ASSERT(ctx->Const.FragmentProgram.MaxAddressOffset <= (1 << INST_INDEX_BITS)); 76 77 /* If this fails, increase prog_instruction::TexSrcUnit size */ 78 ASSERT(MAX_TEXTURE_UNITS <= (1 << 5)); 79 80 /* If this fails, increase prog_instruction::TexSrcTarget size */ 81 ASSERT(NUM_TEXTURE_TARGETS <= (1 << 3)); 82 83 ctx->Program.ErrorPos = -1; 84 ctx->Program.ErrorString = _mesa_strdup(""); 85 86#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program 87 ctx->VertexProgram.Enabled = GL_FALSE; 88#if FEATURE_es2_glsl 89 ctx->VertexProgram.PointSizeEnabled = 90 (ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE; 91#else 92 ctx->VertexProgram.PointSizeEnabled = GL_FALSE; 93#endif 94 ctx->VertexProgram.TwoSideEnabled = GL_FALSE; 95 _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, 96 ctx->Shared->DefaultVertexProgram); 97 assert(ctx->VertexProgram.Current); 98 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) { 99 ctx->VertexProgram.TrackMatrix[i] = GL_NONE; 100 ctx->VertexProgram.TrackMatrixTransform[i] = GL_IDENTITY_NV; 101 } 102 ctx->VertexProgram.Cache = _mesa_new_program_cache(); 103#endif 104 105#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program 106 ctx->FragmentProgram.Enabled = GL_FALSE; 107 _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, 108 ctx->Shared->DefaultFragmentProgram); 109 assert(ctx->FragmentProgram.Current); 110 ctx->FragmentProgram.Cache = _mesa_new_program_cache(); 111#endif 112 113#if FEATURE_ARB_geometry_shader4 114 ctx->GeometryProgram.Enabled = GL_FALSE; 115 /* right now by default we don't have a geometry program */ 116 _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, 117 NULL); 118 ctx->GeometryProgram.Cache = _mesa_new_program_cache(); 119#endif 120 121 /* XXX probably move this stuff */ 122#if FEATURE_ATI_fragment_shader 123 ctx->ATIFragmentShader.Enabled = GL_FALSE; 124 ctx->ATIFragmentShader.Current = ctx->Shared->DefaultFragmentShader; 125 assert(ctx->ATIFragmentShader.Current); 126 ctx->ATIFragmentShader.Current->RefCount++; 127#endif 128} 129 130 131/** 132 * Free a context's vertex/fragment program state 133 */ 134void 135_mesa_free_program_data(struct gl_context *ctx) 136{ 137#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program 138 _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL); 139 _mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache); 140#endif 141#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program 142 _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL); 143 _mesa_delete_program_cache(ctx, ctx->FragmentProgram.Cache); 144#endif 145#if FEATURE_ARB_geometry_shader4 146 _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL); 147 _mesa_delete_program_cache(ctx, ctx->GeometryProgram.Cache); 148#endif 149 /* XXX probably move this stuff */ 150#if FEATURE_ATI_fragment_shader 151 if (ctx->ATIFragmentShader.Current) { 152 ctx->ATIFragmentShader.Current->RefCount--; 153 if (ctx->ATIFragmentShader.Current->RefCount <= 0) { 154 free(ctx->ATIFragmentShader.Current); 155 } 156 } 157#endif 158 free((void *) ctx->Program.ErrorString); 159} 160 161 162/** 163 * Update the default program objects in the given context to reference those 164 * specified in the shared state and release those referencing the old 165 * shared state. 166 */ 167void 168_mesa_update_default_objects_program(struct gl_context *ctx) 169{ 170#if FEATURE_NV_vertex_program || FEATURE_ARB_vertex_program 171 _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, 172 (struct gl_vertex_program *) 173 ctx->Shared->DefaultVertexProgram); 174 assert(ctx->VertexProgram.Current); 175#endif 176 177#if FEATURE_NV_fragment_program || FEATURE_ARB_fragment_program 178 _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, 179 (struct gl_fragment_program *) 180 ctx->Shared->DefaultFragmentProgram); 181 assert(ctx->FragmentProgram.Current); 182#endif 183 184#if FEATURE_ARB_geometry_shader4 185 _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, 186 (struct gl_geometry_program *) 187 ctx->Shared->DefaultGeometryProgram); 188#endif 189 190 /* XXX probably move this stuff */ 191#if FEATURE_ATI_fragment_shader 192 if (ctx->ATIFragmentShader.Current) { 193 ctx->ATIFragmentShader.Current->RefCount--; 194 if (ctx->ATIFragmentShader.Current->RefCount <= 0) { 195 free(ctx->ATIFragmentShader.Current); 196 } 197 } 198 ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) ctx->Shared->DefaultFragmentShader; 199 assert(ctx->ATIFragmentShader.Current); 200 ctx->ATIFragmentShader.Current->RefCount++; 201#endif 202} 203 204 205/** 206 * Set the vertex/fragment program error state (position and error string). 207 * This is generally called from within the parsers. 208 */ 209void 210_mesa_set_program_error(struct gl_context *ctx, GLint pos, const char *string) 211{ 212 ctx->Program.ErrorPos = pos; 213 free((void *) ctx->Program.ErrorString); 214 if (!string) 215 string = ""; 216 ctx->Program.ErrorString = _mesa_strdup(string); 217} 218 219 220/** 221 * Find the line number and column for 'pos' within 'string'. 222 * Return a copy of the line which contains 'pos'. Free the line with 223 * free(). 224 * \param string the program string 225 * \param pos the position within the string 226 * \param line returns the line number corresponding to 'pos'. 227 * \param col returns the column number corresponding to 'pos'. 228 * \return copy of the line containing 'pos'. 229 */ 230const GLubyte * 231_mesa_find_line_column(const GLubyte *string, const GLubyte *pos, 232 GLint *line, GLint *col) 233{ 234 const GLubyte *lineStart = string; 235 const GLubyte *p = string; 236 GLubyte *s; 237 int len; 238 239 *line = 1; 240 241 while (p != pos) { 242 if (*p == (GLubyte) '\n') { 243 (*line)++; 244 lineStart = p + 1; 245 } 246 p++; 247 } 248 249 *col = (pos - lineStart) + 1; 250 251 /* return copy of this line */ 252 while (*p != 0 && *p != '\n') 253 p++; 254 len = p - lineStart; 255 s = (GLubyte *) malloc(len + 1); 256 memcpy(s, lineStart, len); 257 s[len] = 0; 258 259 return s; 260} 261 262 263/** 264 * Initialize a new vertex/fragment program object. 265 */ 266static struct gl_program * 267_mesa_init_program_struct( struct gl_context *ctx, struct gl_program *prog, 268 GLenum target, GLuint id) 269{ 270 (void) ctx; 271 if (prog) { 272 GLuint i; 273 memset(prog, 0, sizeof(*prog)); 274 prog->Id = id; 275 prog->Target = target; 276 prog->Resident = GL_TRUE; 277 prog->RefCount = 1; 278 prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB; 279 280 /* default mapping from samplers to texture units */ 281 for (i = 0; i < MAX_SAMPLERS; i++) 282 prog->SamplerUnits[i] = i; 283 } 284 285 return prog; 286} 287 288 289/** 290 * Initialize a new fragment program object. 291 */ 292struct gl_program * 293_mesa_init_fragment_program( struct gl_context *ctx, struct gl_fragment_program *prog, 294 GLenum target, GLuint id) 295{ 296 if (prog) 297 return _mesa_init_program_struct( ctx, &prog->Base, target, id ); 298 else 299 return NULL; 300} 301 302 303/** 304 * Initialize a new vertex program object. 305 */ 306struct gl_program * 307_mesa_init_vertex_program( struct gl_context *ctx, struct gl_vertex_program *prog, 308 GLenum target, GLuint id) 309{ 310 if (prog) 311 return _mesa_init_program_struct( ctx, &prog->Base, target, id ); 312 else 313 return NULL; 314} 315 316 317/** 318 * Initialize a new geometry program object. 319 */ 320struct gl_program * 321_mesa_init_geometry_program( struct gl_context *ctx, struct gl_geometry_program *prog, 322 GLenum target, GLuint id) 323{ 324 if (prog) 325 return _mesa_init_program_struct( ctx, &prog->Base, target, id ); 326 else 327 return NULL; 328} 329 330 331/** 332 * Allocate and initialize a new fragment/vertex program object but 333 * don't put it into the program hash table. Called via 334 * ctx->Driver.NewProgram. May be overridden (ie. replaced) by a 335 * device driver function to implement OO deriviation with additional 336 * types not understood by this function. 337 * 338 * \param ctx context 339 * \param id program id/number 340 * \param target program target/type 341 * \return pointer to new program object 342 */ 343struct gl_program * 344_mesa_new_program(struct gl_context *ctx, GLenum target, GLuint id) 345{ 346 struct gl_program *prog; 347 switch (target) { 348 case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */ 349 case GL_VERTEX_STATE_PROGRAM_NV: 350 prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program), 351 target, id ); 352 break; 353 case GL_FRAGMENT_PROGRAM_NV: 354 case GL_FRAGMENT_PROGRAM_ARB: 355 prog =_mesa_init_fragment_program(ctx, 356 CALLOC_STRUCT(gl_fragment_program), 357 target, id ); 358 break; 359 case MESA_GEOMETRY_PROGRAM: 360 prog = _mesa_init_geometry_program(ctx, 361 CALLOC_STRUCT(gl_geometry_program), 362 target, id); 363 break; 364 default: 365 _mesa_problem(ctx, "bad target in _mesa_new_program"); 366 prog = NULL; 367 } 368 return prog; 369} 370 371 372/** 373 * Delete a program and remove it from the hash table, ignoring the 374 * reference count. 375 * Called via ctx->Driver.DeleteProgram. May be wrapped (OO deriviation) 376 * by a device driver function. 377 */ 378void 379_mesa_delete_program(struct gl_context *ctx, struct gl_program *prog) 380{ 381 (void) ctx; 382 ASSERT(prog); 383 ASSERT(prog->RefCount==0); 384 385 if (prog == &_mesa_DummyProgram) 386 return; 387 388 if (prog->String) 389 free(prog->String); 390 391 _mesa_free_instructions(prog->Instructions, prog->NumInstructions); 392 393 if (prog->Parameters) { 394 _mesa_free_parameter_list(prog->Parameters); 395 } 396 if (prog->Varying) { 397 _mesa_free_parameter_list(prog->Varying); 398 } 399 if (prog->Attributes) { 400 _mesa_free_parameter_list(prog->Attributes); 401 } 402 403 free(prog); 404} 405 406 407/** 408 * Return the gl_program object for a given ID. 409 * Basically just a wrapper for _mesa_HashLookup() to avoid a lot of 410 * casts elsewhere. 411 */ 412struct gl_program * 413_mesa_lookup_program(struct gl_context *ctx, GLuint id) 414{ 415 if (id) 416 return (struct gl_program *) _mesa_HashLookup(ctx->Shared->Programs, id); 417 else 418 return NULL; 419} 420 421 422/** 423 * Reference counting for vertex/fragment programs 424 */ 425void 426_mesa_reference_program(struct gl_context *ctx, 427 struct gl_program **ptr, 428 struct gl_program *prog) 429{ 430 assert(ptr); 431 if (*ptr && prog) { 432 /* sanity check */ 433 if ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB) 434 ASSERT(prog->Target == GL_VERTEX_PROGRAM_ARB); 435 else if ((*ptr)->Target == GL_FRAGMENT_PROGRAM_ARB) 436 ASSERT(prog->Target == GL_FRAGMENT_PROGRAM_ARB || 437 prog->Target == GL_FRAGMENT_PROGRAM_NV); 438 else if ((*ptr)->Target == MESA_GEOMETRY_PROGRAM) 439 ASSERT(prog->Target == MESA_GEOMETRY_PROGRAM); 440 } 441 if (*ptr == prog) { 442 return; /* no change */ 443 } 444 if (*ptr) { 445 GLboolean deleteFlag; 446 447 /*_glthread_LOCK_MUTEX((*ptr)->Mutex);*/ 448#if 0 449 printf("Program %p ID=%u Target=%s Refcount-- to %d\n", 450 *ptr, (*ptr)->Id, 451 ((*ptr)->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : 452 ((*ptr)->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")), 453 (*ptr)->RefCount - 1); 454#endif 455 ASSERT((*ptr)->RefCount > 0); 456 (*ptr)->RefCount--; 457 458 deleteFlag = ((*ptr)->RefCount == 0); 459 /*_glthread_UNLOCK_MUTEX((*ptr)->Mutex);*/ 460 461 if (deleteFlag) { 462 ASSERT(ctx); 463 ctx->Driver.DeleteProgram(ctx, *ptr); 464 } 465 466 *ptr = NULL; 467 } 468 469 assert(!*ptr); 470 if (prog) { 471 /*_glthread_LOCK_MUTEX(prog->Mutex);*/ 472 prog->RefCount++; 473#if 0 474 printf("Program %p ID=%u Target=%s Refcount++ to %d\n", 475 prog, prog->Id, 476 (prog->Target == GL_VERTEX_PROGRAM_ARB ? "VP" : 477 (prog->Target == MESA_GEOMETRY_PROGRAM ? "GP" : "FP")), 478 prog->RefCount); 479#endif 480 /*_glthread_UNLOCK_MUTEX(prog->Mutex);*/ 481 } 482 483 *ptr = prog; 484} 485 486 487/** 488 * Return a copy of a program. 489 * XXX Problem here if the program object is actually OO-derivation 490 * made by a device driver. 491 */ 492struct gl_program * 493_mesa_clone_program(struct gl_context *ctx, const struct gl_program *prog) 494{ 495 struct gl_program *clone; 496 497 clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id); 498 if (!clone) 499 return NULL; 500 501 assert(clone->Target == prog->Target); 502 assert(clone->RefCount == 1); 503 504 clone->String = (GLubyte *) _mesa_strdup((char *) prog->String); 505 clone->Format = prog->Format; 506 clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions); 507 if (!clone->Instructions) { 508 _mesa_reference_program(ctx, &clone, NULL); 509 return NULL; 510 } 511 _mesa_copy_instructions(clone->Instructions, prog->Instructions, 512 prog->NumInstructions); 513 clone->InputsRead = prog->InputsRead; 514 clone->OutputsWritten = prog->OutputsWritten; 515 clone->SamplersUsed = prog->SamplersUsed; 516 clone->ShadowSamplers = prog->ShadowSamplers; 517 memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed)); 518 519 if (prog->Parameters) 520 clone->Parameters = _mesa_clone_parameter_list(prog->Parameters); 521 memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); 522 if (prog->Varying) 523 clone->Varying = _mesa_clone_parameter_list(prog->Varying); 524 if (prog->Attributes) 525 clone->Attributes = _mesa_clone_parameter_list(prog->Attributes); 526 memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); 527 clone->IndirectRegisterFiles = prog->IndirectRegisterFiles; 528 clone->NumInstructions = prog->NumInstructions; 529 clone->NumTemporaries = prog->NumTemporaries; 530 clone->NumParameters = prog->NumParameters; 531 clone->NumAttributes = prog->NumAttributes; 532 clone->NumAddressRegs = prog->NumAddressRegs; 533 clone->NumNativeInstructions = prog->NumNativeInstructions; 534 clone->NumNativeTemporaries = prog->NumNativeTemporaries; 535 clone->NumNativeParameters = prog->NumNativeParameters; 536 clone->NumNativeAttributes = prog->NumNativeAttributes; 537 clone->NumNativeAddressRegs = prog->NumNativeAddressRegs; 538 clone->NumAluInstructions = prog->NumAluInstructions; 539 clone->NumTexInstructions = prog->NumTexInstructions; 540 clone->NumTexIndirections = prog->NumTexIndirections; 541 clone->NumNativeAluInstructions = prog->NumNativeAluInstructions; 542 clone->NumNativeTexInstructions = prog->NumNativeTexInstructions; 543 clone->NumNativeTexIndirections = prog->NumNativeTexIndirections; 544 545 switch (prog->Target) { 546 case GL_VERTEX_PROGRAM_ARB: 547 { 548 const struct gl_vertex_program *vp 549 = (const struct gl_vertex_program *) prog; 550 struct gl_vertex_program *vpc = (struct gl_vertex_program *) clone; 551 vpc->IsPositionInvariant = vp->IsPositionInvariant; 552 vpc->IsNVProgram = vp->IsNVProgram; 553 } 554 break; 555 case GL_FRAGMENT_PROGRAM_ARB: 556 { 557 const struct gl_fragment_program *fp 558 = (const struct gl_fragment_program *) prog; 559 struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone; 560 fpc->UsesKill = fp->UsesKill; 561 fpc->OriginUpperLeft = fp->OriginUpperLeft; 562 fpc->PixelCenterInteger = fp->PixelCenterInteger; 563 } 564 break; 565 case MESA_GEOMETRY_PROGRAM: 566 { 567 const struct gl_geometry_program *gp 568 = (const struct gl_geometry_program *) prog; 569 struct gl_geometry_program *gpc = (struct gl_geometry_program *) clone; 570 gpc->VerticesOut = gp->VerticesOut; 571 gpc->InputType = gp->InputType; 572 gpc->OutputType = gp->OutputType; 573 } 574 break; 575 default: 576 _mesa_problem(NULL, "Unexpected target in _mesa_clone_program"); 577 } 578 579 return clone; 580} 581 582 583/** 584 * Insert 'count' NOP instructions at 'start' in the given program. 585 * Adjust branch targets accordingly. 586 */ 587GLboolean 588_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count) 589{ 590 const GLuint origLen = prog->NumInstructions; 591 const GLuint newLen = origLen + count; 592 struct prog_instruction *newInst; 593 GLuint i; 594 595 /* adjust branches */ 596 for (i = 0; i < prog->NumInstructions; i++) { 597 struct prog_instruction *inst = prog->Instructions + i; 598 if (inst->BranchTarget > 0) { 599 if ((GLuint)inst->BranchTarget >= start) { 600 inst->BranchTarget += count; 601 } 602 } 603 } 604 605 /* Alloc storage for new instructions */ 606 newInst = _mesa_alloc_instructions(newLen); 607 if (!newInst) { 608 return GL_FALSE; 609 } 610 611 /* Copy 'start' instructions into new instruction buffer */ 612 _mesa_copy_instructions(newInst, prog->Instructions, start); 613 614 /* init the new instructions */ 615 _mesa_init_instructions(newInst + start, count); 616 617 /* Copy the remaining/tail instructions to new inst buffer */ 618 _mesa_copy_instructions(newInst + start + count, 619 prog->Instructions + start, 620 origLen - start); 621 622 /* free old instructions */ 623 _mesa_free_instructions(prog->Instructions, origLen); 624 625 /* install new instructions */ 626 prog->Instructions = newInst; 627 prog->NumInstructions = newLen; 628 629 return GL_TRUE; 630} 631 632/** 633 * Delete 'count' instructions at 'start' in the given program. 634 * Adjust branch targets accordingly. 635 */ 636GLboolean 637_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count) 638{ 639 const GLuint origLen = prog->NumInstructions; 640 const GLuint newLen = origLen - count; 641 struct prog_instruction *newInst; 642 GLuint i; 643 644 /* adjust branches */ 645 for (i = 0; i < prog->NumInstructions; i++) { 646 struct prog_instruction *inst = prog->Instructions + i; 647 if (inst->BranchTarget > 0) { 648 if (inst->BranchTarget > (GLint) start) { 649 inst->BranchTarget -= count; 650 } 651 } 652 } 653 654 /* Alloc storage for new instructions */ 655 newInst = _mesa_alloc_instructions(newLen); 656 if (!newInst) { 657 return GL_FALSE; 658 } 659 660 /* Copy 'start' instructions into new instruction buffer */ 661 _mesa_copy_instructions(newInst, prog->Instructions, start); 662 663 /* Copy the remaining/tail instructions to new inst buffer */ 664 _mesa_copy_instructions(newInst + start, 665 prog->Instructions + start + count, 666 newLen - start); 667 668 /* free old instructions */ 669 _mesa_free_instructions(prog->Instructions, origLen); 670 671 /* install new instructions */ 672 prog->Instructions = newInst; 673 prog->NumInstructions = newLen; 674 675 return GL_TRUE; 676} 677 678 679/** 680 * Search instructions for registers that match (oldFile, oldIndex), 681 * replacing them with (newFile, newIndex). 682 */ 683static void 684replace_registers(struct prog_instruction *inst, GLuint numInst, 685 GLuint oldFile, GLuint oldIndex, 686 GLuint newFile, GLuint newIndex) 687{ 688 GLuint i, j; 689 for (i = 0; i < numInst; i++) { 690 /* src regs */ 691 for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) { 692 if (inst[i].SrcReg[j].File == oldFile && 693 inst[i].SrcReg[j].Index == oldIndex) { 694 inst[i].SrcReg[j].File = newFile; 695 inst[i].SrcReg[j].Index = newIndex; 696 } 697 } 698 /* dst reg */ 699 if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) { 700 inst[i].DstReg.File = newFile; 701 inst[i].DstReg.Index = newIndex; 702 } 703 } 704} 705 706 707/** 708 * Search instructions for references to program parameters. When found, 709 * increment the parameter index by 'offset'. 710 * Used when combining programs. 711 */ 712static void 713adjust_param_indexes(struct prog_instruction *inst, GLuint numInst, 714 GLuint offset) 715{ 716 GLuint i, j; 717 for (i = 0; i < numInst; i++) { 718 for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) { 719 GLuint f = inst[i].SrcReg[j].File; 720 if (f == PROGRAM_CONSTANT || 721 f == PROGRAM_UNIFORM || 722 f == PROGRAM_STATE_VAR) { 723 inst[i].SrcReg[j].Index += offset; 724 } 725 } 726 } 727} 728 729 730/** 731 * Combine two programs into one. Fix instructions so the outputs of 732 * the first program go to the inputs of the second program. 733 */ 734struct gl_program * 735_mesa_combine_programs(struct gl_context *ctx, 736 const struct gl_program *progA, 737 const struct gl_program *progB) 738{ 739 struct prog_instruction *newInst; 740 struct gl_program *newProg; 741 const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */ 742 const GLuint lenB = progB->NumInstructions; 743 const GLuint numParamsA = _mesa_num_parameters(progA->Parameters); 744 const GLuint newLength = lenA + lenB; 745 GLboolean usedTemps[MAX_PROGRAM_TEMPS]; 746 GLuint firstTemp = 0; 747 GLbitfield inputsB; 748 GLuint i; 749 750 ASSERT(progA->Target == progB->Target); 751 752 newInst = _mesa_alloc_instructions(newLength); 753 if (!newInst) 754 return GL_FALSE; 755 756 _mesa_copy_instructions(newInst, progA->Instructions, lenA); 757 _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB); 758 759 /* adjust branch / instruction addresses for B's instructions */ 760 for (i = 0; i < lenB; i++) { 761 newInst[lenA + i].BranchTarget += lenA; 762 } 763 764 newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0); 765 newProg->Instructions = newInst; 766 newProg->NumInstructions = newLength; 767 768 /* find used temp regs (we may need new temps below) */ 769 _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY, 770 usedTemps, MAX_PROGRAM_TEMPS); 771 772 if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) { 773 struct gl_fragment_program *fprogA, *fprogB, *newFprog; 774 GLbitfield progB_inputsRead = progB->InputsRead; 775 GLint progB_colorFile, progB_colorIndex; 776 777 fprogA = (struct gl_fragment_program *) progA; 778 fprogB = (struct gl_fragment_program *) progB; 779 newFprog = (struct gl_fragment_program *) newProg; 780 781 newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill; 782 783 /* We'll do a search and replace for instances 784 * of progB_colorFile/progB_colorIndex below... 785 */ 786 progB_colorFile = PROGRAM_INPUT; 787 progB_colorIndex = FRAG_ATTRIB_COL0; 788 789 /* 790 * The fragment program may get color from a state var rather than 791 * a fragment input (vertex output) if it's constant. 792 * See the texenvprogram.c code. 793 * So, search the program's parameter list now to see if the program 794 * gets color from a state var instead of a conventional fragment 795 * input register. 796 */ 797 for (i = 0; i < progB->Parameters->NumParameters; i++) { 798 struct gl_program_parameter *p = &progB->Parameters->Parameters[i]; 799 if (p->Type == PROGRAM_STATE_VAR && 800 p->StateIndexes[0] == STATE_INTERNAL && 801 p->StateIndexes[1] == STATE_CURRENT_ATTRIB && 802 (int) p->StateIndexes[2] == (int) VERT_ATTRIB_COLOR0) { 803 progB_inputsRead |= FRAG_BIT_COL0; 804 progB_colorFile = PROGRAM_STATE_VAR; 805 progB_colorIndex = i; 806 break; 807 } 808 } 809 810 /* Connect color outputs of fprogA to color inputs of fprogB, via a 811 * new temporary register. 812 */ 813 if ((progA->OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) && 814 (progB_inputsRead & FRAG_BIT_COL0)) { 815 GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS, 816 firstTemp); 817 if (tempReg < 0) { 818 _mesa_problem(ctx, "No free temp regs found in " 819 "_mesa_combine_programs(), using 31"); 820 tempReg = 31; 821 } 822 firstTemp = tempReg + 1; 823 824 /* replace writes to result.color[0] with tempReg */ 825 replace_registers(newInst, lenA, 826 PROGRAM_OUTPUT, FRAG_RESULT_COLOR, 827 PROGRAM_TEMPORARY, tempReg); 828 /* replace reads from the input color with tempReg */ 829 replace_registers(newInst + lenA, lenB, 830 progB_colorFile, progB_colorIndex, /* search for */ 831 PROGRAM_TEMPORARY, tempReg /* replace with */ ); 832 } 833 834 /* compute combined program's InputsRead */ 835 inputsB = progB_inputsRead; 836 if (progA->OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) { 837 inputsB &= ~(1 << FRAG_ATTRIB_COL0); 838 } 839 newProg->InputsRead = progA->InputsRead | inputsB; 840 newProg->OutputsWritten = progB->OutputsWritten; 841 newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed; 842 } 843 else { 844 /* vertex program */ 845 assert(0); /* XXX todo */ 846 } 847 848 /* 849 * Merge parameters (uniforms, constants, etc) 850 */ 851 newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters, 852 progB->Parameters); 853 854 adjust_param_indexes(newInst + lenA, lenB, numParamsA); 855 856 857 return newProg; 858} 859 860 861/** 862 * Populate the 'used' array with flags indicating which registers (TEMPs, 863 * INPUTs, OUTPUTs, etc, are used by the given program. 864 * \param file type of register to scan for 865 * \param used returns true/false flags for in use / free 866 * \param usedSize size of the 'used' array 867 */ 868void 869_mesa_find_used_registers(const struct gl_program *prog, 870 gl_register_file file, 871 GLboolean used[], GLuint usedSize) 872{ 873 GLuint i, j; 874 875 memset(used, 0, usedSize); 876 877 for (i = 0; i < prog->NumInstructions; i++) { 878 const struct prog_instruction *inst = prog->Instructions + i; 879 const GLuint n = _mesa_num_inst_src_regs(inst->Opcode); 880 881 if (inst->DstReg.File == file) { 882 ASSERT(inst->DstReg.Index < usedSize); 883 if(inst->DstReg.Index < usedSize) 884 used[inst->DstReg.Index] = GL_TRUE; 885 } 886 887 for (j = 0; j < n; j++) { 888 if (inst->SrcReg[j].File == file) { 889 ASSERT(inst->SrcReg[j].Index < usedSize); 890 if(inst->SrcReg[j].Index < usedSize) 891 used[inst->SrcReg[j].Index] = GL_TRUE; 892 } 893 } 894 } 895} 896 897 898/** 899 * Scan the given 'used' register flag array for the first entry 900 * that's >= firstReg. 901 * \param used vector of flags indicating registers in use (as returned 902 * by _mesa_find_used_registers()) 903 * \param usedSize size of the 'used' array 904 * \param firstReg first register to start searching at 905 * \return index of unused register, or -1 if none. 906 */ 907GLint 908_mesa_find_free_register(const GLboolean used[], 909 GLuint usedSize, GLuint firstReg) 910{ 911 GLuint i; 912 913 assert(firstReg < usedSize); 914 915 for (i = firstReg; i < usedSize; i++) 916 if (!used[i]) 917 return i; 918 919 return -1; 920} 921 922 923 924/** 925 * Check if the given register index is valid (doesn't exceed implementation- 926 * dependent limits). 927 * \return GL_TRUE if OK, GL_FALSE if bad index 928 */ 929GLboolean 930_mesa_valid_register_index(const struct gl_context *ctx, 931 gl_shader_type shaderType, 932 gl_register_file file, GLint index) 933{ 934 const struct gl_program_constants *c; 935 936 switch (shaderType) { 937 case MESA_SHADER_VERTEX: 938 c = &ctx->Const.VertexProgram; 939 break; 940 case MESA_SHADER_FRAGMENT: 941 c = &ctx->Const.FragmentProgram; 942 break; 943 case MESA_SHADER_GEOMETRY: 944 c = &ctx->Const.GeometryProgram; 945 break; 946 default: 947 _mesa_problem(ctx, 948 "unexpected shader type in _mesa_valid_register_index()"); 949 return GL_FALSE; 950 } 951 952 switch (file) { 953 case PROGRAM_UNDEFINED: 954 return GL_TRUE; /* XXX or maybe false? */ 955 956 case PROGRAM_TEMPORARY: 957 return index >= 0 && index < c->MaxTemps; 958 959 case PROGRAM_ENV_PARAM: 960 return index >= 0 && index < c->MaxEnvParams; 961 962 case PROGRAM_LOCAL_PARAM: 963 return index >= 0 && index < c->MaxLocalParams; 964 965 case PROGRAM_NAMED_PARAM: 966 return index >= 0 && index < c->MaxParameters; 967 968 case PROGRAM_UNIFORM: 969 case PROGRAM_STATE_VAR: 970 /* aka constant buffer */ 971 return index >= 0 && index < c->MaxUniformComponents / 4; 972 973 case PROGRAM_CONSTANT: 974 /* constant buffer w/ possible relative negative addressing */ 975 return (index > (int) c->MaxUniformComponents / -4 && 976 index < c->MaxUniformComponents / 4); 977 978 case PROGRAM_INPUT: 979 if (index < 0) 980 return GL_FALSE; 981 982 switch (shaderType) { 983 case MESA_SHADER_VERTEX: 984 return index < VERT_ATTRIB_GENERIC0 + c->MaxAttribs; 985 case MESA_SHADER_FRAGMENT: 986 return index < FRAG_ATTRIB_VAR0 + ctx->Const.MaxVarying; 987 case MESA_SHADER_GEOMETRY: 988 return index < GEOM_ATTRIB_VAR0 + ctx->Const.MaxVarying; 989 default: 990 return GL_FALSE; 991 } 992 993 case PROGRAM_OUTPUT: 994 if (index < 0) 995 return GL_FALSE; 996 997 switch (shaderType) { 998 case MESA_SHADER_VERTEX: 999 return index < VERT_RESULT_VAR0 + ctx->Const.MaxVarying; 1000 case MESA_SHADER_FRAGMENT: 1001 return index < FRAG_RESULT_DATA0 + ctx->Const.MaxDrawBuffers; 1002 case MESA_SHADER_GEOMETRY: 1003 return index < GEOM_RESULT_VAR0 + ctx->Const.MaxVarying; 1004 default: 1005 return GL_FALSE; 1006 } 1007 1008 case PROGRAM_ADDRESS: 1009 return index >= 0 && index < c->MaxAddressRegs; 1010 1011 default: 1012 _mesa_problem(ctx, 1013 "unexpected register file in _mesa_valid_register_index()"); 1014 return GL_FALSE; 1015 } 1016} 1017 1018 1019 1020/** 1021 * "Post-process" a GPU program. This is intended to be used for debugging. 1022 * Example actions include no-op'ing instructions or changing instruction 1023 * behaviour. 1024 */ 1025void 1026_mesa_postprocess_program(struct gl_context *ctx, struct gl_program *prog) 1027{ 1028 static const GLfloat white[4] = { 0.5, 0.5, 0.5, 0.5 }; 1029 GLuint i; 1030 GLuint whiteSwizzle; 1031 GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters, 1032 white, 4, &whiteSwizzle); 1033 1034 (void) whiteIndex; 1035 1036 for (i = 0; i < prog->NumInstructions; i++) { 1037 struct prog_instruction *inst = prog->Instructions + i; 1038 const GLuint n = _mesa_num_inst_src_regs(inst->Opcode); 1039 1040 (void) n; 1041 1042 if (_mesa_is_tex_instruction(inst->Opcode)) { 1043#if 0 1044 /* replace TEX/TXP/TXB with MOV */ 1045 inst->Opcode = OPCODE_MOV; 1046 inst->DstReg.WriteMask = WRITEMASK_XYZW; 1047 inst->SrcReg[0].Swizzle = SWIZZLE_XYZW; 1048 inst->SrcReg[0].Negate = NEGATE_NONE; 1049#endif 1050 1051#if 0 1052 /* disable shadow texture mode */ 1053 inst->TexShadow = 0; 1054#endif 1055 } 1056 1057 if (inst->Opcode == OPCODE_TXP) { 1058#if 0 1059 inst->Opcode = OPCODE_MOV; 1060 inst->DstReg.WriteMask = WRITEMASK_XYZW; 1061 inst->SrcReg[0].File = PROGRAM_CONSTANT; 1062 inst->SrcReg[0].Index = whiteIndex; 1063 inst->SrcReg[0].Swizzle = SWIZZLE_XYZW; 1064 inst->SrcReg[0].Negate = NEGATE_NONE; 1065#endif 1066#if 0 1067 inst->TexShadow = 0; 1068#endif 1069#if 0 1070 inst->Opcode = OPCODE_TEX; 1071 inst->TexShadow = 0; 1072#endif 1073 } 1074 1075 } 1076} 1077