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