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