Merge branch 'nouveau-import'
[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
165 if(INTEL_DEBUG&DEBUG_TEXTURE)
166 fprintf(stderr, "%s\n", __FUNCTION__);
167
168
169 /* The EXT version of the DOT3 extension does not support the
170 * scale factor, but the ARB version (and the version in OpenGL
171 * 1.3) does.
172 */
173 switch (combine->ModeRGB) {
174 case GL_DOT3_RGB_EXT:
175 alpha_shift = combine->ScaleShiftA;
176 rgb_shift = 0;
177 break;
178
179 case GL_DOT3_RGBA_EXT:
180 alpha_shift = 0;
181 rgb_shift = 0;
182 break;
183
184 default:
185 rgb_shift = combine->ScaleShiftRGB;
186 alpha_shift = combine->ScaleShiftA;
187 break;
188 }
189
190
191 switch(combine->ModeRGB) {
192 case GL_REPLACE:
193 blendop = TEXBLENDOP_ARG1;
194 break;
195 case GL_MODULATE:
196 blendop = TEXBLENDOP_MODULATE;
197 break;
198 case GL_ADD:
199 blendop = TEXBLENDOP_ADD;
200 break;
201 case GL_ADD_SIGNED:
202 blendop = TEXBLENDOP_ADDSIGNED;
203 break;
204 case GL_INTERPOLATE:
205 blendop = TEXBLENDOP_BLEND;
206 break;
207 case GL_SUBTRACT:
208 blendop = TEXBLENDOP_SUBTRACT;
209 break;
210 case GL_DOT3_RGB_EXT:
211 case GL_DOT3_RGB:
212 blendop = TEXBLENDOP_DOT3;
213 break;
214 case GL_DOT3_RGBA_EXT:
215 case GL_DOT3_RGBA:
216 blendop = TEXBLENDOP_DOT3;
217 break;
218 default:
219 return pass_through( state, blendUnit );
220 }
221
222 blendop |= (rgb_shift << TEXOP_SCALE_SHIFT);
223
224
225 /* Handle RGB args */
226 for(i = 0; i < 3; i++) {
227 switch(combine->SourceRGB[i]) {
228 case GL_TEXTURE:
229 args_RGB[i] = texel_op;
230 break;
231 case GL_TEXTURE0:
232 case GL_TEXTURE1:
233 case GL_TEXTURE2:
234 case GL_TEXTURE3:
235 args_RGB[i] = GetTexelOp( combine->SourceRGB[i] - GL_TEXTURE0 );
236 break;
237 case GL_CONSTANT:
238 args_RGB[i] = TEXBLENDARG_FACTOR_N;
239 need_factor = 1;
240 break;
241 case GL_PRIMARY_COLOR:
242 args_RGB[i] = TEXBLENDARG_DIFFUSE;
243 break;
244 case GL_PREVIOUS:
245 args_RGB[i] = TEXBLENDARG_CURRENT;
246 break;
247 default:
248 return pass_through( state, blendUnit );
249 }
250
251 switch(combine->OperandRGB[i]) {
252 case GL_SRC_COLOR:
253 args_RGB[i] |= 0;
254 break;
255 case GL_ONE_MINUS_SRC_COLOR:
256 args_RGB[i] |= TEXBLENDARG_INV_ARG;
257 break;
258 case GL_SRC_ALPHA:
259 args_RGB[i] |= TEXBLENDARG_REPLICATE_ALPHA;
260 break;
261 case GL_ONE_MINUS_SRC_ALPHA:
262 args_RGB[i] |= (TEXBLENDARG_REPLICATE_ALPHA |
263 TEXBLENDARG_INV_ARG);
264 break;
265 default:
266 return pass_through( state, blendUnit );
267 }
268 }
269
270
271 /* Need to knobble the alpha calculations of TEXBLENDOP_DOT4 to
272 * match the spec. Can't use DOT3 as it won't propogate values
273 * into alpha as required:
274 *
275 * Note - the global factor is set up with alpha == .5, so
276 * the alpha part of the DOT4 calculation should be zero.
277 */
278 if ( combine->ModeRGB == GL_DOT3_RGBA_EXT ||
279 combine->ModeRGB == GL_DOT3_RGBA ) {
280 ablendop = TEXBLENDOP_DOT4;
281 args_A[0] = TEXBLENDARG_FACTOR; /* the global factor */
282 args_A[1] = TEXBLENDARG_FACTOR;
283 args_A[2] = TEXBLENDARG_FACTOR;
284 }
285 else {
286 switch(combine->ModeA) {
287 case GL_REPLACE:
288 ablendop = TEXBLENDOP_ARG1;
289 break;
290 case GL_MODULATE:
291 ablendop = TEXBLENDOP_MODULATE;
292 break;
293 case GL_ADD:
294 ablendop = TEXBLENDOP_ADD;
295 break;
296 case GL_ADD_SIGNED:
297 ablendop = TEXBLENDOP_ADDSIGNED;
298 break;
299 case GL_INTERPOLATE:
300 ablendop = TEXBLENDOP_BLEND;
301 break;
302 case GL_SUBTRACT:
303 ablendop = TEXBLENDOP_SUBTRACT;
304 break;
305 default:
306 return pass_through( state, blendUnit );
307 }
308
309
310 ablendop |= (alpha_shift << TEXOP_SCALE_SHIFT);
311
312 /* Handle A args */
313 for(i = 0; i < 3; i++) {
314 switch(combine->SourceA[i]) {
315 case GL_TEXTURE:
316 args_A[i] = texel_op;
317 break;
318 case GL_TEXTURE0:
319 case GL_TEXTURE1:
320 case GL_TEXTURE2:
321 case GL_TEXTURE3:
322 args_A[i] = GetTexelOp( combine->SourceA[i] - GL_TEXTURE0 );
323 break;
324 case GL_CONSTANT:
325 args_A[i] = TEXBLENDARG_FACTOR_N;
326 need_factor = 1;
327 break;
328 case GL_PRIMARY_COLOR:
329 args_A[i] = TEXBLENDARG_DIFFUSE;
330 break;
331 case GL_PREVIOUS:
332 args_A[i] = TEXBLENDARG_CURRENT;
333 break;
334 default:
335 return pass_through( state, blendUnit );
336 }
337
338 switch(combine->OperandA[i]) {
339 case GL_SRC_ALPHA:
340 args_A[i] |= 0;
341 break;
342 case GL_ONE_MINUS_SRC_ALPHA:
343 args_A[i] |= TEXBLENDARG_INV_ARG;
344 break;
345 default:
346 return pass_through( state, blendUnit );
347 }
348 }
349 }
350
351
352
353 /* Native Arg1 == Arg0 in GL_EXT_texture_env_combine spec */
354 /* Native Arg2 == Arg1 in GL_EXT_texture_env_combine spec */
355 /* Native Arg0 == Arg2 in GL_EXT_texture_env_combine spec */
356
357 /* When we render we need to figure out which is the last really enabled
358 * tex unit, and put last stage on it
359 */
360
361
362 /* Build color & alpha pipelines */
363
364 used = 0;
365 state[used++] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) |
366 TEXPIPE_COLOR |
367 ENABLE_TEXOUTPUT_WRT_SEL |
368 TEXOP_OUTPUT_CURRENT |
369 DISABLE_TEX_CNTRL_STAGE |
370 TEXOP_MODIFY_PARMS |
371 blendop);
372 state[used++] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) |
373 TEXPIPE_ALPHA |
374 ENABLE_TEXOUTPUT_WRT_SEL |
375 TEXOP_OUTPUT_CURRENT |
376 TEXOP_MODIFY_PARMS |
377 ablendop);
378
379 for ( i = 0 ; i < numColorArgs ; i++ ) {
380 state[used++] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) |
381 tex_blend_rgb[i] | args_RGB[i]);
382 }
383
384 for ( i = 0 ; i < numAlphaArgs ; i++ ) {
385 state[used++] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) |
386 tex_blend_a[i] | args_A[i]);
387 }
388
389
390 if (need_factor)
391 return emit_factor( blendUnit, state, used, factor );
392 else
393 return used;
394 }
395
396
397 static void emit_texblend( i830ContextPtr i830, GLuint unit, GLuint blendUnit,
398 GLboolean last_stage )
399 {
400 struct gl_texture_unit *texUnit = &i830->intel.ctx.Texture.Unit[unit];
401 GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz;
402
403
404 if (0) fprintf(stderr, "%s unit %d\n", __FUNCTION__, unit);
405
406 /* Update i830->state.TexBlend
407 */
408 tmp_sz = i830SetTexEnvCombine(i830, texUnit->_CurrentCombine, blendUnit,
409 GetTexelOp(unit), tmp,
410 texUnit->EnvColor );
411
412 if (last_stage)
413 tmp[0] |= TEXOP_LAST_STAGE;
414
415 if (tmp_sz != i830->state.TexBlendWordsUsed[blendUnit] ||
416 memcmp( tmp, i830->state.TexBlend[blendUnit], tmp_sz * sizeof(GLuint))) {
417
418 I830_STATECHANGE( i830, I830_UPLOAD_TEXBLEND(blendUnit) );
419 memcpy( i830->state.TexBlend[blendUnit], tmp, tmp_sz * sizeof(GLuint));
420 i830->state.TexBlendWordsUsed[blendUnit] = tmp_sz;
421 }
422
423 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND(blendUnit), GL_TRUE);
424 }
425
426 static void emit_passthrough( i830ContextPtr i830 )
427 {
428 GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz;
429 GLuint unit = 0;
430
431 tmp_sz = pass_through( tmp, unit );
432 tmp[0] |= TEXOP_LAST_STAGE;
433
434 if (tmp_sz != i830->state.TexBlendWordsUsed[unit] ||
435 memcmp( tmp, i830->state.TexBlend[unit], tmp_sz * sizeof(GLuint))) {
436
437 I830_STATECHANGE( i830, I830_UPLOAD_TEXBLEND(unit) );
438 memcpy( i830->state.TexBlend[unit], tmp, tmp_sz * sizeof(GLuint));
439 i830->state.TexBlendWordsUsed[unit] = tmp_sz;
440 }
441
442 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND(unit), GL_TRUE);
443 }
444
445 void i830EmitTextureBlend( i830ContextPtr i830 )
446 {
447 GLcontext *ctx = &i830->intel.ctx;
448 GLuint unit, last_stage = 0, blendunit = 0;
449
450 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND_ALL, GL_FALSE);
451
452 if (ctx->Texture._EnabledUnits) {
453 for (unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++)
454 if (ctx->Texture.Unit[unit]._ReallyEnabled)
455 last_stage = unit;
456
457 for (unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++)
458 if (ctx->Texture.Unit[unit]._ReallyEnabled)
459 emit_texblend( i830, unit, blendunit++, last_stage == unit );
460 }
461 else {
462 emit_passthrough( i830 );
463 }
464 }
465