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_fixedfunc_texture_unit *texUnit =
392       &i830->intel.ctx.Texture.FixedFuncUnit[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