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