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