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