Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 1 | /* |
2 | * Mesa 3-D graphics library |
||
3 | * |
||
4 | * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. |
||
5 | * |
||
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
7 | * copy of this software and associated documentation files (the "Software"), |
||
8 | * to deal in the Software without restriction, including without limitation |
||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
10 | * and/or sell copies of the Software, and to permit persons to whom the |
||
11 | * Software is furnished to do so, subject to the following conditions: |
||
12 | * |
||
13 | * The above copyright notice and this permission notice shall be included |
||
14 | * in all copies or substantial portions of the Software. |
||
15 | * |
||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
||
20 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
||
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||
22 | * OTHER DEALINGS IN THE SOFTWARE. |
||
23 | */ |
||
24 | |||
25 | /** |
||
26 | * \file programopt.c |
||
27 | * Vertex/Fragment program optimizations and transformations for program |
||
28 | * options, etc. |
||
29 | * |
||
30 | * \author Brian Paul |
||
31 | */ |
||
32 | |||
33 | |||
34 | #include "main/glheader.h" |
||
35 | #include "main/context.h" |
||
36 | #include "prog_parameter.h" |
||
37 | #include "prog_statevars.h" |
||
38 | #include "program.h" |
||
39 | #include "programopt.h" |
||
40 | #include "prog_instruction.h" |
||
41 | |||
42 | |||
43 | /** |
||
44 | * This function inserts instructions for coordinate modelview * projection |
||
45 | * into a vertex program. |
||
46 | * May be used to implement the position_invariant option. |
||
47 | */ |
||
48 | static void |
||
49 | _mesa_insert_mvp_dp4_code(struct gl_context *ctx, struct gl_vertex_program *vprog) |
||
50 | { |
||
51 | struct prog_instruction *newInst; |
||
52 | const GLuint origLen = vprog->Base.NumInstructions; |
||
53 | const GLuint newLen = origLen + 4; |
||
54 | GLuint i; |
||
55 | |||
56 | /* |
||
57 | * Setup state references for the modelview/projection matrix. |
||
58 | * XXX we should check if these state vars are already declared. |
||
59 | */ |
||
60 | static const gl_state_index mvpState[4][STATE_LENGTH] = { |
||
61 | { STATE_MVP_MATRIX, 0, 0, 0, 0 }, /* state.matrix.mvp.row[0] */ |
||
62 | { STATE_MVP_MATRIX, 0, 1, 1, 0 }, /* state.matrix.mvp.row[1] */ |
||
63 | { STATE_MVP_MATRIX, 0, 2, 2, 0 }, /* state.matrix.mvp.row[2] */ |
||
64 | { STATE_MVP_MATRIX, 0, 3, 3, 0 }, /* state.matrix.mvp.row[3] */ |
||
65 | }; |
||
66 | GLint mvpRef[4]; |
||
67 | |||
68 | for (i = 0; i < 4; i++) { |
||
69 | mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters, |
||
70 | mvpState[i]); |
||
71 | } |
||
72 | |||
73 | /* Alloc storage for new instructions */ |
||
74 | newInst = _mesa_alloc_instructions(newLen); |
||
75 | if (!newInst) { |
||
76 | _mesa_error(ctx, GL_OUT_OF_MEMORY, |
||
77 | "glProgramString(inserting position_invariant code)"); |
||
78 | return; |
||
79 | } |
||
80 | |||
81 | /* |
||
82 | * Generated instructions: |
||
83 | * newInst[0] = DP4 result.position.x, mvp.row[0], vertex.position; |
||
84 | * newInst[1] = DP4 result.position.y, mvp.row[1], vertex.position; |
||
85 | * newInst[2] = DP4 result.position.z, mvp.row[2], vertex.position; |
||
86 | * newInst[3] = DP4 result.position.w, mvp.row[3], vertex.position; |
||
87 | */ |
||
88 | _mesa_init_instructions(newInst, 4); |
||
89 | for (i = 0; i < 4; i++) { |
||
90 | newInst[i].Opcode = OPCODE_DP4; |
||
91 | newInst[i].DstReg.File = PROGRAM_OUTPUT; |
||
92 | newInst[i].DstReg.Index = VARYING_SLOT_POS; |
||
93 | newInst[i].DstReg.WriteMask = (WRITEMASK_X << i); |
||
94 | newInst[i].SrcReg[0].File = PROGRAM_STATE_VAR; |
||
95 | newInst[i].SrcReg[0].Index = mvpRef[i]; |
||
96 | newInst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP; |
||
97 | newInst[i].SrcReg[1].File = PROGRAM_INPUT; |
||
98 | newInst[i].SrcReg[1].Index = VERT_ATTRIB_POS; |
||
99 | newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; |
||
100 | } |
||
101 | |||
102 | /* Append original instructions after new instructions */ |
||
103 | _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen); |
||
104 | |||
105 | /* free old instructions */ |
||
106 | _mesa_free_instructions(vprog->Base.Instructions, origLen); |
||
107 | |||
108 | /* install new instructions */ |
||
109 | vprog->Base.Instructions = newInst; |
||
110 | vprog->Base.NumInstructions = newLen; |
||
111 | vprog->Base.InputsRead |= VERT_BIT_POS; |
||
112 | vprog->Base.OutputsWritten |= BITFIELD64_BIT(VARYING_SLOT_POS); |
||
113 | } |
||
114 | |||
115 | |||
116 | static void |
||
117 | _mesa_insert_mvp_mad_code(struct gl_context *ctx, struct gl_vertex_program *vprog) |
||
118 | { |
||
119 | struct prog_instruction *newInst; |
||
120 | const GLuint origLen = vprog->Base.NumInstructions; |
||
121 | const GLuint newLen = origLen + 4; |
||
122 | GLuint hposTemp; |
||
123 | GLuint i; |
||
124 | |||
125 | /* |
||
126 | * Setup state references for the modelview/projection matrix. |
||
127 | * XXX we should check if these state vars are already declared. |
||
128 | */ |
||
129 | static const gl_state_index mvpState[4][STATE_LENGTH] = { |
||
130 | { STATE_MVP_MATRIX, 0, 0, 0, STATE_MATRIX_TRANSPOSE }, |
||
131 | { STATE_MVP_MATRIX, 0, 1, 1, STATE_MATRIX_TRANSPOSE }, |
||
132 | { STATE_MVP_MATRIX, 0, 2, 2, STATE_MATRIX_TRANSPOSE }, |
||
133 | { STATE_MVP_MATRIX, 0, 3, 3, STATE_MATRIX_TRANSPOSE }, |
||
134 | }; |
||
135 | GLint mvpRef[4]; |
||
136 | |||
137 | for (i = 0; i < 4; i++) { |
||
138 | mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters, |
||
139 | mvpState[i]); |
||
140 | } |
||
141 | |||
142 | /* Alloc storage for new instructions */ |
||
143 | newInst = _mesa_alloc_instructions(newLen); |
||
144 | if (!newInst) { |
||
145 | _mesa_error(ctx, GL_OUT_OF_MEMORY, |
||
146 | "glProgramString(inserting position_invariant code)"); |
||
147 | return; |
||
148 | } |
||
149 | |||
150 | /* TEMP hposTemp; */ |
||
151 | hposTemp = vprog->Base.NumTemporaries++; |
||
152 | |||
153 | /* |
||
154 | * Generated instructions: |
||
155 | * emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]); |
||
156 | * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp); |
||
157 | * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp); |
||
158 | * emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp); |
||
159 | */ |
||
160 | _mesa_init_instructions(newInst, 4); |
||
161 | |||
162 | newInst[0].Opcode = OPCODE_MUL; |
||
163 | newInst[0].DstReg.File = PROGRAM_TEMPORARY; |
||
164 | newInst[0].DstReg.Index = hposTemp; |
||
165 | newInst[0].DstReg.WriteMask = WRITEMASK_XYZW; |
||
166 | newInst[0].SrcReg[0].File = PROGRAM_INPUT; |
||
167 | newInst[0].SrcReg[0].Index = VERT_ATTRIB_POS; |
||
168 | newInst[0].SrcReg[0].Swizzle = SWIZZLE_XXXX; |
||
169 | newInst[0].SrcReg[1].File = PROGRAM_STATE_VAR; |
||
170 | newInst[0].SrcReg[1].Index = mvpRef[0]; |
||
171 | newInst[0].SrcReg[1].Swizzle = SWIZZLE_NOOP; |
||
172 | |||
173 | for (i = 1; i <= 2; i++) { |
||
174 | newInst[i].Opcode = OPCODE_MAD; |
||
175 | newInst[i].DstReg.File = PROGRAM_TEMPORARY; |
||
176 | newInst[i].DstReg.Index = hposTemp; |
||
177 | newInst[i].DstReg.WriteMask = WRITEMASK_XYZW; |
||
178 | newInst[i].SrcReg[0].File = PROGRAM_INPUT; |
||
179 | newInst[i].SrcReg[0].Index = VERT_ATTRIB_POS; |
||
180 | newInst[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(i,i,i,i); |
||
181 | newInst[i].SrcReg[1].File = PROGRAM_STATE_VAR; |
||
182 | newInst[i].SrcReg[1].Index = mvpRef[i]; |
||
183 | newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP; |
||
184 | newInst[i].SrcReg[2].File = PROGRAM_TEMPORARY; |
||
185 | newInst[i].SrcReg[2].Index = hposTemp; |
||
186 | newInst[1].SrcReg[2].Swizzle = SWIZZLE_NOOP; |
||
187 | } |
||
188 | |||
189 | newInst[3].Opcode = OPCODE_MAD; |
||
190 | newInst[3].DstReg.File = PROGRAM_OUTPUT; |
||
191 | newInst[3].DstReg.Index = VARYING_SLOT_POS; |
||
192 | newInst[3].DstReg.WriteMask = WRITEMASK_XYZW; |
||
193 | newInst[3].SrcReg[0].File = PROGRAM_INPUT; |
||
194 | newInst[3].SrcReg[0].Index = VERT_ATTRIB_POS; |
||
195 | newInst[3].SrcReg[0].Swizzle = SWIZZLE_WWWW; |
||
196 | newInst[3].SrcReg[1].File = PROGRAM_STATE_VAR; |
||
197 | newInst[3].SrcReg[1].Index = mvpRef[3]; |
||
198 | newInst[3].SrcReg[1].Swizzle = SWIZZLE_NOOP; |
||
199 | newInst[3].SrcReg[2].File = PROGRAM_TEMPORARY; |
||
200 | newInst[3].SrcReg[2].Index = hposTemp; |
||
201 | newInst[3].SrcReg[2].Swizzle = SWIZZLE_NOOP; |
||
202 | |||
203 | |||
204 | /* Append original instructions after new instructions */ |
||
205 | _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen); |
||
206 | |||
207 | /* free old instructions */ |
||
208 | _mesa_free_instructions(vprog->Base.Instructions, origLen); |
||
209 | |||
210 | /* install new instructions */ |
||
211 | vprog->Base.Instructions = newInst; |
||
212 | vprog->Base.NumInstructions = newLen; |
||
213 | vprog->Base.InputsRead |= VERT_BIT_POS; |
||
214 | vprog->Base.OutputsWritten |= BITFIELD64_BIT(VARYING_SLOT_POS); |
||
215 | } |
||
216 | |||
217 | |||
218 | void |
||
219 | _mesa_insert_mvp_code(struct gl_context *ctx, struct gl_vertex_program *vprog) |
||
220 | { |
||
221 | if (ctx->Const.ShaderCompilerOptions[MESA_SHADER_VERTEX].OptimizeForAOS) |
||
222 | _mesa_insert_mvp_dp4_code( ctx, vprog ); |
||
223 | else |
||
224 | _mesa_insert_mvp_mad_code( ctx, vprog ); |
||
225 | } |
||
226 | |||
227 | |||
228 | |||
229 | |||
230 | |||
231 | |||
232 | /** |
||
233 | * Append instructions to implement fog |
||
234 | * |
||
235 | * The \c fragment.fogcoord input is used to compute the fog blend factor. |
||
236 | * |
||
237 | * \param ctx The GL context |
||
238 | * \param fprog Fragment program that fog instructions will be appended to. |
||
239 | * \param fog_mode Fog mode. One of \c GL_EXP, \c GL_EXP2, or \c GL_LINEAR. |
||
240 | * \param saturate True if writes to color outputs should be clamped to [0, 1] |
||
241 | * |
||
242 | * \note |
||
243 | * This function sets \c VARYING_BIT_FOGC in \c fprog->Base.InputsRead. |
||
244 | * |
||
245 | * \todo With a little work, this function could be adapted to add fog code |
||
246 | * to vertex programs too. |
||
247 | */ |
||
248 | void |
||
249 | _mesa_append_fog_code(struct gl_context *ctx, |
||
250 | struct gl_fragment_program *fprog, GLenum fog_mode, |
||
251 | GLboolean saturate) |
||
252 | { |
||
253 | static const gl_state_index fogPStateOpt[STATE_LENGTH] |
||
254 | = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 }; |
||
255 | static const gl_state_index fogColorState[STATE_LENGTH] |
||
256 | = { STATE_FOG_COLOR, 0, 0, 0, 0}; |
||
257 | struct prog_instruction *newInst, *inst; |
||
258 | const GLuint origLen = fprog->Base.NumInstructions; |
||
259 | const GLuint newLen = origLen + 5; |
||
260 | GLuint i; |
||
261 | GLint fogPRefOpt, fogColorRef; /* state references */ |
||
262 | GLuint colorTemp, fogFactorTemp; /* temporary registerss */ |
||
263 | |||
264 | if (fog_mode == GL_NONE) { |
||
265 | _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program" |
||
266 | " with fog_mode == GL_NONE"); |
||
267 | return; |
||
268 | } |
||
269 | |||
270 | if (!(fprog->Base.OutputsWritten & (1 << FRAG_RESULT_COLOR))) { |
||
271 | /* program doesn't output color, so nothing to do */ |
||
272 | return; |
||
273 | } |
||
274 | |||
275 | /* Alloc storage for new instructions */ |
||
276 | newInst = _mesa_alloc_instructions(newLen); |
||
277 | if (!newInst) { |
||
278 | _mesa_error(ctx, GL_OUT_OF_MEMORY, |
||
279 | "glProgramString(inserting fog_option code)"); |
||
280 | return; |
||
281 | } |
||
282 | |||
283 | /* Copy orig instructions into new instruction buffer */ |
||
284 | _mesa_copy_instructions(newInst, fprog->Base.Instructions, origLen); |
||
285 | |||
286 | /* PARAM fogParamsRefOpt = internal optimized fog params; */ |
||
287 | fogPRefOpt |
||
288 | = _mesa_add_state_reference(fprog->Base.Parameters, fogPStateOpt); |
||
289 | /* PARAM fogColorRef = state.fog.color; */ |
||
290 | fogColorRef |
||
291 | = _mesa_add_state_reference(fprog->Base.Parameters, fogColorState); |
||
292 | |||
293 | /* TEMP colorTemp; */ |
||
294 | colorTemp = fprog->Base.NumTemporaries++; |
||
295 | /* TEMP fogFactorTemp; */ |
||
296 | fogFactorTemp = fprog->Base.NumTemporaries++; |
||
297 | |||
298 | /* Scan program to find where result.color is written */ |
||
299 | inst = newInst; |
||
300 | for (i = 0; i < fprog->Base.NumInstructions; i++) { |
||
301 | if (inst->Opcode == OPCODE_END) |
||
302 | break; |
||
303 | if (inst->DstReg.File == PROGRAM_OUTPUT && |
||
304 | inst->DstReg.Index == FRAG_RESULT_COLOR) { |
||
305 | /* change the instruction to write to colorTemp w/ clamping */ |
||
306 | inst->DstReg.File = PROGRAM_TEMPORARY; |
||
307 | inst->DstReg.Index = colorTemp; |
||
308 | inst->SaturateMode = saturate; |
||
309 | /* don't break (may be several writes to result.color) */ |
||
310 | } |
||
311 | inst++; |
||
312 | } |
||
313 | assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */ |
||
314 | |||
315 | _mesa_init_instructions(inst, 5); |
||
316 | |||
317 | /* emit instructions to compute fog blending factor */ |
||
318 | /* this is always clamped to [0, 1] regardless of fragment clamping */ |
||
319 | if (fog_mode == GL_LINEAR) { |
||
320 | /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */ |
||
321 | inst->Opcode = OPCODE_MAD; |
||
322 | inst->DstReg.File = PROGRAM_TEMPORARY; |
||
323 | inst->DstReg.Index = fogFactorTemp; |
||
324 | inst->DstReg.WriteMask = WRITEMASK_X; |
||
325 | inst->SrcReg[0].File = PROGRAM_INPUT; |
||
326 | inst->SrcReg[0].Index = VARYING_SLOT_FOGC; |
||
327 | inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; |
||
328 | inst->SrcReg[1].File = PROGRAM_STATE_VAR; |
||
329 | inst->SrcReg[1].Index = fogPRefOpt; |
||
330 | inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; |
||
331 | inst->SrcReg[2].File = PROGRAM_STATE_VAR; |
||
332 | inst->SrcReg[2].Index = fogPRefOpt; |
||
333 | inst->SrcReg[2].Swizzle = SWIZZLE_YYYY; |
||
334 | inst->SaturateMode = SATURATE_ZERO_ONE; |
||
335 | inst++; |
||
336 | } |
||
337 | else { |
||
338 | assert(fog_mode == GL_EXP || fog_mode == GL_EXP2); |
||
339 | /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */ |
||
340 | /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */ |
||
341 | /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */ |
||
342 | inst->Opcode = OPCODE_MUL; |
||
343 | inst->DstReg.File = PROGRAM_TEMPORARY; |
||
344 | inst->DstReg.Index = fogFactorTemp; |
||
345 | inst->DstReg.WriteMask = WRITEMASK_X; |
||
346 | inst->SrcReg[0].File = PROGRAM_STATE_VAR; |
||
347 | inst->SrcReg[0].Index = fogPRefOpt; |
||
348 | inst->SrcReg[0].Swizzle |
||
349 | = (fog_mode == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW; |
||
350 | inst->SrcReg[1].File = PROGRAM_INPUT; |
||
351 | inst->SrcReg[1].Index = VARYING_SLOT_FOGC; |
||
352 | inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; |
||
353 | inst++; |
||
354 | if (fog_mode == GL_EXP2) { |
||
355 | /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */ |
||
356 | inst->Opcode = OPCODE_MUL; |
||
357 | inst->DstReg.File = PROGRAM_TEMPORARY; |
||
358 | inst->DstReg.Index = fogFactorTemp; |
||
359 | inst->DstReg.WriteMask = WRITEMASK_X; |
||
360 | inst->SrcReg[0].File = PROGRAM_TEMPORARY; |
||
361 | inst->SrcReg[0].Index = fogFactorTemp; |
||
362 | inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; |
||
363 | inst->SrcReg[1].File = PROGRAM_TEMPORARY; |
||
364 | inst->SrcReg[1].Index = fogFactorTemp; |
||
365 | inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; |
||
366 | inst++; |
||
367 | } |
||
368 | /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */ |
||
369 | inst->Opcode = OPCODE_EX2; |
||
370 | inst->DstReg.File = PROGRAM_TEMPORARY; |
||
371 | inst->DstReg.Index = fogFactorTemp; |
||
372 | inst->DstReg.WriteMask = WRITEMASK_X; |
||
373 | inst->SrcReg[0].File = PROGRAM_TEMPORARY; |
||
374 | inst->SrcReg[0].Index = fogFactorTemp; |
||
375 | inst->SrcReg[0].Negate = NEGATE_XYZW; |
||
376 | inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; |
||
377 | inst->SaturateMode = SATURATE_ZERO_ONE; |
||
378 | inst++; |
||
379 | } |
||
380 | /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */ |
||
381 | inst->Opcode = OPCODE_LRP; |
||
382 | inst->DstReg.File = PROGRAM_OUTPUT; |
||
383 | inst->DstReg.Index = FRAG_RESULT_COLOR; |
||
384 | inst->DstReg.WriteMask = WRITEMASK_XYZ; |
||
385 | inst->SrcReg[0].File = PROGRAM_TEMPORARY; |
||
386 | inst->SrcReg[0].Index = fogFactorTemp; |
||
387 | inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; |
||
388 | inst->SrcReg[1].File = PROGRAM_TEMPORARY; |
||
389 | inst->SrcReg[1].Index = colorTemp; |
||
390 | inst->SrcReg[1].Swizzle = SWIZZLE_NOOP; |
||
391 | inst->SrcReg[2].File = PROGRAM_STATE_VAR; |
||
392 | inst->SrcReg[2].Index = fogColorRef; |
||
393 | inst->SrcReg[2].Swizzle = SWIZZLE_NOOP; |
||
394 | inst++; |
||
395 | /* MOV result.color.w, colorTemp.x; # copy alpha */ |
||
396 | inst->Opcode = OPCODE_MOV; |
||
397 | inst->DstReg.File = PROGRAM_OUTPUT; |
||
398 | inst->DstReg.Index = FRAG_RESULT_COLOR; |
||
399 | inst->DstReg.WriteMask = WRITEMASK_W; |
||
400 | inst->SrcReg[0].File = PROGRAM_TEMPORARY; |
||
401 | inst->SrcReg[0].Index = colorTemp; |
||
402 | inst->SrcReg[0].Swizzle = SWIZZLE_NOOP; |
||
403 | inst++; |
||
404 | /* END; */ |
||
405 | inst->Opcode = OPCODE_END; |
||
406 | inst++; |
||
407 | |||
408 | /* free old instructions */ |
||
409 | _mesa_free_instructions(fprog->Base.Instructions, origLen); |
||
410 | |||
411 | /* install new instructions */ |
||
412 | fprog->Base.Instructions = newInst; |
||
413 | fprog->Base.NumInstructions = inst - newInst; |
||
414 | fprog->Base.InputsRead |= VARYING_BIT_FOGC; |
||
415 | assert(fprog->Base.OutputsWritten & (1 << FRAG_RESULT_COLOR)); |
||
416 | } |
||
417 | |||
418 | |||
419 | |||
420 | static GLboolean |
||
421 | is_texture_instruction(const struct prog_instruction *inst) |
||
422 | { |
||
423 | switch (inst->Opcode) { |
||
424 | case OPCODE_TEX: |
||
425 | case OPCODE_TXB: |
||
426 | case OPCODE_TXD: |
||
427 | case OPCODE_TXL: |
||
428 | case OPCODE_TXP: |
||
429 | case OPCODE_TXP_NV: |
||
430 | return GL_TRUE; |
||
431 | default: |
||
432 | return GL_FALSE; |
||
433 | } |
||
434 | } |
||
435 | |||
436 | |||
437 | /** |
||
438 | * Count the number of texure indirections in the given program. |
||
439 | * The program's NumTexIndirections field will be updated. |
||
440 | * See the GL_ARB_fragment_program spec (issue 24) for details. |
||
441 | * XXX we count texture indirections in texenvprogram.c (maybe use this code |
||
442 | * instead and elsewhere). |
||
443 | */ |
||
444 | void |
||
445 | _mesa_count_texture_indirections(struct gl_program *prog) |
||
446 | { |
||
447 | GLuint indirections = 1; |
||
448 | GLbitfield tempsOutput = 0x0; |
||
449 | GLbitfield aluTemps = 0x0; |
||
450 | GLuint i; |
||
451 | |||
452 | for (i = 0; i < prog->NumInstructions; i++) { |
||
453 | const struct prog_instruction *inst = prog->Instructions + i; |
||
454 | |||
455 | if (is_texture_instruction(inst)) { |
||
456 | if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) && |
||
457 | (tempsOutput & (1 << inst->SrcReg[0].Index))) || |
||
458 | ((inst->Opcode != OPCODE_KIL) && |
||
459 | (inst->DstReg.File == PROGRAM_TEMPORARY) && |
||
460 | (aluTemps & (1 << inst->DstReg.Index)))) |
||
461 | { |
||
462 | indirections++; |
||
463 | tempsOutput = 0x0; |
||
464 | aluTemps = 0x0; |
||
465 | } |
||
466 | } |
||
467 | else { |
||
468 | GLuint j; |
||
469 | for (j = 0; j < 3; j++) { |
||
470 | if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) |
||
471 | aluTemps |= (1 << inst->SrcReg[j].Index); |
||
472 | } |
||
473 | if (inst->DstReg.File == PROGRAM_TEMPORARY) |
||
474 | aluTemps |= (1 << inst->DstReg.Index); |
||
475 | } |
||
476 | |||
477 | if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY)) |
||
478 | tempsOutput |= (1 << inst->DstReg.Index); |
||
479 | } |
||
480 | |||
481 | prog->NumTexIndirections = indirections; |
||
482 | } |
||
483 | |||
484 | |||
485 | /** |
||
486 | * Count number of texture instructions in given program and update the |
||
487 | * program's NumTexInstructions field. |
||
488 | */ |
||
489 | void |
||
490 | _mesa_count_texture_instructions(struct gl_program *prog) |
||
491 | { |
||
492 | GLuint i; |
||
493 | prog->NumTexInstructions = 0; |
||
494 | for (i = 0; i < prog->NumInstructions; i++) { |
||
495 | prog->NumTexInstructions += is_texture_instruction(prog->Instructions + i); |
||
496 | } |
||
497 | } |
||
498 | |||
499 | |||
500 | /** |
||
501 | * Scan/rewrite program to remove reads of custom (output) registers. |
||
502 | * The passed type has to be PROGRAM_OUTPUT. |
||
503 | * On some hardware, trying to read an output register causes trouble. |
||
504 | * So, rewrite the program to use a temporary register in this case. |
||
505 | */ |
||
506 | void |
||
507 | _mesa_remove_output_reads(struct gl_program *prog, gl_register_file type) |
||
508 | { |
||
509 | GLuint i; |
||
510 | GLint outputMap[VARYING_SLOT_MAX]; |
||
511 | GLuint numVaryingReads = 0; |
||
512 | GLboolean usedTemps[MAX_PROGRAM_TEMPS]; |
||
513 | GLuint firstTemp = 0; |
||
514 | |||
515 | _mesa_find_used_registers(prog, PROGRAM_TEMPORARY, |
||
516 | usedTemps, MAX_PROGRAM_TEMPS); |
||
517 | |||
518 | assert(type == PROGRAM_OUTPUT); |
||
519 | |||
520 | for (i = 0; i < VARYING_SLOT_MAX; i++) |
||
521 | outputMap[i] = -1; |
||
522 | |||
523 | /* look for instructions which read from varying vars */ |
||
524 | for (i = 0; i < prog->NumInstructions; i++) { |
||
525 | struct prog_instruction *inst = prog->Instructions + i; |
||
526 | const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); |
||
527 | GLuint j; |
||
528 | for (j = 0; j < numSrc; j++) { |
||
529 | if (inst->SrcReg[j].File == type) { |
||
530 | /* replace the read with a temp reg */ |
||
531 | const GLuint var = inst->SrcReg[j].Index; |
||
532 | if (outputMap[var] == -1) { |
||
533 | numVaryingReads++; |
||
534 | outputMap[var] = _mesa_find_free_register(usedTemps, |
||
535 | MAX_PROGRAM_TEMPS, |
||
536 | firstTemp); |
||
537 | firstTemp = outputMap[var] + 1; |
||
538 | } |
||
539 | inst->SrcReg[j].File = PROGRAM_TEMPORARY; |
||
540 | inst->SrcReg[j].Index = outputMap[var]; |
||
541 | } |
||
542 | } |
||
543 | } |
||
544 | |||
545 | if (numVaryingReads == 0) |
||
546 | return; /* nothing to be done */ |
||
547 | |||
548 | /* look for instructions which write to the varying vars identified above */ |
||
549 | for (i = 0; i < prog->NumInstructions; i++) { |
||
550 | struct prog_instruction *inst = prog->Instructions + i; |
||
551 | if (inst->DstReg.File == type && |
||
552 | outputMap[inst->DstReg.Index] >= 0) { |
||
553 | /* change inst to write to the temp reg, instead of the varying */ |
||
554 | inst->DstReg.File = PROGRAM_TEMPORARY; |
||
555 | inst->DstReg.Index = outputMap[inst->DstReg.Index]; |
||
556 | } |
||
557 | } |
||
558 | |||
559 | /* insert new instructions to copy the temp vars to the varying vars */ |
||
560 | { |
||
561 | struct prog_instruction *inst; |
||
562 | GLint endPos, var; |
||
563 | |||
564 | /* Look for END instruction and insert the new varying writes */ |
||
565 | endPos = -1; |
||
566 | for (i = 0; i < prog->NumInstructions; i++) { |
||
567 | struct prog_instruction *inst = prog->Instructions + i; |
||
568 | if (inst->Opcode == OPCODE_END) { |
||
569 | endPos = i; |
||
570 | _mesa_insert_instructions(prog, i, numVaryingReads); |
||
571 | break; |
||
572 | } |
||
573 | } |
||
574 | |||
575 | assert(endPos >= 0); |
||
576 | |||
577 | /* insert new MOV instructions here */ |
||
578 | inst = prog->Instructions + endPos; |
||
579 | for (var = 0; var < VARYING_SLOT_MAX; var++) { |
||
580 | if (outputMap[var] >= 0) { |
||
581 | /* MOV VAR[var], TEMP[tmp]; */ |
||
582 | inst->Opcode = OPCODE_MOV; |
||
583 | inst->DstReg.File = type; |
||
584 | inst->DstReg.Index = var; |
||
585 | inst->SrcReg[0].File = PROGRAM_TEMPORARY; |
||
586 | inst->SrcReg[0].Index = outputMap[var]; |
||
587 | inst++; |
||
588 | } |
||
589 | } |
||
590 | } |
||
591 | }>>>>>>>><>><>><>>><>><>>><>>><>=>>><>>> |