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