Merge branch 'mesa_7_6_branch' into mesa_7_7_branch
[mesa.git] / src / mesa / drivers / dri / i915 / i830_texblend.c
1 /**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * 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
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include "main/glheader.h"
29 #include "main/macros.h"
30 #include "main/mtypes.h"
31 #include "main/simple_list.h"
32 #include "main/enums.h"
33 #include "main/texstore.h"
34 #include "main/mm.h"
35
36 #include "intel_screen.h"
37 #include "intel_tex.h"
38
39 #include "i830_context.h"
40 #include "i830_reg.h"
41
42
43 /* ================================================================
44 * Texture combine functions
45 */
46 static GLuint
47 pass_through(GLuint * state, GLuint blendUnit)
48 {
49 state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) |
50 TEXPIPE_COLOR |
51 ENABLE_TEXOUTPUT_WRT_SEL |
52 TEXOP_OUTPUT_CURRENT |
53 DISABLE_TEX_CNTRL_STAGE |
54 TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS | TEXBLENDOP_ARG1);
55 state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) |
56 TEXPIPE_ALPHA |
57 ENABLE_TEXOUTPUT_WRT_SEL |
58 TEXOP_OUTPUT_CURRENT |
59 TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS | TEXBLENDOP_ARG1);
60 state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) |
61 TEXPIPE_COLOR |
62 TEXBLEND_ARG1 |
63 TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_CURRENT);
64 state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) |
65 TEXPIPE_ALPHA |
66 TEXBLEND_ARG1 |
67 TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_CURRENT);
68
69 return 4;
70 }
71
72 static GLuint
73 emit_factor(GLuint blendUnit, GLuint * state, GLuint count,
74 const GLfloat * factor)
75 {
76 GLubyte r, g, b, a;
77 GLuint col;
78
79 if (0)
80 fprintf(stderr, "emit constant %d: %.2f %.2f %.2f %.2f\n",
81 blendUnit, factor[0], factor[1], factor[2], factor[3]);
82
83 UNCLAMPED_FLOAT_TO_UBYTE(r, factor[0]);
84 UNCLAMPED_FLOAT_TO_UBYTE(g, factor[1]);
85 UNCLAMPED_FLOAT_TO_UBYTE(b, factor[2]);
86 UNCLAMPED_FLOAT_TO_UBYTE(a, factor[3]);
87
88 col = ((a << 24) | (r << 16) | (g << 8) | b);
89
90 state[count++] = _3DSTATE_COLOR_FACTOR_N_CMD(blendUnit);
91 state[count++] = col;
92
93 return count;
94 }
95
96
97 static INLINE GLuint
98 GetTexelOp(GLint unit)
99 {
100 switch (unit) {
101 case 0:
102 return TEXBLENDARG_TEXEL0;
103 case 1:
104 return TEXBLENDARG_TEXEL1;
105 case 2:
106 return TEXBLENDARG_TEXEL2;
107 case 3:
108 return TEXBLENDARG_TEXEL3;
109 default:
110 return TEXBLENDARG_TEXEL0;
111 }
112 }
113
114
115 /**
116 * Calculate the hardware instuctions to setup the current texture enviromnemt
117 * settings. Since \c gl_texture_unit::_CurrentCombine is used, both
118 * "classic" texture enviroments and GL_ARB_texture_env_combine type texture
119 * environments are treated identically.
120 *
121 * \todo
122 * This function should return \c GLboolean. When \c GL_FALSE is returned,
123 * it means that an environment is selected that the hardware cannot do. This
124 * is the way the Radeon and R200 drivers work.
125 *
126 * \todo
127 * Looking at i830_3d_regs.h, it seems the i830 can do part of
128 * GL_ATI_texture_env_combine3. It can handle using \c GL_ONE and
129 * \c GL_ZERO as combine inputs (which the code already supports). It can
130 * also handle the \c GL_MODULATE_ADD_ATI mode. Is it worth investigating
131 * partial support for the extension?
132 */
133 GLuint
134 i830SetTexEnvCombine(struct i830_context * i830,
135 const struct gl_tex_env_combine_state * combine,
136 GLint blendUnit,
137 GLuint texel_op, GLuint * state, const GLfloat * factor)
138 {
139 const GLuint numColorArgs = combine->_NumArgsRGB;
140 const GLuint numAlphaArgs = combine->_NumArgsA;
141
142 GLuint blendop;
143 GLuint ablendop;
144 GLuint args_RGB[3];
145 GLuint args_A[3];
146 GLuint rgb_shift;
147 GLuint alpha_shift;
148 GLboolean need_factor = 0;
149 int i;
150 unsigned used;
151 static const GLuint tex_blend_rgb[3] = {
152 TEXPIPE_COLOR | TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS,
153 TEXPIPE_COLOR | TEXBLEND_ARG2 | TEXBLENDARG_MODIFY_PARMS,
154 TEXPIPE_COLOR | TEXBLEND_ARG0 | TEXBLENDARG_MODIFY_PARMS,
155 };
156 static const GLuint tex_blend_a[3] = {
157 TEXPIPE_ALPHA | TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS,
158 TEXPIPE_ALPHA | TEXBLEND_ARG2 | TEXBLENDARG_MODIFY_PARMS,
159 TEXPIPE_ALPHA | TEXBLEND_ARG0 | TEXBLENDARG_MODIFY_PARMS,
160 };
161
162 if (INTEL_DEBUG & DEBUG_TEXTURE)
163 fprintf(stderr, "%s\n", __FUNCTION__);
164
165
166 /* The EXT version of the DOT3 extension does not support the
167 * scale factor, but the ARB version (and the version in OpenGL
168 * 1.3) does.
169 */
170 switch (combine->ModeRGB) {
171 case GL_DOT3_RGB_EXT:
172 alpha_shift = combine->ScaleShiftA;
173 rgb_shift = 0;
174 break;
175
176 case GL_DOT3_RGBA_EXT:
177 alpha_shift = 0;
178 rgb_shift = 0;
179 break;
180
181 default:
182 rgb_shift = combine->ScaleShiftRGB;
183 alpha_shift = combine->ScaleShiftA;
184 break;
185 }
186
187
188 switch (combine->ModeRGB) {
189 case GL_REPLACE:
190 blendop = TEXBLENDOP_ARG1;
191 break;
192 case GL_MODULATE:
193 blendop = TEXBLENDOP_MODULATE;
194 break;
195 case GL_ADD:
196 blendop = TEXBLENDOP_ADD;
197 break;
198 case GL_ADD_SIGNED:
199 blendop = TEXBLENDOP_ADDSIGNED;
200 break;
201 case GL_INTERPOLATE:
202 blendop = TEXBLENDOP_BLEND;
203 break;
204 case GL_SUBTRACT:
205 blendop = TEXBLENDOP_SUBTRACT;
206 break;
207 case GL_DOT3_RGB_EXT:
208 case GL_DOT3_RGB:
209 blendop = TEXBLENDOP_DOT3;
210 break;
211 case GL_DOT3_RGBA_EXT:
212 case GL_DOT3_RGBA:
213 blendop = TEXBLENDOP_DOT3;
214 break;
215 default:
216 return pass_through(state, blendUnit);
217 }
218
219 blendop |= (rgb_shift << TEXOP_SCALE_SHIFT);
220
221
222 /* Handle RGB args */
223 for (i = 0; i < 3; i++) {
224 switch (combine->SourceRGB[i]) {
225 case GL_TEXTURE:
226 args_RGB[i] = texel_op;
227 break;
228 case GL_TEXTURE0:
229 case GL_TEXTURE1:
230 case GL_TEXTURE2:
231 case GL_TEXTURE3:
232 args_RGB[i] = GetTexelOp(combine->SourceRGB[i] - GL_TEXTURE0);
233 break;
234 case GL_CONSTANT:
235 args_RGB[i] = TEXBLENDARG_FACTOR_N;
236 need_factor = 1;
237 break;
238 case GL_PRIMARY_COLOR:
239 args_RGB[i] = TEXBLENDARG_DIFFUSE;
240 break;
241 case GL_PREVIOUS:
242 args_RGB[i] = TEXBLENDARG_CURRENT;
243 break;
244 default:
245 return pass_through(state, blendUnit);
246 }
247
248 switch (combine->OperandRGB[i]) {
249 case GL_SRC_COLOR:
250 args_RGB[i] |= 0;
251 break;
252 case GL_ONE_MINUS_SRC_COLOR:
253 args_RGB[i] |= TEXBLENDARG_INV_ARG;
254 break;
255 case GL_SRC_ALPHA:
256 args_RGB[i] |= TEXBLENDARG_REPLICATE_ALPHA;
257 break;
258 case GL_ONE_MINUS_SRC_ALPHA:
259 args_RGB[i] |= (TEXBLENDARG_REPLICATE_ALPHA | TEXBLENDARG_INV_ARG);
260 break;
261 default:
262 return pass_through(state, blendUnit);
263 }
264 }
265
266
267 /* Need to knobble the alpha calculations of TEXBLENDOP_DOT4 to
268 * match the spec. Can't use DOT3 as it won't propogate values
269 * into alpha as required:
270 *
271 * Note - the global factor is set up with alpha == .5, so
272 * the alpha part of the DOT4 calculation should be zero.
273 */
274 if (combine->ModeRGB == GL_DOT3_RGBA_EXT ||
275 combine->ModeRGB == GL_DOT3_RGBA) {
276 ablendop = TEXBLENDOP_DOT4;
277 args_A[0] = TEXBLENDARG_FACTOR; /* the global factor */
278 args_A[1] = TEXBLENDARG_FACTOR;
279 args_A[2] = TEXBLENDARG_FACTOR;
280 }
281 else {
282 switch (combine->ModeA) {
283 case GL_REPLACE:
284 ablendop = TEXBLENDOP_ARG1;
285 break;
286 case GL_MODULATE:
287 ablendop = TEXBLENDOP_MODULATE;
288 break;
289 case GL_ADD:
290 ablendop = TEXBLENDOP_ADD;
291 break;
292 case GL_ADD_SIGNED:
293 ablendop = TEXBLENDOP_ADDSIGNED;
294 break;
295 case GL_INTERPOLATE:
296 ablendop = TEXBLENDOP_BLEND;
297 break;
298 case GL_SUBTRACT:
299 ablendop = TEXBLENDOP_SUBTRACT;
300 break;
301 default:
302 return pass_through(state, blendUnit);
303 }
304
305
306 ablendop |= (alpha_shift << TEXOP_SCALE_SHIFT);
307
308 /* Handle A args */
309 for (i = 0; i < 3; i++) {
310 switch (combine->SourceA[i]) {
311 case GL_TEXTURE:
312 args_A[i] = texel_op;
313 break;
314 case GL_TEXTURE0:
315 case GL_TEXTURE1:
316 case GL_TEXTURE2:
317 case GL_TEXTURE3:
318 args_A[i] = GetTexelOp(combine->SourceA[i] - GL_TEXTURE0);
319 break;
320 case GL_CONSTANT:
321 args_A[i] = TEXBLENDARG_FACTOR_N;
322 need_factor = 1;
323 break;
324 case GL_PRIMARY_COLOR:
325 args_A[i] = TEXBLENDARG_DIFFUSE;
326 break;
327 case GL_PREVIOUS:
328 args_A[i] = TEXBLENDARG_CURRENT;
329 break;
330 default:
331 return pass_through(state, blendUnit);
332 }
333
334 switch (combine->OperandA[i]) {
335 case GL_SRC_ALPHA:
336 args_A[i] |= 0;
337 break;
338 case GL_ONE_MINUS_SRC_ALPHA:
339 args_A[i] |= TEXBLENDARG_INV_ARG;
340 break;
341 default:
342 return pass_through(state, blendUnit);
343 }
344 }
345 }
346
347
348
349 /* Native Arg1 == Arg0 in GL_EXT_texture_env_combine spec */
350 /* Native Arg2 == Arg1 in GL_EXT_texture_env_combine spec */
351 /* Native Arg0 == Arg2 in GL_EXT_texture_env_combine spec */
352
353 /* When we render we need to figure out which is the last really enabled
354 * tex unit, and put last stage on it
355 */
356
357
358 /* Build color & alpha pipelines */
359
360 used = 0;
361 state[used++] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) |
362 TEXPIPE_COLOR |
363 ENABLE_TEXOUTPUT_WRT_SEL |
364 TEXOP_OUTPUT_CURRENT |
365 DISABLE_TEX_CNTRL_STAGE | TEXOP_MODIFY_PARMS | blendop);
366 state[used++] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) |
367 TEXPIPE_ALPHA |
368 ENABLE_TEXOUTPUT_WRT_SEL |
369 TEXOP_OUTPUT_CURRENT | TEXOP_MODIFY_PARMS | ablendop);
370
371 for (i = 0; i < numColorArgs; i++) {
372 state[used++] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) |
373 tex_blend_rgb[i] | args_RGB[i]);
374 }
375
376 for (i = 0; i < numAlphaArgs; i++) {
377 state[used++] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) |
378 tex_blend_a[i] | args_A[i]);
379 }
380
381
382 if (need_factor)
383 return emit_factor(blendUnit, state, used, factor);
384 else
385 return used;
386 }
387
388
389 static void
390 emit_texblend(struct i830_context *i830, GLuint unit, GLuint blendUnit,
391 GLboolean last_stage)
392 {
393 struct gl_texture_unit *texUnit = &i830->intel.ctx.Texture.Unit[unit];
394 GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz;
395
396
397 if (0)
398 fprintf(stderr, "%s unit %d\n", __FUNCTION__, unit);
399
400 /* Update i830->state.TexBlend
401 */
402 tmp_sz = i830SetTexEnvCombine(i830, texUnit->_CurrentCombine, blendUnit,
403 GetTexelOp(unit), tmp, texUnit->EnvColor);
404
405 if (last_stage)
406 tmp[0] |= TEXOP_LAST_STAGE;
407
408 if (tmp_sz != i830->state.TexBlendWordsUsed[blendUnit] ||
409 memcmp(tmp, i830->state.TexBlend[blendUnit],
410 tmp_sz * sizeof(GLuint))) {
411
412 I830_STATECHANGE(i830, I830_UPLOAD_TEXBLEND(blendUnit));
413 memcpy(i830->state.TexBlend[blendUnit], tmp, tmp_sz * sizeof(GLuint));
414 i830->state.TexBlendWordsUsed[blendUnit] = tmp_sz;
415 }
416
417 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND(blendUnit), GL_TRUE);
418 }
419
420 static void
421 emit_passthrough(struct i830_context *i830)
422 {
423 GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz;
424 GLuint unit = 0;
425
426 tmp_sz = pass_through(tmp, unit);
427 tmp[0] |= TEXOP_LAST_STAGE;
428
429 if (tmp_sz != i830->state.TexBlendWordsUsed[unit] ||
430 memcmp(tmp, i830->state.TexBlend[unit], tmp_sz * sizeof(GLuint))) {
431
432 I830_STATECHANGE(i830, I830_UPLOAD_TEXBLEND(unit));
433 memcpy(i830->state.TexBlend[unit], tmp, tmp_sz * sizeof(GLuint));
434 i830->state.TexBlendWordsUsed[unit] = tmp_sz;
435 }
436
437 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND(unit), GL_TRUE);
438 }
439
440 void
441 i830EmitTextureBlend(struct i830_context *i830)
442 {
443 GLcontext *ctx = &i830->intel.ctx;
444 GLuint unit, last_stage = 0, blendunit = 0;
445
446 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND_ALL, GL_FALSE);
447
448 if (ctx->Texture._EnabledUnits) {
449 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++)
450 if (ctx->Texture.Unit[unit]._ReallyEnabled)
451 last_stage = unit;
452
453 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++)
454 if (ctx->Texture.Unit[unit]._ReallyEnabled)
455 emit_texblend(i830, unit, blendunit++, last_stage == unit);
456 }
457 else {
458 emit_passthrough(i830);
459 }
460 }