Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1901 | serge | 1 | /************************************************************************** |
2 | * |
||
3 | * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. |
||
4 | * All Rights Reserved. |
||
5 | * Copyright 2009 VMware, Inc. 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 |
||
9 | * "Software"), to deal in the Software without restriction, including |
||
10 | * without limitation the rights to use, copy, modify, merge, publish, |
||
11 | * distribute, sub license, and/or sell copies of the Software, and to |
||
12 | * permit persons to whom the Software is furnished to do so, subject to |
||
13 | * the following conditions: |
||
14 | * |
||
15 | * The above copyright notice and this permission notice (including the |
||
16 | * next paragraph) shall be included in all copies or substantial portions |
||
17 | * of the Software. |
||
18 | * |
||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
20 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
||
22 | * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR |
||
23 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||
24 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||
25 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
26 | * |
||
27 | **************************************************************************/ |
||
28 | |||
29 | #include "glheader.h" |
||
30 | #include "imports.h" |
||
31 | #include "program/program.h" |
||
32 | #include "program/prog_parameter.h" |
||
33 | #include "program/prog_cache.h" |
||
34 | #include "program/prog_instruction.h" |
||
35 | #include "program/prog_print.h" |
||
36 | #include "program/prog_statevars.h" |
||
37 | #include "program/programopt.h" |
||
38 | #include "texenvprogram.h" |
||
39 | |||
40 | |||
41 | /* |
||
42 | * Note on texture units: |
||
43 | * |
||
44 | * The number of texture units supported by fixed-function fragment |
||
45 | * processing is MAX_TEXTURE_COORD_UNITS, not MAX_TEXTURE_IMAGE_UNITS. |
||
46 | * That's because there's a one-to-one correspondence between texture |
||
47 | * coordinates and samplers in fixed-function processing. |
||
48 | * |
||
49 | * Since fixed-function vertex processing is limited to MAX_TEXTURE_COORD_UNITS |
||
50 | * sets of texcoords, so is fixed-function fragment processing. |
||
51 | * |
||
52 | * We can safely use ctx->Const.MaxTextureUnits for loop bounds. |
||
53 | */ |
||
54 | |||
55 | |||
56 | struct texenvprog_cache_item |
||
57 | { |
||
58 | GLuint hash; |
||
59 | void *key; |
||
60 | struct gl_fragment_program *data; |
||
61 | struct texenvprog_cache_item *next; |
||
62 | }; |
||
63 | |||
64 | static GLboolean |
||
65 | texenv_doing_secondary_color(struct gl_context *ctx) |
||
66 | { |
||
67 | if (ctx->Light.Enabled && |
||
68 | (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) |
||
69 | return GL_TRUE; |
||
70 | |||
71 | if (ctx->Fog.ColorSumEnabled) |
||
72 | return GL_TRUE; |
||
73 | |||
74 | return GL_FALSE; |
||
75 | } |
||
76 | |||
77 | /** |
||
78 | * Up to nine instructions per tex unit, plus fog, specular color. |
||
79 | */ |
||
80 | #define MAX_INSTRUCTIONS ((MAX_TEXTURE_COORD_UNITS * 9) + 12) |
||
81 | |||
82 | #define DISASSEM (MESA_VERBOSE & VERBOSE_DISASSEM) |
||
83 | |||
84 | struct mode_opt { |
||
85 | #ifdef __GNUC__ |
||
86 | __extension__ GLubyte Source:4; /**< SRC_x */ |
||
87 | __extension__ GLubyte Operand:3; /**< OPR_x */ |
||
88 | #else |
||
89 | GLubyte Source; /**< SRC_x */ |
||
90 | GLubyte Operand; /**< OPR_x */ |
||
91 | #endif |
||
92 | }; |
||
93 | |||
94 | struct state_key { |
||
95 | GLuint nr_enabled_units:8; |
||
96 | GLuint enabled_units:8; |
||
97 | GLuint separate_specular:1; |
||
98 | GLuint fog_enabled:1; |
||
99 | GLuint fog_mode:2; /**< FOG_x */ |
||
100 | GLuint inputs_available:12; |
||
101 | GLuint num_draw_buffers:4; |
||
102 | |||
103 | /* NOTE: This array of structs must be last! (see "keySize" below) */ |
||
104 | struct { |
||
105 | GLuint enabled:1; |
||
106 | GLuint source_index:3; /**< TEXTURE_x_INDEX */ |
||
107 | GLuint shadow:1; |
||
108 | GLuint ScaleShiftRGB:2; |
||
109 | GLuint ScaleShiftA:2; |
||
110 | |||
111 | GLuint NumArgsRGB:3; /**< up to MAX_COMBINER_TERMS */ |
||
112 | GLuint ModeRGB:5; /**< MODE_x */ |
||
113 | |||
114 | GLuint NumArgsA:3; /**< up to MAX_COMBINER_TERMS */ |
||
115 | GLuint ModeA:5; /**< MODE_x */ |
||
116 | |||
117 | GLuint texture_cyl_wrap:1; /**< For gallium test/debug only */ |
||
118 | |||
119 | struct mode_opt OptRGB[MAX_COMBINER_TERMS]; |
||
120 | struct mode_opt OptA[MAX_COMBINER_TERMS]; |
||
121 | } unit[MAX_TEXTURE_UNITS]; |
||
122 | }; |
||
123 | |||
124 | #define FOG_LINEAR 0 |
||
125 | #define FOG_EXP 1 |
||
126 | #define FOG_EXP2 2 |
||
127 | #define FOG_UNKNOWN 3 |
||
128 | |||
129 | static GLuint translate_fog_mode( GLenum mode ) |
||
130 | { |
||
131 | switch (mode) { |
||
132 | case GL_LINEAR: return FOG_LINEAR; |
||
133 | case GL_EXP: return FOG_EXP; |
||
134 | case GL_EXP2: return FOG_EXP2; |
||
135 | default: return FOG_UNKNOWN; |
||
136 | } |
||
137 | } |
||
138 | |||
139 | #define OPR_SRC_COLOR 0 |
||
140 | #define OPR_ONE_MINUS_SRC_COLOR 1 |
||
141 | #define OPR_SRC_ALPHA 2 |
||
142 | #define OPR_ONE_MINUS_SRC_ALPHA 3 |
||
143 | #define OPR_ZERO 4 |
||
144 | #define OPR_ONE 5 |
||
145 | #define OPR_UNKNOWN 7 |
||
146 | |||
147 | static GLuint translate_operand( GLenum operand ) |
||
148 | { |
||
149 | switch (operand) { |
||
150 | case GL_SRC_COLOR: return OPR_SRC_COLOR; |
||
151 | case GL_ONE_MINUS_SRC_COLOR: return OPR_ONE_MINUS_SRC_COLOR; |
||
152 | case GL_SRC_ALPHA: return OPR_SRC_ALPHA; |
||
153 | case GL_ONE_MINUS_SRC_ALPHA: return OPR_ONE_MINUS_SRC_ALPHA; |
||
154 | case GL_ZERO: return OPR_ZERO; |
||
155 | case GL_ONE: return OPR_ONE; |
||
156 | default: |
||
157 | assert(0); |
||
158 | return OPR_UNKNOWN; |
||
159 | } |
||
160 | } |
||
161 | |||
162 | #define SRC_TEXTURE 0 |
||
163 | #define SRC_TEXTURE0 1 |
||
164 | #define SRC_TEXTURE1 2 |
||
165 | #define SRC_TEXTURE2 3 |
||
166 | #define SRC_TEXTURE3 4 |
||
167 | #define SRC_TEXTURE4 5 |
||
168 | #define SRC_TEXTURE5 6 |
||
169 | #define SRC_TEXTURE6 7 |
||
170 | #define SRC_TEXTURE7 8 |
||
171 | #define SRC_CONSTANT 9 |
||
172 | #define SRC_PRIMARY_COLOR 10 |
||
173 | #define SRC_PREVIOUS 11 |
||
174 | #define SRC_ZERO 12 |
||
175 | #define SRC_UNKNOWN 15 |
||
176 | |||
177 | static GLuint translate_source( GLenum src ) |
||
178 | { |
||
179 | switch (src) { |
||
180 | case GL_TEXTURE: return SRC_TEXTURE; |
||
181 | case GL_TEXTURE0: |
||
182 | case GL_TEXTURE1: |
||
183 | case GL_TEXTURE2: |
||
184 | case GL_TEXTURE3: |
||
185 | case GL_TEXTURE4: |
||
186 | case GL_TEXTURE5: |
||
187 | case GL_TEXTURE6: |
||
188 | case GL_TEXTURE7: return SRC_TEXTURE0 + (src - GL_TEXTURE0); |
||
189 | case GL_CONSTANT: return SRC_CONSTANT; |
||
190 | case GL_PRIMARY_COLOR: return SRC_PRIMARY_COLOR; |
||
191 | case GL_PREVIOUS: return SRC_PREVIOUS; |
||
192 | case GL_ZERO: |
||
193 | return SRC_ZERO; |
||
194 | default: |
||
195 | assert(0); |
||
196 | return SRC_UNKNOWN; |
||
197 | } |
||
198 | } |
||
199 | |||
200 | #define MODE_REPLACE 0 /* r = a0 */ |
||
201 | #define MODE_MODULATE 1 /* r = a0 * a1 */ |
||
202 | #define MODE_ADD 2 /* r = a0 + a1 */ |
||
203 | #define MODE_ADD_SIGNED 3 /* r = a0 + a1 - 0.5 */ |
||
204 | #define MODE_INTERPOLATE 4 /* r = a0 * a2 + a1 * (1 - a2) */ |
||
205 | #define MODE_SUBTRACT 5 /* r = a0 - a1 */ |
||
206 | #define MODE_DOT3_RGB 6 /* r = a0 . a1 */ |
||
207 | #define MODE_DOT3_RGB_EXT 7 /* r = a0 . a1 */ |
||
208 | #define MODE_DOT3_RGBA 8 /* r = a0 . a1 */ |
||
209 | #define MODE_DOT3_RGBA_EXT 9 /* r = a0 . a1 */ |
||
210 | #define MODE_MODULATE_ADD_ATI 10 /* r = a0 * a2 + a1 */ |
||
211 | #define MODE_MODULATE_SIGNED_ADD_ATI 11 /* r = a0 * a2 + a1 - 0.5 */ |
||
212 | #define MODE_MODULATE_SUBTRACT_ATI 12 /* r = a0 * a2 - a1 */ |
||
213 | #define MODE_ADD_PRODUCTS 13 /* r = a0 * a1 + a2 * a3 */ |
||
214 | #define MODE_ADD_PRODUCTS_SIGNED 14 /* r = a0 * a1 + a2 * a3 - 0.5 */ |
||
215 | #define MODE_BUMP_ENVMAP_ATI 15 /* special */ |
||
216 | #define MODE_UNKNOWN 16 |
||
217 | |||
218 | /** |
||
219 | * Translate GL combiner state into a MODE_x value |
||
220 | */ |
||
221 | static GLuint translate_mode( GLenum envMode, GLenum mode ) |
||
222 | { |
||
223 | switch (mode) { |
||
224 | case GL_REPLACE: return MODE_REPLACE; |
||
225 | case GL_MODULATE: return MODE_MODULATE; |
||
226 | case GL_ADD: |
||
227 | if (envMode == GL_COMBINE4_NV) |
||
228 | return MODE_ADD_PRODUCTS; |
||
229 | else |
||
230 | return MODE_ADD; |
||
231 | case GL_ADD_SIGNED: |
||
232 | if (envMode == GL_COMBINE4_NV) |
||
233 | return MODE_ADD_PRODUCTS_SIGNED; |
||
234 | else |
||
235 | return MODE_ADD_SIGNED; |
||
236 | case GL_INTERPOLATE: return MODE_INTERPOLATE; |
||
237 | case GL_SUBTRACT: return MODE_SUBTRACT; |
||
238 | case GL_DOT3_RGB: return MODE_DOT3_RGB; |
||
239 | case GL_DOT3_RGB_EXT: return MODE_DOT3_RGB_EXT; |
||
240 | case GL_DOT3_RGBA: return MODE_DOT3_RGBA; |
||
241 | case GL_DOT3_RGBA_EXT: return MODE_DOT3_RGBA_EXT; |
||
242 | case GL_MODULATE_ADD_ATI: return MODE_MODULATE_ADD_ATI; |
||
243 | case GL_MODULATE_SIGNED_ADD_ATI: return MODE_MODULATE_SIGNED_ADD_ATI; |
||
244 | case GL_MODULATE_SUBTRACT_ATI: return MODE_MODULATE_SUBTRACT_ATI; |
||
245 | case GL_BUMP_ENVMAP_ATI: return MODE_BUMP_ENVMAP_ATI; |
||
246 | default: |
||
247 | assert(0); |
||
248 | return MODE_UNKNOWN; |
||
249 | } |
||
250 | } |
||
251 | |||
252 | |||
253 | /** |
||
254 | * Do we need to clamp the results of the given texture env/combine mode? |
||
255 | * If the inputs to the mode are in [0,1] we don't always have to clamp |
||
256 | * the results. |
||
257 | */ |
||
258 | static GLboolean |
||
259 | need_saturate( GLuint mode ) |
||
260 | { |
||
261 | switch (mode) { |
||
262 | case MODE_REPLACE: |
||
263 | case MODE_MODULATE: |
||
264 | case MODE_INTERPOLATE: |
||
265 | return GL_FALSE; |
||
266 | case MODE_ADD: |
||
267 | case MODE_ADD_SIGNED: |
||
268 | case MODE_SUBTRACT: |
||
269 | case MODE_DOT3_RGB: |
||
270 | case MODE_DOT3_RGB_EXT: |
||
271 | case MODE_DOT3_RGBA: |
||
272 | case MODE_DOT3_RGBA_EXT: |
||
273 | case MODE_MODULATE_ADD_ATI: |
||
274 | case MODE_MODULATE_SIGNED_ADD_ATI: |
||
275 | case MODE_MODULATE_SUBTRACT_ATI: |
||
276 | case MODE_ADD_PRODUCTS: |
||
277 | case MODE_ADD_PRODUCTS_SIGNED: |
||
278 | case MODE_BUMP_ENVMAP_ATI: |
||
279 | return GL_TRUE; |
||
280 | default: |
||
281 | assert(0); |
||
282 | return GL_FALSE; |
||
283 | } |
||
284 | } |
||
285 | |||
286 | |||
287 | |||
288 | /** |
||
289 | * Translate TEXTURE_x_BIT to TEXTURE_x_INDEX. |
||
290 | */ |
||
291 | static GLuint translate_tex_src_bit( GLbitfield bit ) |
||
292 | { |
||
293 | ASSERT(bit); |
||
294 | return _mesa_ffs(bit) - 1; |
||
295 | } |
||
296 | |||
297 | |||
298 | #define VERT_BIT_TEX_ANY (0xff << VERT_ATTRIB_TEX0) |
||
299 | #define VERT_RESULT_TEX_ANY (0xff << VERT_RESULT_TEX0) |
||
300 | |||
301 | /** |
||
302 | * Identify all possible varying inputs. The fragment program will |
||
303 | * never reference non-varying inputs, but will track them via state |
||
304 | * constants instead. |
||
305 | * |
||
306 | * This function figures out all the inputs that the fragment program |
||
307 | * has access to. The bitmask is later reduced to just those which |
||
308 | * are actually referenced. |
||
309 | */ |
||
310 | static GLbitfield get_fp_input_mask( struct gl_context *ctx ) |
||
311 | { |
||
312 | /* _NEW_PROGRAM */ |
||
313 | const GLboolean vertexShader = |
||
314 | (ctx->Shader.CurrentVertexProgram && |
||
315 | ctx->Shader.CurrentVertexProgram->LinkStatus && |
||
316 | ctx->Shader.CurrentVertexProgram->VertexProgram); |
||
317 | const GLboolean vertexProgram = ctx->VertexProgram._Enabled; |
||
318 | GLbitfield fp_inputs = 0x0; |
||
319 | |||
320 | if (ctx->VertexProgram._Overriden) { |
||
321 | /* Somebody's messing with the vertex program and we don't have |
||
322 | * a clue what's happening. Assume that it could be producing |
||
323 | * all possible outputs. |
||
324 | */ |
||
325 | fp_inputs = ~0; |
||
326 | } |
||
327 | else if (ctx->RenderMode == GL_FEEDBACK) { |
||
328 | /* _NEW_RENDERMODE */ |
||
329 | fp_inputs = (FRAG_BIT_COL0 | FRAG_BIT_TEX0); |
||
330 | } |
||
331 | else if (!(vertexProgram || vertexShader) || |
||
332 | !ctx->VertexProgram._Current) { |
||
333 | /* Fixed function vertex logic */ |
||
334 | /* _NEW_ARRAY */ |
||
335 | GLbitfield varying_inputs = ctx->varying_vp_inputs; |
||
336 | |||
337 | /* These get generated in the setup routine regardless of the |
||
338 | * vertex program: |
||
339 | */ |
||
340 | /* _NEW_POINT */ |
||
341 | if (ctx->Point.PointSprite) |
||
342 | varying_inputs |= FRAG_BITS_TEX_ANY; |
||
343 | |||
344 | /* First look at what values may be computed by the generated |
||
345 | * vertex program: |
||
346 | */ |
||
347 | /* _NEW_LIGHT */ |
||
348 | if (ctx->Light.Enabled) { |
||
349 | fp_inputs |= FRAG_BIT_COL0; |
||
350 | |||
351 | if (texenv_doing_secondary_color(ctx)) |
||
352 | fp_inputs |= FRAG_BIT_COL1; |
||
353 | } |
||
354 | |||
355 | /* _NEW_TEXTURE */ |
||
356 | fp_inputs |= (ctx->Texture._TexGenEnabled | |
||
357 | ctx->Texture._TexMatEnabled) << FRAG_ATTRIB_TEX0; |
||
358 | |||
359 | /* Then look at what might be varying as a result of enabled |
||
360 | * arrays, etc: |
||
361 | */ |
||
362 | if (varying_inputs & VERT_BIT_COLOR0) |
||
363 | fp_inputs |= FRAG_BIT_COL0; |
||
364 | if (varying_inputs & VERT_BIT_COLOR1) |
||
365 | fp_inputs |= FRAG_BIT_COL1; |
||
366 | |||
367 | fp_inputs |= (((varying_inputs & VERT_BIT_TEX_ANY) >> VERT_ATTRIB_TEX0) |
||
368 | << FRAG_ATTRIB_TEX0); |
||
369 | |||
370 | } |
||
371 | else { |
||
372 | /* calculate from vp->outputs */ |
||
373 | struct gl_vertex_program *vprog; |
||
374 | GLbitfield64 vp_outputs; |
||
375 | |||
376 | /* Choose GLSL vertex shader over ARB vertex program. Need this |
||
377 | * since vertex shader state validation comes after fragment state |
||
378 | * validation (see additional comments in state.c). |
||
379 | */ |
||
380 | if (vertexShader) |
||
381 | vprog = ctx->Shader.CurrentVertexProgram->VertexProgram; |
||
382 | else |
||
383 | vprog = ctx->VertexProgram.Current; |
||
384 | |||
385 | vp_outputs = vprog->Base.OutputsWritten; |
||
386 | |||
387 | /* These get generated in the setup routine regardless of the |
||
388 | * vertex program: |
||
389 | */ |
||
390 | /* _NEW_POINT */ |
||
391 | if (ctx->Point.PointSprite) |
||
392 | vp_outputs |= FRAG_BITS_TEX_ANY; |
||
393 | |||
394 | if (vp_outputs & (1 << VERT_RESULT_COL0)) |
||
395 | fp_inputs |= FRAG_BIT_COL0; |
||
396 | if (vp_outputs & (1 << VERT_RESULT_COL1)) |
||
397 | fp_inputs |= FRAG_BIT_COL1; |
||
398 | |||
399 | fp_inputs |= (((vp_outputs & VERT_RESULT_TEX_ANY) >> VERT_RESULT_TEX0) |
||
400 | << FRAG_ATTRIB_TEX0); |
||
401 | } |
||
402 | |||
403 | return fp_inputs; |
||
404 | } |
||
405 | |||
406 | |||
407 | /** |
||
408 | * Examine current texture environment state and generate a unique |
||
409 | * key to identify it. |
||
410 | */ |
||
411 | static GLuint make_state_key( struct gl_context *ctx, struct state_key *key ) |
||
412 | { |
||
413 | GLuint i, j; |
||
414 | GLbitfield inputs_referenced = FRAG_BIT_COL0; |
||
415 | const GLbitfield inputs_available = get_fp_input_mask( ctx ); |
||
416 | GLuint keySize; |
||
417 | |||
418 | memset(key, 0, sizeof(*key)); |
||
419 | |||
420 | /* _NEW_TEXTURE */ |
||
421 | for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { |
||
422 | const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; |
||
423 | const struct gl_texture_object *texObj = texUnit->_Current; |
||
424 | const struct gl_tex_env_combine_state *comb = texUnit->_CurrentCombine; |
||
425 | GLenum format; |
||
426 | |||
427 | if (!texUnit->_ReallyEnabled || !texUnit->Enabled) |
||
428 | continue; |
||
429 | |||
430 | format = texObj->Image[0][texObj->BaseLevel]->_BaseFormat; |
||
431 | |||
432 | key->unit[i].enabled = 1; |
||
433 | key->enabled_units |= (1< |
||
434 | key->nr_enabled_units = i + 1; |
||
435 | inputs_referenced |= FRAG_BIT_TEX(i); |
||
436 | |||
437 | key->unit[i].source_index = |
||
438 | translate_tex_src_bit(texUnit->_ReallyEnabled); |
||
439 | |||
440 | key->unit[i].shadow = ((texObj->CompareMode == GL_COMPARE_R_TO_TEXTURE) && |
||
441 | ((format == GL_DEPTH_COMPONENT) || |
||
442 | (format == GL_DEPTH_STENCIL_EXT))); |
||
443 | |||
444 | key->unit[i].NumArgsRGB = comb->_NumArgsRGB; |
||
445 | key->unit[i].NumArgsA = comb->_NumArgsA; |
||
446 | |||
447 | key->unit[i].ModeRGB = |
||
448 | translate_mode(texUnit->EnvMode, comb->ModeRGB); |
||
449 | key->unit[i].ModeA = |
||
450 | translate_mode(texUnit->EnvMode, comb->ModeA); |
||
451 | |||
452 | key->unit[i].ScaleShiftRGB = comb->ScaleShiftRGB; |
||
453 | key->unit[i].ScaleShiftA = comb->ScaleShiftA; |
||
454 | |||
455 | for (j = 0; j < MAX_COMBINER_TERMS; j++) { |
||
456 | key->unit[i].OptRGB[j].Operand = translate_operand(comb->OperandRGB[j]); |
||
457 | key->unit[i].OptA[j].Operand = translate_operand(comb->OperandA[j]); |
||
458 | key->unit[i].OptRGB[j].Source = translate_source(comb->SourceRGB[j]); |
||
459 | key->unit[i].OptA[j].Source = translate_source(comb->SourceA[j]); |
||
460 | } |
||
461 | |||
462 | if (key->unit[i].ModeRGB == MODE_BUMP_ENVMAP_ATI) { |
||
463 | /* requires some special translation */ |
||
464 | key->unit[i].NumArgsRGB = 2; |
||
465 | key->unit[i].ScaleShiftRGB = 0; |
||
466 | key->unit[i].OptRGB[0].Operand = OPR_SRC_COLOR; |
||
467 | key->unit[i].OptRGB[0].Source = SRC_TEXTURE; |
||
468 | key->unit[i].OptRGB[1].Operand = OPR_SRC_COLOR; |
||
469 | key->unit[i].OptRGB[1].Source = texUnit->BumpTarget - GL_TEXTURE0 + SRC_TEXTURE0; |
||
470 | } |
||
471 | |||
472 | /* this is a back-door for enabling cylindrical texture wrap mode */ |
||
473 | if (texObj->Priority == 0.125) |
||
474 | key->unit[i].texture_cyl_wrap = 1; |
||
475 | } |
||
476 | |||
477 | /* _NEW_LIGHT | _NEW_FOG */ |
||
478 | if (texenv_doing_secondary_color(ctx)) { |
||
479 | key->separate_specular = 1; |
||
480 | inputs_referenced |= FRAG_BIT_COL1; |
||
481 | } |
||
482 | |||
483 | /* _NEW_FOG */ |
||
484 | if (ctx->Fog.Enabled) { |
||
485 | key->fog_enabled = 1; |
||
486 | key->fog_mode = translate_fog_mode(ctx->Fog.Mode); |
||
487 | inputs_referenced |= FRAG_BIT_FOGC; /* maybe */ |
||
488 | } |
||
489 | |||
490 | /* _NEW_BUFFERS */ |
||
491 | key->num_draw_buffers = ctx->DrawBuffer->_NumColorDrawBuffers; |
||
492 | |||
493 | key->inputs_available = (inputs_available & inputs_referenced); |
||
494 | |||
495 | /* compute size of state key, ignoring unused texture units */ |
||
496 | keySize = sizeof(*key) - sizeof(key->unit) |
||
497 | + key->nr_enabled_units * sizeof(key->unit[0]); |
||
498 | |||
499 | return keySize; |
||
500 | } |
||
501 | |||
502 | |||
503 | /** |
||
504 | * Use uregs to represent registers internally, translate to Mesa's |
||
505 | * expected formats on emit. |
||
506 | * |
||
507 | * NOTE: These are passed by value extensively in this file rather |
||
508 | * than as usual by pointer reference. If this disturbs you, try |
||
509 | * remembering they are just 32bits in size. |
||
510 | * |
||
511 | * GCC is smart enough to deal with these dword-sized structures in |
||
512 | * much the same way as if I had defined them as dwords and was using |
||
513 | * macros to access and set the fields. This is much nicer and easier |
||
514 | * to evolve. |
||
515 | */ |
||
516 | struct ureg { |
||
517 | GLuint file:4; |
||
518 | GLuint idx:8; |
||
519 | GLuint negatebase:1; |
||
520 | GLuint swz:12; |
||
521 | GLuint pad:7; |
||
522 | }; |
||
523 | |||
524 | static const struct ureg undef = { |
||
525 | PROGRAM_UNDEFINED, |
||
526 | ~0, |
||
527 | 0, |
||
528 | 0, |
||
529 | |||
530 | }; |
||
531 | |||
532 | |||
533 | /** State used to build the fragment program: |
||
534 | */ |
||
535 | struct texenv_fragment_program { |
||
536 | struct gl_fragment_program *program; |
||
537 | struct state_key *state; |
||
538 | |||
539 | GLbitfield alu_temps; /**< Track texture indirections, see spec. */ |
||
540 | GLbitfield temps_output; /**< Track texture indirections, see spec. */ |
||
541 | GLbitfield temp_in_use; /**< Tracks temporary regs which are in use. */ |
||
542 | GLboolean error; |
||
543 | |||
544 | struct ureg src_texture[MAX_TEXTURE_COORD_UNITS]; |
||
545 | /* Reg containing each texture unit's sampled texture color, |
||
546 | * else undef. |
||
547 | */ |
||
548 | |||
549 | struct ureg texcoord_tex[MAX_TEXTURE_COORD_UNITS]; |
||
550 | /* Reg containing texcoord for a texture unit, |
||
551 | * needed for bump mapping, else undef. |
||
552 | */ |
||
553 | |||
554 | struct ureg src_previous; /**< Reg containing color from previous |
||
555 | * stage. May need to be decl'd. |
||
556 | */ |
||
557 | |||
558 | GLuint last_tex_stage; /**< Number of last enabled texture unit */ |
||
559 | |||
560 | struct ureg half; |
||
561 | struct ureg one; |
||
562 | struct ureg zero; |
||
563 | }; |
||
564 | |||
565 | |||
566 | |||
567 | static struct ureg make_ureg(GLuint file, GLuint idx) |
||
568 | { |
||
569 | struct ureg reg; |
||
570 | reg.file = file; |
||
571 | reg.idx = idx; |
||
572 | reg.negatebase = 0; |
||
573 | reg.swz = SWIZZLE_NOOP; |
||
574 | reg.pad = 0; |
||
575 | return reg; |
||
576 | } |
||
577 | |||
578 | static struct ureg swizzle( struct ureg reg, int x, int y, int z, int w ) |
||
579 | { |
||
580 | reg.swz = MAKE_SWIZZLE4(GET_SWZ(reg.swz, x), |
||
581 | GET_SWZ(reg.swz, y), |
||
582 | GET_SWZ(reg.swz, z), |
||
583 | GET_SWZ(reg.swz, w)); |
||
584 | |||
585 | return reg; |
||
586 | } |
||
587 | |||
588 | static struct ureg swizzle1( struct ureg reg, int x ) |
||
589 | { |
||
590 | return swizzle(reg, x, x, x, x); |
||
591 | } |
||
592 | |||
593 | static struct ureg negate( struct ureg reg ) |
||
594 | { |
||
595 | reg.negatebase ^= 1; |
||
596 | return reg; |
||
597 | } |
||
598 | |||
599 | static GLboolean is_undef( struct ureg reg ) |
||
600 | { |
||
601 | return reg.file == PROGRAM_UNDEFINED; |
||
602 | } |
||
603 | |||
604 | |||
605 | static struct ureg get_temp( struct texenv_fragment_program *p ) |
||
606 | { |
||
607 | GLint bit; |
||
608 | |||
609 | /* First try and reuse temps which have been used already: |
||
610 | */ |
||
611 | bit = _mesa_ffs( ~p->temp_in_use & p->alu_temps ); |
||
612 | |||
613 | /* Then any unused temporary: |
||
614 | */ |
||
615 | if (!bit) |
||
616 | bit = _mesa_ffs( ~p->temp_in_use ); |
||
617 | |||
618 | if (!bit) { |
||
619 | _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__); |
||
620 | exit(1); |
||
621 | } |
||
622 | |||
623 | if ((GLuint) bit > p->program->Base.NumTemporaries) |
||
624 | p->program->Base.NumTemporaries = bit; |
||
625 | |||
626 | p->temp_in_use |= 1<<(bit-1); |
||
627 | return make_ureg(PROGRAM_TEMPORARY, (bit-1)); |
||
628 | } |
||
629 | |||
630 | static struct ureg get_tex_temp( struct texenv_fragment_program *p ) |
||
631 | { |
||
632 | int bit; |
||
633 | |||
634 | /* First try to find available temp not previously used (to avoid |
||
635 | * starting a new texture indirection). According to the spec, the |
||
636 | * ~p->temps_output isn't necessary, but will keep it there for |
||
637 | * now: |
||
638 | */ |
||
639 | bit = _mesa_ffs( ~p->temp_in_use & ~p->alu_temps & ~p->temps_output ); |
||
640 | |||
641 | /* Then any unused temporary: |
||
642 | */ |
||
643 | if (!bit) |
||
644 | bit = _mesa_ffs( ~p->temp_in_use ); |
||
645 | |||
646 | if (!bit) { |
||
647 | _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__); |
||
648 | exit(1); |
||
649 | } |
||
650 | |||
651 | if ((GLuint) bit > p->program->Base.NumTemporaries) |
||
652 | p->program->Base.NumTemporaries = bit; |
||
653 | |||
654 | p->temp_in_use |= 1<<(bit-1); |
||
655 | return make_ureg(PROGRAM_TEMPORARY, (bit-1)); |
||
656 | } |
||
657 | |||
658 | |||
659 | /** Mark a temp reg as being no longer allocatable. */ |
||
660 | static void reserve_temp( struct texenv_fragment_program *p, struct ureg r ) |
||
661 | { |
||
662 | if (r.file == PROGRAM_TEMPORARY) |
||
663 | p->temps_output |= (1 << r.idx); |
||
664 | } |
||
665 | |||
666 | |||
667 | static void release_temps(struct gl_context *ctx, struct texenv_fragment_program *p ) |
||
668 | { |
||
669 | GLuint max_temp = ctx->Const.FragmentProgram.MaxTemps; |
||
670 | |||
671 | /* KW: To support tex_env_crossbar, don't release the registers in |
||
672 | * temps_output. |
||
673 | */ |
||
674 | if (max_temp >= sizeof(int) * 8) |
||
675 | p->temp_in_use = p->temps_output; |
||
676 | else |
||
677 | p->temp_in_use = ~((1< |
||
678 | } |
||
679 | |||
680 | |||
681 | static struct ureg register_param5( struct texenv_fragment_program *p, |
||
682 | GLint s0, |
||
683 | GLint s1, |
||
684 | GLint s2, |
||
685 | GLint s3, |
||
686 | GLint s4) |
||
687 | { |
||
688 | gl_state_index tokens[STATE_LENGTH]; |
||
689 | GLuint idx; |
||
690 | tokens[0] = s0; |
||
691 | tokens[1] = s1; |
||
692 | tokens[2] = s2; |
||
693 | tokens[3] = s3; |
||
694 | tokens[4] = s4; |
||
695 | idx = _mesa_add_state_reference( p->program->Base.Parameters, tokens ); |
||
696 | return make_ureg(PROGRAM_STATE_VAR, idx); |
||
697 | } |
||
698 | |||
699 | |||
700 | #define register_param1(p,s0) register_param5(p,s0,0,0,0,0) |
||
701 | #define register_param2(p,s0,s1) register_param5(p,s0,s1,0,0,0) |
||
702 | #define register_param3(p,s0,s1,s2) register_param5(p,s0,s1,s2,0,0) |
||
703 | #define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0) |
||
704 | |||
705 | static GLuint frag_to_vert_attrib( GLuint attrib ) |
||
706 | { |
||
707 | switch (attrib) { |
||
708 | case FRAG_ATTRIB_COL0: return VERT_ATTRIB_COLOR0; |
||
709 | case FRAG_ATTRIB_COL1: return VERT_ATTRIB_COLOR1; |
||
710 | default: |
||
711 | assert(attrib >= FRAG_ATTRIB_TEX0); |
||
712 | assert(attrib <= FRAG_ATTRIB_TEX7); |
||
713 | return attrib - FRAG_ATTRIB_TEX0 + VERT_ATTRIB_TEX0; |
||
714 | } |
||
715 | } |
||
716 | |||
717 | |||
718 | static struct ureg register_input( struct texenv_fragment_program *p, GLuint input ) |
||
719 | { |
||
720 | if (p->state->inputs_available & (1< |
||
721 | p->program->Base.InputsRead |= (1 << input); |
||
722 | return make_ureg(PROGRAM_INPUT, input); |
||
723 | } |
||
724 | else { |
||
725 | GLuint idx = frag_to_vert_attrib( input ); |
||
726 | return register_param3( p, STATE_INTERNAL, STATE_CURRENT_ATTRIB, idx ); |
||
727 | } |
||
728 | } |
||
729 | |||
730 | |||
731 | static void emit_arg( struct prog_src_register *reg, |
||
732 | struct ureg ureg ) |
||
733 | { |
||
734 | reg->File = ureg.file; |
||
735 | reg->Index = ureg.idx; |
||
736 | reg->Swizzle = ureg.swz; |
||
737 | reg->Negate = ureg.negatebase ? NEGATE_XYZW : NEGATE_NONE; |
||
738 | reg->Abs = GL_FALSE; |
||
739 | } |
||
740 | |||
741 | static void emit_dst( struct prog_dst_register *dst, |
||
742 | struct ureg ureg, GLuint mask ) |
||
743 | { |
||
744 | dst->File = ureg.file; |
||
745 | dst->Index = ureg.idx; |
||
746 | dst->WriteMask = mask; |
||
747 | dst->CondMask = COND_TR; /* always pass cond test */ |
||
748 | dst->CondSwizzle = SWIZZLE_NOOP; |
||
749 | } |
||
750 | |||
751 | static struct prog_instruction * |
||
752 | emit_op(struct texenv_fragment_program *p, |
||
753 | enum prog_opcode op, |
||
754 | struct ureg dest, |
||
755 | GLuint mask, |
||
756 | GLboolean saturate, |
||
757 | struct ureg src0, |
||
758 | struct ureg src1, |
||
759 | struct ureg src2 ) |
||
760 | { |
||
761 | const GLuint nr = p->program->Base.NumInstructions++; |
||
762 | struct prog_instruction *inst = &p->program->Base.Instructions[nr]; |
||
763 | |||
764 | assert(nr < MAX_INSTRUCTIONS); |
||
765 | |||
766 | _mesa_init_instructions(inst, 1); |
||
767 | inst->Opcode = op; |
||
768 | |||
769 | emit_arg( &inst->SrcReg[0], src0 ); |
||
770 | emit_arg( &inst->SrcReg[1], src1 ); |
||
771 | emit_arg( &inst->SrcReg[2], src2 ); |
||
772 | |||
773 | inst->SaturateMode = saturate ? SATURATE_ZERO_ONE : SATURATE_OFF; |
||
774 | |||
775 | emit_dst( &inst->DstReg, dest, mask ); |
||
776 | |||
777 | #if 0 |
||
778 | /* Accounting for indirection tracking: |
||
779 | */ |
||
780 | if (dest.file == PROGRAM_TEMPORARY) |
||
781 | p->temps_output |= 1 << dest.idx; |
||
782 | #endif |
||
783 | |||
784 | return inst; |
||
785 | } |
||
786 | |||
787 | |||
788 | static struct ureg emit_arith( struct texenv_fragment_program *p, |
||
789 | enum prog_opcode op, |
||
790 | struct ureg dest, |
||
791 | GLuint mask, |
||
792 | GLboolean saturate, |
||
793 | struct ureg src0, |
||
794 | struct ureg src1, |
||
795 | struct ureg src2 ) |
||
796 | { |
||
797 | emit_op(p, op, dest, mask, saturate, src0, src1, src2); |
||
798 | |||
799 | /* Accounting for indirection tracking: |
||
800 | */ |
||
801 | if (src0.file == PROGRAM_TEMPORARY) |
||
802 | p->alu_temps |= 1 << src0.idx; |
||
803 | |||
804 | if (!is_undef(src1) && src1.file == PROGRAM_TEMPORARY) |
||
805 | p->alu_temps |= 1 << src1.idx; |
||
806 | |||
807 | if (!is_undef(src2) && src2.file == PROGRAM_TEMPORARY) |
||
808 | p->alu_temps |= 1 << src2.idx; |
||
809 | |||
810 | if (dest.file == PROGRAM_TEMPORARY) |
||
811 | p->alu_temps |= 1 << dest.idx; |
||
812 | |||
813 | p->program->Base.NumAluInstructions++; |
||
814 | return dest; |
||
815 | } |
||
816 | |||
817 | static struct ureg emit_texld( struct texenv_fragment_program *p, |
||
818 | enum prog_opcode op, |
||
819 | struct ureg dest, |
||
820 | GLuint destmask, |
||
821 | GLuint tex_unit, |
||
822 | GLuint tex_idx, |
||
823 | GLuint tex_shadow, |
||
824 | struct ureg coord ) |
||
825 | { |
||
826 | struct prog_instruction *inst = emit_op( p, op, |
||
827 | dest, destmask, |
||
828 | GL_FALSE, /* don't saturate? */ |
||
829 | coord, /* arg 0? */ |
||
830 | undef, |
||
831 | undef); |
||
832 | |||
833 | inst->TexSrcTarget = tex_idx; |
||
834 | inst->TexSrcUnit = tex_unit; |
||
835 | inst->TexShadow = tex_shadow; |
||
836 | |||
837 | p->program->Base.NumTexInstructions++; |
||
838 | |||
839 | /* Accounting for indirection tracking: |
||
840 | */ |
||
841 | reserve_temp(p, dest); |
||
842 | |||
843 | #if 0 |
||
844 | /* Is this a texture indirection? |
||
845 | */ |
||
846 | if ((coord.file == PROGRAM_TEMPORARY && |
||
847 | (p->temps_output & (1< |
||
848 | (dest.file == PROGRAM_TEMPORARY && |
||
849 | (p->alu_temps & (1< |
||
850 | p->program->Base.NumTexIndirections++; |
||
851 | p->temps_output = 1< |
||
852 | p->alu_temps = 0; |
||
853 | assert(0); /* KW: texture env crossbar */ |
||
854 | } |
||
855 | #endif |
||
856 | |||
857 | return dest; |
||
858 | } |
||
859 | |||
860 | |||
861 | static struct ureg register_const4f( struct texenv_fragment_program *p, |
||
862 | GLfloat s0, |
||
863 | GLfloat s1, |
||
864 | GLfloat s2, |
||
865 | GLfloat s3) |
||
866 | { |
||
867 | GLfloat values[4]; |
||
868 | GLuint idx, swizzle; |
||
869 | struct ureg r; |
||
870 | values[0] = s0; |
||
871 | values[1] = s1; |
||
872 | values[2] = s2; |
||
873 | values[3] = s3; |
||
874 | idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values, 4, |
||
875 | &swizzle ); |
||
876 | r = make_ureg(PROGRAM_CONSTANT, idx); |
||
877 | r.swz = swizzle; |
||
878 | return r; |
||
879 | } |
||
880 | |||
881 | #define register_scalar_const(p, s0) register_const4f(p, s0, s0, s0, s0) |
||
882 | #define register_const1f(p, s0) register_const4f(p, s0, 0, 0, 1) |
||
883 | #define register_const2f(p, s0, s1) register_const4f(p, s0, s1, 0, 1) |
||
884 | #define register_const3f(p, s0, s1, s2) register_const4f(p, s0, s1, s2, 1) |
||
885 | |||
886 | |||
887 | static struct ureg get_one( struct texenv_fragment_program *p ) |
||
888 | { |
||
889 | if (is_undef(p->one)) |
||
890 | p->one = register_scalar_const(p, 1.0); |
||
891 | return p->one; |
||
892 | } |
||
893 | |||
894 | static struct ureg get_half( struct texenv_fragment_program *p ) |
||
895 | { |
||
896 | if (is_undef(p->half)) |
||
897 | p->half = register_scalar_const(p, 0.5); |
||
898 | return p->half; |
||
899 | } |
||
900 | |||
901 | static struct ureg get_zero( struct texenv_fragment_program *p ) |
||
902 | { |
||
903 | if (is_undef(p->zero)) |
||
904 | p->zero = register_scalar_const(p, 0.0); |
||
905 | return p->zero; |
||
906 | } |
||
907 | |||
908 | |||
909 | static void program_error( struct texenv_fragment_program *p, const char *msg ) |
||
910 | { |
||
911 | _mesa_problem(NULL, "%s", msg); |
||
912 | p->error = 1; |
||
913 | } |
||
914 | |||
915 | static struct ureg get_source( struct texenv_fragment_program *p, |
||
916 | GLuint src, GLuint unit ) |
||
917 | { |
||
918 | switch (src) { |
||
919 | case SRC_TEXTURE: |
||
920 | assert(!is_undef(p->src_texture[unit])); |
||
921 | return p->src_texture[unit]; |
||
922 | |||
923 | case SRC_TEXTURE0: |
||
924 | case SRC_TEXTURE1: |
||
925 | case SRC_TEXTURE2: |
||
926 | case SRC_TEXTURE3: |
||
927 | case SRC_TEXTURE4: |
||
928 | case SRC_TEXTURE5: |
||
929 | case SRC_TEXTURE6: |
||
930 | case SRC_TEXTURE7: |
||
931 | assert(!is_undef(p->src_texture[src - SRC_TEXTURE0])); |
||
932 | return p->src_texture[src - SRC_TEXTURE0]; |
||
933 | |||
934 | case SRC_CONSTANT: |
||
935 | return register_param2(p, STATE_TEXENV_COLOR, unit); |
||
936 | |||
937 | case SRC_PRIMARY_COLOR: |
||
938 | return register_input(p, FRAG_ATTRIB_COL0); |
||
939 | |||
940 | case SRC_ZERO: |
||
941 | return get_zero(p); |
||
942 | |||
943 | case SRC_PREVIOUS: |
||
944 | if (is_undef(p->src_previous)) |
||
945 | return register_input(p, FRAG_ATTRIB_COL0); |
||
946 | else |
||
947 | return p->src_previous; |
||
948 | |||
949 | default: |
||
950 | assert(0); |
||
951 | return undef; |
||
952 | } |
||
953 | } |
||
954 | |||
955 | static struct ureg emit_combine_source( struct texenv_fragment_program *p, |
||
956 | GLuint mask, |
||
957 | GLuint unit, |
||
958 | GLuint source, |
||
959 | GLuint operand ) |
||
960 | { |
||
961 | struct ureg arg, src, one; |
||
962 | |||
963 | src = get_source(p, source, unit); |
||
964 | |||
965 | switch (operand) { |
||
966 | case OPR_ONE_MINUS_SRC_COLOR: |
||
967 | /* Get unused tmp, |
||
968 | * Emit tmp = 1.0 - arg.xyzw |
||
969 | */ |
||
970 | arg = get_temp( p ); |
||
971 | one = get_one( p ); |
||
972 | return emit_arith( p, OPCODE_SUB, arg, mask, 0, one, src, undef); |
||
973 | |||
974 | case OPR_SRC_ALPHA: |
||
975 | if (mask == WRITEMASK_W) |
||
976 | return src; |
||
977 | else |
||
978 | return swizzle1( src, SWIZZLE_W ); |
||
979 | case OPR_ONE_MINUS_SRC_ALPHA: |
||
980 | /* Get unused tmp, |
||
981 | * Emit tmp = 1.0 - arg.wwww |
||
982 | */ |
||
983 | arg = get_temp(p); |
||
984 | one = get_one(p); |
||
985 | return emit_arith(p, OPCODE_SUB, arg, mask, 0, |
||
986 | one, swizzle1(src, SWIZZLE_W), undef); |
||
987 | case OPR_ZERO: |
||
988 | return get_zero(p); |
||
989 | case OPR_ONE: |
||
990 | return get_one(p); |
||
991 | case OPR_SRC_COLOR: |
||
992 | return src; |
||
993 | default: |
||
994 | assert(0); |
||
995 | return src; |
||
996 | } |
||
997 | } |
||
998 | |||
999 | /** |
||
1000 | * Check if the RGB and Alpha sources and operands match for the given |
||
1001 | * texture unit's combinder state. When the RGB and A sources and |
||
1002 | * operands match, we can emit fewer instructions. |
||
1003 | */ |
||
1004 | static GLboolean args_match( const struct state_key *key, GLuint unit ) |
||
1005 | { |
||
1006 | GLuint i, numArgs = key->unit[unit].NumArgsRGB; |
||
1007 | |||
1008 | for (i = 0; i < numArgs; i++) { |
||
1009 | if (key->unit[unit].OptA[i].Source != key->unit[unit].OptRGB[i].Source) |
||
1010 | return GL_FALSE; |
||
1011 | |||
1012 | switch (key->unit[unit].OptA[i].Operand) { |
||
1013 | case OPR_SRC_ALPHA: |
||
1014 | switch (key->unit[unit].OptRGB[i].Operand) { |
||
1015 | case OPR_SRC_COLOR: |
||
1016 | case OPR_SRC_ALPHA: |
||
1017 | break; |
||
1018 | default: |
||
1019 | return GL_FALSE; |
||
1020 | } |
||
1021 | break; |
||
1022 | case OPR_ONE_MINUS_SRC_ALPHA: |
||
1023 | switch (key->unit[unit].OptRGB[i].Operand) { |
||
1024 | case OPR_ONE_MINUS_SRC_COLOR: |
||
1025 | case OPR_ONE_MINUS_SRC_ALPHA: |
||
1026 | break; |
||
1027 | default: |
||
1028 | return GL_FALSE; |
||
1029 | } |
||
1030 | break; |
||
1031 | default: |
||
1032 | return GL_FALSE; /* impossible */ |
||
1033 | } |
||
1034 | } |
||
1035 | |||
1036 | return GL_TRUE; |
||
1037 | } |
||
1038 | |||
1039 | static struct ureg emit_combine( struct texenv_fragment_program *p, |
||
1040 | struct ureg dest, |
||
1041 | GLuint mask, |
||
1042 | GLboolean saturate, |
||
1043 | GLuint unit, |
||
1044 | GLuint nr, |
||
1045 | GLuint mode, |
||
1046 | const struct mode_opt *opt) |
||
1047 | { |
||
1048 | struct ureg src[MAX_COMBINER_TERMS]; |
||
1049 | struct ureg tmp, half; |
||
1050 | GLuint i; |
||
1051 | |||
1052 | assert(nr <= MAX_COMBINER_TERMS); |
||
1053 | |||
1054 | for (i = 0; i < nr; i++) |
||
1055 | src[i] = emit_combine_source( p, mask, unit, opt[i].Source, opt[i].Operand ); |
||
1056 | |||
1057 | switch (mode) { |
||
1058 | case MODE_REPLACE: |
||
1059 | if (mask == WRITEMASK_XYZW && !saturate) |
||
1060 | return src[0]; |
||
1061 | else |
||
1062 | return emit_arith( p, OPCODE_MOV, dest, mask, saturate, src[0], undef, undef ); |
||
1063 | case MODE_MODULATE: |
||
1064 | return emit_arith( p, OPCODE_MUL, dest, mask, saturate, |
||
1065 | src[0], src[1], undef ); |
||
1066 | case MODE_ADD: |
||
1067 | return emit_arith( p, OPCODE_ADD, dest, mask, saturate, |
||
1068 | src[0], src[1], undef ); |
||
1069 | case MODE_ADD_SIGNED: |
||
1070 | /* tmp = arg0 + arg1 |
||
1071 | * result = tmp - .5 |
||
1072 | */ |
||
1073 | half = get_half(p); |
||
1074 | tmp = get_temp( p ); |
||
1075 | emit_arith( p, OPCODE_ADD, tmp, mask, 0, src[0], src[1], undef ); |
||
1076 | emit_arith( p, OPCODE_SUB, dest, mask, saturate, tmp, half, undef ); |
||
1077 | return dest; |
||
1078 | case MODE_INTERPOLATE: |
||
1079 | /* Arg0 * (Arg2) + Arg1 * (1-Arg2) -- note arguments are reordered: |
||
1080 | */ |
||
1081 | return emit_arith( p, OPCODE_LRP, dest, mask, saturate, src[2], src[0], src[1] ); |
||
1082 | |||
1083 | case MODE_SUBTRACT: |
||
1084 | return emit_arith( p, OPCODE_SUB, dest, mask, saturate, src[0], src[1], undef ); |
||
1085 | |||
1086 | case MODE_DOT3_RGBA: |
||
1087 | case MODE_DOT3_RGBA_EXT: |
||
1088 | case MODE_DOT3_RGB_EXT: |
||
1089 | case MODE_DOT3_RGB: { |
||
1090 | struct ureg tmp0 = get_temp( p ); |
||
1091 | struct ureg tmp1 = get_temp( p ); |
||
1092 | struct ureg neg1 = register_scalar_const(p, -1); |
||
1093 | struct ureg two = register_scalar_const(p, 2); |
||
1094 | |||
1095 | /* tmp0 = 2*src0 - 1 |
||
1096 | * tmp1 = 2*src1 - 1 |
||
1097 | * |
||
1098 | * dst = tmp0 dot3 tmp1 |
||
1099 | */ |
||
1100 | emit_arith( p, OPCODE_MAD, tmp0, WRITEMASK_XYZW, 0, |
||
1101 | two, src[0], neg1); |
||
1102 | |||
1103 | if (memcmp(&src[0], &src[1], sizeof(struct ureg)) == 0) |
||
1104 | tmp1 = tmp0; |
||
1105 | else |
||
1106 | emit_arith( p, OPCODE_MAD, tmp1, WRITEMASK_XYZW, 0, |
||
1107 | two, src[1], neg1); |
||
1108 | emit_arith( p, OPCODE_DP3, dest, mask, saturate, tmp0, tmp1, undef); |
||
1109 | return dest; |
||
1110 | } |
||
1111 | case MODE_MODULATE_ADD_ATI: |
||
1112 | /* Arg0 * Arg2 + Arg1 */ |
||
1113 | return emit_arith( p, OPCODE_MAD, dest, mask, saturate, |
||
1114 | src[0], src[2], src[1] ); |
||
1115 | case MODE_MODULATE_SIGNED_ADD_ATI: { |
||
1116 | /* Arg0 * Arg2 + Arg1 - 0.5 */ |
||
1117 | struct ureg tmp0 = get_temp(p); |
||
1118 | half = get_half(p); |
||
1119 | emit_arith( p, OPCODE_MAD, tmp0, mask, 0, src[0], src[2], src[1] ); |
||
1120 | emit_arith( p, OPCODE_SUB, dest, mask, saturate, tmp0, half, undef ); |
||
1121 | return dest; |
||
1122 | } |
||
1123 | case MODE_MODULATE_SUBTRACT_ATI: |
||
1124 | /* Arg0 * Arg2 - Arg1 */ |
||
1125 | emit_arith( p, OPCODE_MAD, dest, mask, 0, src[0], src[2], negate(src[1]) ); |
||
1126 | return dest; |
||
1127 | case MODE_ADD_PRODUCTS: |
||
1128 | /* Arg0 * Arg1 + Arg2 * Arg3 */ |
||
1129 | { |
||
1130 | struct ureg tmp0 = get_temp(p); |
||
1131 | emit_arith( p, OPCODE_MUL, tmp0, mask, 0, src[0], src[1], undef ); |
||
1132 | emit_arith( p, OPCODE_MAD, dest, mask, saturate, src[2], src[3], tmp0 ); |
||
1133 | } |
||
1134 | return dest; |
||
1135 | case MODE_ADD_PRODUCTS_SIGNED: |
||
1136 | /* Arg0 * Arg1 + Arg2 * Arg3 - 0.5 */ |
||
1137 | { |
||
1138 | struct ureg tmp0 = get_temp(p); |
||
1139 | half = get_half(p); |
||
1140 | emit_arith( p, OPCODE_MUL, tmp0, mask, 0, src[0], src[1], undef ); |
||
1141 | emit_arith( p, OPCODE_MAD, tmp0, mask, 0, src[2], src[3], tmp0 ); |
||
1142 | emit_arith( p, OPCODE_SUB, dest, mask, saturate, tmp0, half, undef ); |
||
1143 | } |
||
1144 | return dest; |
||
1145 | case MODE_BUMP_ENVMAP_ATI: |
||
1146 | /* special - not handled here */ |
||
1147 | assert(0); |
||
1148 | return src[0]; |
||
1149 | default: |
||
1150 | assert(0); |
||
1151 | return src[0]; |
||
1152 | } |
||
1153 | } |
||
1154 | |||
1155 | |||
1156 | /** |
||
1157 | * Generate instructions for one texture unit's env/combiner mode. |
||
1158 | */ |
||
1159 | static struct ureg |
||
1160 | emit_texenv(struct texenv_fragment_program *p, GLuint unit) |
||
1161 | { |
||
1162 | const struct state_key *key = p->state; |
||
1163 | GLboolean rgb_saturate, alpha_saturate; |
||
1164 | GLuint rgb_shift, alpha_shift; |
||
1165 | struct ureg out, dest; |
||
1166 | |||
1167 | if (!key->unit[unit].enabled) { |
||
1168 | return get_source(p, SRC_PREVIOUS, 0); |
||
1169 | } |
||
1170 | if (key->unit[unit].ModeRGB == MODE_BUMP_ENVMAP_ATI) { |
||
1171 | /* this isn't really a env stage delivering a color and handled elsewhere */ |
||
1172 | return get_source(p, SRC_PREVIOUS, 0); |
||
1173 | } |
||
1174 | |||
1175 | switch (key->unit[unit].ModeRGB) { |
||
1176 | case MODE_DOT3_RGB_EXT: |
||
1177 | alpha_shift = key->unit[unit].ScaleShiftA; |
||
1178 | rgb_shift = 0; |
||
1179 | break; |
||
1180 | case MODE_DOT3_RGBA_EXT: |
||
1181 | alpha_shift = 0; |
||
1182 | rgb_shift = 0; |
||
1183 | break; |
||
1184 | default: |
||
1185 | rgb_shift = key->unit[unit].ScaleShiftRGB; |
||
1186 | alpha_shift = key->unit[unit].ScaleShiftA; |
||
1187 | break; |
||
1188 | } |
||
1189 | |||
1190 | /* If we'll do rgb/alpha shifting don't saturate in emit_combine(). |
||
1191 | * We don't want to clamp twice. |
||
1192 | */ |
||
1193 | if (rgb_shift) |
||
1194 | rgb_saturate = GL_FALSE; /* saturate after rgb shift */ |
||
1195 | else if (need_saturate(key->unit[unit].ModeRGB)) |
||
1196 | rgb_saturate = GL_TRUE; |
||
1197 | else |
||
1198 | rgb_saturate = GL_FALSE; |
||
1199 | |||
1200 | if (alpha_shift) |
||
1201 | alpha_saturate = GL_FALSE; /* saturate after alpha shift */ |
||
1202 | else if (need_saturate(key->unit[unit].ModeA)) |
||
1203 | alpha_saturate = GL_TRUE; |
||
1204 | else |
||
1205 | alpha_saturate = GL_FALSE; |
||
1206 | |||
1207 | /* If this is the very last calculation (and various other conditions |
||
1208 | * are met), emit directly to the color output register. Otherwise, |
||
1209 | * emit to a temporary register. |
||
1210 | */ |
||
1211 | if (key->separate_specular || |
||
1212 | unit != p->last_tex_stage || |
||
1213 | alpha_shift || |
||
1214 | key->num_draw_buffers != 1 || |
||
1215 | rgb_shift) |
||
1216 | dest = get_temp( p ); |
||
1217 | else |
||
1218 | dest = make_ureg(PROGRAM_OUTPUT, FRAG_RESULT_COLOR); |
||
1219 | |||
1220 | /* Emit the RGB and A combine ops |
||
1221 | */ |
||
1222 | if (key->unit[unit].ModeRGB == key->unit[unit].ModeA && |
||
1223 | args_match(key, unit)) { |
||
1224 | out = emit_combine( p, dest, WRITEMASK_XYZW, rgb_saturate, |
||
1225 | unit, |
||
1226 | key->unit[unit].NumArgsRGB, |
||
1227 | key->unit[unit].ModeRGB, |
||
1228 | key->unit[unit].OptRGB); |
||
1229 | } |
||
1230 | else if (key->unit[unit].ModeRGB == MODE_DOT3_RGBA_EXT || |
||
1231 | key->unit[unit].ModeRGB == MODE_DOT3_RGBA) { |
||
1232 | out = emit_combine( p, dest, WRITEMASK_XYZW, rgb_saturate, |
||
1233 | unit, |
||
1234 | key->unit[unit].NumArgsRGB, |
||
1235 | key->unit[unit].ModeRGB, |
||
1236 | key->unit[unit].OptRGB); |
||
1237 | } |
||
1238 | else { |
||
1239 | /* Need to do something to stop from re-emitting identical |
||
1240 | * argument calculations here: |
||
1241 | */ |
||
1242 | out = emit_combine( p, dest, WRITEMASK_XYZ, rgb_saturate, |
||
1243 | unit, |
||
1244 | key->unit[unit].NumArgsRGB, |
||
1245 | key->unit[unit].ModeRGB, |
||
1246 | key->unit[unit].OptRGB); |
||
1247 | out = emit_combine( p, dest, WRITEMASK_W, alpha_saturate, |
||
1248 | unit, |
||
1249 | key->unit[unit].NumArgsA, |
||
1250 | key->unit[unit].ModeA, |
||
1251 | key->unit[unit].OptA); |
||
1252 | } |
||
1253 | |||
1254 | /* Deal with the final shift: |
||
1255 | */ |
||
1256 | if (alpha_shift || rgb_shift) { |
||
1257 | struct ureg shift; |
||
1258 | GLboolean saturate = GL_TRUE; /* always saturate at this point */ |
||
1259 | |||
1260 | if (rgb_shift == alpha_shift) { |
||
1261 | shift = register_scalar_const(p, (GLfloat)(1< |
||
1262 | } |
||
1263 | else { |
||
1264 | shift = register_const4f(p, |
||
1265 | (GLfloat)(1< |
||
1266 | (GLfloat)(1< |
||
1267 | (GLfloat)(1< |
||
1268 | (GLfloat)(1< |
||
1269 | } |
||
1270 | return emit_arith( p, OPCODE_MUL, dest, WRITEMASK_XYZW, |
||
1271 | saturate, out, shift, undef ); |
||
1272 | } |
||
1273 | else |
||
1274 | return out; |
||
1275 | } |
||
1276 | |||
1277 | |||
1278 | /** |
||
1279 | * Generate instruction for getting a texture source term. |
||
1280 | */ |
||
1281 | static void load_texture( struct texenv_fragment_program *p, GLuint unit ) |
||
1282 | { |
||
1283 | if (is_undef(p->src_texture[unit])) { |
||
1284 | const GLuint texTarget = p->state->unit[unit].source_index; |
||
1285 | struct ureg texcoord; |
||
1286 | struct ureg tmp = get_tex_temp( p ); |
||
1287 | |||
1288 | if (is_undef(p->texcoord_tex[unit])) { |
||
1289 | texcoord = register_input(p, FRAG_ATTRIB_TEX0+unit); |
||
1290 | } |
||
1291 | else { |
||
1292 | /* might want to reuse this reg for tex output actually */ |
||
1293 | texcoord = p->texcoord_tex[unit]; |
||
1294 | } |
||
1295 | |||
1296 | /* TODO: Use D0_MASK_XY where possible. |
||
1297 | */ |
||
1298 | if (p->state->unit[unit].enabled) { |
||
1299 | GLboolean shadow = GL_FALSE; |
||
1300 | |||
1301 | if (p->state->unit[unit].shadow) { |
||
1302 | p->program->Base.ShadowSamplers |= 1 << unit; |
||
1303 | shadow = GL_TRUE; |
||
1304 | } |
||
1305 | |||
1306 | p->src_texture[unit] = emit_texld( p, OPCODE_TXP, |
||
1307 | tmp, WRITEMASK_XYZW, |
||
1308 | unit, texTarget, shadow, |
||
1309 | texcoord ); |
||
1310 | |||
1311 | p->program->Base.SamplersUsed |= (1 << unit); |
||
1312 | /* This identity mapping should already be in place |
||
1313 | * (see _mesa_init_program_struct()) but let's be safe. |
||
1314 | */ |
||
1315 | p->program->Base.SamplerUnits[unit] = unit; |
||
1316 | } |
||
1317 | else |
||
1318 | p->src_texture[unit] = get_zero(p); |
||
1319 | |||
1320 | if (p->state->unit[unit].texture_cyl_wrap) { |
||
1321 | /* set flag which is checked by Mesa->Gallium program translation */ |
||
1322 | p->program->Base.InputFlags[0] |= PROG_PARAM_BIT_CYL_WRAP; |
||
1323 | } |
||
1324 | |||
1325 | } |
||
1326 | } |
||
1327 | |||
1328 | static GLboolean load_texenv_source( struct texenv_fragment_program *p, |
||
1329 | GLuint src, GLuint unit ) |
||
1330 | { |
||
1331 | switch (src) { |
||
1332 | case SRC_TEXTURE: |
||
1333 | load_texture(p, unit); |
||
1334 | break; |
||
1335 | |||
1336 | case SRC_TEXTURE0: |
||
1337 | case SRC_TEXTURE1: |
||
1338 | case SRC_TEXTURE2: |
||
1339 | case SRC_TEXTURE3: |
||
1340 | case SRC_TEXTURE4: |
||
1341 | case SRC_TEXTURE5: |
||
1342 | case SRC_TEXTURE6: |
||
1343 | case SRC_TEXTURE7: |
||
1344 | load_texture(p, src - SRC_TEXTURE0); |
||
1345 | break; |
||
1346 | |||
1347 | default: |
||
1348 | /* not a texture src - do nothing */ |
||
1349 | break; |
||
1350 | } |
||
1351 | |||
1352 | return GL_TRUE; |
||
1353 | } |
||
1354 | |||
1355 | |||
1356 | /** |
||
1357 | * Generate instructions for loading all texture source terms. |
||
1358 | */ |
||
1359 | static GLboolean |
||
1360 | load_texunit_sources( struct texenv_fragment_program *p, GLuint unit ) |
||
1361 | { |
||
1362 | const struct state_key *key = p->state; |
||
1363 | GLuint i; |
||
1364 | |||
1365 | for (i = 0; i < key->unit[unit].NumArgsRGB; i++) { |
||
1366 | load_texenv_source( p, key->unit[unit].OptRGB[i].Source, unit ); |
||
1367 | } |
||
1368 | |||
1369 | for (i = 0; i < key->unit[unit].NumArgsA; i++) { |
||
1370 | load_texenv_source( p, key->unit[unit].OptA[i].Source, unit ); |
||
1371 | } |
||
1372 | |||
1373 | return GL_TRUE; |
||
1374 | } |
||
1375 | |||
1376 | /** |
||
1377 | * Generate instructions for loading bump map textures. |
||
1378 | */ |
||
1379 | static GLboolean |
||
1380 | load_texunit_bumpmap( struct texenv_fragment_program *p, GLuint unit ) |
||
1381 | { |
||
1382 | const struct state_key *key = p->state; |
||
1383 | GLuint bumpedUnitNr = key->unit[unit].OptRGB[1].Source - SRC_TEXTURE0; |
||
1384 | struct ureg texcDst, bumpMapRes; |
||
1385 | struct ureg constdudvcolor = register_const4f(p, 0.0, 0.0, 0.0, 1.0); |
||
1386 | struct ureg texcSrc = register_input(p, FRAG_ATTRIB_TEX0 + bumpedUnitNr); |
||
1387 | struct ureg rotMat0 = register_param3( p, STATE_INTERNAL, STATE_ROT_MATRIX_0, unit ); |
||
1388 | struct ureg rotMat1 = register_param3( p, STATE_INTERNAL, STATE_ROT_MATRIX_1, unit ); |
||
1389 | |||
1390 | load_texenv_source( p, unit + SRC_TEXTURE0, unit ); |
||
1391 | |||
1392 | bumpMapRes = get_source(p, key->unit[unit].OptRGB[0].Source, unit); |
||
1393 | texcDst = get_tex_temp( p ); |
||
1394 | p->texcoord_tex[bumpedUnitNr] = texcDst; |
||
1395 | |||
1396 | /* Apply rot matrix and add coords to be available in next phase. |
||
1397 | * dest = (Arg0.xxxx * rotMat0 + Arg1) + (Arg0.yyyy * rotMat1) |
||
1398 | * note only 2 coords are affected the rest are left unchanged (mul by 0) |
||
1399 | */ |
||
1400 | emit_arith( p, OPCODE_MAD, texcDst, WRITEMASK_XYZW, 0, |
||
1401 | swizzle1(bumpMapRes, SWIZZLE_X), rotMat0, texcSrc ); |
||
1402 | emit_arith( p, OPCODE_MAD, texcDst, WRITEMASK_XYZW, 0, |
||
1403 | swizzle1(bumpMapRes, SWIZZLE_Y), rotMat1, texcDst ); |
||
1404 | |||
1405 | /* Move 0,0,0,1 into bumpmap src if someone (crossbar) is foolish |
||
1406 | * enough to access this later, should optimize away. |
||
1407 | */ |
||
1408 | emit_arith( p, OPCODE_MOV, bumpMapRes, WRITEMASK_XYZW, 0, |
||
1409 | constdudvcolor, undef, undef ); |
||
1410 | |||
1411 | return GL_TRUE; |
||
1412 | } |
||
1413 | |||
1414 | /** |
||
1415 | * Generate a new fragment program which implements the context's |
||
1416 | * current texture env/combine mode. |
||
1417 | */ |
||
1418 | static void |
||
1419 | create_new_program(struct gl_context *ctx, struct state_key *key, |
||
1420 | struct gl_fragment_program *program) |
||
1421 | { |
||
1422 | struct prog_instruction instBuffer[MAX_INSTRUCTIONS]; |
||
1423 | struct texenv_fragment_program p; |
||
1424 | GLuint unit; |
||
1425 | struct ureg cf, out; |
||
1426 | int i; |
||
1427 | |||
1428 | memset(&p, 0, sizeof(p)); |
||
1429 | p.state = key; |
||
1430 | p.program = program; |
||
1431 | |||
1432 | /* During code generation, use locally-allocated instruction buffer, |
||
1433 | * then alloc dynamic storage below. |
||
1434 | */ |
||
1435 | p.program->Base.Instructions = instBuffer; |
||
1436 | p.program->Base.Target = GL_FRAGMENT_PROGRAM_ARB; |
||
1437 | p.program->Base.String = NULL; |
||
1438 | p.program->Base.NumTexIndirections = 1; /* is this right? */ |
||
1439 | p.program->Base.NumTexInstructions = 0; |
||
1440 | p.program->Base.NumAluInstructions = 0; |
||
1441 | p.program->Base.NumInstructions = 0; |
||
1442 | p.program->Base.NumTemporaries = 0; |
||
1443 | p.program->Base.NumParameters = 0; |
||
1444 | p.program->Base.NumAttributes = 0; |
||
1445 | p.program->Base.NumAddressRegs = 0; |
||
1446 | p.program->Base.Parameters = _mesa_new_parameter_list(); |
||
1447 | p.program->Base.InputsRead = 0x0; |
||
1448 | |||
1449 | if (key->num_draw_buffers == 1) |
||
1450 | p.program->Base.OutputsWritten = 1 << FRAG_RESULT_COLOR; |
||
1451 | else { |
||
1452 | for (i = 0; i < key->num_draw_buffers; i++) |
||
1453 | p.program->Base.OutputsWritten |= (1 << (FRAG_RESULT_DATA0 + i)); |
||
1454 | } |
||
1455 | |||
1456 | for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { |
||
1457 | p.src_texture[unit] = undef; |
||
1458 | p.texcoord_tex[unit] = undef; |
||
1459 | } |
||
1460 | |||
1461 | p.src_previous = undef; |
||
1462 | p.half = undef; |
||
1463 | p.zero = undef; |
||
1464 | p.one = undef; |
||
1465 | |||
1466 | p.last_tex_stage = 0; |
||
1467 | release_temps(ctx, &p); |
||
1468 | |||
1469 | if (key->enabled_units && key->num_draw_buffers) { |
||
1470 | GLboolean needbumpstage = GL_FALSE; |
||
1471 | |||
1472 | /* Zeroth pass - bump map textures first */ |
||
1473 | for (unit = 0; unit < key->nr_enabled_units; unit++) |
||
1474 | if (key->unit[unit].enabled && |
||
1475 | key->unit[unit].ModeRGB == MODE_BUMP_ENVMAP_ATI) { |
||
1476 | needbumpstage = GL_TRUE; |
||
1477 | load_texunit_bumpmap( &p, unit ); |
||
1478 | } |
||
1479 | if (needbumpstage) |
||
1480 | p.program->Base.NumTexIndirections++; |
||
1481 | |||
1482 | /* First pass - to support texture_env_crossbar, first identify |
||
1483 | * all referenced texture sources and emit texld instructions |
||
1484 | * for each: |
||
1485 | */ |
||
1486 | for (unit = 0; unit < key->nr_enabled_units; unit++) |
||
1487 | if (key->unit[unit].enabled) { |
||
1488 | load_texunit_sources( &p, unit ); |
||
1489 | p.last_tex_stage = unit; |
||
1490 | } |
||
1491 | |||
1492 | /* Second pass - emit combine instructions to build final color: |
||
1493 | */ |
||
1494 | for (unit = 0; unit < key->nr_enabled_units; unit++) |
||
1495 | if (key->unit[unit].enabled) { |
||
1496 | p.src_previous = emit_texenv( &p, unit ); |
||
1497 | reserve_temp(&p, p.src_previous); /* don't re-use this temp reg */ |
||
1498 | release_temps(ctx, &p); /* release all temps */ |
||
1499 | } |
||
1500 | } |
||
1501 | |||
1502 | cf = get_source( &p, SRC_PREVIOUS, 0 ); |
||
1503 | |||
1504 | for (i = 0; i < key->num_draw_buffers; i++) { |
||
1505 | if (key->num_draw_buffers == 1) |
||
1506 | out = make_ureg( PROGRAM_OUTPUT, FRAG_RESULT_COLOR ); |
||
1507 | else { |
||
1508 | out = make_ureg( PROGRAM_OUTPUT, FRAG_RESULT_DATA0 + i ); |
||
1509 | } |
||
1510 | |||
1511 | if (key->separate_specular) { |
||
1512 | /* Emit specular add. |
||
1513 | */ |
||
1514 | struct ureg s = register_input(&p, FRAG_ATTRIB_COL1); |
||
1515 | emit_arith( &p, OPCODE_ADD, out, WRITEMASK_XYZ, 0, cf, s, undef ); |
||
1516 | emit_arith( &p, OPCODE_MOV, out, WRITEMASK_W, 0, cf, undef, undef ); |
||
1517 | } |
||
1518 | else if (memcmp(&cf, &out, sizeof(cf)) != 0) { |
||
1519 | /* Will wind up in here if no texture enabled or a couple of |
||
1520 | * other scenarios (GL_REPLACE for instance). |
||
1521 | */ |
||
1522 | emit_arith( &p, OPCODE_MOV, out, WRITEMASK_XYZW, 0, cf, undef, undef ); |
||
1523 | } |
||
1524 | } |
||
1525 | /* Finish up: |
||
1526 | */ |
||
1527 | emit_arith( &p, OPCODE_END, undef, WRITEMASK_XYZW, 0, undef, undef, undef); |
||
1528 | |||
1529 | if (key->fog_enabled) { |
||
1530 | /* Pull fog mode from struct gl_context, the value in the state key is |
||
1531 | * a reduced value and not what is expected in FogOption |
||
1532 | */ |
||
1533 | p.program->FogOption = ctx->Fog.Mode; |
||
1534 | p.program->Base.InputsRead |= FRAG_BIT_FOGC; |
||
1535 | } |
||
1536 | else { |
||
1537 | p.program->FogOption = GL_NONE; |
||
1538 | } |
||
1539 | |||
1540 | if (p.program->Base.NumTexIndirections > ctx->Const.FragmentProgram.MaxTexIndirections) |
||
1541 | program_error(&p, "Exceeded max nr indirect texture lookups"); |
||
1542 | |||
1543 | if (p.program->Base.NumTexInstructions > ctx->Const.FragmentProgram.MaxTexInstructions) |
||
1544 | program_error(&p, "Exceeded max TEX instructions"); |
||
1545 | |||
1546 | if (p.program->Base.NumAluInstructions > ctx->Const.FragmentProgram.MaxAluInstructions) |
||
1547 | program_error(&p, "Exceeded max ALU instructions"); |
||
1548 | |||
1549 | ASSERT(p.program->Base.NumInstructions <= MAX_INSTRUCTIONS); |
||
1550 | |||
1551 | /* Allocate final instruction array */ |
||
1552 | p.program->Base.Instructions |
||
1553 | = _mesa_alloc_instructions(p.program->Base.NumInstructions); |
||
1554 | if (!p.program->Base.Instructions) { |
||
1555 | _mesa_error(ctx, GL_OUT_OF_MEMORY, |
||
1556 | "generating tex env program"); |
||
1557 | return; |
||
1558 | } |
||
1559 | _mesa_copy_instructions(p.program->Base.Instructions, instBuffer, |
||
1560 | p.program->Base.NumInstructions); |
||
1561 | |||
1562 | if (key->num_draw_buffers && p.program->FogOption) { |
||
1563 | _mesa_append_fog_code(ctx, p.program); |
||
1564 | p.program->FogOption = GL_NONE; |
||
1565 | } |
||
1566 | |||
1567 | |||
1568 | /* Notify driver the fragment program has (actually) changed. |
||
1569 | */ |
||
1570 | if (ctx->Driver.ProgramStringNotify) { |
||
1571 | GLboolean ok = ctx->Driver.ProgramStringNotify(ctx, |
||
1572 | GL_FRAGMENT_PROGRAM_ARB, |
||
1573 | &p.program->Base); |
||
1574 | /* Driver should be able to handle any texenv programs as long as |
||
1575 | * the driver correctly reported max number of texture units correctly, |
||
1576 | * etc. |
||
1577 | */ |
||
1578 | ASSERT(ok); |
||
1579 | (void) ok; /* silence unused var warning */ |
||
1580 | } |
||
1581 | |||
1582 | if (DISASSEM) { |
||
1583 | _mesa_print_program(&p.program->Base); |
||
1584 | printf("\n"); |
||
1585 | } |
||
1586 | } |
||
1587 | |||
1588 | |||
1589 | /** |
||
1590 | * Return a fragment program which implements the current |
||
1591 | * fixed-function texture, fog and color-sum operations. |
||
1592 | */ |
||
1593 | struct gl_fragment_program * |
||
1594 | _mesa_get_fixed_func_fragment_program(struct gl_context *ctx) |
||
1595 | { |
||
1596 | struct gl_fragment_program *prog; |
||
1597 | struct state_key key; |
||
1598 | GLuint keySize; |
||
1599 | |||
1600 | keySize = make_state_key(ctx, &key); |
||
1601 | |||
1602 | prog = (struct gl_fragment_program *) |
||
1603 | _mesa_search_program_cache(ctx->FragmentProgram.Cache, |
||
1604 | &key, keySize); |
||
1605 | |||
1606 | if (!prog) { |
||
1607 | prog = (struct gl_fragment_program *) |
||
1608 | ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); |
||
1609 | |||
1610 | create_new_program(ctx, &key, prog); |
||
1611 | |||
1612 | _mesa_program_cache_insert(ctx, ctx->FragmentProgram.Cache, |
||
1613 | &key, keySize, &prog->Base); |
||
1614 | } |
||
1615 | |||
1616 | return prog; |
||
1617 | }=>>>>>>><>>><>>>><>><> |