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