i830_texblend.c revision 35fd72756a05463568d94862f4fcd234903e1204
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 */
48static GLuint
49pass_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
74static GLuint
75emit_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
99static INLINE GLuint
100GetTexelOp(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 */
135GLuint
136i830SetTexEnvCombine(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
391static void
392emit_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
422static void
423emit_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
442void
443i830EmitTextureBlend(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}
463