Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1901 | serge | 1 | /* |
2 | * Mesa 3-D graphics library |
||
3 | * Version: 6.5.3 |
||
4 | * |
||
5 | * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. |
||
6 | * |
||
7 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
8 | * copy of this software and associated documentation files (the "Software"), |
||
9 | * to deal in the Software without restriction, including without limitation |
||
10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
11 | * and/or sell copies of the Software, and to permit persons to whom the |
||
12 | * Software is furnished to do so, subject to the following conditions: |
||
13 | * |
||
14 | * The above copyright notice and this permission notice shall be included |
||
15 | * in all copies or substantial portions of the Software. |
||
16 | * |
||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
18 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
20 | * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
||
21 | * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
||
22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR 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 = VERT_RESULT_HPOS; |
||
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(VERT_RESULT_HPOS); |
||
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 = VERT_RESULT_HPOS; |
||
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(VERT_RESULT_HPOS); |
||
215 | } |
||
216 | |||
217 | |||
218 | void |
||
219 | _mesa_insert_mvp_code(struct gl_context *ctx, struct gl_vertex_program *vprog) |
||
220 | { |
||
221 | if (ctx->mvp_with_dp4) |
||
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 extra instructions onto the given fragment program to implement |
||
234 | * the fog mode specified by fprog->FogOption. |
||
235 | * The fragment.fogcoord input is used to compute the fog blend factor. |
||
236 | * |
||
237 | * XXX with a little work, this function could be adapted to add fog code |
||
238 | * to vertex programs too. |
||
239 | */ |
||
240 | void |
||
241 | _mesa_append_fog_code(struct gl_context *ctx, struct gl_fragment_program *fprog) |
||
242 | { |
||
243 | static const gl_state_index fogPStateOpt[STATE_LENGTH] |
||
244 | = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 }; |
||
245 | static const gl_state_index fogColorState[STATE_LENGTH] |
||
246 | = { STATE_FOG_COLOR, 0, 0, 0, 0}; |
||
247 | struct prog_instruction *newInst, *inst; |
||
248 | const GLuint origLen = fprog->Base.NumInstructions; |
||
249 | const GLuint newLen = origLen + 5; |
||
250 | GLuint i; |
||
251 | GLint fogPRefOpt, fogColorRef; /* state references */ |
||
252 | GLuint colorTemp, fogFactorTemp; /* temporary registerss */ |
||
253 | |||
254 | if (fprog->FogOption == GL_NONE) { |
||
255 | _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program" |
||
256 | " with FogOption == GL_NONE"); |
||
257 | return; |
||
258 | } |
||
259 | |||
260 | /* Alloc storage for new instructions */ |
||
261 | newInst = _mesa_alloc_instructions(newLen); |
||
262 | if (!newInst) { |
||
263 | _mesa_error(ctx, GL_OUT_OF_MEMORY, |
||
264 | "glProgramString(inserting fog_option code)"); |
||
265 | return; |
||
266 | } |
||
267 | |||
268 | /* Copy orig instructions into new instruction buffer */ |
||
269 | _mesa_copy_instructions(newInst, fprog->Base.Instructions, origLen); |
||
270 | |||
271 | /* PARAM fogParamsRefOpt = internal optimized fog params; */ |
||
272 | fogPRefOpt |
||
273 | = _mesa_add_state_reference(fprog->Base.Parameters, fogPStateOpt); |
||
274 | /* PARAM fogColorRef = state.fog.color; */ |
||
275 | fogColorRef |
||
276 | = _mesa_add_state_reference(fprog->Base.Parameters, fogColorState); |
||
277 | |||
278 | /* TEMP colorTemp; */ |
||
279 | colorTemp = fprog->Base.NumTemporaries++; |
||
280 | /* TEMP fogFactorTemp; */ |
||
281 | fogFactorTemp = fprog->Base.NumTemporaries++; |
||
282 | |||
283 | /* Scan program to find where result.color is written */ |
||
284 | inst = newInst; |
||
285 | for (i = 0; i < fprog->Base.NumInstructions; i++) { |
||
286 | if (inst->Opcode == OPCODE_END) |
||
287 | break; |
||
288 | if (inst->DstReg.File == PROGRAM_OUTPUT && |
||
289 | inst->DstReg.Index == FRAG_RESULT_COLOR) { |
||
290 | /* change the instruction to write to colorTemp w/ clamping */ |
||
291 | inst->DstReg.File = PROGRAM_TEMPORARY; |
||
292 | inst->DstReg.Index = colorTemp; |
||
293 | inst->SaturateMode = SATURATE_ZERO_ONE; |
||
294 | /* don't break (may be several writes to result.color) */ |
||
295 | } |
||
296 | inst++; |
||
297 | } |
||
298 | assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */ |
||
299 | |||
300 | _mesa_init_instructions(inst, 5); |
||
301 | |||
302 | /* emit instructions to compute fog blending factor */ |
||
303 | if (fprog->FogOption == GL_LINEAR) { |
||
304 | /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */ |
||
305 | inst->Opcode = OPCODE_MAD; |
||
306 | inst->DstReg.File = PROGRAM_TEMPORARY; |
||
307 | inst->DstReg.Index = fogFactorTemp; |
||
308 | inst->DstReg.WriteMask = WRITEMASK_X; |
||
309 | inst->SrcReg[0].File = PROGRAM_INPUT; |
||
310 | inst->SrcReg[0].Index = FRAG_ATTRIB_FOGC; |
||
311 | inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; |
||
312 | inst->SrcReg[1].File = PROGRAM_STATE_VAR; |
||
313 | inst->SrcReg[1].Index = fogPRefOpt; |
||
314 | inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; |
||
315 | inst->SrcReg[2].File = PROGRAM_STATE_VAR; |
||
316 | inst->SrcReg[2].Index = fogPRefOpt; |
||
317 | inst->SrcReg[2].Swizzle = SWIZZLE_YYYY; |
||
318 | inst->SaturateMode = SATURATE_ZERO_ONE; |
||
319 | inst++; |
||
320 | } |
||
321 | else { |
||
322 | ASSERT(fprog->FogOption == GL_EXP || fprog->FogOption == GL_EXP2); |
||
323 | /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */ |
||
324 | /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */ |
||
325 | /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */ |
||
326 | inst->Opcode = OPCODE_MUL; |
||
327 | inst->DstReg.File = PROGRAM_TEMPORARY; |
||
328 | inst->DstReg.Index = fogFactorTemp; |
||
329 | inst->DstReg.WriteMask = WRITEMASK_X; |
||
330 | inst->SrcReg[0].File = PROGRAM_STATE_VAR; |
||
331 | inst->SrcReg[0].Index = fogPRefOpt; |
||
332 | inst->SrcReg[0].Swizzle |
||
333 | = (fprog->FogOption == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW; |
||
334 | inst->SrcReg[1].File = PROGRAM_INPUT; |
||
335 | inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC; |
||
336 | inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; |
||
337 | inst++; |
||
338 | if (fprog->FogOption == GL_EXP2) { |
||
339 | /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */ |
||
340 | inst->Opcode = OPCODE_MUL; |
||
341 | inst->DstReg.File = PROGRAM_TEMPORARY; |
||
342 | inst->DstReg.Index = fogFactorTemp; |
||
343 | inst->DstReg.WriteMask = WRITEMASK_X; |
||
344 | inst->SrcReg[0].File = PROGRAM_TEMPORARY; |
||
345 | inst->SrcReg[0].Index = fogFactorTemp; |
||
346 | inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; |
||
347 | inst->SrcReg[1].File = PROGRAM_TEMPORARY; |
||
348 | inst->SrcReg[1].Index = fogFactorTemp; |
||
349 | inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; |
||
350 | inst++; |
||
351 | } |
||
352 | /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */ |
||
353 | inst->Opcode = OPCODE_EX2; |
||
354 | inst->DstReg.File = PROGRAM_TEMPORARY; |
||
355 | inst->DstReg.Index = fogFactorTemp; |
||
356 | inst->DstReg.WriteMask = WRITEMASK_X; |
||
357 | inst->SrcReg[0].File = PROGRAM_TEMPORARY; |
||
358 | inst->SrcReg[0].Index = fogFactorTemp; |
||
359 | inst->SrcReg[0].Negate = NEGATE_XYZW; |
||
360 | inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; |
||
361 | inst->SaturateMode = SATURATE_ZERO_ONE; |
||
362 | inst++; |
||
363 | } |
||
364 | /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */ |
||
365 | inst->Opcode = OPCODE_LRP; |
||
366 | inst->DstReg.File = PROGRAM_OUTPUT; |
||
367 | inst->DstReg.Index = FRAG_RESULT_COLOR; |
||
368 | inst->DstReg.WriteMask = WRITEMASK_XYZ; |
||
369 | inst->SrcReg[0].File = PROGRAM_TEMPORARY; |
||
370 | inst->SrcReg[0].Index = fogFactorTemp; |
||
371 | inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; |
||
372 | inst->SrcReg[1].File = PROGRAM_TEMPORARY; |
||
373 | inst->SrcReg[1].Index = colorTemp; |
||
374 | inst->SrcReg[1].Swizzle = SWIZZLE_NOOP; |
||
375 | inst->SrcReg[2].File = PROGRAM_STATE_VAR; |
||
376 | inst->SrcReg[2].Index = fogColorRef; |
||
377 | inst->SrcReg[2].Swizzle = SWIZZLE_NOOP; |
||
378 | inst++; |
||
379 | /* MOV result.color.w, colorTemp.x; # copy alpha */ |
||
380 | inst->Opcode = OPCODE_MOV; |
||
381 | inst->DstReg.File = PROGRAM_OUTPUT; |
||
382 | inst->DstReg.Index = FRAG_RESULT_COLOR; |
||
383 | inst->DstReg.WriteMask = WRITEMASK_W; |
||
384 | inst->SrcReg[0].File = PROGRAM_TEMPORARY; |
||
385 | inst->SrcReg[0].Index = colorTemp; |
||
386 | inst->SrcReg[0].Swizzle = SWIZZLE_NOOP; |
||
387 | inst++; |
||
388 | /* END; */ |
||
389 | inst->Opcode = OPCODE_END; |
||
390 | inst++; |
||
391 | |||
392 | /* free old instructions */ |
||
393 | _mesa_free_instructions(fprog->Base.Instructions, origLen); |
||
394 | |||
395 | /* install new instructions */ |
||
396 | fprog->Base.Instructions = newInst; |
||
397 | fprog->Base.NumInstructions = inst - newInst; |
||
398 | fprog->Base.InputsRead |= FRAG_BIT_FOGC; |
||
399 | /* XXX do this? fprog->FogOption = GL_NONE; */ |
||
400 | } |
||
401 | |||
402 | |||
403 | |||
404 | static GLboolean |
||
405 | is_texture_instruction(const struct prog_instruction *inst) |
||
406 | { |
||
407 | switch (inst->Opcode) { |
||
408 | case OPCODE_TEX: |
||
409 | case OPCODE_TXB: |
||
410 | case OPCODE_TXD: |
||
411 | case OPCODE_TXL: |
||
412 | case OPCODE_TXP: |
||
413 | case OPCODE_TXP_NV: |
||
414 | return GL_TRUE; |
||
415 | default: |
||
416 | return GL_FALSE; |
||
417 | } |
||
418 | } |
||
419 | |||
420 | |||
421 | /** |
||
422 | * Count the number of texure indirections in the given program. |
||
423 | * The program's NumTexIndirections field will be updated. |
||
424 | * See the GL_ARB_fragment_program spec (issue 24) for details. |
||
425 | * XXX we count texture indirections in texenvprogram.c (maybe use this code |
||
426 | * instead and elsewhere). |
||
427 | */ |
||
428 | void |
||
429 | _mesa_count_texture_indirections(struct gl_program *prog) |
||
430 | { |
||
431 | GLuint indirections = 1; |
||
432 | GLbitfield tempsOutput = 0x0; |
||
433 | GLbitfield aluTemps = 0x0; |
||
434 | GLuint i; |
||
435 | |||
436 | for (i = 0; i < prog->NumInstructions; i++) { |
||
437 | const struct prog_instruction *inst = prog->Instructions + i; |
||
438 | |||
439 | if (is_texture_instruction(inst)) { |
||
440 | if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) && |
||
441 | (tempsOutput & (1 << inst->SrcReg[0].Index))) || |
||
442 | ((inst->Opcode != OPCODE_KIL) && |
||
443 | (inst->DstReg.File == PROGRAM_TEMPORARY) && |
||
444 | (aluTemps & (1 << inst->DstReg.Index)))) |
||
445 | { |
||
446 | indirections++; |
||
447 | tempsOutput = 0x0; |
||
448 | aluTemps = 0x0; |
||
449 | } |
||
450 | } |
||
451 | else { |
||
452 | GLuint j; |
||
453 | for (j = 0; j < 3; j++) { |
||
454 | if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) |
||
455 | aluTemps |= (1 << inst->SrcReg[j].Index); |
||
456 | } |
||
457 | if (inst->DstReg.File == PROGRAM_TEMPORARY) |
||
458 | aluTemps |= (1 << inst->DstReg.Index); |
||
459 | } |
||
460 | |||
461 | if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY)) |
||
462 | tempsOutput |= (1 << inst->DstReg.Index); |
||
463 | } |
||
464 | |||
465 | prog->NumTexIndirections = indirections; |
||
466 | } |
||
467 | |||
468 | |||
469 | /** |
||
470 | * Count number of texture instructions in given program and update the |
||
471 | * program's NumTexInstructions field. |
||
472 | */ |
||
473 | void |
||
474 | _mesa_count_texture_instructions(struct gl_program *prog) |
||
475 | { |
||
476 | GLuint i; |
||
477 | prog->NumTexInstructions = 0; |
||
478 | for (i = 0; i < prog->NumInstructions; i++) { |
||
479 | prog->NumTexInstructions += is_texture_instruction(prog->Instructions + i); |
||
480 | } |
||
481 | } |
||
482 | |||
483 | |||
484 | /** |
||
485 | * Scan/rewrite program to remove reads of custom (output) registers. |
||
486 | * The passed type has to be either PROGRAM_OUTPUT or PROGRAM_VARYING |
||
487 | * (for vertex shaders). |
||
488 | * In GLSL shaders, varying vars can be read and written. |
||
489 | * On some hardware, trying to read an output register causes trouble. |
||
490 | * So, rewrite the program to use a temporary register in this case. |
||
491 | */ |
||
492 | void |
||
493 | _mesa_remove_output_reads(struct gl_program *prog, gl_register_file type) |
||
494 | { |
||
495 | GLuint i; |
||
496 | GLint outputMap[VERT_RESULT_MAX]; |
||
497 | GLuint numVaryingReads = 0; |
||
498 | GLboolean usedTemps[MAX_PROGRAM_TEMPS]; |
||
499 | GLuint firstTemp = 0; |
||
500 | |||
501 | _mesa_find_used_registers(prog, PROGRAM_TEMPORARY, |
||
502 | usedTemps, MAX_PROGRAM_TEMPS); |
||
503 | |||
504 | assert(type == PROGRAM_VARYING || type == PROGRAM_OUTPUT); |
||
505 | assert(prog->Target == GL_VERTEX_PROGRAM_ARB || type != PROGRAM_VARYING); |
||
506 | |||
507 | for (i = 0; i < VERT_RESULT_MAX; i++) |
||
508 | outputMap[i] = -1; |
||
509 | |||
510 | /* look for instructions which read from varying vars */ |
||
511 | for (i = 0; i < prog->NumInstructions; i++) { |
||
512 | struct prog_instruction *inst = prog->Instructions + i; |
||
513 | const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); |
||
514 | GLuint j; |
||
515 | for (j = 0; j < numSrc; j++) { |
||
516 | if (inst->SrcReg[j].File == type) { |
||
517 | /* replace the read with a temp reg */ |
||
518 | const GLuint var = inst->SrcReg[j].Index; |
||
519 | if (outputMap[var] == -1) { |
||
520 | numVaryingReads++; |
||
521 | outputMap[var] = _mesa_find_free_register(usedTemps, |
||
522 | MAX_PROGRAM_TEMPS, |
||
523 | firstTemp); |
||
524 | firstTemp = outputMap[var] + 1; |
||
525 | } |
||
526 | inst->SrcReg[j].File = PROGRAM_TEMPORARY; |
||
527 | inst->SrcReg[j].Index = outputMap[var]; |
||
528 | } |
||
529 | } |
||
530 | } |
||
531 | |||
532 | if (numVaryingReads == 0) |
||
533 | return; /* nothing to be done */ |
||
534 | |||
535 | /* look for instructions which write to the varying vars identified above */ |
||
536 | for (i = 0; i < prog->NumInstructions; i++) { |
||
537 | struct prog_instruction *inst = prog->Instructions + i; |
||
538 | if (inst->DstReg.File == type && |
||
539 | outputMap[inst->DstReg.Index] >= 0) { |
||
540 | /* change inst to write to the temp reg, instead of the varying */ |
||
541 | inst->DstReg.File = PROGRAM_TEMPORARY; |
||
542 | inst->DstReg.Index = outputMap[inst->DstReg.Index]; |
||
543 | } |
||
544 | } |
||
545 | |||
546 | /* insert new instructions to copy the temp vars to the varying vars */ |
||
547 | { |
||
548 | struct prog_instruction *inst; |
||
549 | GLint endPos, var; |
||
550 | |||
551 | /* Look for END instruction and insert the new varying writes */ |
||
552 | endPos = -1; |
||
553 | for (i = 0; i < prog->NumInstructions; i++) { |
||
554 | struct prog_instruction *inst = prog->Instructions + i; |
||
555 | if (inst->Opcode == OPCODE_END) { |
||
556 | endPos = i; |
||
557 | _mesa_insert_instructions(prog, i, numVaryingReads); |
||
558 | break; |
||
559 | } |
||
560 | } |
||
561 | |||
562 | assert(endPos >= 0); |
||
563 | |||
564 | /* insert new MOV instructions here */ |
||
565 | inst = prog->Instructions + endPos; |
||
566 | for (var = 0; var < VERT_RESULT_MAX; var++) { |
||
567 | if (outputMap[var] >= 0) { |
||
568 | /* MOV VAR[var], TEMP[tmp]; */ |
||
569 | inst->Opcode = OPCODE_MOV; |
||
570 | inst->DstReg.File = type; |
||
571 | inst->DstReg.Index = var; |
||
572 | inst->SrcReg[0].File = PROGRAM_TEMPORARY; |
||
573 | inst->SrcReg[0].Index = outputMap[var]; |
||
574 | inst++; |
||
575 | } |
||
576 | } |
||
577 | } |
||
578 | } |
||
579 | |||
580 | |||
581 | /** |
||
582 | * Make the given fragment program into a "no-op" shader. |
||
583 | * Actually, just copy the incoming fragment color (or texcoord) |
||
584 | * to the output color. |
||
585 | * This is for debug/test purposes. |
||
586 | */ |
||
587 | void |
||
588 | _mesa_nop_fragment_program(struct gl_context *ctx, struct gl_fragment_program *prog) |
||
589 | { |
||
590 | struct prog_instruction *inst; |
||
591 | GLuint inputAttr; |
||
592 | |||
593 | inst = _mesa_alloc_instructions(2); |
||
594 | if (!inst) { |
||
595 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_fragment_program"); |
||
596 | return; |
||
597 | } |
||
598 | |||
599 | _mesa_init_instructions(inst, 2); |
||
600 | |||
601 | inst[0].Opcode = OPCODE_MOV; |
||
602 | inst[0].DstReg.File = PROGRAM_OUTPUT; |
||
603 | inst[0].DstReg.Index = FRAG_RESULT_COLOR; |
||
604 | inst[0].SrcReg[0].File = PROGRAM_INPUT; |
||
605 | if (prog->Base.InputsRead & FRAG_BIT_COL0) |
||
606 | inputAttr = FRAG_ATTRIB_COL0; |
||
607 | else |
||
608 | inputAttr = FRAG_ATTRIB_TEX0; |
||
609 | inst[0].SrcReg[0].Index = inputAttr; |
||
610 | |||
611 | inst[1].Opcode = OPCODE_END; |
||
612 | |||
613 | _mesa_free_instructions(prog->Base.Instructions, |
||
614 | prog->Base.NumInstructions); |
||
615 | |||
616 | prog->Base.Instructions = inst; |
||
617 | prog->Base.NumInstructions = 2; |
||
618 | prog->Base.InputsRead = 1 << inputAttr; |
||
619 | prog->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR); |
||
620 | } |
||
621 | |||
622 | |||
623 | /** |
||
624 | * \sa _mesa_nop_fragment_program |
||
625 | * Replace the given vertex program with a "no-op" program that just |
||
626 | * transforms vertex position and emits color. |
||
627 | */ |
||
628 | void |
||
629 | _mesa_nop_vertex_program(struct gl_context *ctx, struct gl_vertex_program *prog) |
||
630 | { |
||
631 | struct prog_instruction *inst; |
||
632 | GLuint inputAttr; |
||
633 | |||
634 | /* |
||
635 | * Start with a simple vertex program that emits color. |
||
636 | */ |
||
637 | inst = _mesa_alloc_instructions(2); |
||
638 | if (!inst) { |
||
639 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_vertex_program"); |
||
640 | return; |
||
641 | } |
||
642 | |||
643 | _mesa_init_instructions(inst, 2); |
||
644 | |||
645 | inst[0].Opcode = OPCODE_MOV; |
||
646 | inst[0].DstReg.File = PROGRAM_OUTPUT; |
||
647 | inst[0].DstReg.Index = VERT_RESULT_COL0; |
||
648 | inst[0].SrcReg[0].File = PROGRAM_INPUT; |
||
649 | if (prog->Base.InputsRead & VERT_BIT_COLOR0) |
||
650 | inputAttr = VERT_ATTRIB_COLOR0; |
||
651 | else |
||
652 | inputAttr = VERT_ATTRIB_TEX0; |
||
653 | inst[0].SrcReg[0].Index = inputAttr; |
||
654 | |||
655 | inst[1].Opcode = OPCODE_END; |
||
656 | |||
657 | _mesa_free_instructions(prog->Base.Instructions, |
||
658 | prog->Base.NumInstructions); |
||
659 | |||
660 | prog->Base.Instructions = inst; |
||
661 | prog->Base.NumInstructions = 2; |
||
662 | prog->Base.InputsRead = 1 << inputAttr; |
||
663 | prog->Base.OutputsWritten = BITFIELD64_BIT(VERT_RESULT_COL0); |
||
664 | |||
665 | /* |
||
666 | * Now insert code to do standard modelview/projection transformation. |
||
667 | */ |
||
668 | _mesa_insert_mvp_code(ctx, prog); |
||
669 | }><>><>>>>>>>>><>><>><>>><>><>>>=>>><>>> |