Home | History | Annotate | Download | only in i915
      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
     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
     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
     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
    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
    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
    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
    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