OSDN Git Service

i915/sync: Implement DRI2_Fence extension
[android-x86/external-mesa.git] / src / mesa / drivers / dri / i915 / i830_texblend.c
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 "util/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  */
45 static GLuint
46 pass_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
71 static GLuint
72 emit_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
96 static inline GLuint
97 GetTexelOp(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  */
132 GLuint
133 i830SetTexEnvCombine(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    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", __func__);
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_DOT4;
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       numAlphaArgs = 2;
277       args_A[0] = TEXBLENDARG_FACTOR;   /* the global factor */
278       args_A[1] = TEXBLENDARG_FACTOR;
279       args_A[2] = TEXBLENDARG_FACTOR;
280    }
281    else {
282       switch (combine->ModeA) {
283       case GL_REPLACE:
284          ablendop = TEXBLENDOP_ARG1;
285          break;
286       case GL_MODULATE:
287          ablendop = TEXBLENDOP_MODULATE;
288          break;
289       case GL_ADD:
290          ablendop = TEXBLENDOP_ADD;
291          break;
292       case GL_ADD_SIGNED:
293          ablendop = TEXBLENDOP_ADDSIGNED;
294          break;
295       case GL_INTERPOLATE:
296          ablendop = TEXBLENDOP_BLEND;
297          break;
298       case GL_SUBTRACT:
299          ablendop = TEXBLENDOP_SUBTRACT;
300          break;
301       default:
302          return pass_through(state, blendUnit);
303       }
304
305
306       ablendop |= (alpha_shift << TEXOP_SCALE_SHIFT);
307
308       /* Handle A args */
309       for (i = 0; i < 3; i++) {
310          switch (combine->SourceA[i]) {
311          case GL_TEXTURE:
312             args_A[i] = texel_op;
313             break;
314          case GL_TEXTURE0:
315          case GL_TEXTURE1:
316          case GL_TEXTURE2:
317          case GL_TEXTURE3:
318             args_A[i] = GetTexelOp(combine->SourceA[i] - GL_TEXTURE0);
319             break;
320          case GL_CONSTANT:
321             args_A[i] = TEXBLENDARG_FACTOR_N;
322             need_factor = 1;
323             break;
324          case GL_PRIMARY_COLOR:
325             args_A[i] = TEXBLENDARG_DIFFUSE;
326             break;
327          case GL_PREVIOUS:
328             args_A[i] = TEXBLENDARG_CURRENT;
329             break;
330          default:
331             return pass_through(state, blendUnit);
332          }
333
334          switch (combine->OperandA[i]) {
335          case GL_SRC_ALPHA:
336             args_A[i] |= 0;
337             break;
338          case GL_ONE_MINUS_SRC_ALPHA:
339             args_A[i] |= TEXBLENDARG_INV_ARG;
340             break;
341          default:
342             return pass_through(state, blendUnit);
343          }
344       }
345    }
346
347
348
349    /* Native Arg1 == Arg0 in GL_EXT_texture_env_combine spec */
350    /* Native Arg2 == Arg1 in GL_EXT_texture_env_combine spec */
351    /* Native Arg0 == Arg2 in GL_EXT_texture_env_combine spec */
352
353    /* When we render we need to figure out which is the last really enabled
354     * tex unit, and put last stage on it
355     */
356
357
358    /* Build color & alpha pipelines */
359
360    used = 0;
361    state[used++] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) |
362                     TEXPIPE_COLOR |
363                     ENABLE_TEXOUTPUT_WRT_SEL |
364                     TEXOP_OUTPUT_CURRENT |
365                     DISABLE_TEX_CNTRL_STAGE | TEXOP_MODIFY_PARMS | blendop);
366    state[used++] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) |
367                     TEXPIPE_ALPHA |
368                     ENABLE_TEXOUTPUT_WRT_SEL |
369                     TEXOP_OUTPUT_CURRENT | TEXOP_MODIFY_PARMS | ablendop);
370
371    for (i = 0; i < numColorArgs; i++) {
372       state[used++] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) |
373                        tex_blend_rgb[i] | args_RGB[i]);
374    }
375
376    for (i = 0; i < numAlphaArgs; i++) {
377       state[used++] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) |
378                        tex_blend_a[i] | args_A[i]);
379    }
380
381
382    if (need_factor)
383       return emit_factor(blendUnit, state, used, factor);
384    else
385       return used;
386 }
387
388
389 static void
390 emit_texblend(struct i830_context *i830, GLuint unit, GLuint blendUnit,
391               bool last_stage)
392 {
393    struct gl_texture_unit *texUnit = &i830->intel.ctx.Texture.Unit[unit];
394    GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz;
395
396
397    if (0)
398       fprintf(stderr, "%s unit %d\n", __func__, unit);
399
400    /* Update i830->state.TexBlend
401     */
402    tmp_sz = i830SetTexEnvCombine(i830, texUnit->_CurrentCombine, blendUnit,
403                                  GetTexelOp(unit), tmp, texUnit->EnvColor);
404
405    if (last_stage)
406       tmp[0] |= TEXOP_LAST_STAGE;
407
408    if (tmp_sz != i830->state.TexBlendWordsUsed[blendUnit] ||
409        memcmp(tmp, i830->state.TexBlend[blendUnit],
410               tmp_sz * sizeof(GLuint))) {
411
412       I830_STATECHANGE(i830, I830_UPLOAD_TEXBLEND(blendUnit));
413       memcpy(i830->state.TexBlend[blendUnit], tmp, tmp_sz * sizeof(GLuint));
414       i830->state.TexBlendWordsUsed[blendUnit] = tmp_sz;
415    }
416
417    I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND(blendUnit), true);
418 }
419
420 static void
421 emit_passthrough(struct i830_context *i830)
422 {
423    GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz;
424    GLuint unit = 0;
425
426    tmp_sz = pass_through(tmp, unit);
427    tmp[0] |= TEXOP_LAST_STAGE;
428
429    if (tmp_sz != i830->state.TexBlendWordsUsed[unit] ||
430        memcmp(tmp, i830->state.TexBlend[unit], tmp_sz * sizeof(GLuint))) {
431
432       I830_STATECHANGE(i830, I830_UPLOAD_TEXBLEND(unit));
433       memcpy(i830->state.TexBlend[unit], tmp, tmp_sz * sizeof(GLuint));
434       i830->state.TexBlendWordsUsed[unit] = tmp_sz;
435    }
436
437    I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND(unit), true);
438 }
439
440 void
441 i830EmitTextureBlend(struct i830_context *i830)
442 {
443    struct gl_context *ctx = &i830->intel.ctx;
444    GLuint unit, blendunit = 0;
445
446    I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND_ALL, false);
447
448    if (ctx->Texture._MaxEnabledTexImageUnit != -1) {
449       for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++)
450          if (ctx->Texture.Unit[unit]._Current)
451             emit_texblend(i830, unit, blendunit++,
452                           unit == ctx->Texture._MaxEnabledTexImageUnit);
453    } else {
454       emit_passthrough(i830);
455    }
456 }