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 "main/glheader.h"
29#include "main/macros.h"
30#include "main/mtypes.h"
31#include "main/simple_list.h"
32#include "main/enums.h"
33#include "main/mm.h"
34
35#include "intel_screen.h"
36#include "intel_tex.h"
37
38#include "i830_context.h"
39#include "i830_reg.h"
40
41
42/* ================================================================
43 * Texture combine functions
44 */
45static GLuint
46pass_through(GLuint * state, GLuint blendUnit)
47{
48   state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) |
49               TEXPIPE_COLOR |
50               ENABLE_TEXOUTPUT_WRT_SEL |
51               TEXOP_OUTPUT_CURRENT |
52               DISABLE_TEX_CNTRL_STAGE |
53               TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS | TEXBLENDOP_ARG1);
54   state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) |
55               TEXPIPE_ALPHA |
56               ENABLE_TEXOUTPUT_WRT_SEL |
57               TEXOP_OUTPUT_CURRENT |
58               TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS | TEXBLENDOP_ARG1);
59   state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) |
60               TEXPIPE_COLOR |
61               TEXBLEND_ARG1 |
62               TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_CURRENT);
63   state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) |
64               TEXPIPE_ALPHA |
65               TEXBLEND_ARG1 |
66               TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_CURRENT);
67
68   return 4;
69}
70
71static GLuint
72emit_factor(GLuint blendUnit, GLuint * state, GLuint count,
73            const GLfloat * factor)
74{
75   GLubyte r, g, b, a;
76   GLuint col;
77
78   if (0)
79      fprintf(stderr, "emit constant %d: %.2f %.2f %.2f %.2f\n",
80              blendUnit, factor[0], factor[1], factor[2], factor[3]);
81
82   UNCLAMPED_FLOAT_TO_UBYTE(r, factor[0]);
83   UNCLAMPED_FLOAT_TO_UBYTE(g, factor[1]);
84   UNCLAMPED_FLOAT_TO_UBYTE(b, factor[2]);
85   UNCLAMPED_FLOAT_TO_UBYTE(a, factor[3]);
86
87   col = ((a << 24) | (r << 16) | (g << 8) | b);
88
89   state[count++] = _3DSTATE_COLOR_FACTOR_N_CMD(blendUnit);
90   state[count++] = col;
91
92   return count;
93}
94
95
96static INLINE GLuint
97GetTexelOp(GLint unit)
98{
99   switch (unit) {
100   case 0:
101      return TEXBLENDARG_TEXEL0;
102   case 1:
103      return TEXBLENDARG_TEXEL1;
104   case 2:
105      return TEXBLENDARG_TEXEL2;
106   case 3:
107      return TEXBLENDARG_TEXEL3;
108   default:
109      return TEXBLENDARG_TEXEL0;
110   }
111}
112
113
114/**
115 * Calculate the hardware instuctions to setup the current texture enviromnemt
116 * settings.  Since \c gl_texture_unit::_CurrentCombine is used, both
117 * "classic" texture enviroments and GL_ARB_texture_env_combine type texture
118 * environments are treated identically.
119 *
120 * \todo
121 * This function should return \c bool.  When \c false is returned,
122 * it means that an environment is selected that the hardware cannot do.  This
123 * is the way the Radeon and R200 drivers work.
124 *
125 * \todo
126 * Looking at i830_3d_regs.h, it seems the i830 can do part of
127 * GL_ATI_texture_env_combine3.  It can handle using \c GL_ONE and
128 * \c GL_ZERO as combine inputs (which the code already supports).  It can
129 * also handle the \c GL_MODULATE_ADD_ATI mode.  Is it worth investigating
130 * partial support for the extension?
131 */
132GLuint
133i830SetTexEnvCombine(struct i830_context * i830,
134                     const struct gl_tex_env_combine_state * combine,
135                     GLint blendUnit,
136                     GLuint texel_op, GLuint * state, const GLfloat * factor)
137{
138   const GLuint numColorArgs = combine->_NumArgsRGB;
139   const GLuint numAlphaArgs = combine->_NumArgsA;
140
141   GLuint blendop;
142   GLuint ablendop;
143   GLuint args_RGB[3];
144   GLuint args_A[3];
145   GLuint rgb_shift;
146   GLuint alpha_shift;
147   bool need_factor = 0;
148   int i;
149   unsigned used;
150   static const GLuint tex_blend_rgb[3] = {
151      TEXPIPE_COLOR | TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS,
152      TEXPIPE_COLOR | TEXBLEND_ARG2 | TEXBLENDARG_MODIFY_PARMS,
153      TEXPIPE_COLOR | TEXBLEND_ARG0 | TEXBLENDARG_MODIFY_PARMS,
154   };
155   static const GLuint tex_blend_a[3] = {
156      TEXPIPE_ALPHA | TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS,
157      TEXPIPE_ALPHA | TEXBLEND_ARG2 | TEXBLENDARG_MODIFY_PARMS,
158      TEXPIPE_ALPHA | TEXBLEND_ARG0 | TEXBLENDARG_MODIFY_PARMS,
159   };
160
161   if (INTEL_DEBUG & DEBUG_TEXTURE)
162      fprintf(stderr, "%s\n", __FUNCTION__);
163
164
165   /* The EXT version of the DOT3 extension does not support the
166    * scale factor, but the ARB version (and the version in OpenGL
167    * 1.3) does.
168    */
169   switch (combine->ModeRGB) {
170   case GL_DOT3_RGB_EXT:
171      alpha_shift = combine->ScaleShiftA;
172      rgb_shift = 0;
173      break;
174
175   case GL_DOT3_RGBA_EXT:
176      alpha_shift = 0;
177      rgb_shift = 0;
178      break;
179
180   default:
181      rgb_shift = combine->ScaleShiftRGB;
182      alpha_shift = combine->ScaleShiftA;
183      break;
184   }
185
186
187   switch (combine->ModeRGB) {
188   case GL_REPLACE:
189      blendop = TEXBLENDOP_ARG1;
190      break;
191   case GL_MODULATE:
192      blendop = TEXBLENDOP_MODULATE;
193      break;
194   case GL_ADD:
195      blendop = TEXBLENDOP_ADD;
196      break;
197   case GL_ADD_SIGNED:
198      blendop = TEXBLENDOP_ADDSIGNED;
199      break;
200   case GL_INTERPOLATE:
201      blendop = TEXBLENDOP_BLEND;
202      break;
203   case GL_SUBTRACT:
204      blendop = TEXBLENDOP_SUBTRACT;
205      break;
206   case GL_DOT3_RGB_EXT:
207   case GL_DOT3_RGB:
208      blendop = TEXBLENDOP_DOT3;
209      break;
210   case GL_DOT3_RGBA_EXT:
211   case GL_DOT3_RGBA:
212      blendop = TEXBLENDOP_DOT3;
213      break;
214   default:
215      return pass_through(state, blendUnit);
216   }
217
218   blendop |= (rgb_shift << TEXOP_SCALE_SHIFT);
219
220
221   /* Handle RGB args */
222   for (i = 0; i < 3; i++) {
223      switch (combine->SourceRGB[i]) {
224      case GL_TEXTURE:
225         args_RGB[i] = texel_op;
226         break;
227      case GL_TEXTURE0:
228      case GL_TEXTURE1:
229      case GL_TEXTURE2:
230      case GL_TEXTURE3:
231         args_RGB[i] = GetTexelOp(combine->SourceRGB[i] - GL_TEXTURE0);
232         break;
233      case GL_CONSTANT:
234         args_RGB[i] = TEXBLENDARG_FACTOR_N;
235         need_factor = 1;
236         break;
237      case GL_PRIMARY_COLOR:
238         args_RGB[i] = TEXBLENDARG_DIFFUSE;
239         break;
240      case GL_PREVIOUS:
241         args_RGB[i] = TEXBLENDARG_CURRENT;
242         break;
243      default:
244         return pass_through(state, blendUnit);
245      }
246
247      switch (combine->OperandRGB[i]) {
248      case GL_SRC_COLOR:
249         args_RGB[i] |= 0;
250         break;
251      case GL_ONE_MINUS_SRC_COLOR:
252         args_RGB[i] |= TEXBLENDARG_INV_ARG;
253         break;
254      case GL_SRC_ALPHA:
255         args_RGB[i] |= TEXBLENDARG_REPLICATE_ALPHA;
256         break;
257      case GL_ONE_MINUS_SRC_ALPHA:
258         args_RGB[i] |= (TEXBLENDARG_REPLICATE_ALPHA | TEXBLENDARG_INV_ARG);
259         break;
260      default:
261         return pass_through(state, blendUnit);
262      }
263   }
264
265
266   /* Need to knobble the alpha calculations of TEXBLENDOP_DOT4 to
267    * match the spec.  Can't use DOT3 as it won't propogate values
268    * into alpha as required:
269    *
270    * Note - the global factor is set up with alpha == .5, so
271    * the alpha part of the DOT4 calculation should be zero.
272    */
273   if (combine->ModeRGB == GL_DOT3_RGBA_EXT ||
274       combine->ModeRGB == GL_DOT3_RGBA) {
275      ablendop = TEXBLENDOP_DOT4;
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
388static void
389emit_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", __FUNCTION__, 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
419static void
420emit_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
439void
440i830EmitTextureBlend(struct i830_context *i830)
441{
442   struct gl_context *ctx = &i830->intel.ctx;
443   GLuint unit, last_stage = 0, blendunit = 0;
444
445   I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND_ALL, false);
446
447   if (ctx->Texture._EnabledUnits) {
448      for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++)
449         if (ctx->Texture.Unit[unit]._ReallyEnabled)
450            last_stage = unit;
451
452      for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++)
453         if (ctx->Texture.Unit[unit]._ReallyEnabled)
454            emit_texblend(i830, unit, blendunit++, last_stage == unit);
455   }
456   else {
457      emit_passthrough(i830);
458   }
459}
460