1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg/** 26848b8605Smrg * \file programopt.c 27848b8605Smrg * Vertex/Fragment program optimizations and transformations for program 28848b8605Smrg * options, etc. 29848b8605Smrg * 30848b8605Smrg * \author Brian Paul 31848b8605Smrg */ 32848b8605Smrg 33848b8605Smrg 34848b8605Smrg#include "main/glheader.h" 35848b8605Smrg#include "main/context.h" 36848b8605Smrg#include "prog_parameter.h" 37848b8605Smrg#include "prog_statevars.h" 38848b8605Smrg#include "program.h" 39848b8605Smrg#include "programopt.h" 40848b8605Smrg#include "prog_instruction.h" 41848b8605Smrg 42848b8605Smrg 43848b8605Smrg/** 44848b8605Smrg * This function inserts instructions for coordinate modelview * projection 45848b8605Smrg * into a vertex program. 46848b8605Smrg * May be used to implement the position_invariant option. 47848b8605Smrg */ 48848b8605Smrgstatic void 49b8e80941Smrginsert_mvp_dp4_code(struct gl_context *ctx, struct gl_program *vprog) 50848b8605Smrg{ 51848b8605Smrg struct prog_instruction *newInst; 52b8e80941Smrg const GLuint origLen = vprog->arb.NumInstructions; 53848b8605Smrg const GLuint newLen = origLen + 4; 54848b8605Smrg GLuint i; 55848b8605Smrg 56848b8605Smrg /* 57848b8605Smrg * Setup state references for the modelview/projection matrix. 58848b8605Smrg * XXX we should check if these state vars are already declared. 59848b8605Smrg */ 60b8e80941Smrg static const gl_state_index16 mvpState[4][STATE_LENGTH] = { 61848b8605Smrg { STATE_MVP_MATRIX, 0, 0, 0, 0 }, /* state.matrix.mvp.row[0] */ 62848b8605Smrg { STATE_MVP_MATRIX, 0, 1, 1, 0 }, /* state.matrix.mvp.row[1] */ 63848b8605Smrg { STATE_MVP_MATRIX, 0, 2, 2, 0 }, /* state.matrix.mvp.row[2] */ 64848b8605Smrg { STATE_MVP_MATRIX, 0, 3, 3, 0 }, /* state.matrix.mvp.row[3] */ 65848b8605Smrg }; 66848b8605Smrg GLint mvpRef[4]; 67848b8605Smrg 68848b8605Smrg for (i = 0; i < 4; i++) { 69b8e80941Smrg mvpRef[i] = _mesa_add_state_reference(vprog->Parameters, mvpState[i]); 70848b8605Smrg } 71848b8605Smrg 72848b8605Smrg /* Alloc storage for new instructions */ 73b8e80941Smrg newInst = rzalloc_array(vprog, struct prog_instruction, newLen); 74848b8605Smrg if (!newInst) { 75848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, 76848b8605Smrg "glProgramString(inserting position_invariant code)"); 77848b8605Smrg return; 78848b8605Smrg } 79848b8605Smrg 80848b8605Smrg /* 81848b8605Smrg * Generated instructions: 82848b8605Smrg * newInst[0] = DP4 result.position.x, mvp.row[0], vertex.position; 83848b8605Smrg * newInst[1] = DP4 result.position.y, mvp.row[1], vertex.position; 84848b8605Smrg * newInst[2] = DP4 result.position.z, mvp.row[2], vertex.position; 85848b8605Smrg * newInst[3] = DP4 result.position.w, mvp.row[3], vertex.position; 86848b8605Smrg */ 87848b8605Smrg _mesa_init_instructions(newInst, 4); 88848b8605Smrg for (i = 0; i < 4; i++) { 89848b8605Smrg newInst[i].Opcode = OPCODE_DP4; 90848b8605Smrg newInst[i].DstReg.File = PROGRAM_OUTPUT; 91848b8605Smrg newInst[i].DstReg.Index = VARYING_SLOT_POS; 92848b8605Smrg newInst[i].DstReg.WriteMask = (WRITEMASK_X << i); 93848b8605Smrg newInst[i].SrcReg[0].File = PROGRAM_STATE_VAR; 94848b8605Smrg newInst[i].SrcReg[0].Index = mvpRef[i]; 95848b8605Smrg newInst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP; 96848b8605Smrg newInst[i].SrcReg[1].File = PROGRAM_INPUT; 97848b8605Smrg newInst[i].SrcReg[1].Index = VERT_ATTRIB_POS; 98848b8605Smrg newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; 99848b8605Smrg } 100848b8605Smrg 101848b8605Smrg /* Append original instructions after new instructions */ 102b8e80941Smrg _mesa_copy_instructions (newInst + 4, vprog->arb.Instructions, origLen); 103848b8605Smrg 104848b8605Smrg /* free old instructions */ 105b8e80941Smrg ralloc_free(vprog->arb.Instructions); 106848b8605Smrg 107848b8605Smrg /* install new instructions */ 108b8e80941Smrg vprog->arb.Instructions = newInst; 109b8e80941Smrg vprog->arb.NumInstructions = newLen; 110b8e80941Smrg vprog->info.inputs_read |= VERT_BIT_POS; 111b8e80941Smrg vprog->info.outputs_written |= BITFIELD64_BIT(VARYING_SLOT_POS); 112848b8605Smrg} 113848b8605Smrg 114848b8605Smrg 115848b8605Smrgstatic void 116b8e80941Smrginsert_mvp_mad_code(struct gl_context *ctx, struct gl_program *vprog) 117848b8605Smrg{ 118848b8605Smrg struct prog_instruction *newInst; 119b8e80941Smrg const GLuint origLen = vprog->arb.NumInstructions; 120848b8605Smrg const GLuint newLen = origLen + 4; 121848b8605Smrg GLuint hposTemp; 122848b8605Smrg GLuint i; 123848b8605Smrg 124848b8605Smrg /* 125848b8605Smrg * Setup state references for the modelview/projection matrix. 126848b8605Smrg * XXX we should check if these state vars are already declared. 127848b8605Smrg */ 128b8e80941Smrg static const gl_state_index16 mvpState[4][STATE_LENGTH] = { 129848b8605Smrg { STATE_MVP_MATRIX, 0, 0, 0, STATE_MATRIX_TRANSPOSE }, 130848b8605Smrg { STATE_MVP_MATRIX, 0, 1, 1, STATE_MATRIX_TRANSPOSE }, 131848b8605Smrg { STATE_MVP_MATRIX, 0, 2, 2, STATE_MATRIX_TRANSPOSE }, 132848b8605Smrg { STATE_MVP_MATRIX, 0, 3, 3, STATE_MATRIX_TRANSPOSE }, 133848b8605Smrg }; 134848b8605Smrg GLint mvpRef[4]; 135848b8605Smrg 136848b8605Smrg for (i = 0; i < 4; i++) { 137b8e80941Smrg mvpRef[i] = _mesa_add_state_reference(vprog->Parameters, mvpState[i]); 138848b8605Smrg } 139848b8605Smrg 140848b8605Smrg /* Alloc storage for new instructions */ 141b8e80941Smrg newInst = rzalloc_array(vprog, struct prog_instruction, newLen); 142848b8605Smrg if (!newInst) { 143848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, 144848b8605Smrg "glProgramString(inserting position_invariant code)"); 145848b8605Smrg return; 146848b8605Smrg } 147848b8605Smrg 148848b8605Smrg /* TEMP hposTemp; */ 149b8e80941Smrg hposTemp = vprog->arb.NumTemporaries++; 150848b8605Smrg 151848b8605Smrg /* 152848b8605Smrg * Generated instructions: 153848b8605Smrg * emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]); 154848b8605Smrg * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp); 155848b8605Smrg * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp); 156848b8605Smrg * emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp); 157848b8605Smrg */ 158848b8605Smrg _mesa_init_instructions(newInst, 4); 159848b8605Smrg 160848b8605Smrg newInst[0].Opcode = OPCODE_MUL; 161848b8605Smrg newInst[0].DstReg.File = PROGRAM_TEMPORARY; 162848b8605Smrg newInst[0].DstReg.Index = hposTemp; 163848b8605Smrg newInst[0].DstReg.WriteMask = WRITEMASK_XYZW; 164848b8605Smrg newInst[0].SrcReg[0].File = PROGRAM_INPUT; 165848b8605Smrg newInst[0].SrcReg[0].Index = VERT_ATTRIB_POS; 166848b8605Smrg newInst[0].SrcReg[0].Swizzle = SWIZZLE_XXXX; 167848b8605Smrg newInst[0].SrcReg[1].File = PROGRAM_STATE_VAR; 168848b8605Smrg newInst[0].SrcReg[1].Index = mvpRef[0]; 169848b8605Smrg newInst[0].SrcReg[1].Swizzle = SWIZZLE_NOOP; 170848b8605Smrg 171848b8605Smrg for (i = 1; i <= 2; i++) { 172848b8605Smrg newInst[i].Opcode = OPCODE_MAD; 173848b8605Smrg newInst[i].DstReg.File = PROGRAM_TEMPORARY; 174848b8605Smrg newInst[i].DstReg.Index = hposTemp; 175848b8605Smrg newInst[i].DstReg.WriteMask = WRITEMASK_XYZW; 176848b8605Smrg newInst[i].SrcReg[0].File = PROGRAM_INPUT; 177848b8605Smrg newInst[i].SrcReg[0].Index = VERT_ATTRIB_POS; 178848b8605Smrg newInst[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(i,i,i,i); 179848b8605Smrg newInst[i].SrcReg[1].File = PROGRAM_STATE_VAR; 180848b8605Smrg newInst[i].SrcReg[1].Index = mvpRef[i]; 181848b8605Smrg newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; 182848b8605Smrg newInst[i].SrcReg[2].File = PROGRAM_TEMPORARY; 183848b8605Smrg newInst[i].SrcReg[2].Index = hposTemp; 184848b8605Smrg newInst[1].SrcReg[2].Swizzle = SWIZZLE_NOOP; 185848b8605Smrg } 186848b8605Smrg 187848b8605Smrg newInst[3].Opcode = OPCODE_MAD; 188848b8605Smrg newInst[3].DstReg.File = PROGRAM_OUTPUT; 189848b8605Smrg newInst[3].DstReg.Index = VARYING_SLOT_POS; 190848b8605Smrg newInst[3].DstReg.WriteMask = WRITEMASK_XYZW; 191848b8605Smrg newInst[3].SrcReg[0].File = PROGRAM_INPUT; 192848b8605Smrg newInst[3].SrcReg[0].Index = VERT_ATTRIB_POS; 193848b8605Smrg newInst[3].SrcReg[0].Swizzle = SWIZZLE_WWWW; 194848b8605Smrg newInst[3].SrcReg[1].File = PROGRAM_STATE_VAR; 195848b8605Smrg newInst[3].SrcReg[1].Index = mvpRef[3]; 196848b8605Smrg newInst[3].SrcReg[1].Swizzle = SWIZZLE_NOOP; 197848b8605Smrg newInst[3].SrcReg[2].File = PROGRAM_TEMPORARY; 198848b8605Smrg newInst[3].SrcReg[2].Index = hposTemp; 199848b8605Smrg newInst[3].SrcReg[2].Swizzle = SWIZZLE_NOOP; 200848b8605Smrg 201848b8605Smrg 202848b8605Smrg /* Append original instructions after new instructions */ 203b8e80941Smrg _mesa_copy_instructions (newInst + 4, vprog->arb.Instructions, origLen); 204848b8605Smrg 205848b8605Smrg /* free old instructions */ 206b8e80941Smrg ralloc_free(vprog->arb.Instructions); 207848b8605Smrg 208848b8605Smrg /* install new instructions */ 209b8e80941Smrg vprog->arb.Instructions = newInst; 210b8e80941Smrg vprog->arb.NumInstructions = newLen; 211b8e80941Smrg vprog->info.inputs_read |= VERT_BIT_POS; 212b8e80941Smrg vprog->info.outputs_written |= BITFIELD64_BIT(VARYING_SLOT_POS); 213848b8605Smrg} 214848b8605Smrg 215848b8605Smrg 216848b8605Smrgvoid 217b8e80941Smrg_mesa_insert_mvp_code(struct gl_context *ctx, struct gl_program *vprog) 218848b8605Smrg{ 219848b8605Smrg if (ctx->Const.ShaderCompilerOptions[MESA_SHADER_VERTEX].OptimizeForAOS) 220b8e80941Smrg insert_mvp_dp4_code( ctx, vprog ); 221848b8605Smrg else 222b8e80941Smrg insert_mvp_mad_code( ctx, vprog ); 223848b8605Smrg} 224848b8605Smrg 225848b8605Smrg 226848b8605Smrg 227848b8605Smrg 228848b8605Smrg 229848b8605Smrg 230848b8605Smrg/** 231848b8605Smrg * Append instructions to implement fog 232848b8605Smrg * 233848b8605Smrg * The \c fragment.fogcoord input is used to compute the fog blend factor. 234848b8605Smrg * 235848b8605Smrg * \param ctx The GL context 236848b8605Smrg * \param fprog Fragment program that fog instructions will be appended to. 237848b8605Smrg * \param fog_mode Fog mode. One of \c GL_EXP, \c GL_EXP2, or \c GL_LINEAR. 238848b8605Smrg * \param saturate True if writes to color outputs should be clamped to [0, 1] 239848b8605Smrg * 240848b8605Smrg * \note 241b8e80941Smrg * This function sets \c VARYING_BIT_FOGC in \c fprog->info.inputs_read. 242848b8605Smrg * 243848b8605Smrg * \todo With a little work, this function could be adapted to add fog code 244848b8605Smrg * to vertex programs too. 245848b8605Smrg */ 246848b8605Smrgvoid 247b8e80941Smrg_mesa_append_fog_code(struct gl_context *ctx, struct gl_program *fprog, 248b8e80941Smrg GLenum fog_mode, GLboolean saturate) 249848b8605Smrg{ 250b8e80941Smrg static const gl_state_index16 fogPStateOpt[STATE_LENGTH] 251848b8605Smrg = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 }; 252b8e80941Smrg static const gl_state_index16 fogColorState[STATE_LENGTH] 253848b8605Smrg = { STATE_FOG_COLOR, 0, 0, 0, 0}; 254848b8605Smrg struct prog_instruction *newInst, *inst; 255b8e80941Smrg const GLuint origLen = fprog->arb.NumInstructions; 256848b8605Smrg const GLuint newLen = origLen + 5; 257848b8605Smrg GLuint i; 258848b8605Smrg GLint fogPRefOpt, fogColorRef; /* state references */ 259848b8605Smrg GLuint colorTemp, fogFactorTemp; /* temporary registerss */ 260848b8605Smrg 261848b8605Smrg if (fog_mode == GL_NONE) { 262848b8605Smrg _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program" 263848b8605Smrg " with fog_mode == GL_NONE"); 264848b8605Smrg return; 265848b8605Smrg } 266848b8605Smrg 267b8e80941Smrg if (!(fprog->info.outputs_written & (1 << FRAG_RESULT_COLOR))) { 268848b8605Smrg /* program doesn't output color, so nothing to do */ 269848b8605Smrg return; 270848b8605Smrg } 271848b8605Smrg 272848b8605Smrg /* Alloc storage for new instructions */ 273b8e80941Smrg newInst = rzalloc_array(fprog, struct prog_instruction, newLen); 274848b8605Smrg if (!newInst) { 275848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, 276848b8605Smrg "glProgramString(inserting fog_option code)"); 277848b8605Smrg return; 278848b8605Smrg } 279848b8605Smrg 280848b8605Smrg /* Copy orig instructions into new instruction buffer */ 281b8e80941Smrg _mesa_copy_instructions(newInst, fprog->arb.Instructions, origLen); 282848b8605Smrg 283848b8605Smrg /* PARAM fogParamsRefOpt = internal optimized fog params; */ 284848b8605Smrg fogPRefOpt 285b8e80941Smrg = _mesa_add_state_reference(fprog->Parameters, fogPStateOpt); 286848b8605Smrg /* PARAM fogColorRef = state.fog.color; */ 287848b8605Smrg fogColorRef 288b8e80941Smrg = _mesa_add_state_reference(fprog->Parameters, fogColorState); 289848b8605Smrg 290848b8605Smrg /* TEMP colorTemp; */ 291b8e80941Smrg colorTemp = fprog->arb.NumTemporaries++; 292848b8605Smrg /* TEMP fogFactorTemp; */ 293b8e80941Smrg fogFactorTemp = fprog->arb.NumTemporaries++; 294848b8605Smrg 295848b8605Smrg /* Scan program to find where result.color is written */ 296848b8605Smrg inst = newInst; 297b8e80941Smrg for (i = 0; i < fprog->arb.NumInstructions; i++) { 298848b8605Smrg if (inst->Opcode == OPCODE_END) 299848b8605Smrg break; 300848b8605Smrg if (inst->DstReg.File == PROGRAM_OUTPUT && 301848b8605Smrg inst->DstReg.Index == FRAG_RESULT_COLOR) { 302848b8605Smrg /* change the instruction to write to colorTemp w/ clamping */ 303848b8605Smrg inst->DstReg.File = PROGRAM_TEMPORARY; 304848b8605Smrg inst->DstReg.Index = colorTemp; 305b8e80941Smrg inst->Saturate = saturate; 306848b8605Smrg /* don't break (may be several writes to result.color) */ 307848b8605Smrg } 308848b8605Smrg inst++; 309848b8605Smrg } 310848b8605Smrg assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */ 311848b8605Smrg 312848b8605Smrg _mesa_init_instructions(inst, 5); 313848b8605Smrg 314848b8605Smrg /* emit instructions to compute fog blending factor */ 315848b8605Smrg /* this is always clamped to [0, 1] regardless of fragment clamping */ 316848b8605Smrg if (fog_mode == GL_LINEAR) { 317848b8605Smrg /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */ 318848b8605Smrg inst->Opcode = OPCODE_MAD; 319848b8605Smrg inst->DstReg.File = PROGRAM_TEMPORARY; 320848b8605Smrg inst->DstReg.Index = fogFactorTemp; 321848b8605Smrg inst->DstReg.WriteMask = WRITEMASK_X; 322848b8605Smrg inst->SrcReg[0].File = PROGRAM_INPUT; 323848b8605Smrg inst->SrcReg[0].Index = VARYING_SLOT_FOGC; 324848b8605Smrg inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 325848b8605Smrg inst->SrcReg[1].File = PROGRAM_STATE_VAR; 326848b8605Smrg inst->SrcReg[1].Index = fogPRefOpt; 327848b8605Smrg inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; 328848b8605Smrg inst->SrcReg[2].File = PROGRAM_STATE_VAR; 329848b8605Smrg inst->SrcReg[2].Index = fogPRefOpt; 330848b8605Smrg inst->SrcReg[2].Swizzle = SWIZZLE_YYYY; 331b8e80941Smrg inst->Saturate = GL_TRUE; 332848b8605Smrg inst++; 333848b8605Smrg } 334848b8605Smrg else { 335b8e80941Smrg assert(fog_mode == GL_EXP || fog_mode == GL_EXP2); 336848b8605Smrg /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */ 337848b8605Smrg /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */ 338848b8605Smrg /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */ 339848b8605Smrg inst->Opcode = OPCODE_MUL; 340848b8605Smrg inst->DstReg.File = PROGRAM_TEMPORARY; 341848b8605Smrg inst->DstReg.Index = fogFactorTemp; 342848b8605Smrg inst->DstReg.WriteMask = WRITEMASK_X; 343848b8605Smrg inst->SrcReg[0].File = PROGRAM_STATE_VAR; 344848b8605Smrg inst->SrcReg[0].Index = fogPRefOpt; 345848b8605Smrg inst->SrcReg[0].Swizzle 346848b8605Smrg = (fog_mode == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW; 347848b8605Smrg inst->SrcReg[1].File = PROGRAM_INPUT; 348848b8605Smrg inst->SrcReg[1].Index = VARYING_SLOT_FOGC; 349848b8605Smrg inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; 350848b8605Smrg inst++; 351848b8605Smrg if (fog_mode == GL_EXP2) { 352848b8605Smrg /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */ 353848b8605Smrg inst->Opcode = OPCODE_MUL; 354848b8605Smrg inst->DstReg.File = PROGRAM_TEMPORARY; 355848b8605Smrg inst->DstReg.Index = fogFactorTemp; 356848b8605Smrg inst->DstReg.WriteMask = WRITEMASK_X; 357848b8605Smrg inst->SrcReg[0].File = PROGRAM_TEMPORARY; 358848b8605Smrg inst->SrcReg[0].Index = fogFactorTemp; 359848b8605Smrg inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 360848b8605Smrg inst->SrcReg[1].File = PROGRAM_TEMPORARY; 361848b8605Smrg inst->SrcReg[1].Index = fogFactorTemp; 362848b8605Smrg inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; 363848b8605Smrg inst++; 364848b8605Smrg } 365848b8605Smrg /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */ 366848b8605Smrg inst->Opcode = OPCODE_EX2; 367848b8605Smrg inst->DstReg.File = PROGRAM_TEMPORARY; 368848b8605Smrg inst->DstReg.Index = fogFactorTemp; 369848b8605Smrg inst->DstReg.WriteMask = WRITEMASK_X; 370848b8605Smrg inst->SrcReg[0].File = PROGRAM_TEMPORARY; 371848b8605Smrg inst->SrcReg[0].Index = fogFactorTemp; 372848b8605Smrg inst->SrcReg[0].Negate = NEGATE_XYZW; 373848b8605Smrg inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 374b8e80941Smrg inst->Saturate = GL_TRUE; 375848b8605Smrg inst++; 376848b8605Smrg } 377848b8605Smrg /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */ 378848b8605Smrg inst->Opcode = OPCODE_LRP; 379848b8605Smrg inst->DstReg.File = PROGRAM_OUTPUT; 380848b8605Smrg inst->DstReg.Index = FRAG_RESULT_COLOR; 381848b8605Smrg inst->DstReg.WriteMask = WRITEMASK_XYZ; 382848b8605Smrg inst->SrcReg[0].File = PROGRAM_TEMPORARY; 383848b8605Smrg inst->SrcReg[0].Index = fogFactorTemp; 384848b8605Smrg inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 385848b8605Smrg inst->SrcReg[1].File = PROGRAM_TEMPORARY; 386848b8605Smrg inst->SrcReg[1].Index = colorTemp; 387848b8605Smrg inst->SrcReg[1].Swizzle = SWIZZLE_NOOP; 388848b8605Smrg inst->SrcReg[2].File = PROGRAM_STATE_VAR; 389848b8605Smrg inst->SrcReg[2].Index = fogColorRef; 390848b8605Smrg inst->SrcReg[2].Swizzle = SWIZZLE_NOOP; 391848b8605Smrg inst++; 392848b8605Smrg /* MOV result.color.w, colorTemp.x; # copy alpha */ 393848b8605Smrg inst->Opcode = OPCODE_MOV; 394848b8605Smrg inst->DstReg.File = PROGRAM_OUTPUT; 395848b8605Smrg inst->DstReg.Index = FRAG_RESULT_COLOR; 396848b8605Smrg inst->DstReg.WriteMask = WRITEMASK_W; 397848b8605Smrg inst->SrcReg[0].File = PROGRAM_TEMPORARY; 398848b8605Smrg inst->SrcReg[0].Index = colorTemp; 399848b8605Smrg inst->SrcReg[0].Swizzle = SWIZZLE_NOOP; 400848b8605Smrg inst++; 401848b8605Smrg /* END; */ 402848b8605Smrg inst->Opcode = OPCODE_END; 403848b8605Smrg inst++; 404848b8605Smrg 405848b8605Smrg /* free old instructions */ 406b8e80941Smrg ralloc_free(fprog->arb.Instructions); 407848b8605Smrg 408848b8605Smrg /* install new instructions */ 409b8e80941Smrg fprog->arb.Instructions = newInst; 410b8e80941Smrg fprog->arb.NumInstructions = inst - newInst; 411b8e80941Smrg fprog->info.inputs_read |= VARYING_BIT_FOGC; 412b8e80941Smrg assert(fprog->info.outputs_written & (1 << FRAG_RESULT_COLOR)); 413848b8605Smrg} 414848b8605Smrg 415848b8605Smrg 416848b8605Smrg 417848b8605Smrgstatic GLboolean 418848b8605Smrgis_texture_instruction(const struct prog_instruction *inst) 419848b8605Smrg{ 420848b8605Smrg switch (inst->Opcode) { 421848b8605Smrg case OPCODE_TEX: 422848b8605Smrg case OPCODE_TXB: 423848b8605Smrg case OPCODE_TXD: 424848b8605Smrg case OPCODE_TXL: 425848b8605Smrg case OPCODE_TXP: 426848b8605Smrg return GL_TRUE; 427848b8605Smrg default: 428848b8605Smrg return GL_FALSE; 429848b8605Smrg } 430848b8605Smrg} 431848b8605Smrg 432848b8605Smrg 433848b8605Smrg/** 434848b8605Smrg * Count the number of texure indirections in the given program. 435848b8605Smrg * The program's NumTexIndirections field will be updated. 436848b8605Smrg * See the GL_ARB_fragment_program spec (issue 24) for details. 437848b8605Smrg * XXX we count texture indirections in texenvprogram.c (maybe use this code 438848b8605Smrg * instead and elsewhere). 439848b8605Smrg */ 440848b8605Smrgvoid 441848b8605Smrg_mesa_count_texture_indirections(struct gl_program *prog) 442848b8605Smrg{ 443848b8605Smrg GLuint indirections = 1; 444848b8605Smrg GLbitfield tempsOutput = 0x0; 445848b8605Smrg GLbitfield aluTemps = 0x0; 446848b8605Smrg GLuint i; 447848b8605Smrg 448b8e80941Smrg for (i = 0; i < prog->arb.NumInstructions; i++) { 449b8e80941Smrg const struct prog_instruction *inst = prog->arb.Instructions + i; 450848b8605Smrg 451848b8605Smrg if (is_texture_instruction(inst)) { 452848b8605Smrg if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) && 453848b8605Smrg (tempsOutput & (1 << inst->SrcReg[0].Index))) || 454848b8605Smrg ((inst->Opcode != OPCODE_KIL) && 455848b8605Smrg (inst->DstReg.File == PROGRAM_TEMPORARY) && 456848b8605Smrg (aluTemps & (1 << inst->DstReg.Index)))) 457848b8605Smrg { 458848b8605Smrg indirections++; 459848b8605Smrg tempsOutput = 0x0; 460848b8605Smrg aluTemps = 0x0; 461848b8605Smrg } 462848b8605Smrg } 463848b8605Smrg else { 464848b8605Smrg GLuint j; 465848b8605Smrg for (j = 0; j < 3; j++) { 466848b8605Smrg if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) 467848b8605Smrg aluTemps |= (1 << inst->SrcReg[j].Index); 468848b8605Smrg } 469848b8605Smrg if (inst->DstReg.File == PROGRAM_TEMPORARY) 470848b8605Smrg aluTemps |= (1 << inst->DstReg.Index); 471848b8605Smrg } 472848b8605Smrg 473848b8605Smrg if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY)) 474848b8605Smrg tempsOutput |= (1 << inst->DstReg.Index); 475848b8605Smrg } 476848b8605Smrg 477b8e80941Smrg prog->arb.NumTexIndirections = indirections; 478848b8605Smrg} 479848b8605Smrg 480848b8605Smrg 481848b8605Smrg/** 482848b8605Smrg * Count number of texture instructions in given program and update the 483848b8605Smrg * program's NumTexInstructions field. 484848b8605Smrg */ 485848b8605Smrgvoid 486848b8605Smrg_mesa_count_texture_instructions(struct gl_program *prog) 487848b8605Smrg{ 488848b8605Smrg GLuint i; 489b8e80941Smrg prog->arb.NumTexInstructions = 0; 490b8e80941Smrg for (i = 0; i < prog->arb.NumInstructions; i++) { 491b8e80941Smrg prog->arb.NumTexInstructions += 492b8e80941Smrg is_texture_instruction(prog->arb.Instructions + i); 493848b8605Smrg } 494848b8605Smrg} 495848b8605Smrg 496848b8605Smrg 497848b8605Smrg/** 498848b8605Smrg * Scan/rewrite program to remove reads of custom (output) registers. 499848b8605Smrg * The passed type has to be PROGRAM_OUTPUT. 500848b8605Smrg * On some hardware, trying to read an output register causes trouble. 501848b8605Smrg * So, rewrite the program to use a temporary register in this case. 502848b8605Smrg */ 503848b8605Smrgvoid 504848b8605Smrg_mesa_remove_output_reads(struct gl_program *prog, gl_register_file type) 505848b8605Smrg{ 506848b8605Smrg GLuint i; 507848b8605Smrg GLint outputMap[VARYING_SLOT_MAX]; 508848b8605Smrg GLuint numVaryingReads = 0; 509848b8605Smrg GLboolean usedTemps[MAX_PROGRAM_TEMPS]; 510848b8605Smrg GLuint firstTemp = 0; 511848b8605Smrg 512848b8605Smrg _mesa_find_used_registers(prog, PROGRAM_TEMPORARY, 513848b8605Smrg usedTemps, MAX_PROGRAM_TEMPS); 514848b8605Smrg 515848b8605Smrg assert(type == PROGRAM_OUTPUT); 516848b8605Smrg 517848b8605Smrg for (i = 0; i < VARYING_SLOT_MAX; i++) 518848b8605Smrg outputMap[i] = -1; 519848b8605Smrg 520848b8605Smrg /* look for instructions which read from varying vars */ 521b8e80941Smrg for (i = 0; i < prog->arb.NumInstructions; i++) { 522b8e80941Smrg struct prog_instruction *inst = prog->arb.Instructions + i; 523848b8605Smrg const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); 524848b8605Smrg GLuint j; 525848b8605Smrg for (j = 0; j < numSrc; j++) { 526848b8605Smrg if (inst->SrcReg[j].File == type) { 527848b8605Smrg /* replace the read with a temp reg */ 528848b8605Smrg const GLuint var = inst->SrcReg[j].Index; 529848b8605Smrg if (outputMap[var] == -1) { 530848b8605Smrg numVaryingReads++; 531848b8605Smrg outputMap[var] = _mesa_find_free_register(usedTemps, 532848b8605Smrg MAX_PROGRAM_TEMPS, 533848b8605Smrg firstTemp); 534848b8605Smrg firstTemp = outputMap[var] + 1; 535848b8605Smrg } 536848b8605Smrg inst->SrcReg[j].File = PROGRAM_TEMPORARY; 537848b8605Smrg inst->SrcReg[j].Index = outputMap[var]; 538848b8605Smrg } 539848b8605Smrg } 540848b8605Smrg } 541848b8605Smrg 542848b8605Smrg if (numVaryingReads == 0) 543848b8605Smrg return; /* nothing to be done */ 544848b8605Smrg 545848b8605Smrg /* look for instructions which write to the varying vars identified above */ 546b8e80941Smrg for (i = 0; i < prog->arb.NumInstructions; i++) { 547b8e80941Smrg struct prog_instruction *inst = prog->arb.Instructions + i; 548848b8605Smrg if (inst->DstReg.File == type && 549848b8605Smrg outputMap[inst->DstReg.Index] >= 0) { 550848b8605Smrg /* change inst to write to the temp reg, instead of the varying */ 551848b8605Smrg inst->DstReg.File = PROGRAM_TEMPORARY; 552848b8605Smrg inst->DstReg.Index = outputMap[inst->DstReg.Index]; 553848b8605Smrg } 554848b8605Smrg } 555848b8605Smrg 556848b8605Smrg /* insert new instructions to copy the temp vars to the varying vars */ 557848b8605Smrg { 558848b8605Smrg struct prog_instruction *inst; 559848b8605Smrg GLint endPos, var; 560848b8605Smrg 561848b8605Smrg /* Look for END instruction and insert the new varying writes */ 562848b8605Smrg endPos = -1; 563b8e80941Smrg for (i = 0; i < prog->arb.NumInstructions; i++) { 564b8e80941Smrg struct prog_instruction *inst = prog->arb.Instructions + i; 565848b8605Smrg if (inst->Opcode == OPCODE_END) { 566848b8605Smrg endPos = i; 567848b8605Smrg _mesa_insert_instructions(prog, i, numVaryingReads); 568848b8605Smrg break; 569848b8605Smrg } 570848b8605Smrg } 571848b8605Smrg 572848b8605Smrg assert(endPos >= 0); 573848b8605Smrg 574848b8605Smrg /* insert new MOV instructions here */ 575b8e80941Smrg inst = prog->arb.Instructions + endPos; 576848b8605Smrg for (var = 0; var < VARYING_SLOT_MAX; var++) { 577848b8605Smrg if (outputMap[var] >= 0) { 578848b8605Smrg /* MOV VAR[var], TEMP[tmp]; */ 579848b8605Smrg inst->Opcode = OPCODE_MOV; 580848b8605Smrg inst->DstReg.File = type; 581848b8605Smrg inst->DstReg.Index = var; 582848b8605Smrg inst->SrcReg[0].File = PROGRAM_TEMPORARY; 583848b8605Smrg inst->SrcReg[0].Index = outputMap[var]; 584848b8605Smrg inst++; 585848b8605Smrg } 586848b8605Smrg } 587848b8605Smrg } 588848b8605Smrg} 589848b8605Smrg 590848b8605Smrgvoid 591b8e80941Smrg_mesa_program_fragment_position_to_sysval(struct gl_program *prog) 592848b8605Smrg{ 593b8e80941Smrg GLuint i; 594848b8605Smrg 595b8e80941Smrg if (prog->Target != GL_FRAGMENT_PROGRAM_ARB || 596b8e80941Smrg !(prog->info.inputs_read & BITFIELD64_BIT(VARYING_SLOT_POS))) 597848b8605Smrg return; 598848b8605Smrg 599b8e80941Smrg prog->info.inputs_read &= ~BITFIELD64_BIT(VARYING_SLOT_POS); 600b8e80941Smrg prog->info.system_values_read |= 1 << SYSTEM_VALUE_FRAG_COORD; 601848b8605Smrg 602b8e80941Smrg for (i = 0; i < prog->arb.NumInstructions; i++) { 603b8e80941Smrg struct prog_instruction *inst = prog->arb.Instructions + i; 604b8e80941Smrg const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); 605b8e80941Smrg GLuint j; 606848b8605Smrg 607b8e80941Smrg for (j = 0; j < numSrc; j++) { 608b8e80941Smrg if (inst->SrcReg[j].File == PROGRAM_INPUT && 609b8e80941Smrg inst->SrcReg[j].Index == VARYING_SLOT_POS) { 610b8e80941Smrg inst->SrcReg[j].File = PROGRAM_SYSTEM_VALUE; 611b8e80941Smrg inst->SrcReg[j].Index = SYSTEM_VALUE_FRAG_COORD; 612b8e80941Smrg } 613b8e80941Smrg } 614848b8605Smrg } 615848b8605Smrg} 616