programopt.c revision 3464ebd5
13464ebd5Sriastradh/* 23464ebd5Sriastradh * Mesa 3-D graphics library 33464ebd5Sriastradh * Version: 6.5.3 43464ebd5Sriastradh * 53464ebd5Sriastradh * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 63464ebd5Sriastradh * 73464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a 83464ebd5Sriastradh * copy of this software and associated documentation files (the "Software"), 93464ebd5Sriastradh * to deal in the Software without restriction, including without limitation 103464ebd5Sriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 113464ebd5Sriastradh * and/or sell copies of the Software, and to permit persons to whom the 123464ebd5Sriastradh * Software is furnished to do so, subject to the following conditions: 133464ebd5Sriastradh * 143464ebd5Sriastradh * The above copyright notice and this permission notice shall be included 153464ebd5Sriastradh * in all copies or substantial portions of the Software. 163464ebd5Sriastradh * 173464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 183464ebd5Sriastradh * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 193464ebd5Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 203464ebd5Sriastradh * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 213464ebd5Sriastradh * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 223464ebd5Sriastradh * CONNECTION WITH THE SOFTWARE OR THE USE OR 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 493464ebd5Sriastradh_mesa_insert_mvp_dp4_code(struct gl_context *ctx, struct gl_vertex_program *vprog) 503464ebd5Sriastradh{ 513464ebd5Sriastradh struct prog_instruction *newInst; 523464ebd5Sriastradh const GLuint origLen = vprog->Base.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 */ 603464ebd5Sriastradh static const gl_state_index 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++) { 693464ebd5Sriastradh mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters, 703464ebd5Sriastradh mvpState[i]); 713464ebd5Sriastradh } 723464ebd5Sriastradh 733464ebd5Sriastradh /* Alloc storage for new instructions */ 743464ebd5Sriastradh newInst = _mesa_alloc_instructions(newLen); 753464ebd5Sriastradh if (!newInst) { 763464ebd5Sriastradh _mesa_error(ctx, GL_OUT_OF_MEMORY, 773464ebd5Sriastradh "glProgramString(inserting position_invariant code)"); 783464ebd5Sriastradh return; 793464ebd5Sriastradh } 803464ebd5Sriastradh 813464ebd5Sriastradh /* 823464ebd5Sriastradh * Generated instructions: 833464ebd5Sriastradh * newInst[0] = DP4 result.position.x, mvp.row[0], vertex.position; 843464ebd5Sriastradh * newInst[1] = DP4 result.position.y, mvp.row[1], vertex.position; 853464ebd5Sriastradh * newInst[2] = DP4 result.position.z, mvp.row[2], vertex.position; 863464ebd5Sriastradh * newInst[3] = DP4 result.position.w, mvp.row[3], vertex.position; 873464ebd5Sriastradh */ 883464ebd5Sriastradh _mesa_init_instructions(newInst, 4); 893464ebd5Sriastradh for (i = 0; i < 4; i++) { 903464ebd5Sriastradh newInst[i].Opcode = OPCODE_DP4; 913464ebd5Sriastradh newInst[i].DstReg.File = PROGRAM_OUTPUT; 923464ebd5Sriastradh newInst[i].DstReg.Index = VERT_RESULT_HPOS; 933464ebd5Sriastradh newInst[i].DstReg.WriteMask = (WRITEMASK_X << i); 943464ebd5Sriastradh newInst[i].SrcReg[0].File = PROGRAM_STATE_VAR; 953464ebd5Sriastradh newInst[i].SrcReg[0].Index = mvpRef[i]; 963464ebd5Sriastradh newInst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP; 973464ebd5Sriastradh newInst[i].SrcReg[1].File = PROGRAM_INPUT; 983464ebd5Sriastradh newInst[i].SrcReg[1].Index = VERT_ATTRIB_POS; 993464ebd5Sriastradh newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; 1003464ebd5Sriastradh } 1013464ebd5Sriastradh 1023464ebd5Sriastradh /* Append original instructions after new instructions */ 1033464ebd5Sriastradh _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen); 1043464ebd5Sriastradh 1053464ebd5Sriastradh /* free old instructions */ 1063464ebd5Sriastradh _mesa_free_instructions(vprog->Base.Instructions, origLen); 1073464ebd5Sriastradh 1083464ebd5Sriastradh /* install new instructions */ 1093464ebd5Sriastradh vprog->Base.Instructions = newInst; 1103464ebd5Sriastradh vprog->Base.NumInstructions = newLen; 1113464ebd5Sriastradh vprog->Base.InputsRead |= VERT_BIT_POS; 1123464ebd5Sriastradh vprog->Base.OutputsWritten |= BITFIELD64_BIT(VERT_RESULT_HPOS); 1133464ebd5Sriastradh} 1143464ebd5Sriastradh 1153464ebd5Sriastradh 1163464ebd5Sriastradhstatic void 1173464ebd5Sriastradh_mesa_insert_mvp_mad_code(struct gl_context *ctx, struct gl_vertex_program *vprog) 1183464ebd5Sriastradh{ 1193464ebd5Sriastradh struct prog_instruction *newInst; 1203464ebd5Sriastradh const GLuint origLen = vprog->Base.NumInstructions; 1213464ebd5Sriastradh const GLuint newLen = origLen + 4; 1223464ebd5Sriastradh GLuint hposTemp; 1233464ebd5Sriastradh GLuint i; 1243464ebd5Sriastradh 1253464ebd5Sriastradh /* 1263464ebd5Sriastradh * Setup state references for the modelview/projection matrix. 1273464ebd5Sriastradh * XXX we should check if these state vars are already declared. 1283464ebd5Sriastradh */ 1293464ebd5Sriastradh static const gl_state_index mvpState[4][STATE_LENGTH] = { 1303464ebd5Sriastradh { STATE_MVP_MATRIX, 0, 0, 0, STATE_MATRIX_TRANSPOSE }, 1313464ebd5Sriastradh { STATE_MVP_MATRIX, 0, 1, 1, STATE_MATRIX_TRANSPOSE }, 1323464ebd5Sriastradh { STATE_MVP_MATRIX, 0, 2, 2, STATE_MATRIX_TRANSPOSE }, 1333464ebd5Sriastradh { STATE_MVP_MATRIX, 0, 3, 3, STATE_MATRIX_TRANSPOSE }, 1343464ebd5Sriastradh }; 1353464ebd5Sriastradh GLint mvpRef[4]; 1363464ebd5Sriastradh 1373464ebd5Sriastradh for (i = 0; i < 4; i++) { 1383464ebd5Sriastradh mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters, 1393464ebd5Sriastradh mvpState[i]); 1403464ebd5Sriastradh } 1413464ebd5Sriastradh 1423464ebd5Sriastradh /* Alloc storage for new instructions */ 1433464ebd5Sriastradh newInst = _mesa_alloc_instructions(newLen); 1443464ebd5Sriastradh if (!newInst) { 1453464ebd5Sriastradh _mesa_error(ctx, GL_OUT_OF_MEMORY, 1463464ebd5Sriastradh "glProgramString(inserting position_invariant code)"); 1473464ebd5Sriastradh return; 1483464ebd5Sriastradh } 1493464ebd5Sriastradh 1503464ebd5Sriastradh /* TEMP hposTemp; */ 1513464ebd5Sriastradh hposTemp = vprog->Base.NumTemporaries++; 1523464ebd5Sriastradh 1533464ebd5Sriastradh /* 1543464ebd5Sriastradh * Generated instructions: 1553464ebd5Sriastradh * emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]); 1563464ebd5Sriastradh * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp); 1573464ebd5Sriastradh * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp); 1583464ebd5Sriastradh * emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp); 1593464ebd5Sriastradh */ 1603464ebd5Sriastradh _mesa_init_instructions(newInst, 4); 1613464ebd5Sriastradh 1623464ebd5Sriastradh newInst[0].Opcode = OPCODE_MUL; 1633464ebd5Sriastradh newInst[0].DstReg.File = PROGRAM_TEMPORARY; 1643464ebd5Sriastradh newInst[0].DstReg.Index = hposTemp; 1653464ebd5Sriastradh newInst[0].DstReg.WriteMask = WRITEMASK_XYZW; 1663464ebd5Sriastradh newInst[0].SrcReg[0].File = PROGRAM_INPUT; 1673464ebd5Sriastradh newInst[0].SrcReg[0].Index = VERT_ATTRIB_POS; 1683464ebd5Sriastradh newInst[0].SrcReg[0].Swizzle = SWIZZLE_XXXX; 1693464ebd5Sriastradh newInst[0].SrcReg[1].File = PROGRAM_STATE_VAR; 1703464ebd5Sriastradh newInst[0].SrcReg[1].Index = mvpRef[0]; 1713464ebd5Sriastradh newInst[0].SrcReg[1].Swizzle = SWIZZLE_NOOP; 1723464ebd5Sriastradh 1733464ebd5Sriastradh for (i = 1; i <= 2; i++) { 1743464ebd5Sriastradh newInst[i].Opcode = OPCODE_MAD; 1753464ebd5Sriastradh newInst[i].DstReg.File = PROGRAM_TEMPORARY; 1763464ebd5Sriastradh newInst[i].DstReg.Index = hposTemp; 1773464ebd5Sriastradh newInst[i].DstReg.WriteMask = WRITEMASK_XYZW; 1783464ebd5Sriastradh newInst[i].SrcReg[0].File = PROGRAM_INPUT; 1793464ebd5Sriastradh newInst[i].SrcReg[0].Index = VERT_ATTRIB_POS; 1803464ebd5Sriastradh newInst[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(i,i,i,i); 1813464ebd5Sriastradh newInst[i].SrcReg[1].File = PROGRAM_STATE_VAR; 1823464ebd5Sriastradh newInst[i].SrcReg[1].Index = mvpRef[i]; 1833464ebd5Sriastradh newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; 1843464ebd5Sriastradh newInst[i].SrcReg[2].File = PROGRAM_TEMPORARY; 1853464ebd5Sriastradh newInst[i].SrcReg[2].Index = hposTemp; 1863464ebd5Sriastradh newInst[1].SrcReg[2].Swizzle = SWIZZLE_NOOP; 1873464ebd5Sriastradh } 1883464ebd5Sriastradh 1893464ebd5Sriastradh newInst[3].Opcode = OPCODE_MAD; 1903464ebd5Sriastradh newInst[3].DstReg.File = PROGRAM_OUTPUT; 1913464ebd5Sriastradh newInst[3].DstReg.Index = VERT_RESULT_HPOS; 1923464ebd5Sriastradh newInst[3].DstReg.WriteMask = WRITEMASK_XYZW; 1933464ebd5Sriastradh newInst[3].SrcReg[0].File = PROGRAM_INPUT; 1943464ebd5Sriastradh newInst[3].SrcReg[0].Index = VERT_ATTRIB_POS; 1953464ebd5Sriastradh newInst[3].SrcReg[0].Swizzle = SWIZZLE_WWWW; 1963464ebd5Sriastradh newInst[3].SrcReg[1].File = PROGRAM_STATE_VAR; 1973464ebd5Sriastradh newInst[3].SrcReg[1].Index = mvpRef[3]; 1983464ebd5Sriastradh newInst[3].SrcReg[1].Swizzle = SWIZZLE_NOOP; 1993464ebd5Sriastradh newInst[3].SrcReg[2].File = PROGRAM_TEMPORARY; 2003464ebd5Sriastradh newInst[3].SrcReg[2].Index = hposTemp; 2013464ebd5Sriastradh newInst[3].SrcReg[2].Swizzle = SWIZZLE_NOOP; 2023464ebd5Sriastradh 2033464ebd5Sriastradh 2043464ebd5Sriastradh /* Append original instructions after new instructions */ 2053464ebd5Sriastradh _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen); 2063464ebd5Sriastradh 2073464ebd5Sriastradh /* free old instructions */ 2083464ebd5Sriastradh _mesa_free_instructions(vprog->Base.Instructions, origLen); 2093464ebd5Sriastradh 2103464ebd5Sriastradh /* install new instructions */ 2113464ebd5Sriastradh vprog->Base.Instructions = newInst; 2123464ebd5Sriastradh vprog->Base.NumInstructions = newLen; 2133464ebd5Sriastradh vprog->Base.InputsRead |= VERT_BIT_POS; 2143464ebd5Sriastradh vprog->Base.OutputsWritten |= BITFIELD64_BIT(VERT_RESULT_HPOS); 2153464ebd5Sriastradh} 2163464ebd5Sriastradh 2173464ebd5Sriastradh 2183464ebd5Sriastradhvoid 2193464ebd5Sriastradh_mesa_insert_mvp_code(struct gl_context *ctx, struct gl_vertex_program *vprog) 2203464ebd5Sriastradh{ 2213464ebd5Sriastradh if (ctx->mvp_with_dp4) 2223464ebd5Sriastradh _mesa_insert_mvp_dp4_code( ctx, vprog ); 2233464ebd5Sriastradh else 2243464ebd5Sriastradh _mesa_insert_mvp_mad_code( ctx, vprog ); 2253464ebd5Sriastradh} 2263464ebd5Sriastradh 2273464ebd5Sriastradh 2283464ebd5Sriastradh 2293464ebd5Sriastradh 2303464ebd5Sriastradh 2313464ebd5Sriastradh 2323464ebd5Sriastradh/** 2333464ebd5Sriastradh * Append instructions to implement fog 2343464ebd5Sriastradh * 2353464ebd5Sriastradh * The \c fragment.fogcoord input is used to compute the fog blend factor. 2363464ebd5Sriastradh * 2373464ebd5Sriastradh * \param ctx The GL context 2383464ebd5Sriastradh * \param fprog Fragment program that fog instructions will be appended to. 2393464ebd5Sriastradh * \param fog_mode Fog mode. One of \c GL_EXP, \c GL_EXP2, or \c GL_LINEAR. 2403464ebd5Sriastradh * \param saturate True if writes to color outputs should be clamped to [0, 1] 2413464ebd5Sriastradh * 2423464ebd5Sriastradh * \note 2433464ebd5Sriastradh * This function sets \c FRAG_BIT_FOGC in \c fprog->Base.InputsRead. 2443464ebd5Sriastradh * 2453464ebd5Sriastradh * \todo With a little work, this function could be adapted to add fog code 2463464ebd5Sriastradh * to vertex programs too. 2473464ebd5Sriastradh */ 2483464ebd5Sriastradhvoid 2493464ebd5Sriastradh_mesa_append_fog_code(struct gl_context *ctx, 2503464ebd5Sriastradh struct gl_fragment_program *fprog, GLenum fog_mode, 2513464ebd5Sriastradh GLboolean saturate) 2523464ebd5Sriastradh{ 2533464ebd5Sriastradh static const gl_state_index fogPStateOpt[STATE_LENGTH] 2543464ebd5Sriastradh = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 }; 2553464ebd5Sriastradh static const gl_state_index fogColorState[STATE_LENGTH] 2563464ebd5Sriastradh = { STATE_FOG_COLOR, 0, 0, 0, 0}; 2573464ebd5Sriastradh struct prog_instruction *newInst, *inst; 2583464ebd5Sriastradh const GLuint origLen = fprog->Base.NumInstructions; 2593464ebd5Sriastradh const GLuint newLen = origLen + 5; 2603464ebd5Sriastradh GLuint i; 2613464ebd5Sriastradh GLint fogPRefOpt, fogColorRef; /* state references */ 2623464ebd5Sriastradh GLuint colorTemp, fogFactorTemp; /* temporary registerss */ 2633464ebd5Sriastradh 2643464ebd5Sriastradh if (fog_mode == GL_NONE) { 2653464ebd5Sriastradh _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program" 2663464ebd5Sriastradh " with fog_mode == GL_NONE"); 2673464ebd5Sriastradh return; 2683464ebd5Sriastradh } 2693464ebd5Sriastradh 2703464ebd5Sriastradh if (!(fprog->Base.OutputsWritten & (1 << FRAG_RESULT_COLOR))) { 2713464ebd5Sriastradh /* program doesn't output color, so nothing to do */ 2723464ebd5Sriastradh return; 2733464ebd5Sriastradh } 2743464ebd5Sriastradh 2753464ebd5Sriastradh /* Alloc storage for new instructions */ 2763464ebd5Sriastradh newInst = _mesa_alloc_instructions(newLen); 2773464ebd5Sriastradh if (!newInst) { 2783464ebd5Sriastradh _mesa_error(ctx, GL_OUT_OF_MEMORY, 2793464ebd5Sriastradh "glProgramString(inserting fog_option code)"); 2803464ebd5Sriastradh return; 2813464ebd5Sriastradh } 2823464ebd5Sriastradh 2833464ebd5Sriastradh /* Copy orig instructions into new instruction buffer */ 2843464ebd5Sriastradh _mesa_copy_instructions(newInst, fprog->Base.Instructions, origLen); 2853464ebd5Sriastradh 2863464ebd5Sriastradh /* PARAM fogParamsRefOpt = internal optimized fog params; */ 2873464ebd5Sriastradh fogPRefOpt 2883464ebd5Sriastradh = _mesa_add_state_reference(fprog->Base.Parameters, fogPStateOpt); 2893464ebd5Sriastradh /* PARAM fogColorRef = state.fog.color; */ 2903464ebd5Sriastradh fogColorRef 2913464ebd5Sriastradh = _mesa_add_state_reference(fprog->Base.Parameters, fogColorState); 2923464ebd5Sriastradh 2933464ebd5Sriastradh /* TEMP colorTemp; */ 2943464ebd5Sriastradh colorTemp = fprog->Base.NumTemporaries++; 2953464ebd5Sriastradh /* TEMP fogFactorTemp; */ 2963464ebd5Sriastradh fogFactorTemp = fprog->Base.NumTemporaries++; 2973464ebd5Sriastradh 2983464ebd5Sriastradh /* Scan program to find where result.color is written */ 2993464ebd5Sriastradh inst = newInst; 3003464ebd5Sriastradh for (i = 0; i < fprog->Base.NumInstructions; i++) { 3013464ebd5Sriastradh if (inst->Opcode == OPCODE_END) 3023464ebd5Sriastradh break; 3033464ebd5Sriastradh if (inst->DstReg.File == PROGRAM_OUTPUT && 3043464ebd5Sriastradh inst->DstReg.Index == FRAG_RESULT_COLOR) { 3053464ebd5Sriastradh /* change the instruction to write to colorTemp w/ clamping */ 3063464ebd5Sriastradh inst->DstReg.File = PROGRAM_TEMPORARY; 3073464ebd5Sriastradh inst->DstReg.Index = colorTemp; 3083464ebd5Sriastradh inst->SaturateMode = saturate; 3093464ebd5Sriastradh /* don't break (may be several writes to result.color) */ 3103464ebd5Sriastradh } 3113464ebd5Sriastradh inst++; 3123464ebd5Sriastradh } 3133464ebd5Sriastradh assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */ 3143464ebd5Sriastradh 3153464ebd5Sriastradh _mesa_init_instructions(inst, 5); 3163464ebd5Sriastradh 3173464ebd5Sriastradh /* emit instructions to compute fog blending factor */ 3183464ebd5Sriastradh /* this is always clamped to [0, 1] regardless of fragment clamping */ 3193464ebd5Sriastradh if (fog_mode == GL_LINEAR) { 3203464ebd5Sriastradh /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */ 3213464ebd5Sriastradh inst->Opcode = OPCODE_MAD; 3223464ebd5Sriastradh inst->DstReg.File = PROGRAM_TEMPORARY; 3233464ebd5Sriastradh inst->DstReg.Index = fogFactorTemp; 3243464ebd5Sriastradh inst->DstReg.WriteMask = WRITEMASK_X; 3253464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_INPUT; 3263464ebd5Sriastradh inst->SrcReg[0].Index = FRAG_ATTRIB_FOGC; 3273464ebd5Sriastradh inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 3283464ebd5Sriastradh inst->SrcReg[1].File = PROGRAM_STATE_VAR; 3293464ebd5Sriastradh inst->SrcReg[1].Index = fogPRefOpt; 3303464ebd5Sriastradh inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; 3313464ebd5Sriastradh inst->SrcReg[2].File = PROGRAM_STATE_VAR; 3323464ebd5Sriastradh inst->SrcReg[2].Index = fogPRefOpt; 3333464ebd5Sriastradh inst->SrcReg[2].Swizzle = SWIZZLE_YYYY; 3343464ebd5Sriastradh inst->SaturateMode = SATURATE_ZERO_ONE; 3353464ebd5Sriastradh inst++; 3363464ebd5Sriastradh } 3373464ebd5Sriastradh else { 3383464ebd5Sriastradh ASSERT(fog_mode == GL_EXP || fog_mode == GL_EXP2); 3393464ebd5Sriastradh /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */ 3403464ebd5Sriastradh /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */ 3413464ebd5Sriastradh /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */ 3423464ebd5Sriastradh inst->Opcode = OPCODE_MUL; 3433464ebd5Sriastradh inst->DstReg.File = PROGRAM_TEMPORARY; 3443464ebd5Sriastradh inst->DstReg.Index = fogFactorTemp; 3453464ebd5Sriastradh inst->DstReg.WriteMask = WRITEMASK_X; 3463464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_STATE_VAR; 3473464ebd5Sriastradh inst->SrcReg[0].Index = fogPRefOpt; 3483464ebd5Sriastradh inst->SrcReg[0].Swizzle 3493464ebd5Sriastradh = (fog_mode == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW; 3503464ebd5Sriastradh inst->SrcReg[1].File = PROGRAM_INPUT; 3513464ebd5Sriastradh inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC; 3523464ebd5Sriastradh inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; 3533464ebd5Sriastradh inst++; 3543464ebd5Sriastradh if (fog_mode == GL_EXP2) { 3553464ebd5Sriastradh /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */ 3563464ebd5Sriastradh inst->Opcode = OPCODE_MUL; 3573464ebd5Sriastradh inst->DstReg.File = PROGRAM_TEMPORARY; 3583464ebd5Sriastradh inst->DstReg.Index = fogFactorTemp; 3593464ebd5Sriastradh inst->DstReg.WriteMask = WRITEMASK_X; 3603464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_TEMPORARY; 3613464ebd5Sriastradh inst->SrcReg[0].Index = fogFactorTemp; 3623464ebd5Sriastradh inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 3633464ebd5Sriastradh inst->SrcReg[1].File = PROGRAM_TEMPORARY; 3643464ebd5Sriastradh inst->SrcReg[1].Index = fogFactorTemp; 3653464ebd5Sriastradh inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; 3663464ebd5Sriastradh inst++; 3673464ebd5Sriastradh } 3683464ebd5Sriastradh /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */ 3693464ebd5Sriastradh inst->Opcode = OPCODE_EX2; 3703464ebd5Sriastradh inst->DstReg.File = PROGRAM_TEMPORARY; 3713464ebd5Sriastradh inst->DstReg.Index = fogFactorTemp; 3723464ebd5Sriastradh inst->DstReg.WriteMask = WRITEMASK_X; 3733464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_TEMPORARY; 3743464ebd5Sriastradh inst->SrcReg[0].Index = fogFactorTemp; 3753464ebd5Sriastradh inst->SrcReg[0].Negate = NEGATE_XYZW; 3763464ebd5Sriastradh inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 3773464ebd5Sriastradh inst->SaturateMode = SATURATE_ZERO_ONE; 3783464ebd5Sriastradh inst++; 3793464ebd5Sriastradh } 3803464ebd5Sriastradh /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */ 3813464ebd5Sriastradh inst->Opcode = OPCODE_LRP; 3823464ebd5Sriastradh inst->DstReg.File = PROGRAM_OUTPUT; 3833464ebd5Sriastradh inst->DstReg.Index = FRAG_RESULT_COLOR; 3843464ebd5Sriastradh inst->DstReg.WriteMask = WRITEMASK_XYZ; 3853464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_TEMPORARY; 3863464ebd5Sriastradh inst->SrcReg[0].Index = fogFactorTemp; 3873464ebd5Sriastradh inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; 3883464ebd5Sriastradh inst->SrcReg[1].File = PROGRAM_TEMPORARY; 3893464ebd5Sriastradh inst->SrcReg[1].Index = colorTemp; 3903464ebd5Sriastradh inst->SrcReg[1].Swizzle = SWIZZLE_NOOP; 3913464ebd5Sriastradh inst->SrcReg[2].File = PROGRAM_STATE_VAR; 3923464ebd5Sriastradh inst->SrcReg[2].Index = fogColorRef; 3933464ebd5Sriastradh inst->SrcReg[2].Swizzle = SWIZZLE_NOOP; 3943464ebd5Sriastradh inst++; 3953464ebd5Sriastradh /* MOV result.color.w, colorTemp.x; # copy alpha */ 3963464ebd5Sriastradh inst->Opcode = OPCODE_MOV; 3973464ebd5Sriastradh inst->DstReg.File = PROGRAM_OUTPUT; 3983464ebd5Sriastradh inst->DstReg.Index = FRAG_RESULT_COLOR; 3993464ebd5Sriastradh inst->DstReg.WriteMask = WRITEMASK_W; 4003464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_TEMPORARY; 4013464ebd5Sriastradh inst->SrcReg[0].Index = colorTemp; 4023464ebd5Sriastradh inst->SrcReg[0].Swizzle = SWIZZLE_NOOP; 4033464ebd5Sriastradh inst++; 4043464ebd5Sriastradh /* END; */ 4053464ebd5Sriastradh inst->Opcode = OPCODE_END; 4063464ebd5Sriastradh inst++; 4073464ebd5Sriastradh 4083464ebd5Sriastradh /* free old instructions */ 4093464ebd5Sriastradh _mesa_free_instructions(fprog->Base.Instructions, origLen); 4103464ebd5Sriastradh 4113464ebd5Sriastradh /* install new instructions */ 4123464ebd5Sriastradh fprog->Base.Instructions = newInst; 4133464ebd5Sriastradh fprog->Base.NumInstructions = inst - newInst; 4143464ebd5Sriastradh fprog->Base.InputsRead |= FRAG_BIT_FOGC; 4153464ebd5Sriastradh assert(fprog->Base.OutputsWritten & (1 << FRAG_RESULT_COLOR)); 4163464ebd5Sriastradh} 4173464ebd5Sriastradh 4183464ebd5Sriastradh 4193464ebd5Sriastradh 4203464ebd5Sriastradhstatic GLboolean 4213464ebd5Sriastradhis_texture_instruction(const struct prog_instruction *inst) 4223464ebd5Sriastradh{ 4233464ebd5Sriastradh switch (inst->Opcode) { 4243464ebd5Sriastradh case OPCODE_TEX: 4253464ebd5Sriastradh case OPCODE_TXB: 4263464ebd5Sriastradh case OPCODE_TXD: 4273464ebd5Sriastradh case OPCODE_TXL: 4283464ebd5Sriastradh case OPCODE_TXP: 4293464ebd5Sriastradh case OPCODE_TXP_NV: 4303464ebd5Sriastradh return GL_TRUE; 4313464ebd5Sriastradh default: 4323464ebd5Sriastradh return GL_FALSE; 4333464ebd5Sriastradh } 4343464ebd5Sriastradh} 4353464ebd5Sriastradh 4363464ebd5Sriastradh 4373464ebd5Sriastradh/** 4383464ebd5Sriastradh * Count the number of texure indirections in the given program. 4393464ebd5Sriastradh * The program's NumTexIndirections field will be updated. 4403464ebd5Sriastradh * See the GL_ARB_fragment_program spec (issue 24) for details. 4413464ebd5Sriastradh * XXX we count texture indirections in texenvprogram.c (maybe use this code 4423464ebd5Sriastradh * instead and elsewhere). 4433464ebd5Sriastradh */ 4443464ebd5Sriastradhvoid 4453464ebd5Sriastradh_mesa_count_texture_indirections(struct gl_program *prog) 4463464ebd5Sriastradh{ 4473464ebd5Sriastradh GLuint indirections = 1; 4483464ebd5Sriastradh GLbitfield tempsOutput = 0x0; 4493464ebd5Sriastradh GLbitfield aluTemps = 0x0; 4503464ebd5Sriastradh GLuint i; 4513464ebd5Sriastradh 4523464ebd5Sriastradh for (i = 0; i < prog->NumInstructions; i++) { 4533464ebd5Sriastradh const struct prog_instruction *inst = prog->Instructions + i; 4543464ebd5Sriastradh 4553464ebd5Sriastradh if (is_texture_instruction(inst)) { 4563464ebd5Sriastradh if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) && 4573464ebd5Sriastradh (tempsOutput & (1 << inst->SrcReg[0].Index))) || 4583464ebd5Sriastradh ((inst->Opcode != OPCODE_KIL) && 4593464ebd5Sriastradh (inst->DstReg.File == PROGRAM_TEMPORARY) && 4603464ebd5Sriastradh (aluTemps & (1 << inst->DstReg.Index)))) 4613464ebd5Sriastradh { 4623464ebd5Sriastradh indirections++; 4633464ebd5Sriastradh tempsOutput = 0x0; 4643464ebd5Sriastradh aluTemps = 0x0; 4653464ebd5Sriastradh } 4663464ebd5Sriastradh } 4673464ebd5Sriastradh else { 4683464ebd5Sriastradh GLuint j; 4693464ebd5Sriastradh for (j = 0; j < 3; j++) { 4703464ebd5Sriastradh if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) 4713464ebd5Sriastradh aluTemps |= (1 << inst->SrcReg[j].Index); 4723464ebd5Sriastradh } 4733464ebd5Sriastradh if (inst->DstReg.File == PROGRAM_TEMPORARY) 4743464ebd5Sriastradh aluTemps |= (1 << inst->DstReg.Index); 4753464ebd5Sriastradh } 4763464ebd5Sriastradh 4773464ebd5Sriastradh if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY)) 4783464ebd5Sriastradh tempsOutput |= (1 << inst->DstReg.Index); 4793464ebd5Sriastradh } 4803464ebd5Sriastradh 4813464ebd5Sriastradh prog->NumTexIndirections = indirections; 4823464ebd5Sriastradh} 4833464ebd5Sriastradh 4843464ebd5Sriastradh 4853464ebd5Sriastradh/** 4863464ebd5Sriastradh * Count number of texture instructions in given program and update the 4873464ebd5Sriastradh * program's NumTexInstructions field. 4883464ebd5Sriastradh */ 4893464ebd5Sriastradhvoid 4903464ebd5Sriastradh_mesa_count_texture_instructions(struct gl_program *prog) 4913464ebd5Sriastradh{ 4923464ebd5Sriastradh GLuint i; 4933464ebd5Sriastradh prog->NumTexInstructions = 0; 4943464ebd5Sriastradh for (i = 0; i < prog->NumInstructions; i++) { 4953464ebd5Sriastradh prog->NumTexInstructions += is_texture_instruction(prog->Instructions + i); 4963464ebd5Sriastradh } 4973464ebd5Sriastradh} 4983464ebd5Sriastradh 4993464ebd5Sriastradh 5003464ebd5Sriastradh/** 5013464ebd5Sriastradh * Scan/rewrite program to remove reads of custom (output) registers. 5023464ebd5Sriastradh * The passed type has to be either PROGRAM_OUTPUT or PROGRAM_VARYING 5033464ebd5Sriastradh * (for vertex shaders). 5043464ebd5Sriastradh * In GLSL shaders, varying vars can be read and written. 5053464ebd5Sriastradh * On some hardware, trying to read an output register causes trouble. 5063464ebd5Sriastradh * So, rewrite the program to use a temporary register in this case. 5073464ebd5Sriastradh */ 5083464ebd5Sriastradhvoid 5093464ebd5Sriastradh_mesa_remove_output_reads(struct gl_program *prog, gl_register_file type) 5103464ebd5Sriastradh{ 5113464ebd5Sriastradh GLuint i; 5123464ebd5Sriastradh GLint outputMap[VERT_RESULT_MAX]; 5133464ebd5Sriastradh GLuint numVaryingReads = 0; 5143464ebd5Sriastradh GLboolean usedTemps[MAX_PROGRAM_TEMPS]; 5153464ebd5Sriastradh GLuint firstTemp = 0; 5163464ebd5Sriastradh 5173464ebd5Sriastradh _mesa_find_used_registers(prog, PROGRAM_TEMPORARY, 5183464ebd5Sriastradh usedTemps, MAX_PROGRAM_TEMPS); 5193464ebd5Sriastradh 5203464ebd5Sriastradh assert(type == PROGRAM_VARYING || type == PROGRAM_OUTPUT); 5213464ebd5Sriastradh assert(prog->Target == GL_VERTEX_PROGRAM_ARB || type != PROGRAM_VARYING); 5223464ebd5Sriastradh 5233464ebd5Sriastradh for (i = 0; i < VERT_RESULT_MAX; i++) 5243464ebd5Sriastradh outputMap[i] = -1; 5253464ebd5Sriastradh 5263464ebd5Sriastradh /* look for instructions which read from varying vars */ 5273464ebd5Sriastradh for (i = 0; i < prog->NumInstructions; i++) { 5283464ebd5Sriastradh struct prog_instruction *inst = prog->Instructions + i; 5293464ebd5Sriastradh const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); 5303464ebd5Sriastradh GLuint j; 5313464ebd5Sriastradh for (j = 0; j < numSrc; j++) { 5323464ebd5Sriastradh if (inst->SrcReg[j].File == type) { 5333464ebd5Sriastradh /* replace the read with a temp reg */ 5343464ebd5Sriastradh const GLuint var = inst->SrcReg[j].Index; 5353464ebd5Sriastradh if (outputMap[var] == -1) { 5363464ebd5Sriastradh numVaryingReads++; 5373464ebd5Sriastradh outputMap[var] = _mesa_find_free_register(usedTemps, 5383464ebd5Sriastradh MAX_PROGRAM_TEMPS, 5393464ebd5Sriastradh firstTemp); 5403464ebd5Sriastradh firstTemp = outputMap[var] + 1; 5413464ebd5Sriastradh } 5423464ebd5Sriastradh inst->SrcReg[j].File = PROGRAM_TEMPORARY; 5433464ebd5Sriastradh inst->SrcReg[j].Index = outputMap[var]; 5443464ebd5Sriastradh } 5453464ebd5Sriastradh } 5463464ebd5Sriastradh } 5473464ebd5Sriastradh 5483464ebd5Sriastradh if (numVaryingReads == 0) 5493464ebd5Sriastradh return; /* nothing to be done */ 5503464ebd5Sriastradh 5513464ebd5Sriastradh /* look for instructions which write to the varying vars identified above */ 5523464ebd5Sriastradh for (i = 0; i < prog->NumInstructions; i++) { 5533464ebd5Sriastradh struct prog_instruction *inst = prog->Instructions + i; 5543464ebd5Sriastradh if (inst->DstReg.File == type && 5553464ebd5Sriastradh outputMap[inst->DstReg.Index] >= 0) { 5563464ebd5Sriastradh /* change inst to write to the temp reg, instead of the varying */ 5573464ebd5Sriastradh inst->DstReg.File = PROGRAM_TEMPORARY; 5583464ebd5Sriastradh inst->DstReg.Index = outputMap[inst->DstReg.Index]; 5593464ebd5Sriastradh } 5603464ebd5Sriastradh } 5613464ebd5Sriastradh 5623464ebd5Sriastradh /* insert new instructions to copy the temp vars to the varying vars */ 5633464ebd5Sriastradh { 5643464ebd5Sriastradh struct prog_instruction *inst; 5653464ebd5Sriastradh GLint endPos, var; 5663464ebd5Sriastradh 5673464ebd5Sriastradh /* Look for END instruction and insert the new varying writes */ 5683464ebd5Sriastradh endPos = -1; 5693464ebd5Sriastradh for (i = 0; i < prog->NumInstructions; i++) { 5703464ebd5Sriastradh struct prog_instruction *inst = prog->Instructions + i; 5713464ebd5Sriastradh if (inst->Opcode == OPCODE_END) { 5723464ebd5Sriastradh endPos = i; 5733464ebd5Sriastradh _mesa_insert_instructions(prog, i, numVaryingReads); 5743464ebd5Sriastradh break; 5753464ebd5Sriastradh } 5763464ebd5Sriastradh } 5773464ebd5Sriastradh 5783464ebd5Sriastradh assert(endPos >= 0); 5793464ebd5Sriastradh 5803464ebd5Sriastradh /* insert new MOV instructions here */ 5813464ebd5Sriastradh inst = prog->Instructions + endPos; 5823464ebd5Sriastradh for (var = 0; var < VERT_RESULT_MAX; var++) { 5833464ebd5Sriastradh if (outputMap[var] >= 0) { 5843464ebd5Sriastradh /* MOV VAR[var], TEMP[tmp]; */ 5853464ebd5Sriastradh inst->Opcode = OPCODE_MOV; 5863464ebd5Sriastradh inst->DstReg.File = type; 5873464ebd5Sriastradh inst->DstReg.Index = var; 5883464ebd5Sriastradh inst->SrcReg[0].File = PROGRAM_TEMPORARY; 5893464ebd5Sriastradh inst->SrcReg[0].Index = outputMap[var]; 5903464ebd5Sriastradh inst++; 5913464ebd5Sriastradh } 5923464ebd5Sriastradh } 5933464ebd5Sriastradh } 5943464ebd5Sriastradh} 5953464ebd5Sriastradh 5963464ebd5Sriastradh 5973464ebd5Sriastradh/** 5983464ebd5Sriastradh * Make the given fragment program into a "no-op" shader. 5993464ebd5Sriastradh * Actually, just copy the incoming fragment color (or texcoord) 6003464ebd5Sriastradh * to the output color. 6013464ebd5Sriastradh * This is for debug/test purposes. 6023464ebd5Sriastradh */ 6033464ebd5Sriastradhvoid 6043464ebd5Sriastradh_mesa_nop_fragment_program(struct gl_context *ctx, struct gl_fragment_program *prog) 6053464ebd5Sriastradh{ 6063464ebd5Sriastradh struct prog_instruction *inst; 6073464ebd5Sriastradh GLuint inputAttr; 6083464ebd5Sriastradh 6093464ebd5Sriastradh inst = _mesa_alloc_instructions(2); 6103464ebd5Sriastradh if (!inst) { 6113464ebd5Sriastradh _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_fragment_program"); 6123464ebd5Sriastradh return; 6133464ebd5Sriastradh } 6143464ebd5Sriastradh 6153464ebd5Sriastradh _mesa_init_instructions(inst, 2); 6163464ebd5Sriastradh 6173464ebd5Sriastradh inst[0].Opcode = OPCODE_MOV; 6183464ebd5Sriastradh inst[0].DstReg.File = PROGRAM_OUTPUT; 6193464ebd5Sriastradh inst[0].DstReg.Index = FRAG_RESULT_COLOR; 6203464ebd5Sriastradh inst[0].SrcReg[0].File = PROGRAM_INPUT; 6213464ebd5Sriastradh if (prog->Base.InputsRead & FRAG_BIT_COL0) 6223464ebd5Sriastradh inputAttr = FRAG_ATTRIB_COL0; 6233464ebd5Sriastradh else 6243464ebd5Sriastradh inputAttr = FRAG_ATTRIB_TEX0; 6253464ebd5Sriastradh inst[0].SrcReg[0].Index = inputAttr; 6263464ebd5Sriastradh 6273464ebd5Sriastradh inst[1].Opcode = OPCODE_END; 6283464ebd5Sriastradh 6293464ebd5Sriastradh _mesa_free_instructions(prog->Base.Instructions, 6303464ebd5Sriastradh prog->Base.NumInstructions); 6313464ebd5Sriastradh 6323464ebd5Sriastradh prog->Base.Instructions = inst; 6333464ebd5Sriastradh prog->Base.NumInstructions = 2; 6343464ebd5Sriastradh prog->Base.InputsRead = 1 << inputAttr; 6353464ebd5Sriastradh prog->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR); 6363464ebd5Sriastradh} 6373464ebd5Sriastradh 6383464ebd5Sriastradh 6393464ebd5Sriastradh/** 6403464ebd5Sriastradh * \sa _mesa_nop_fragment_program 6413464ebd5Sriastradh * Replace the given vertex program with a "no-op" program that just 6423464ebd5Sriastradh * transforms vertex position and emits color. 6433464ebd5Sriastradh */ 6443464ebd5Sriastradhvoid 6453464ebd5Sriastradh_mesa_nop_vertex_program(struct gl_context *ctx, struct gl_vertex_program *prog) 6463464ebd5Sriastradh{ 6473464ebd5Sriastradh struct prog_instruction *inst; 6483464ebd5Sriastradh GLuint inputAttr; 6493464ebd5Sriastradh 6503464ebd5Sriastradh /* 6513464ebd5Sriastradh * Start with a simple vertex program that emits color. 6523464ebd5Sriastradh */ 6533464ebd5Sriastradh inst = _mesa_alloc_instructions(2); 6543464ebd5Sriastradh if (!inst) { 6553464ebd5Sriastradh _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_vertex_program"); 6563464ebd5Sriastradh return; 6573464ebd5Sriastradh } 6583464ebd5Sriastradh 6593464ebd5Sriastradh _mesa_init_instructions(inst, 2); 6603464ebd5Sriastradh 6613464ebd5Sriastradh inst[0].Opcode = OPCODE_MOV; 6623464ebd5Sriastradh inst[0].DstReg.File = PROGRAM_OUTPUT; 6633464ebd5Sriastradh inst[0].DstReg.Index = VERT_RESULT_COL0; 6643464ebd5Sriastradh inst[0].SrcReg[0].File = PROGRAM_INPUT; 6653464ebd5Sriastradh if (prog->Base.InputsRead & VERT_BIT_COLOR0) 6663464ebd5Sriastradh inputAttr = VERT_ATTRIB_COLOR0; 6673464ebd5Sriastradh else 6683464ebd5Sriastradh inputAttr = VERT_ATTRIB_TEX0; 6693464ebd5Sriastradh inst[0].SrcReg[0].Index = inputAttr; 6703464ebd5Sriastradh 6713464ebd5Sriastradh inst[1].Opcode = OPCODE_END; 6723464ebd5Sriastradh 6733464ebd5Sriastradh _mesa_free_instructions(prog->Base.Instructions, 6743464ebd5Sriastradh prog->Base.NumInstructions); 6753464ebd5Sriastradh 6763464ebd5Sriastradh prog->Base.Instructions = inst; 6773464ebd5Sriastradh prog->Base.NumInstructions = 2; 6783464ebd5Sriastradh prog->Base.InputsRead = 1 << inputAttr; 6793464ebd5Sriastradh prog->Base.OutputsWritten = BITFIELD64_BIT(VERT_RESULT_COL0); 6803464ebd5Sriastradh 6813464ebd5Sriastradh /* 6823464ebd5Sriastradh * Now insert code to do standard modelview/projection transformation. 6833464ebd5Sriastradh */ 6843464ebd5Sriastradh _mesa_insert_mvp_code(ctx, prog); 6853464ebd5Sriastradh} 686