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