programopt.c revision 01e04c3f
13464ebd5Sriastradh/* 23464ebd5Sriastradh * Mesa 3-D graphics library 33464ebd5Sriastradh * 43464ebd5Sriastradh * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 53464ebd5Sriastradh * 63464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a 73464ebd5Sriastradh * copy of this software and associated documentation files (the "Software"), 83464ebd5Sriastradh * to deal in the Software without restriction, including without limitation 93464ebd5Sriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 103464ebd5Sriastradh * and/or sell copies of the Software, and to permit persons to whom the 113464ebd5Sriastradh * Software is furnished to do so, subject to the following conditions: 123464ebd5Sriastradh * 133464ebd5Sriastradh * The above copyright notice and this permission notice shall be included 143464ebd5Sriastradh * in all copies or substantial portions of the Software. 153464ebd5Sriastradh * 163464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 173464ebd5Sriastradh * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 183464ebd5Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 233464ebd5Sriastradh */ 243464ebd5Sriastradh 253464ebd5Sriastradh/** 263464ebd5Sriastradh * \file programopt.c 273464ebd5Sriastradh * Vertex/Fragment program optimizations and transformations for program 283464ebd5Sriastradh * options, etc. 293464ebd5Sriastradh * 303464ebd5Sriastradh * \author Brian Paul 313464ebd5Sriastradh */ 323464ebd5Sriastradh 333464ebd5Sriastradh 343464ebd5Sriastradh#include "main/glheader.h" 353464ebd5Sriastradh#include "main/context.h" 363464ebd5Sriastradh#include "prog_parameter.h" 373464ebd5Sriastradh#include "prog_statevars.h" 383464ebd5Sriastradh#include "program.h" 393464ebd5Sriastradh#include "programopt.h" 403464ebd5Sriastradh#include "prog_instruction.h" 413464ebd5Sriastradh 423464ebd5Sriastradh 433464ebd5Sriastradh/** 443464ebd5Sriastradh * This function inserts instructions for coordinate modelview * projection 453464ebd5Sriastradh * into a vertex program. 463464ebd5Sriastradh * May be used to implement the position_invariant option. 473464ebd5Sriastradh */ 483464ebd5Sriastradhstatic void 4901e04c3fSmrginsert_mvp_dp4_code(struct gl_context *ctx, struct gl_program *vprog) 503464ebd5Sriastradh{ 513464ebd5Sriastradh struct prog_instruction *newInst; 5201e04c3fSmrg const GLuint origLen = vprog->arb.NumInstructions; 533464ebd5Sriastradh const GLuint newLen = origLen + 4; 543464ebd5Sriastradh GLuint i; 553464ebd5Sriastradh 563464ebd5Sriastradh /* 573464ebd5Sriastradh * Setup state references for the modelview/projection matrix. 583464ebd5Sriastradh * XXX we should check if these state vars are already declared. 593464ebd5Sriastradh */ 6001e04c3fSmrg static const gl_state_index16 mvpState[4][STATE_LENGTH] = { 613464ebd5Sriastradh { STATE_MVP_MATRIX, 0, 0, 0, 0 }, /* state.matrix.mvp.row[0] */ 623464ebd5Sriastradh { STATE_MVP_MATRIX, 0, 1, 1, 0 }, /* state.matrix.mvp.row[1] */ 633464ebd5Sriastradh { STATE_MVP_MATRIX, 0, 2, 2, 0 }, /* state.matrix.mvp.row[2] */ 643464ebd5Sriastradh { STATE_MVP_MATRIX, 0, 3, 3, 0 }, /* state.matrix.mvp.row[3] */ 653464ebd5Sriastradh }; 663464ebd5Sriastradh GLint mvpRef[4]; 673464ebd5Sriastradh 683464ebd5Sriastradh for (i = 0; i < 4; i++) { 6901e04c3fSmrg mvpRef[i] = _mesa_add_state_reference(vprog->Parameters, mvpState[i]); 703464ebd5Sriastradh } 713464ebd5Sriastradh 723464ebd5Sriastradh /* Alloc storage for new instructions */ 7301e04c3fSmrg newInst = rzalloc_array(vprog, struct prog_instruction, newLen); 743464ebd5Sriastradh if (!newInst) { 753464ebd5Sriastradh _mesa_error(ctx, GL_OUT_OF_MEMORY, 763464ebd5Sriastradh "glProgramString(inserting position_invariant code)"); 773464ebd5Sriastradh return; 783464ebd5Sriastradh } 793464ebd5Sriastradh 803464ebd5Sriastradh /* 813464ebd5Sriastradh * Generated instructions: 823464ebd5Sriastradh * newInst[0] = DP4 result.position.x, mvp.row[0], vertex.position; 833464ebd5Sriastradh * newInst[1] = DP4 result.position.y, mvp.row[1], vertex.position; 843464ebd5Sriastradh * newInst[2] = DP4 result.position.z, mvp.row[2], vertex.position; 853464ebd5Sriastradh * newInst[3] = DP4 result.position.w, mvp.row[3], vertex.position; 863464ebd5Sriastradh */ 873464ebd5Sriastradh _mesa_init_instructions(newInst, 4); 883464ebd5Sriastradh for (i = 0; i < 4; i++) { 893464ebd5Sriastradh newInst[i].Opcode = OPCODE_DP4; 903464ebd5Sriastradh newInst[i].DstReg.File = PROGRAM_OUTPUT; 91af69d88dSmrg newInst[i].DstReg.Index = VARYING_SLOT_POS; 923464ebd5Sriastradh newInst[i].DstReg.WriteMask = (WRITEMASK_X << i); 933464ebd5Sriastradh newInst[i].SrcReg[0].File = PROGRAM_STATE_VAR; 943464ebd5Sriastradh newInst[i].SrcReg[0].Index = mvpRef[i]; 953464ebd5Sriastradh newInst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP; 963464ebd5Sriastradh newInst[i].SrcReg[1].File = PROGRAM_INPUT; 973464ebd5Sriastradh newInst[i].SrcReg[1].Index = VERT_ATTRIB_POS; 983464ebd5Sriastradh newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; 993464ebd5Sriastradh } 1003464ebd5Sriastradh 1013464ebd5Sriastradh /* Append original instructions after new instructions */ 10201e04c3fSmrg _mesa_copy_instructions (newInst + 4, vprog->arb.Instructions, origLen); 1033464ebd5Sriastradh 1043464ebd5Sriastradh /* free old instructions */ 10501e04c3fSmrg ralloc_free(vprog->arb.Instructions); 1063464ebd5Sriastradh 1073464ebd5Sriastradh /* install new instructions */ 10801e04c3fSmrg vprog->arb.Instructions = newInst; 10901e04c3fSmrg vprog->arb.NumInstructions = newLen; 11001e04c3fSmrg vprog->info.inputs_read |= VERT_BIT_POS; 11101e04c3fSmrg vprog->info.outputs_written |= BITFIELD64_BIT(VARYING_SLOT_POS); 1123464ebd5Sriastradh} 1133464ebd5Sriastradh 1143464ebd5Sriastradh 1153464ebd5Sriastradhstatic void 11601e04c3fSmrginsert_mvp_mad_code(struct gl_context *ctx, struct gl_program *vprog) 1173464ebd5Sriastradh{ 1183464ebd5Sriastradh struct prog_instruction *newInst; 11901e04c3fSmrg const GLuint origLen = vprog->arb.NumInstructions; 1203464ebd5Sriastradh const GLuint newLen = origLen + 4; 1213464ebd5Sriastradh GLuint hposTemp; 1223464ebd5Sriastradh GLuint i; 1233464ebd5Sriastradh 1243464ebd5Sriastradh /* 1253464ebd5Sriastradh * Setup state references for the modelview/projection matrix. 1263464ebd5Sriastradh * XXX we should check if these state vars are already declared. 1273464ebd5Sriastradh */ 12801e04c3fSmrg static const gl_state_index16 mvpState[4][STATE_LENGTH] = { 1293464ebd5Sriastradh { STATE_MVP_MATRIX, 0, 0, 0, STATE_MATRIX_TRANSPOSE }, 1303464ebd5Sriastradh { STATE_MVP_MATRIX, 0, 1, 1, STATE_MATRIX_TRANSPOSE }, 1313464ebd5Sriastradh { STATE_MVP_MATRIX, 0, 2, 2, STATE_MATRIX_TRANSPOSE }, 1323464ebd5Sriastradh { STATE_MVP_MATRIX, 0, 3, 3, STATE_MATRIX_TRANSPOSE }, 1333464ebd5Sriastradh }; 1343464ebd5Sriastradh GLint mvpRef[4]; 1353464ebd5Sriastradh 1363464ebd5Sriastradh for (i = 0; i < 4; i++) { 13701e04c3fSmrg mvpRef[i] = _mesa_add_state_reference(vprog->Parameters, mvpState[i]); 1383464ebd5Sriastradh } 1393464ebd5Sriastradh 1403464ebd5Sriastradh /* Alloc storage for new instructions */ 14101e04c3fSmrg newInst = rzalloc_array(vprog, struct prog_instruction, newLen); 1423464ebd5Sriastradh if (!newInst) { 1433464ebd5Sriastradh _mesa_error(ctx, GL_OUT_OF_MEMORY, 1443464ebd5Sriastradh "glProgramString(inserting position_invariant code)"); 1453464ebd5Sriastradh return; 1463464ebd5Sriastradh } 1473464ebd5Sriastradh 1483464ebd5Sriastradh /* TEMP hposTemp; */ 14901e04c3fSmrg hposTemp = vprog->arb.NumTemporaries++; 1503464ebd5Sriastradh 1513464ebd5Sriastradh /* 1523464ebd5Sriastradh * Generated instructions: 1533464ebd5Sriastradh * emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]); 1543464ebd5Sriastradh * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp); 1553464ebd5Sriastradh * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp); 1563464ebd5Sriastradh * emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp); 1573464ebd5Sriastradh */ 1583464ebd5Sriastradh _mesa_init_instructions(newInst, 4); 1593464ebd5Sriastradh 1603464ebd5Sriastradh newInst[0].Opcode = OPCODE_MUL; 1613464ebd5Sriastradh newInst[0].DstReg.File = PROGRAM_TEMPORARY; 1623464ebd5Sriastradh newInst[0].DstReg.Index = hposTemp; 1633464ebd5Sriastradh newInst[0].DstReg.WriteMask = WRITEMASK_XYZW; 1643464ebd5Sriastradh newInst[0].SrcReg[0].File = PROGRAM_INPUT; 1653464ebd5Sriastradh newInst[0].SrcReg[0].Index = VERT_ATTRIB_POS; 1663464ebd5Sriastradh newInst[0].SrcReg[0].Swizzle = SWIZZLE_XXXX; 1673464ebd5Sriastradh newInst[0].SrcReg[1].File = PROGRAM_STATE_VAR; 1683464ebd5Sriastradh newInst[0].SrcReg[1].Index = mvpRef[0]; 1693464ebd5Sriastradh newInst[0].SrcReg[1].Swizzle = SWIZZLE_NOOP; 1703464ebd5Sriastradh 1713464ebd5Sriastradh for (i = 1; i <= 2; i++) { 1723464ebd5Sriastradh newInst[i].Opcode = OPCODE_MAD; 1733464ebd5Sriastradh newInst[i].DstReg.File = PROGRAM_TEMPORARY; 1743464ebd5Sriastradh newInst[i].DstReg.Index = hposTemp; 1753464ebd5Sriastradh newInst[i].DstReg.WriteMask = WRITEMASK_XYZW; 1763464ebd5Sriastradh newInst[i].SrcReg[0].File = PROGRAM_INPUT; 1773464ebd5Sriastradh newInst[i].SrcReg[0].Index = VERT_ATTRIB_POS; 1783464ebd5Sriastradh newInst[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(i,i,i,i); 1793464ebd5Sriastradh newInst[i].SrcReg[1].File = PROGRAM_STATE_VAR; 1803464ebd5Sriastradh newInst[i].SrcReg[1].Index = mvpRef[i]; 1813464ebd5Sriastradh newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; 1823464ebd5Sriastradh newInst[i].SrcReg[2].File = PROGRAM_TEMPORARY; 1833464ebd5Sriastradh newInst[i].SrcReg[2].Index = hposTemp; 1843464ebd5Sriastradh newInst[1].SrcReg[2].Swizzle = SWIZZLE_NOOP; 1853464ebd5Sriastradh } 1863464ebd5Sriastradh 1873464ebd5Sriastradh newInst[3].Opcode = OPCODE_MAD; 1883464ebd5Sriastradh newInst[3].DstReg.File = PROGRAM_OUTPUT; 189af69d88dSmrg newInst[3].DstReg.Index = VARYING_SLOT_POS; 1903464ebd5Sriastradh newInst[3].DstReg.WriteMask = WRITEMASK_XYZW; 1913464ebd5Sriastradh newInst[3].SrcReg[0].File = PROGRAM_INPUT; 1923464ebd5Sriastradh newInst[3].SrcReg[0].Index = VERT_ATTRIB_POS; 1933464ebd5Sriastradh newInst[3].SrcReg[0].Swizzle = SWIZZLE_WWWW; 1943464ebd5Sriastradh newInst[3].SrcReg[1].File = PROGRAM_STATE_VAR; 1953464ebd5Sriastradh newInst[3].SrcReg[1].Index = mvpRef[3]; 1963464ebd5Sriastradh newInst[3].SrcReg[1].Swizzle = SWIZZLE_NOOP; 1973464ebd5Sriastradh newInst[3].SrcReg[2].File = PROGRAM_TEMPORARY; 1983464ebd5Sriastradh newInst[3].SrcReg[2].Index = hposTemp; 1993464ebd5Sriastradh newInst[3].SrcReg[2].Swizzle = SWIZZLE_NOOP; 2003464ebd5Sriastradh 2013464ebd5Sriastradh 2023464ebd5Sriastradh /* Append original instructions after new instructions */ 20301e04c3fSmrg _mesa_copy_instructions (newInst + 4, vprog->arb.Instructions, origLen); 2043464ebd5Sriastradh 2053464ebd5Sriastradh /* free old instructions */ 20601e04c3fSmrg ralloc_free(vprog->arb.Instructions); 2073464ebd5Sriastradh 2083464ebd5Sriastradh /* install new instructions */ 20901e04c3fSmrg vprog->arb.Instructions = newInst; 21001e04c3fSmrg vprog->arb.NumInstructions = newLen; 21101e04c3fSmrg vprog->info.inputs_read |= VERT_BIT_POS; 21201e04c3fSmrg vprog->info.outputs_written |= BITFIELD64_BIT(VARYING_SLOT_POS); 2133464ebd5Sriastradh} 2143464ebd5Sriastradh 2153464ebd5Sriastradh 2163464ebd5Sriastradhvoid 21701e04c3fSmrg_mesa_insert_mvp_code(struct gl_context *ctx, struct gl_program *vprog) 2183464ebd5Sriastradh{ 219af69d88dSmrg if (ctx->Const.ShaderCompilerOptions[MESA_SHADER_VERTEX].OptimizeForAOS) 22001e04c3fSmrg insert_mvp_dp4_code( ctx, vprog ); 2213464ebd5Sriastradh else 22201e04c3fSmrg insert_mvp_mad_code( ctx, vprog ); 2233464ebd5Sriastradh} 2243464ebd5Sriastradh 2253464ebd5Sriastradh 2263464ebd5Sriastradh 2273464ebd5Sriastradh 2283464ebd5Sriastradh 2293464ebd5Sriastradh 2303464ebd5Sriastradh/** 2313464ebd5Sriastradh * Append instructions to implement fog 2323464ebd5Sriastradh * 2333464ebd5Sriastradh * The \c fragment.fogcoord input is used to compute the fog blend factor. 2343464ebd5Sriastradh * 2353464ebd5Sriastradh * \param ctx The GL context 2363464ebd5Sriastradh * \param fprog Fragment program that fog instructions will be appended to. 2373464ebd5Sriastradh * \param fog_mode Fog mode. One of \c GL_EXP, \c GL_EXP2, or \c GL_LINEAR. 2383464ebd5Sriastradh * \param saturate True if writes to color outputs should be clamped to [0, 1] 2393464ebd5Sriastradh * 2403464ebd5Sriastradh * \note 24101e04c3fSmrg * This function sets \c VARYING_BIT_FOGC in \c fprog->info.inputs_read. 2423464ebd5Sriastradh * 2433464ebd5Sriastradh * \todo With a little work, this function could be adapted to add fog code 2443464ebd5Sriastradh * to vertex programs too. 2453464ebd5Sriastradh */ 2463464ebd5Sriastradhvoid 24701e04c3fSmrg_mesa_append_fog_code(struct gl_context *ctx, struct gl_program *fprog, 24801e04c3fSmrg GLenum fog_mode, GLboolean saturate) 2493464ebd5Sriastradh{ 25001e04c3fSmrg static const gl_state_index16 fogPStateOpt[STATE_LENGTH] 2513464ebd5Sriastradh = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 }; 25201e04c3fSmrg static const gl_state_index16 fogColorState[STATE_LENGTH] 2533464ebd5Sriastradh = { STATE_FOG_COLOR, 0, 0, 0, 0}; 2543464ebd5Sriastradh struct prog_instruction *newInst, *inst; 25501e04c3fSmrg const GLuint origLen = fprog->arb.NumInstructions; 2563464ebd5Sriastradh const GLuint newLen = origLen + 5; 2573464ebd5Sriastradh GLuint i; 2583464ebd5Sriastradh GLint fogPRefOpt, fogColorRef; /* state references */ 2593464ebd5Sriastradh GLuint colorTemp, fogFactorTemp; /* temporary registerss */ 2603464ebd5Sriastradh 2613464ebd5Sriastradh if (fog_mode == GL_NONE) { 2623464ebd5Sriastradh _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program" 2633464ebd5Sriastradh " with fog_mode == GL_NONE"); 2643464ebd5Sriastradh return; 2653464ebd5Sriastradh } 2663464ebd5Sriastradh 26701e04c3fSmrg if (!(fprog->info.outputs_written & (1 << FRAG_RESULT_COLOR))) { 2683464ebd5Sriastradh /* program doesn't output color, so nothing to do */ 2693464ebd5Sriastradh return; 2703464ebd5Sriastradh } 2713464ebd5Sriastradh 2723464ebd5Sriastradh /* Alloc storage for new instructions */ 27301e04c3fSmrg newInst = rzalloc_array(fprog, struct prog_instruction, newLen); 2743464ebd5Sriastradh if (!newInst) { 2753464ebd5Sriastradh _mesa_error(ctx, GL_OUT_OF_MEMORY, 2763464ebd5Sriastradh "glProgramString(inserting fog_option code)"); 2773464ebd5Sriastradh return; 2783464ebd5Sriastradh } 2793464ebd5Sriastradh 2803464ebd5Sriastradh /* Copy orig instructions into new instruction buffer */ 28101e04c3fSmrg _mesa_copy_instructions(newInst, fprog->arb.Instructions, origLen); 2823464ebd5Sriastradh 2833464ebd5Sriastradh /* PARAM fogParamsRefOpt = internal optimized fog params; */ 2843464ebd5Sriastradh fogPRefOpt 28501e04c3fSmrg = _mesa_add_state_reference(fprog->Parameters, fogPStateOpt); 2863464ebd5Sriastradh /* PARAM fogColorRef = state.fog.color; */ 2873464ebd5Sriastradh fogColorRef 28801e04c3fSmrg = _mesa_add_state_reference(fprog->Parameters, fogColorState); 2893464ebd5Sriastradh 2903464ebd5Sriastradh /* TEMP colorTemp; */ 29101e04c3fSmrg colorTemp = fprog->arb.NumTemporaries++; 2923464ebd5Sriastradh /* TEMP fogFactorTemp; */ 29301e04c3fSmrg fogFactorTemp = fprog->arb.NumTemporaries++; 2943464ebd5Sriastradh 2953464ebd5Sriastradh /* Scan program to find where result.color is written */ 2963464ebd5Sriastradh inst = newInst; 29701e04c3fSmrg for (i = 0; i < fprog->arb.NumInstructions; i++) { 2983464ebd5Sriastradh if (inst->Opcode == OPCODE_END) 2993464ebd5Sriastradh break; 3003464ebd5Sriastradh if (inst->DstReg.File == PROGRAM_OUTPUT && 3013464ebd5Sriastradh inst->DstReg.Index == FRAG_RESULT_COLOR) { 3023464ebd5Sriastradh /* change the instruction to write to colorTemp w/ clamping */ 3033464ebd5Sriastradh inst->DstReg.File = PROGRAM_TEMPORARY; 3043464ebd5Sriastradh inst->DstReg.Index = colorTemp; 30501e04c3fSmrg inst->Saturate = saturate; 3063464ebd5Sriastradh /* don't break (may be several writes to result.color) */ 3073464ebd5Sriastradh } 3083464ebd5Sriastradh inst++; 3093464ebd5Sriastradh } 3103464ebd5Sriastradh assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */ 3113464ebd5Sriastradh 3123464ebd5Sriastradh _mesa_init_instructions(inst, 5); 3133464ebd5Sriastradh 3143464ebd5Sriastradh /* emit instructions to compute fog blending factor */ 3153464ebd5Sriastradh /* this is always clamped to [0, 1] regardless of fragment clamping */ 3163464ebd5Sriastradh if (fog_mode == GL_LINEAR) { 3173464ebd5Sriastradh /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */ 3183464ebd5Sriastradh inst->Opcode = OPCODE_MAD; 3193464ebd5Sriastradh inst->DstReg.File = PROGRAM_TEMPORARY; 3203464ebd5Sriastradh inst->DstReg.Index = fogFactorTemp; 3213464ebd5Sriastradh inst->DstReg.WriteMask = WRITEMASK_X; 3223464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_INPUT; 323af69d88dSmrg inst->SrcReg[0].Index = VARYING_SLOT_FOGC; 3243464ebd5Sriastradh inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 3253464ebd5Sriastradh inst->SrcReg[1].File = PROGRAM_STATE_VAR; 3263464ebd5Sriastradh inst->SrcReg[1].Index = fogPRefOpt; 3273464ebd5Sriastradh inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; 3283464ebd5Sriastradh inst->SrcReg[2].File = PROGRAM_STATE_VAR; 3293464ebd5Sriastradh inst->SrcReg[2].Index = fogPRefOpt; 3303464ebd5Sriastradh inst->SrcReg[2].Swizzle = SWIZZLE_YYYY; 33101e04c3fSmrg inst->Saturate = GL_TRUE; 3323464ebd5Sriastradh inst++; 3333464ebd5Sriastradh } 3343464ebd5Sriastradh else { 33501e04c3fSmrg assert(fog_mode == GL_EXP || fog_mode == GL_EXP2); 3363464ebd5Sriastradh /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */ 3373464ebd5Sriastradh /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */ 3383464ebd5Sriastradh /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */ 3393464ebd5Sriastradh inst->Opcode = OPCODE_MUL; 3403464ebd5Sriastradh inst->DstReg.File = PROGRAM_TEMPORARY; 3413464ebd5Sriastradh inst->DstReg.Index = fogFactorTemp; 3423464ebd5Sriastradh inst->DstReg.WriteMask = WRITEMASK_X; 3433464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_STATE_VAR; 3443464ebd5Sriastradh inst->SrcReg[0].Index = fogPRefOpt; 3453464ebd5Sriastradh inst->SrcReg[0].Swizzle 3463464ebd5Sriastradh = (fog_mode == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW; 3473464ebd5Sriastradh inst->SrcReg[1].File = PROGRAM_INPUT; 348af69d88dSmrg inst->SrcReg[1].Index = VARYING_SLOT_FOGC; 3493464ebd5Sriastradh inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; 3503464ebd5Sriastradh inst++; 3513464ebd5Sriastradh if (fog_mode == GL_EXP2) { 3523464ebd5Sriastradh /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */ 3533464ebd5Sriastradh inst->Opcode = OPCODE_MUL; 3543464ebd5Sriastradh inst->DstReg.File = PROGRAM_TEMPORARY; 3553464ebd5Sriastradh inst->DstReg.Index = fogFactorTemp; 3563464ebd5Sriastradh inst->DstReg.WriteMask = WRITEMASK_X; 3573464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_TEMPORARY; 3583464ebd5Sriastradh inst->SrcReg[0].Index = fogFactorTemp; 3593464ebd5Sriastradh inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 3603464ebd5Sriastradh inst->SrcReg[1].File = PROGRAM_TEMPORARY; 3613464ebd5Sriastradh inst->SrcReg[1].Index = fogFactorTemp; 3623464ebd5Sriastradh inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; 3633464ebd5Sriastradh inst++; 3643464ebd5Sriastradh } 3653464ebd5Sriastradh /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */ 3663464ebd5Sriastradh inst->Opcode = OPCODE_EX2; 3673464ebd5Sriastradh inst->DstReg.File = PROGRAM_TEMPORARY; 3683464ebd5Sriastradh inst->DstReg.Index = fogFactorTemp; 3693464ebd5Sriastradh inst->DstReg.WriteMask = WRITEMASK_X; 3703464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_TEMPORARY; 3713464ebd5Sriastradh inst->SrcReg[0].Index = fogFactorTemp; 3723464ebd5Sriastradh inst->SrcReg[0].Negate = NEGATE_XYZW; 3733464ebd5Sriastradh inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 37401e04c3fSmrg inst->Saturate = GL_TRUE; 3753464ebd5Sriastradh inst++; 3763464ebd5Sriastradh } 3773464ebd5Sriastradh /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */ 3783464ebd5Sriastradh inst->Opcode = OPCODE_LRP; 3793464ebd5Sriastradh inst->DstReg.File = PROGRAM_OUTPUT; 3803464ebd5Sriastradh inst->DstReg.Index = FRAG_RESULT_COLOR; 3813464ebd5Sriastradh inst->DstReg.WriteMask = WRITEMASK_XYZ; 3823464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_TEMPORARY; 3833464ebd5Sriastradh inst->SrcReg[0].Index = fogFactorTemp; 3843464ebd5Sriastradh inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 3853464ebd5Sriastradh inst->SrcReg[1].File = PROGRAM_TEMPORARY; 3863464ebd5Sriastradh inst->SrcReg[1].Index = colorTemp; 3873464ebd5Sriastradh inst->SrcReg[1].Swizzle = SWIZZLE_NOOP; 3883464ebd5Sriastradh inst->SrcReg[2].File = PROGRAM_STATE_VAR; 3893464ebd5Sriastradh inst->SrcReg[2].Index = fogColorRef; 3903464ebd5Sriastradh inst->SrcReg[2].Swizzle = SWIZZLE_NOOP; 3913464ebd5Sriastradh inst++; 3923464ebd5Sriastradh /* MOV result.color.w, colorTemp.x; # copy alpha */ 3933464ebd5Sriastradh inst->Opcode = OPCODE_MOV; 3943464ebd5Sriastradh inst->DstReg.File = PROGRAM_OUTPUT; 3953464ebd5Sriastradh inst->DstReg.Index = FRAG_RESULT_COLOR; 3963464ebd5Sriastradh inst->DstReg.WriteMask = WRITEMASK_W; 3973464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_TEMPORARY; 3983464ebd5Sriastradh inst->SrcReg[0].Index = colorTemp; 3993464ebd5Sriastradh inst->SrcReg[0].Swizzle = SWIZZLE_NOOP; 4003464ebd5Sriastradh inst++; 4013464ebd5Sriastradh /* END; */ 4023464ebd5Sriastradh inst->Opcode = OPCODE_END; 4033464ebd5Sriastradh inst++; 4043464ebd5Sriastradh 4053464ebd5Sriastradh /* free old instructions */ 40601e04c3fSmrg ralloc_free(fprog->arb.Instructions); 4073464ebd5Sriastradh 4083464ebd5Sriastradh /* install new instructions */ 40901e04c3fSmrg fprog->arb.Instructions = newInst; 41001e04c3fSmrg fprog->arb.NumInstructions = inst - newInst; 41101e04c3fSmrg fprog->info.inputs_read |= VARYING_BIT_FOGC; 41201e04c3fSmrg assert(fprog->info.outputs_written & (1 << FRAG_RESULT_COLOR)); 4133464ebd5Sriastradh} 4143464ebd5Sriastradh 4153464ebd5Sriastradh 4163464ebd5Sriastradh 4173464ebd5Sriastradhstatic GLboolean 4183464ebd5Sriastradhis_texture_instruction(const struct prog_instruction *inst) 4193464ebd5Sriastradh{ 4203464ebd5Sriastradh switch (inst->Opcode) { 4213464ebd5Sriastradh case OPCODE_TEX: 4223464ebd5Sriastradh case OPCODE_TXB: 4233464ebd5Sriastradh case OPCODE_TXD: 4243464ebd5Sriastradh case OPCODE_TXL: 4253464ebd5Sriastradh case OPCODE_TXP: 4263464ebd5Sriastradh return GL_TRUE; 4273464ebd5Sriastradh default: 4283464ebd5Sriastradh return GL_FALSE; 4293464ebd5Sriastradh } 4303464ebd5Sriastradh} 4313464ebd5Sriastradh 4323464ebd5Sriastradh 4333464ebd5Sriastradh/** 4343464ebd5Sriastradh * Count the number of texure indirections in the given program. 4353464ebd5Sriastradh * The program's NumTexIndirections field will be updated. 4363464ebd5Sriastradh * See the GL_ARB_fragment_program spec (issue 24) for details. 4373464ebd5Sriastradh * XXX we count texture indirections in texenvprogram.c (maybe use this code 4383464ebd5Sriastradh * instead and elsewhere). 4393464ebd5Sriastradh */ 4403464ebd5Sriastradhvoid 4413464ebd5Sriastradh_mesa_count_texture_indirections(struct gl_program *prog) 4423464ebd5Sriastradh{ 4433464ebd5Sriastradh GLuint indirections = 1; 4443464ebd5Sriastradh GLbitfield tempsOutput = 0x0; 4453464ebd5Sriastradh GLbitfield aluTemps = 0x0; 4463464ebd5Sriastradh GLuint i; 4473464ebd5Sriastradh 44801e04c3fSmrg for (i = 0; i < prog->arb.NumInstructions; i++) { 44901e04c3fSmrg const struct prog_instruction *inst = prog->arb.Instructions + i; 4503464ebd5Sriastradh 4513464ebd5Sriastradh if (is_texture_instruction(inst)) { 4523464ebd5Sriastradh if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) && 4533464ebd5Sriastradh (tempsOutput & (1 << inst->SrcReg[0].Index))) || 4543464ebd5Sriastradh ((inst->Opcode != OPCODE_KIL) && 4553464ebd5Sriastradh (inst->DstReg.File == PROGRAM_TEMPORARY) && 4563464ebd5Sriastradh (aluTemps & (1 << inst->DstReg.Index)))) 4573464ebd5Sriastradh { 4583464ebd5Sriastradh indirections++; 4593464ebd5Sriastradh tempsOutput = 0x0; 4603464ebd5Sriastradh aluTemps = 0x0; 4613464ebd5Sriastradh } 4623464ebd5Sriastradh } 4633464ebd5Sriastradh else { 4643464ebd5Sriastradh GLuint j; 4653464ebd5Sriastradh for (j = 0; j < 3; j++) { 4663464ebd5Sriastradh if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) 4673464ebd5Sriastradh aluTemps |= (1 << inst->SrcReg[j].Index); 4683464ebd5Sriastradh } 4693464ebd5Sriastradh if (inst->DstReg.File == PROGRAM_TEMPORARY) 4703464ebd5Sriastradh aluTemps |= (1 << inst->DstReg.Index); 4713464ebd5Sriastradh } 4723464ebd5Sriastradh 4733464ebd5Sriastradh if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY)) 4743464ebd5Sriastradh tempsOutput |= (1 << inst->DstReg.Index); 4753464ebd5Sriastradh } 4763464ebd5Sriastradh 47701e04c3fSmrg prog->arb.NumTexIndirections = indirections; 4783464ebd5Sriastradh} 4793464ebd5Sriastradh 4803464ebd5Sriastradh 4813464ebd5Sriastradh/** 4823464ebd5Sriastradh * Count number of texture instructions in given program and update the 4833464ebd5Sriastradh * program's NumTexInstructions field. 4843464ebd5Sriastradh */ 4853464ebd5Sriastradhvoid 4863464ebd5Sriastradh_mesa_count_texture_instructions(struct gl_program *prog) 4873464ebd5Sriastradh{ 4883464ebd5Sriastradh GLuint i; 48901e04c3fSmrg prog->arb.NumTexInstructions = 0; 49001e04c3fSmrg for (i = 0; i < prog->arb.NumInstructions; i++) { 49101e04c3fSmrg prog->arb.NumTexInstructions += 49201e04c3fSmrg is_texture_instruction(prog->arb.Instructions + i); 4933464ebd5Sriastradh } 4943464ebd5Sriastradh} 4953464ebd5Sriastradh 4963464ebd5Sriastradh 4973464ebd5Sriastradh/** 4983464ebd5Sriastradh * Scan/rewrite program to remove reads of custom (output) registers. 499af69d88dSmrg * The passed type has to be PROGRAM_OUTPUT. 5003464ebd5Sriastradh * On some hardware, trying to read an output register causes trouble. 5013464ebd5Sriastradh * So, rewrite the program to use a temporary register in this case. 5023464ebd5Sriastradh */ 5033464ebd5Sriastradhvoid 5043464ebd5Sriastradh_mesa_remove_output_reads(struct gl_program *prog, gl_register_file type) 5053464ebd5Sriastradh{ 5063464ebd5Sriastradh GLuint i; 507af69d88dSmrg GLint outputMap[VARYING_SLOT_MAX]; 5083464ebd5Sriastradh GLuint numVaryingReads = 0; 5093464ebd5Sriastradh GLboolean usedTemps[MAX_PROGRAM_TEMPS]; 5103464ebd5Sriastradh GLuint firstTemp = 0; 5113464ebd5Sriastradh 5123464ebd5Sriastradh _mesa_find_used_registers(prog, PROGRAM_TEMPORARY, 5133464ebd5Sriastradh usedTemps, MAX_PROGRAM_TEMPS); 5143464ebd5Sriastradh 515af69d88dSmrg assert(type == PROGRAM_OUTPUT); 5163464ebd5Sriastradh 517af69d88dSmrg for (i = 0; i < VARYING_SLOT_MAX; i++) 5183464ebd5Sriastradh outputMap[i] = -1; 5193464ebd5Sriastradh 5203464ebd5Sriastradh /* look for instructions which read from varying vars */ 52101e04c3fSmrg for (i = 0; i < prog->arb.NumInstructions; i++) { 52201e04c3fSmrg struct prog_instruction *inst = prog->arb.Instructions + i; 5233464ebd5Sriastradh const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); 5243464ebd5Sriastradh GLuint j; 5253464ebd5Sriastradh for (j = 0; j < numSrc; j++) { 5263464ebd5Sriastradh if (inst->SrcReg[j].File == type) { 5273464ebd5Sriastradh /* replace the read with a temp reg */ 5283464ebd5Sriastradh const GLuint var = inst->SrcReg[j].Index; 5293464ebd5Sriastradh if (outputMap[var] == -1) { 5303464ebd5Sriastradh numVaryingReads++; 5313464ebd5Sriastradh outputMap[var] = _mesa_find_free_register(usedTemps, 5323464ebd5Sriastradh MAX_PROGRAM_TEMPS, 5333464ebd5Sriastradh firstTemp); 5343464ebd5Sriastradh firstTemp = outputMap[var] + 1; 5353464ebd5Sriastradh } 5363464ebd5Sriastradh inst->SrcReg[j].File = PROGRAM_TEMPORARY; 5373464ebd5Sriastradh inst->SrcReg[j].Index = outputMap[var]; 5383464ebd5Sriastradh } 5393464ebd5Sriastradh } 5403464ebd5Sriastradh } 5413464ebd5Sriastradh 5423464ebd5Sriastradh if (numVaryingReads == 0) 5433464ebd5Sriastradh return; /* nothing to be done */ 5443464ebd5Sriastradh 5453464ebd5Sriastradh /* look for instructions which write to the varying vars identified above */ 54601e04c3fSmrg for (i = 0; i < prog->arb.NumInstructions; i++) { 54701e04c3fSmrg struct prog_instruction *inst = prog->arb.Instructions + i; 5483464ebd5Sriastradh if (inst->DstReg.File == type && 5493464ebd5Sriastradh outputMap[inst->DstReg.Index] >= 0) { 5503464ebd5Sriastradh /* change inst to write to the temp reg, instead of the varying */ 5513464ebd5Sriastradh inst->DstReg.File = PROGRAM_TEMPORARY; 5523464ebd5Sriastradh inst->DstReg.Index = outputMap[inst->DstReg.Index]; 5533464ebd5Sriastradh } 5543464ebd5Sriastradh } 5553464ebd5Sriastradh 5563464ebd5Sriastradh /* insert new instructions to copy the temp vars to the varying vars */ 5573464ebd5Sriastradh { 5583464ebd5Sriastradh struct prog_instruction *inst; 5593464ebd5Sriastradh GLint endPos, var; 5603464ebd5Sriastradh 5613464ebd5Sriastradh /* Look for END instruction and insert the new varying writes */ 5623464ebd5Sriastradh endPos = -1; 56301e04c3fSmrg for (i = 0; i < prog->arb.NumInstructions; i++) { 56401e04c3fSmrg struct prog_instruction *inst = prog->arb.Instructions + i; 5653464ebd5Sriastradh if (inst->Opcode == OPCODE_END) { 5663464ebd5Sriastradh endPos = i; 5673464ebd5Sriastradh _mesa_insert_instructions(prog, i, numVaryingReads); 5683464ebd5Sriastradh break; 5693464ebd5Sriastradh } 5703464ebd5Sriastradh } 5713464ebd5Sriastradh 5723464ebd5Sriastradh assert(endPos >= 0); 5733464ebd5Sriastradh 5743464ebd5Sriastradh /* insert new MOV instructions here */ 57501e04c3fSmrg inst = prog->arb.Instructions + endPos; 576af69d88dSmrg for (var = 0; var < VARYING_SLOT_MAX; var++) { 5773464ebd5Sriastradh if (outputMap[var] >= 0) { 5783464ebd5Sriastradh /* MOV VAR[var], TEMP[tmp]; */ 5793464ebd5Sriastradh inst->Opcode = OPCODE_MOV; 5803464ebd5Sriastradh inst->DstReg.File = type; 5813464ebd5Sriastradh inst->DstReg.Index = var; 5823464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_TEMPORARY; 5833464ebd5Sriastradh inst->SrcReg[0].Index = outputMap[var]; 5843464ebd5Sriastradh inst++; 5853464ebd5Sriastradh } 5863464ebd5Sriastradh } 5873464ebd5Sriastradh } 5883464ebd5Sriastradh} 5893464ebd5Sriastradh 5903464ebd5Sriastradhvoid 59101e04c3fSmrg_mesa_program_fragment_position_to_sysval(struct gl_program *prog) 5923464ebd5Sriastradh{ 59301e04c3fSmrg GLuint i; 5943464ebd5Sriastradh 59501e04c3fSmrg if (prog->Target != GL_FRAGMENT_PROGRAM_ARB || 59601e04c3fSmrg !(prog->info.inputs_read & BITFIELD64_BIT(VARYING_SLOT_POS))) 5973464ebd5Sriastradh return; 5983464ebd5Sriastradh 59901e04c3fSmrg prog->info.inputs_read &= ~BITFIELD64_BIT(VARYING_SLOT_POS); 60001e04c3fSmrg prog->info.system_values_read |= 1 << SYSTEM_VALUE_FRAG_COORD; 6013464ebd5Sriastradh 60201e04c3fSmrg for (i = 0; i < prog->arb.NumInstructions; i++) { 60301e04c3fSmrg struct prog_instruction *inst = prog->arb.Instructions + i; 60401e04c3fSmrg const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); 60501e04c3fSmrg GLuint j; 6063464ebd5Sriastradh 60701e04c3fSmrg for (j = 0; j < numSrc; j++) { 60801e04c3fSmrg if (inst->SrcReg[j].File == PROGRAM_INPUT && 60901e04c3fSmrg inst->SrcReg[j].Index == VARYING_SLOT_POS) { 61001e04c3fSmrg inst->SrcReg[j].File = PROGRAM_SYSTEM_VALUE; 61101e04c3fSmrg inst->SrcReg[j].Index = SYSTEM_VALUE_FRAG_COORD; 61201e04c3fSmrg } 61301e04c3fSmrg } 6143464ebd5Sriastradh } 6153464ebd5Sriastradh} 616