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