programopt.c revision f5eea0cc7a8c568b00035427294812712c6c6081
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Mesa 3-D graphics library
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Version:  6.5.2
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Permission is hereby granted, free of charge, to any person obtaining a
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * copy of this software and associated documentation files (the "Software"),
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * to deal in the Software without restriction, including without limitation
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the rights to use, copy, modify, merge, publish, distribute, sublicense,
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * and/or sell copies of the Software, and to permit persons to whom the
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Software is furnished to do so, subject to the following conditions:
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The above copyright notice and this permission notice shall be included
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * in all copies or substantial portions of the Software.
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/**
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * \file  programopt.c
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Vertex/Fragment program optimizations and transformations for program
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * options, etc.
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * \author Brian Paul
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "glheader.h"
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "context.h"
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "imports.h"
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "mtypes.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "program.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "programopt.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "program_instruction.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This function inserts instructions for coordinate modelview * projection
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * into a vertex program.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * May be used to implement the position_invariant option.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   struct prog_instruction *newInst;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   const GLuint origLen = vprog->Base.NumInstructions;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   const GLuint newLen = origLen + 4;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   GLuint i;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   /*
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    * Setup state references for the modelview/projection matrix.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    * XXX we should check if these state vars are already declared.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    */
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   static const GLint mvpState[4][5] = {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { STATE_MATRIX, STATE_MVP, 0, 0, 0 },  /* state.matrix.mvp.row[0] */
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { STATE_MATRIX, STATE_MVP, 0, 1, 1 },  /* state.matrix.mvp.row[1] */
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { STATE_MATRIX, STATE_MVP, 0, 2, 2 },  /* state.matrix.mvp.row[2] */
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { STATE_MATRIX, STATE_MVP, 0, 3, 3 },  /* state.matrix.mvp.row[3] */
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   };
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   GLint mvpRef[4];
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   for (i = 0; i < 4; i++) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            mvpState[i]);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   /* Alloc storage for new instructions */
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   newInst = _mesa_alloc_instructions(newLen);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   if (!newInst) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      _mesa_error(ctx, GL_OUT_OF_MEMORY,
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "glProgramString(inserting position_invariant code)");
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   /*
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    * Generated instructions:
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    * newInst[0] = DP4 result.position.x, mvp.row[0], vertex.position;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    * newInst[1] = DP4 result.position.y, mvp.row[1], vertex.position;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    * newInst[2] = DP4 result.position.z, mvp.row[2], vertex.position;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    * newInst[3] = DP4 result.position.w, mvp.row[3], vertex.position;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    */
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   for (i = 0; i < 4; i++) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      _mesa_init_instruction(newInst + i);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      newInst[i].Opcode = OPCODE_DP4;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      newInst[i].DstReg.File = PROGRAM_OUTPUT;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      newInst[i].DstReg.Index = VERT_RESULT_HPOS;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      newInst[i].DstReg.WriteMask = (WRITEMASK_X << i);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      newInst[i].SrcReg[0].File = PROGRAM_STATE_VAR;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      newInst[i].SrcReg[0].Index = mvpRef[i];
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      newInst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      newInst[i].SrcReg[1].File = PROGRAM_INPUT;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      newInst[i].SrcReg[1].Index = VERT_ATTRIB_POS;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   /* Append original instructions after new instructions */
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   _mesa_memcpy(newInst + 4, vprog->Base.Instructions,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                origLen * sizeof(struct prog_instruction));
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   /* free old instructions */
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   _mesa_free(vprog->Base.Instructions);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   /* install new instructions */
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   vprog->Base.Instructions = newInst;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   vprog->Base.NumInstructions = newLen;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   vprog->Base.InputsRead |= VERT_BIT_POS;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   vprog->Base.OutputsWritten |= (1 << VERT_RESULT_HPOS);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Append extra instructions onto the given fragment program to implement
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the fog mode specified by fprog->FogOption.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The fragment.fogcoord input is used to compute the fog blend factor.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * XXX with a little work, this function could be adapted to add fog code
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * to vertex programs too.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)_mesa_append_fog_code(GLcontext *ctx, struct gl_fragment_program *fprog)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   static const GLint fogParamsState[] = { STATE_FOG_PARAMS, 0, 0, 0, 0 };
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   static const GLint fogColorState[] = { STATE_FOG_COLOR, 0, 0, 0, 0 };
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   struct prog_instruction *newInst, *inst;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   const GLuint origLen = fprog->Base.NumInstructions;
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch   const GLuint newLen = origLen + 6;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   GLuint i;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   GLint fogParamsRef, fogColorRef; /* state references */
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   GLuint colorTemp, fogFactorTemp; /* temporary registerss */
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   GLfloat fogVals[4];
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   GLuint fogConsts;                /* constant values for EXP, EXP2 mode */
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   if (fprog->FogOption != GL_NONE) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program"
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    " with FogOption == GL_NONE");
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   /* Alloc storage for new instructions */
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   newInst = _mesa_alloc_instructions(newLen);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   if (!newInst) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      _mesa_error(ctx, GL_OUT_OF_MEMORY,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "glProgramString(inserting fog_option code)");
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   /* Copy orig instructions into new instruction buffer */
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   _mesa_memcpy(newInst, fprog->Base.Instructions,
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                origLen * sizeof(struct prog_instruction));
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   /* PARAM fogParamsRef = state.fog.params; */
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   fogParamsRef
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      = _mesa_add_state_reference(fprog->Base.Parameters, fogParamsState);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   /* PARAM fogColorRef = state.fog.color; */
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch   fogColorRef
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      = _mesa_add_state_reference(fprog->Base.Parameters, fogColorState);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch   /* TEMP colorTemp; */
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   colorTemp = fprog->Base.NumTemporaries++;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   /* TEMP fogFactorTemp; */
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   fogFactorTemp = fprog->Base.NumTemporaries++;
169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   /* PARAM fogVals = { 1/ln(2), 1/sqrt(ln(2), 0, 0 }; */
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   fogVals[0] = 1.0 / log(2.0);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   fogVals[1] = 1.0 / SQRTF(log(2.0));
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch   fogVals[2] = 0.0;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   fogVals[3] = 0.0;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   fogConsts = _mesa_add_unnamed_constant(fprog->Base.Parameters, fogVals);
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
177c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch   /* Scan program to find where result.color is written */
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   inst = newInst;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   for (i = 0; i < fprog->Base.NumInstructions; i++) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (inst->Opcode == OPCODE_END)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         break;
182      if (inst->DstReg.File == PROGRAM_OUTPUT &&
183          inst->DstReg.Index == FRAG_RESULT_COLR) {
184         /* change the instruction to write to colorTemp w/ clamping */
185         inst->DstReg.File = PROGRAM_TEMPORARY;
186         inst->DstReg.Index = colorTemp;
187         inst->SaturateMode = SATURATE_ZERO_ONE;
188         /* don't break (may be several writes to result.color) */
189      }
190      inst++;
191   }
192   assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */
193
194   for (i = 0; i < 6; i++)
195      _mesa_init_instruction(inst + i);
196
197   /* emit instructions to compute fog blending factor */
198   if (fprog->FogOption == GL_LINEAR) {
199      /* SUB fogFactorTemp.x, fogParamsRef.z, fragment.fogcoord.x; */
200      inst->Opcode = OPCODE_SUB;
201      inst->DstReg.File = PROGRAM_TEMPORARY;
202      inst->DstReg.Index = fogFactorTemp;
203      inst->DstReg.WriteMask = WRITEMASK_X;
204      inst->SrcReg[0].File = PROGRAM_STATE_VAR;
205      inst->SrcReg[0].Index = fogParamsRef;
206      inst->SrcReg[0].Swizzle = SWIZZLE_Z;
207      inst->SrcReg[1].File = PROGRAM_INPUT;
208      inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC;
209      inst++;
210      /* MUL fogFactorTemp.x, fogFactorTemp, fogParamsRef.w; */
211      inst->Opcode = OPCODE_MUL;
212      inst->DstReg.File = PROGRAM_TEMPORARY;
213      inst->DstReg.Index = fogFactorTemp;
214      inst->DstReg.WriteMask = WRITEMASK_X;
215      inst->SrcReg[0].File = PROGRAM_TEMPORARY;
216      inst->SrcReg[0].Index = fogFactorTemp;
217      inst->SrcReg[1].File = PROGRAM_STATE_VAR;
218      inst->SrcReg[1].Index = fogParamsRef;
219      inst->SrcReg[1].Swizzle = SWIZZLE_W;
220      inst++;
221   }
222   else {
223      ASSERT(fprog->FogOption == GL_EXP || fprog->FogOption == GL_EXP2);
224      /* MUL fogFactorTemp.x, fogParamsRef.x, fragment.fogcoord; */
225      inst->Opcode = OPCODE_MUL;
226      inst->DstReg.File = PROGRAM_TEMPORARY;
227      inst->DstReg.Index = fogFactorTemp;
228      inst->DstReg.WriteMask = WRITEMASK_X;
229      inst->SrcReg[0].File = PROGRAM_STATE_VAR;
230      inst->SrcReg[0].Index = fogParamsRef;
231      inst->SrcReg[0].Swizzle = SWIZZLE_X; /* X=density */
232      inst->SrcReg[1].File = PROGRAM_INPUT;
233      inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC;
234      inst->SrcReg[1].Swizzle = SWIZZLE_X;
235      inst++;
236      if (fprog->FogOption == GL_EXP2) {
237         /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */
238         inst->Opcode = OPCODE_MUL;
239         inst->DstReg.File = PROGRAM_TEMPORARY;
240         inst->DstReg.Index = fogFactorTemp;
241         inst->DstReg.WriteMask = WRITEMASK_X;
242         inst->SrcReg[0].File = PROGRAM_TEMPORARY;
243         inst->SrcReg[0].Index = fogFactorTemp;
244         inst->SrcReg[1].File = PROGRAM_TEMPORARY;
245         inst->SrcReg[1].Index = fogFactorTemp;
246         inst++;
247      }
248      /* EXP:  MUL fogFactorTemp.x, fogFactorTemp.x, {1/ln(2)}; */
249      /* EXP2: MUL fogFactorTemp.x, fogFactorTemp.x, {1/sqrt(ln(2))}; */
250      inst->Opcode = OPCODE_MUL;
251      inst->DstReg.File = PROGRAM_TEMPORARY;
252      inst->DstReg.Index = fogFactorTemp;
253      inst->DstReg.WriteMask = WRITEMASK_X;
254      inst->SrcReg[0].File = PROGRAM_TEMPORARY;
255      inst->SrcReg[0].Index = fogFactorTemp;
256      inst->SrcReg[1].File = PROGRAM_CONSTANT;
257      inst->SrcReg[1].Index = fogConsts;
258      inst->SrcReg[1].Swizzle
259         = (fprog->FogOption == GL_EXP) ? SWIZZLE_X : SWIZZLE_Y;
260      inst++;
261      /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */
262      inst->Opcode = OPCODE_EX2;
263      inst->DstReg.File = PROGRAM_TEMPORARY;
264      inst->DstReg.Index = fogFactorTemp;
265      inst->DstReg.WriteMask = WRITEMASK_X;
266      inst->SrcReg[0].File = PROGRAM_TEMPORARY;
267      inst->SrcReg[0].Index = fogFactorTemp;
268      inst->SrcReg[0].NegateBase = GL_TRUE;
269      inst->SaturateMode = SATURATE_ZERO_ONE;
270      inst++;
271   }
272   /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */
273   inst->Opcode = OPCODE_LRP;
274   inst->DstReg.File = PROGRAM_OUTPUT;
275   inst->DstReg.Index = FRAG_RESULT_COLR;
276   inst->DstReg.WriteMask = WRITEMASK_XYZ;
277   inst->SrcReg[0].File = PROGRAM_TEMPORARY;
278   inst->SrcReg[0].Index = fogFactorTemp;
279   inst->SrcReg[0].Swizzle
280      = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X);
281   inst->SrcReg[1].File = PROGRAM_TEMPORARY;
282   inst->SrcReg[1].Index = colorTemp;
283   inst->SrcReg[2].File = PROGRAM_STATE_VAR;
284   inst->SrcReg[2].Index = fogColorRef;
285   inst++;
286   /* MOV result.color.w, colorTemp.x;  # copy alpha */
287   inst->Opcode = OPCODE_MOV;
288   inst->DstReg.File = PROGRAM_OUTPUT;
289   inst->DstReg.Index = FRAG_RESULT_COLR;
290   inst->DstReg.WriteMask = WRITEMASK_W;
291   inst->SrcReg[0].File = PROGRAM_TEMPORARY;
292   inst->SrcReg[0].Index = colorTemp;
293   inst++;
294   /* END; */
295   inst->Opcode = OPCODE_END;
296   inst++;
297
298   /* free old instructions */
299   _mesa_free(fprog->Base.Instructions);
300
301   /* install new instructions */
302   fprog->Base.Instructions = newInst;
303   fprog->Base.NumInstructions = inst - newInst;
304   fprog->Base.InputsRead |= FRAG_BIT_FOGC;
305   /* XXX do this?  fprog->FogOption = GL_NONE; */
306}
307