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 programopt.c 27 * Vertex/Fragment program optimizations and transformations for program 28 * options, etc. 29 * 30 * \author Brian Paul 31 */ 32 33 34 #include "main/glheader.h" 35 #include "main/context.h" 36 #include "prog_parameter.h" 37 #include "prog_statevars.h" 38 #include "program.h" 39 #include "programopt.h" 40 #include "prog_instruction.h" 41 42 43 /** 44 * This function inserts instructions for coordinate modelview * projection 45 * into a vertex program. 46 * May be used to implement the position_invariant option. 47 */ 48 static void 49 _mesa_insert_mvp_dp4_code(struct gl_context *ctx, struct gl_vertex_program *vprog) 50 { 51 struct prog_instruction *newInst; 52 const GLuint origLen = vprog->Base.NumInstructions; 53 const GLuint newLen = origLen + 4; 54 GLuint i; 55 56 /* 57 * Setup state references for the modelview/projection matrix. 58 * XXX we should check if these state vars are already declared. 59 */ 60 static const gl_state_index mvpState[4][STATE_LENGTH] = { 61 { STATE_MVP_MATRIX, 0, 0, 0, 0 }, /* state.matrix.mvp.row[0] */ 62 { STATE_MVP_MATRIX, 0, 1, 1, 0 }, /* state.matrix.mvp.row[1] */ 63 { STATE_MVP_MATRIX, 0, 2, 2, 0 }, /* state.matrix.mvp.row[2] */ 64 { STATE_MVP_MATRIX, 0, 3, 3, 0 }, /* state.matrix.mvp.row[3] */ 65 }; 66 GLint mvpRef[4]; 67 68 for (i = 0; i < 4; i++) { 69 mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters, 70 mvpState[i]); 71 } 72 73 /* Alloc storage for new instructions */ 74 newInst = _mesa_alloc_instructions(newLen); 75 if (!newInst) { 76 _mesa_error(ctx, GL_OUT_OF_MEMORY, 77 "glProgramString(inserting position_invariant code)"); 78 return; 79 } 80 81 /* 82 * Generated instructions: 83 * newInst[0] = DP4 result.position.x, mvp.row[0], vertex.position; 84 * newInst[1] = DP4 result.position.y, mvp.row[1], vertex.position; 85 * newInst[2] = DP4 result.position.z, mvp.row[2], vertex.position; 86 * newInst[3] = DP4 result.position.w, mvp.row[3], vertex.position; 87 */ 88 _mesa_init_instructions(newInst, 4); 89 for (i = 0; i < 4; i++) { 90 newInst[i].Opcode = OPCODE_DP4; 91 newInst[i].DstReg.File = PROGRAM_OUTPUT; 92 newInst[i].DstReg.Index = VERT_RESULT_HPOS; 93 newInst[i].DstReg.WriteMask = (WRITEMASK_X << i); 94 newInst[i].SrcReg[0].File = PROGRAM_STATE_VAR; 95 newInst[i].SrcReg[0].Index = mvpRef[i]; 96 newInst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP; 97 newInst[i].SrcReg[1].File = PROGRAM_INPUT; 98 newInst[i].SrcReg[1].Index = VERT_ATTRIB_POS; 99 newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; 100 } 101 102 /* Append original instructions after new instructions */ 103 _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen); 104 105 /* free old instructions */ 106 _mesa_free_instructions(vprog->Base.Instructions, origLen); 107 108 /* install new instructions */ 109 vprog->Base.Instructions = newInst; 110 vprog->Base.NumInstructions = newLen; 111 vprog->Base.InputsRead |= VERT_BIT_POS; 112 vprog->Base.OutputsWritten |= BITFIELD64_BIT(VERT_RESULT_HPOS); 113 } 114 115 116 static void 117 _mesa_insert_mvp_mad_code(struct gl_context *ctx, struct gl_vertex_program *vprog) 118 { 119 struct prog_instruction *newInst; 120 const GLuint origLen = vprog->Base.NumInstructions; 121 const GLuint newLen = origLen + 4; 122 GLuint hposTemp; 123 GLuint i; 124 125 /* 126 * Setup state references for the modelview/projection matrix. 127 * XXX we should check if these state vars are already declared. 128 */ 129 static const gl_state_index mvpState[4][STATE_LENGTH] = { 130 { STATE_MVP_MATRIX, 0, 0, 0, STATE_MATRIX_TRANSPOSE }, 131 { STATE_MVP_MATRIX, 0, 1, 1, STATE_MATRIX_TRANSPOSE }, 132 { STATE_MVP_MATRIX, 0, 2, 2, STATE_MATRIX_TRANSPOSE }, 133 { STATE_MVP_MATRIX, 0, 3, 3, STATE_MATRIX_TRANSPOSE }, 134 }; 135 GLint mvpRef[4]; 136 137 for (i = 0; i < 4; i++) { 138 mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters, 139 mvpState[i]); 140 } 141 142 /* Alloc storage for new instructions */ 143 newInst = _mesa_alloc_instructions(newLen); 144 if (!newInst) { 145 _mesa_error(ctx, GL_OUT_OF_MEMORY, 146 "glProgramString(inserting position_invariant code)"); 147 return; 148 } 149 150 /* TEMP hposTemp; */ 151 hposTemp = vprog->Base.NumTemporaries++; 152 153 /* 154 * Generated instructions: 155 * emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]); 156 * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp); 157 * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp); 158 * emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp); 159 */ 160 _mesa_init_instructions(newInst, 4); 161 162 newInst[0].Opcode = OPCODE_MUL; 163 newInst[0].DstReg.File = PROGRAM_TEMPORARY; 164 newInst[0].DstReg.Index = hposTemp; 165 newInst[0].DstReg.WriteMask = WRITEMASK_XYZW; 166 newInst[0].SrcReg[0].File = PROGRAM_INPUT; 167 newInst[0].SrcReg[0].Index = VERT_ATTRIB_POS; 168 newInst[0].SrcReg[0].Swizzle = SWIZZLE_XXXX; 169 newInst[0].SrcReg[1].File = PROGRAM_STATE_VAR; 170 newInst[0].SrcReg[1].Index = mvpRef[0]; 171 newInst[0].SrcReg[1].Swizzle = SWIZZLE_NOOP; 172 173 for (i = 1; i <= 2; i++) { 174 newInst[i].Opcode = OPCODE_MAD; 175 newInst[i].DstReg.File = PROGRAM_TEMPORARY; 176 newInst[i].DstReg.Index = hposTemp; 177 newInst[i].DstReg.WriteMask = WRITEMASK_XYZW; 178 newInst[i].SrcReg[0].File = PROGRAM_INPUT; 179 newInst[i].SrcReg[0].Index = VERT_ATTRIB_POS; 180 newInst[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(i,i,i,i); 181 newInst[i].SrcReg[1].File = PROGRAM_STATE_VAR; 182 newInst[i].SrcReg[1].Index = mvpRef[i]; 183 newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; 184 newInst[i].SrcReg[2].File = PROGRAM_TEMPORARY; 185 newInst[i].SrcReg[2].Index = hposTemp; 186 newInst[1].SrcReg[2].Swizzle = SWIZZLE_NOOP; 187 } 188 189 newInst[3].Opcode = OPCODE_MAD; 190 newInst[3].DstReg.File = PROGRAM_OUTPUT; 191 newInst[3].DstReg.Index = VERT_RESULT_HPOS; 192 newInst[3].DstReg.WriteMask = WRITEMASK_XYZW; 193 newInst[3].SrcReg[0].File = PROGRAM_INPUT; 194 newInst[3].SrcReg[0].Index = VERT_ATTRIB_POS; 195 newInst[3].SrcReg[0].Swizzle = SWIZZLE_WWWW; 196 newInst[3].SrcReg[1].File = PROGRAM_STATE_VAR; 197 newInst[3].SrcReg[1].Index = mvpRef[3]; 198 newInst[3].SrcReg[1].Swizzle = SWIZZLE_NOOP; 199 newInst[3].SrcReg[2].File = PROGRAM_TEMPORARY; 200 newInst[3].SrcReg[2].Index = hposTemp; 201 newInst[3].SrcReg[2].Swizzle = SWIZZLE_NOOP; 202 203 204 /* Append original instructions after new instructions */ 205 _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen); 206 207 /* free old instructions */ 208 _mesa_free_instructions(vprog->Base.Instructions, origLen); 209 210 /* install new instructions */ 211 vprog->Base.Instructions = newInst; 212 vprog->Base.NumInstructions = newLen; 213 vprog->Base.InputsRead |= VERT_BIT_POS; 214 vprog->Base.OutputsWritten |= BITFIELD64_BIT(VERT_RESULT_HPOS); 215 } 216 217 218 void 219 _mesa_insert_mvp_code(struct gl_context *ctx, struct gl_vertex_program *vprog) 220 { 221 if (ctx->mvp_with_dp4) 222 _mesa_insert_mvp_dp4_code( ctx, vprog ); 223 else 224 _mesa_insert_mvp_mad_code( ctx, vprog ); 225 } 226 227 228 229 230 231 232 /** 233 * Append instructions to implement fog 234 * 235 * The \c fragment.fogcoord input is used to compute the fog blend factor. 236 * 237 * \param ctx The GL context 238 * \param fprog Fragment program that fog instructions will be appended to. 239 * \param fog_mode Fog mode. One of \c GL_EXP, \c GL_EXP2, or \c GL_LINEAR. 240 * \param saturate True if writes to color outputs should be clamped to [0, 1] 241 * 242 * \note 243 * This function sets \c FRAG_BIT_FOGC in \c fprog->Base.InputsRead. 244 * 245 * \todo With a little work, this function could be adapted to add fog code 246 * to vertex programs too. 247 */ 248 void 249 _mesa_append_fog_code(struct gl_context *ctx, 250 struct gl_fragment_program *fprog, GLenum fog_mode, 251 GLboolean saturate) 252 { 253 static const gl_state_index fogPStateOpt[STATE_LENGTH] 254 = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 }; 255 static const gl_state_index fogColorState[STATE_LENGTH] 256 = { STATE_FOG_COLOR, 0, 0, 0, 0}; 257 struct prog_instruction *newInst, *inst; 258 const GLuint origLen = fprog->Base.NumInstructions; 259 const GLuint newLen = origLen + 5; 260 GLuint i; 261 GLint fogPRefOpt, fogColorRef; /* state references */ 262 GLuint colorTemp, fogFactorTemp; /* temporary registerss */ 263 264 if (fog_mode == GL_NONE) { 265 _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program" 266 " with fog_mode == GL_NONE"); 267 return; 268 } 269 270 if (!(fprog->Base.OutputsWritten & (1 << FRAG_RESULT_COLOR))) { 271 /* program doesn't output color, so nothing to do */ 272 return; 273 } 274 275 /* Alloc storage for new instructions */ 276 newInst = _mesa_alloc_instructions(newLen); 277 if (!newInst) { 278 _mesa_error(ctx, GL_OUT_OF_MEMORY, 279 "glProgramString(inserting fog_option code)"); 280 return; 281 } 282 283 /* Copy orig instructions into new instruction buffer */ 284 _mesa_copy_instructions(newInst, fprog->Base.Instructions, origLen); 285 286 /* PARAM fogParamsRefOpt = internal optimized fog params; */ 287 fogPRefOpt 288 = _mesa_add_state_reference(fprog->Base.Parameters, fogPStateOpt); 289 /* PARAM fogColorRef = state.fog.color; */ 290 fogColorRef 291 = _mesa_add_state_reference(fprog->Base.Parameters, fogColorState); 292 293 /* TEMP colorTemp; */ 294 colorTemp = fprog->Base.NumTemporaries++; 295 /* TEMP fogFactorTemp; */ 296 fogFactorTemp = fprog->Base.NumTemporaries++; 297 298 /* Scan program to find where result.color is written */ 299 inst = newInst; 300 for (i = 0; i < fprog->Base.NumInstructions; i++) { 301 if (inst->Opcode == OPCODE_END) 302 break; 303 if (inst->DstReg.File == PROGRAM_OUTPUT && 304 inst->DstReg.Index == FRAG_RESULT_COLOR) { 305 /* change the instruction to write to colorTemp w/ clamping */ 306 inst->DstReg.File = PROGRAM_TEMPORARY; 307 inst->DstReg.Index = colorTemp; 308 inst->SaturateMode = saturate; 309 /* don't break (may be several writes to result.color) */ 310 } 311 inst++; 312 } 313 assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */ 314 315 _mesa_init_instructions(inst, 5); 316 317 /* emit instructions to compute fog blending factor */ 318 /* this is always clamped to [0, 1] regardless of fragment clamping */ 319 if (fog_mode == GL_LINEAR) { 320 /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */ 321 inst->Opcode = OPCODE_MAD; 322 inst->DstReg.File = PROGRAM_TEMPORARY; 323 inst->DstReg.Index = fogFactorTemp; 324 inst->DstReg.WriteMask = WRITEMASK_X; 325 inst->SrcReg[0].File = PROGRAM_INPUT; 326 inst->SrcReg[0].Index = FRAG_ATTRIB_FOGC; 327 inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 328 inst->SrcReg[1].File = PROGRAM_STATE_VAR; 329 inst->SrcReg[1].Index = fogPRefOpt; 330 inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; 331 inst->SrcReg[2].File = PROGRAM_STATE_VAR; 332 inst->SrcReg[2].Index = fogPRefOpt; 333 inst->SrcReg[2].Swizzle = SWIZZLE_YYYY; 334 inst->SaturateMode = SATURATE_ZERO_ONE; 335 inst++; 336 } 337 else { 338 ASSERT(fog_mode == GL_EXP || fog_mode == GL_EXP2); 339 /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */ 340 /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */ 341 /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */ 342 inst->Opcode = OPCODE_MUL; 343 inst->DstReg.File = PROGRAM_TEMPORARY; 344 inst->DstReg.Index = fogFactorTemp; 345 inst->DstReg.WriteMask = WRITEMASK_X; 346 inst->SrcReg[0].File = PROGRAM_STATE_VAR; 347 inst->SrcReg[0].Index = fogPRefOpt; 348 inst->SrcReg[0].Swizzle 349 = (fog_mode == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW; 350 inst->SrcReg[1].File = PROGRAM_INPUT; 351 inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC; 352 inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; 353 inst++; 354 if (fog_mode == GL_EXP2) { 355 /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */ 356 inst->Opcode = OPCODE_MUL; 357 inst->DstReg.File = PROGRAM_TEMPORARY; 358 inst->DstReg.Index = fogFactorTemp; 359 inst->DstReg.WriteMask = WRITEMASK_X; 360 inst->SrcReg[0].File = PROGRAM_TEMPORARY; 361 inst->SrcReg[0].Index = fogFactorTemp; 362 inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 363 inst->SrcReg[1].File = PROGRAM_TEMPORARY; 364 inst->SrcReg[1].Index = fogFactorTemp; 365 inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; 366 inst++; 367 } 368 /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */ 369 inst->Opcode = OPCODE_EX2; 370 inst->DstReg.File = PROGRAM_TEMPORARY; 371 inst->DstReg.Index = fogFactorTemp; 372 inst->DstReg.WriteMask = WRITEMASK_X; 373 inst->SrcReg[0].File = PROGRAM_TEMPORARY; 374 inst->SrcReg[0].Index = fogFactorTemp; 375 inst->SrcReg[0].Negate = NEGATE_XYZW; 376 inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 377 inst->SaturateMode = SATURATE_ZERO_ONE; 378 inst++; 379 } 380 /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */ 381 inst->Opcode = OPCODE_LRP; 382 inst->DstReg.File = PROGRAM_OUTPUT; 383 inst->DstReg.Index = FRAG_RESULT_COLOR; 384 inst->DstReg.WriteMask = WRITEMASK_XYZ; 385 inst->SrcReg[0].File = PROGRAM_TEMPORARY; 386 inst->SrcReg[0].Index = fogFactorTemp; 387 inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 388 inst->SrcReg[1].File = PROGRAM_TEMPORARY; 389 inst->SrcReg[1].Index = colorTemp; 390 inst->SrcReg[1].Swizzle = SWIZZLE_NOOP; 391 inst->SrcReg[2].File = PROGRAM_STATE_VAR; 392 inst->SrcReg[2].Index = fogColorRef; 393 inst->SrcReg[2].Swizzle = SWIZZLE_NOOP; 394 inst++; 395 /* MOV result.color.w, colorTemp.x; # copy alpha */ 396 inst->Opcode = OPCODE_MOV; 397 inst->DstReg.File = PROGRAM_OUTPUT; 398 inst->DstReg.Index = FRAG_RESULT_COLOR; 399 inst->DstReg.WriteMask = WRITEMASK_W; 400 inst->SrcReg[0].File = PROGRAM_TEMPORARY; 401 inst->SrcReg[0].Index = colorTemp; 402 inst->SrcReg[0].Swizzle = SWIZZLE_NOOP; 403 inst++; 404 /* END; */ 405 inst->Opcode = OPCODE_END; 406 inst++; 407 408 /* free old instructions */ 409 _mesa_free_instructions(fprog->Base.Instructions, origLen); 410 411 /* install new instructions */ 412 fprog->Base.Instructions = newInst; 413 fprog->Base.NumInstructions = inst - newInst; 414 fprog->Base.InputsRead |= FRAG_BIT_FOGC; 415 assert(fprog->Base.OutputsWritten & (1 << FRAG_RESULT_COLOR)); 416 } 417 418 419 420 static GLboolean 421 is_texture_instruction(const struct prog_instruction *inst) 422 { 423 switch (inst->Opcode) { 424 case OPCODE_TEX: 425 case OPCODE_TXB: 426 case OPCODE_TXD: 427 case OPCODE_TXL: 428 case OPCODE_TXP: 429 case OPCODE_TXP_NV: 430 return GL_TRUE; 431 default: 432 return GL_FALSE; 433 } 434 } 435 436 437 /** 438 * Count the number of texure indirections in the given program. 439 * The program's NumTexIndirections field will be updated. 440 * See the GL_ARB_fragment_program spec (issue 24) for details. 441 * XXX we count texture indirections in texenvprogram.c (maybe use this code 442 * instead and elsewhere). 443 */ 444 void 445 _mesa_count_texture_indirections(struct gl_program *prog) 446 { 447 GLuint indirections = 1; 448 GLbitfield tempsOutput = 0x0; 449 GLbitfield aluTemps = 0x0; 450 GLuint i; 451 452 for (i = 0; i < prog->NumInstructions; i++) { 453 const struct prog_instruction *inst = prog->Instructions + i; 454 455 if (is_texture_instruction(inst)) { 456 if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) && 457 (tempsOutput & (1 << inst->SrcReg[0].Index))) || 458 ((inst->Opcode != OPCODE_KIL) && 459 (inst->DstReg.File == PROGRAM_TEMPORARY) && 460 (aluTemps & (1 << inst->DstReg.Index)))) 461 { 462 indirections++; 463 tempsOutput = 0x0; 464 aluTemps = 0x0; 465 } 466 } 467 else { 468 GLuint j; 469 for (j = 0; j < 3; j++) { 470 if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) 471 aluTemps |= (1 << inst->SrcReg[j].Index); 472 } 473 if (inst->DstReg.File == PROGRAM_TEMPORARY) 474 aluTemps |= (1 << inst->DstReg.Index); 475 } 476 477 if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY)) 478 tempsOutput |= (1 << inst->DstReg.Index); 479 } 480 481 prog->NumTexIndirections = indirections; 482 } 483 484 485 /** 486 * Count number of texture instructions in given program and update the 487 * program's NumTexInstructions field. 488 */ 489 void 490 _mesa_count_texture_instructions(struct gl_program *prog) 491 { 492 GLuint i; 493 prog->NumTexInstructions = 0; 494 for (i = 0; i < prog->NumInstructions; i++) { 495 prog->NumTexInstructions += is_texture_instruction(prog->Instructions + i); 496 } 497 } 498 499 500 /** 501 * Scan/rewrite program to remove reads of custom (output) registers. 502 * The passed type has to be either PROGRAM_OUTPUT or PROGRAM_VARYING 503 * (for vertex shaders). 504 * In GLSL shaders, varying vars can be read and written. 505 * On some hardware, trying to read an output register causes trouble. 506 * So, rewrite the program to use a temporary register in this case. 507 */ 508 void 509 _mesa_remove_output_reads(struct gl_program *prog, gl_register_file type) 510 { 511 GLuint i; 512 GLint outputMap[VERT_RESULT_MAX]; 513 GLuint numVaryingReads = 0; 514 GLboolean usedTemps[MAX_PROGRAM_TEMPS]; 515 GLuint firstTemp = 0; 516 517 _mesa_find_used_registers(prog, PROGRAM_TEMPORARY, 518 usedTemps, MAX_PROGRAM_TEMPS); 519 520 assert(type == PROGRAM_VARYING || type == PROGRAM_OUTPUT); 521 assert(prog->Target == GL_VERTEX_PROGRAM_ARB || type != PROGRAM_VARYING); 522 523 for (i = 0; i < VERT_RESULT_MAX; i++) 524 outputMap[i] = -1; 525 526 /* look for instructions which read from varying vars */ 527 for (i = 0; i < prog->NumInstructions; i++) { 528 struct prog_instruction *inst = prog->Instructions + i; 529 const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); 530 GLuint j; 531 for (j = 0; j < numSrc; j++) { 532 if (inst->SrcReg[j].File == type) { 533 /* replace the read with a temp reg */ 534 const GLuint var = inst->SrcReg[j].Index; 535 if (outputMap[var] == -1) { 536 numVaryingReads++; 537 outputMap[var] = _mesa_find_free_register(usedTemps, 538 MAX_PROGRAM_TEMPS, 539 firstTemp); 540 firstTemp = outputMap[var] + 1; 541 } 542 inst->SrcReg[j].File = PROGRAM_TEMPORARY; 543 inst->SrcReg[j].Index = outputMap[var]; 544 } 545 } 546 } 547 548 if (numVaryingReads == 0) 549 return; /* nothing to be done */ 550 551 /* look for instructions which write to the varying vars identified above */ 552 for (i = 0; i < prog->NumInstructions; i++) { 553 struct prog_instruction *inst = prog->Instructions + i; 554 if (inst->DstReg.File == type && 555 outputMap[inst->DstReg.Index] >= 0) { 556 /* change inst to write to the temp reg, instead of the varying */ 557 inst->DstReg.File = PROGRAM_TEMPORARY; 558 inst->DstReg.Index = outputMap[inst->DstReg.Index]; 559 } 560 } 561 562 /* insert new instructions to copy the temp vars to the varying vars */ 563 { 564 struct prog_instruction *inst; 565 GLint endPos, var; 566 567 /* Look for END instruction and insert the new varying writes */ 568 endPos = -1; 569 for (i = 0; i < prog->NumInstructions; i++) { 570 struct prog_instruction *inst = prog->Instructions + i; 571 if (inst->Opcode == OPCODE_END) { 572 endPos = i; 573 _mesa_insert_instructions(prog, i, numVaryingReads); 574 break; 575 } 576 } 577 578 assert(endPos >= 0); 579 580 /* insert new MOV instructions here */ 581 inst = prog->Instructions + endPos; 582 for (var = 0; var < VERT_RESULT_MAX; var++) { 583 if (outputMap[var] >= 0) { 584 /* MOV VAR[var], TEMP[tmp]; */ 585 inst->Opcode = OPCODE_MOV; 586 inst->DstReg.File = type; 587 inst->DstReg.Index = var; 588 inst->SrcReg[0].File = PROGRAM_TEMPORARY; 589 inst->SrcReg[0].Index = outputMap[var]; 590 inst++; 591 } 592 } 593 } 594 } 595 596 597 /** 598 * Make the given fragment program into a "no-op" shader. 599 * Actually, just copy the incoming fragment color (or texcoord) 600 * to the output color. 601 * This is for debug/test purposes. 602 */ 603 void 604 _mesa_nop_fragment_program(struct gl_context *ctx, struct gl_fragment_program *prog) 605 { 606 struct prog_instruction *inst; 607 GLuint inputAttr; 608 609 inst = _mesa_alloc_instructions(2); 610 if (!inst) { 611 _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_fragment_program"); 612 return; 613 } 614 615 _mesa_init_instructions(inst, 2); 616 617 inst[0].Opcode = OPCODE_MOV; 618 inst[0].DstReg.File = PROGRAM_OUTPUT; 619 inst[0].DstReg.Index = FRAG_RESULT_COLOR; 620 inst[0].SrcReg[0].File = PROGRAM_INPUT; 621 if (prog->Base.InputsRead & FRAG_BIT_COL0) 622 inputAttr = FRAG_ATTRIB_COL0; 623 else 624 inputAttr = FRAG_ATTRIB_TEX0; 625 inst[0].SrcReg[0].Index = inputAttr; 626 627 inst[1].Opcode = OPCODE_END; 628 629 _mesa_free_instructions(prog->Base.Instructions, 630 prog->Base.NumInstructions); 631 632 prog->Base.Instructions = inst; 633 prog->Base.NumInstructions = 2; 634 prog->Base.InputsRead = BITFIELD64_BIT(inputAttr); 635 prog->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR); 636 } 637 638 639 /** 640 * \sa _mesa_nop_fragment_program 641 * Replace the given vertex program with a "no-op" program that just 642 * transforms vertex position and emits color. 643 */ 644 void 645 _mesa_nop_vertex_program(struct gl_context *ctx, struct gl_vertex_program *prog) 646 { 647 struct prog_instruction *inst; 648 GLuint inputAttr; 649 650 /* 651 * Start with a simple vertex program that emits color. 652 */ 653 inst = _mesa_alloc_instructions(2); 654 if (!inst) { 655 _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_vertex_program"); 656 return; 657 } 658 659 _mesa_init_instructions(inst, 2); 660 661 inst[0].Opcode = OPCODE_MOV; 662 inst[0].DstReg.File = PROGRAM_OUTPUT; 663 inst[0].DstReg.Index = VERT_RESULT_COL0; 664 inst[0].SrcReg[0].File = PROGRAM_INPUT; 665 if (prog->Base.InputsRead & VERT_BIT_COLOR0) 666 inputAttr = VERT_ATTRIB_COLOR0; 667 else 668 inputAttr = VERT_ATTRIB_TEX0; 669 inst[0].SrcReg[0].Index = inputAttr; 670 671 inst[1].Opcode = OPCODE_END; 672 673 _mesa_free_instructions(prog->Base.Instructions, 674 prog->Base.NumInstructions); 675 676 prog->Base.Instructions = inst; 677 prog->Base.NumInstructions = 2; 678 prog->Base.InputsRead = BITFIELD64_BIT(inputAttr); 679 prog->Base.OutputsWritten = BITFIELD64_BIT(VERT_RESULT_COL0); 680 681 /* 682 * Now insert code to do standard modelview/projection transformation. 683 */ 684 _mesa_insert_mvp_code(ctx, prog); 685 } 686