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