Merge branch '965-glsl'
[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
50 pass_through(GLuint * state, GLuint blendUnit)
51 {
52 state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) |
53 TEXPIPE_COLOR |
54 ENABLE_TEXOUTPUT_WRT_SEL |
55 TEXOP_OUTPUT_CURRENT |
56 DISABLE_TEX_CNTRL_STAGE |
57 TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS | TEXBLENDOP_ARG1);
58 state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) |
59 TEXPIPE_ALPHA |
60 ENABLE_TEXOUTPUT_WRT_SEL |
61 TEXOP_OUTPUT_CURRENT |
62 TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS | TEXBLENDOP_ARG1);
63 state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) |
64 TEXPIPE_COLOR |
65 TEXBLEND_ARG1 |
66 TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_CURRENT);
67 state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) |
68 TEXPIPE_ALPHA |
69 TEXBLEND_ARG1 |
70 TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_CURRENT);
71
72 return 4;
73 }
74
75 static GLuint
76 emit_factor(GLuint blendUnit, GLuint * state, GLuint count,
77 const GLfloat * factor)
78 {
79 GLubyte r, g, b, a;
80 GLuint col;
81
82 if (0)
83 fprintf(stderr, "emit constant %d: %.2f %.2f %.2f %.2f\n",
84 blendUnit, factor[0], factor[1], factor[2], factor[3]);
85
86 UNCLAMPED_FLOAT_TO_UBYTE(r, factor[0]);
87 UNCLAMPED_FLOAT_TO_UBYTE(g, factor[1]);
88 UNCLAMPED_FLOAT_TO_UBYTE(b, factor[2]);
89 UNCLAMPED_FLOAT_TO_UBYTE(a, factor[3]);
90
91 col = ((a << 24) | (r << 16) | (g << 8) | b);
92
93 state[count++] = _3DSTATE_COLOR_FACTOR_N_CMD(blendUnit);
94 state[count++] = col;
95
96 return count;
97 }
98
99
100 static INLINE GLuint
101 GetTexelOp(GLint unit)
102 {
103 switch (unit) {
104 case 0:
105 return TEXBLENDARG_TEXEL0;
106 case 1:
107 return TEXBLENDARG_TEXEL1;
108 case 2:
109 return TEXBLENDARG_TEXEL2;
110 case 3:
111 return TEXBLENDARG_TEXEL3;
112 default:
113 return TEXBLENDARG_TEXEL0;
114 }
115 }
116
117
118 /**
119 * Calculate the hardware instuctions to setup the current texture enviromnemt
120 * settings. Since \c gl_texture_unit::_CurrentCombine is used, both
121 * "classic" texture enviroments and GL_ARB_texture_env_combine type texture
122 * environments are treated identically.
123 *
124 * \todo
125 * This function should return \c GLboolean. When \c GL_FALSE is returned,
126 * it means that an environment is selected that the hardware cannot do. This
127 * is the way the Radeon and R200 drivers work.
128 *
129 * \todo
130 * Looking at i830_3d_regs.h, it seems the i830 can do part of
131 * GL_ATI_texture_env_combine3. It can handle using \c GL_ONE and
132 * \c GL_ZERO as combine inputs (which the code already supports). It can
133 * also handle the \c GL_MODULATE_ADD_ATI mode. Is it worth investigating
134 * partial support for the extension?
135 */
136 GLuint
137 i830SetTexEnvCombine(struct i830_context * i830,
138 const struct gl_tex_env_combine_state * combine,
139 GLint blendUnit,
140 GLuint texel_op, GLuint * state, 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 | TEXBLENDARG_INV_ARG);
263 break;
264 default:
265 return pass_through(state, blendUnit);
266 }
267 }
268
269
270 /* Need to knobble the alpha calculations of TEXBLENDOP_DOT4 to
271 * match the spec. Can't use DOT3 as it won't propogate values
272 * into alpha as required:
273 *
274 * Note - the global factor is set up with alpha == .5, so
275 * the alpha part of the DOT4 calculation should be zero.
276 */
277 if (combine->ModeRGB == GL_DOT3_RGBA_EXT ||
278 combine->ModeRGB == GL_DOT3_RGBA) {
279 ablendop = TEXBLENDOP_DOT4;
280 args_A[0] = TEXBLENDARG_FACTOR; /* the global factor */
281 args_A[1] = TEXBLENDARG_FACTOR;
282 args_A[2] = TEXBLENDARG_FACTOR;
283 }
284 else {
285 switch (combine->ModeA) {
286 case GL_REPLACE:
287 ablendop = TEXBLENDOP_ARG1;
288 break;
289 case GL_MODULATE:
290 ablendop = TEXBLENDOP_MODULATE;
291 break;
292 case GL_ADD:
293 ablendop = TEXBLENDOP_ADD;
294 break;
295 case GL_ADD_SIGNED:
296 ablendop = TEXBLENDOP_ADDSIGNED;
297 break;
298 case GL_INTERPOLATE:
299 ablendop = TEXBLENDOP_BLEND;
300 break;
301 case GL_SUBTRACT:
302 ablendop = TEXBLENDOP_SUBTRACT;
303 break;
304 default:
305 return pass_through(state, blendUnit);
306 }
307
308
309 ablendop |= (alpha_shift << TEXOP_SCALE_SHIFT);
310
311 /* Handle A args */
312 for (i = 0; i < 3; i++) {
313 switch (combine->SourceA[i]) {
314 case GL_TEXTURE:
315 args_A[i] = texel_op;
316 break;
317 case GL_TEXTURE0:
318 case GL_TEXTURE1:
319 case GL_TEXTURE2:
320 case GL_TEXTURE3:
321 args_A[i] = GetTexelOp(combine->SourceA[i] - GL_TEXTURE0);
322 break;
323 case GL_CONSTANT:
324 args_A[i] = TEXBLENDARG_FACTOR_N;
325 need_factor = 1;
326 break;
327 case GL_PRIMARY_COLOR:
328 args_A[i] = TEXBLENDARG_DIFFUSE;
329 break;
330 case GL_PREVIOUS:
331 args_A[i] = TEXBLENDARG_CURRENT;
332 break;
333 default:
334 return pass_through(state, blendUnit);
335 }
336
337 switch (combine->OperandA[i]) {
338 case GL_SRC_ALPHA:
339 args_A[i] |= 0;
340 break;
341 case GL_ONE_MINUS_SRC_ALPHA:
342 args_A[i] |= TEXBLENDARG_INV_ARG;
343 break;
344 default:
345 return pass_through(state, blendUnit);
346 }
347 }
348 }
349
350
351
352 /* Native Arg1 == Arg0 in GL_EXT_texture_env_combine spec */
353 /* Native Arg2 == Arg1 in GL_EXT_texture_env_combine spec */
354 /* Native Arg0 == Arg2 in GL_EXT_texture_env_combine spec */
355
356 /* When we render we need to figure out which is the last really enabled
357 * tex unit, and put last stage on it
358 */
359
360
361 /* Build color & alpha pipelines */
362
363 used = 0;
364 state[used++] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) |
365 TEXPIPE_COLOR |
366 ENABLE_TEXOUTPUT_WRT_SEL |
367 TEXOP_OUTPUT_CURRENT |
368 DISABLE_TEX_CNTRL_STAGE | TEXOP_MODIFY_PARMS | blendop);
369 state[used++] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) |
370 TEXPIPE_ALPHA |
371 ENABLE_TEXOUTPUT_WRT_SEL |
372 TEXOP_OUTPUT_CURRENT | TEXOP_MODIFY_PARMS | ablendop);
373
374 for (i = 0; i < numColorArgs; i++) {
375 state[used++] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) |
376 tex_blend_rgb[i] | args_RGB[i]);
377 }
378
379 for (i = 0; i < numAlphaArgs; i++) {
380 state[used++] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) |
381 tex_blend_a[i] | args_A[i]);
382 }
383
384
385 if (need_factor)
386 return emit_factor(blendUnit, state, used, factor);
387 else
388 return used;
389 }
390
391
392 static void
393 emit_texblend(struct i830_context *i830, GLuint unit, GLuint blendUnit,
394 GLboolean last_stage)
395 {
396 struct gl_texture_unit *texUnit = &i830->intel.ctx.Texture.Unit[unit];
397 GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz;
398
399
400 if (0)
401 fprintf(stderr, "%s unit %d\n", __FUNCTION__, unit);
402
403 /* Update i830->state.TexBlend
404 */
405 tmp_sz = i830SetTexEnvCombine(i830, texUnit->_CurrentCombine, blendUnit,
406 GetTexelOp(unit), tmp, texUnit->EnvColor);
407
408 if (last_stage)
409 tmp[0] |= TEXOP_LAST_STAGE;
410
411 if (tmp_sz != i830->state.TexBlendWordsUsed[blendUnit] ||
412 memcmp(tmp, i830->state.TexBlend[blendUnit],
413 tmp_sz * sizeof(GLuint))) {
414
415 I830_STATECHANGE(i830, I830_UPLOAD_TEXBLEND(blendUnit));
416 memcpy(i830->state.TexBlend[blendUnit], tmp, tmp_sz * sizeof(GLuint));
417 i830->state.TexBlendWordsUsed[blendUnit] = tmp_sz;
418 }
419
420 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND(blendUnit), GL_TRUE);
421 }
422
423 static void
424 emit_passthrough(struct i830_context *i830)
425 {
426 GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz;
427 GLuint unit = 0;
428
429 tmp_sz = pass_through(tmp, unit);
430 tmp[0] |= TEXOP_LAST_STAGE;
431
432 if (tmp_sz != i830->state.TexBlendWordsUsed[unit] ||
433 memcmp(tmp, i830->state.TexBlend[unit], tmp_sz * sizeof(GLuint))) {
434
435 I830_STATECHANGE(i830, I830_UPLOAD_TEXBLEND(unit));
436 memcpy(i830->state.TexBlend[unit], tmp, tmp_sz * sizeof(GLuint));
437 i830->state.TexBlendWordsUsed[unit] = tmp_sz;
438 }
439
440 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND(unit), GL_TRUE);
441 }
442
443 void
444 i830EmitTextureBlend(struct i830_context *i830)
445 {
446 GLcontext *ctx = &i830->intel.ctx;
447 GLuint unit, last_stage = 0, blendunit = 0;
448
449 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND_ALL, GL_FALSE);
450
451 if (ctx->Texture._EnabledUnits) {
452 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++)
453 if (ctx->Texture.Unit[unit]._ReallyEnabled)
454 last_stage = unit;
455
456 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++)
457 if (ctx->Texture.Unit[unit]._ReallyEnabled)
458 emit_texblend(i830, unit, blendunit++, last_stage == unit);
459 }
460 else {
461 emit_passthrough(i830);
462 }
463 }