Home | History | Annotate | Download | only in llvmpipe
      1 /**************************************************************************
      2  *
      3  * Copyright 2009 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 
     29 /**
     30  * @file
     31  * Blend LLVM IR generation -- AoS layout.
     32  *
     33  * AoS blending is in general much slower than SoA, but there are some cases
     34  * where it might be faster. In particular, if a pixel is rendered only once
     35  * then the overhead of tiling and untiling will dominate over the speedup that
     36  * SoA gives. So we might want to detect such cases and fallback to AoS in the
     37  * future, but for now this function is here for historical/benchmarking
     38  * purposes.
     39  *
     40  * Run lp_blend_test after any change to this file.
     41  *
     42  * @author Jose Fonseca <jfonseca (at) vmware.com>
     43  */
     44 
     45 
     46 #include "pipe/p_state.h"
     47 #include "util/u_debug.h"
     48 #include "util/u_format.h"
     49 
     50 #include "gallivm/lp_bld_type.h"
     51 #include "gallivm/lp_bld_const.h"
     52 #include "gallivm/lp_bld_arit.h"
     53 #include "gallivm/lp_bld_logic.h"
     54 #include "gallivm/lp_bld_swizzle.h"
     55 #include "gallivm/lp_bld_bitarit.h"
     56 #include "gallivm/lp_bld_debug.h"
     57 
     58 #include "lp_bld_blend.h"
     59 
     60 
     61 /**
     62  * We may the same values several times, so we keep them here to avoid
     63  * recomputing them. Also reusing the values allows us to do simplifications
     64  * that LLVM optimization passes wouldn't normally be able to do.
     65  */
     66 struct lp_build_blend_aos_context
     67 {
     68    struct lp_build_context base;
     69 
     70    LLVMValueRef src;
     71    LLVMValueRef dst;
     72    LLVMValueRef const_;
     73 
     74    LLVMValueRef inv_src;
     75    LLVMValueRef inv_dst;
     76    LLVMValueRef inv_const;
     77    LLVMValueRef saturate;
     78 
     79    LLVMValueRef rgb_src_factor;
     80    LLVMValueRef alpha_src_factor;
     81    LLVMValueRef rgb_dst_factor;
     82    LLVMValueRef alpha_dst_factor;
     83 };
     84 
     85 
     86 static LLVMValueRef
     87 lp_build_blend_factor_unswizzled(struct lp_build_blend_aos_context *bld,
     88                                  unsigned factor,
     89                                  boolean alpha)
     90 {
     91    switch (factor) {
     92    case PIPE_BLENDFACTOR_ZERO:
     93       return bld->base.zero;
     94    case PIPE_BLENDFACTOR_ONE:
     95       return bld->base.one;
     96    case PIPE_BLENDFACTOR_SRC_COLOR:
     97    case PIPE_BLENDFACTOR_SRC_ALPHA:
     98       return bld->src;
     99    case PIPE_BLENDFACTOR_DST_COLOR:
    100    case PIPE_BLENDFACTOR_DST_ALPHA:
    101       return bld->dst;
    102    case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
    103       if(alpha)
    104          return bld->base.one;
    105       else {
    106          if(!bld->inv_dst)
    107             bld->inv_dst = lp_build_comp(&bld->base, bld->dst);
    108          if(!bld->saturate)
    109             bld->saturate = lp_build_min(&bld->base, bld->src, bld->inv_dst);
    110          return bld->saturate;
    111       }
    112    case PIPE_BLENDFACTOR_CONST_COLOR:
    113    case PIPE_BLENDFACTOR_CONST_ALPHA:
    114       return bld->const_;
    115    case PIPE_BLENDFACTOR_SRC1_COLOR:
    116    case PIPE_BLENDFACTOR_SRC1_ALPHA:
    117       /* TODO */
    118       assert(0);
    119       return bld->base.zero;
    120    case PIPE_BLENDFACTOR_INV_SRC_COLOR:
    121    case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
    122       if(!bld->inv_src)
    123          bld->inv_src = lp_build_comp(&bld->base, bld->src);
    124       return bld->inv_src;
    125    case PIPE_BLENDFACTOR_INV_DST_COLOR:
    126    case PIPE_BLENDFACTOR_INV_DST_ALPHA:
    127       if(!bld->inv_dst)
    128          bld->inv_dst = lp_build_comp(&bld->base, bld->dst);
    129       return bld->inv_dst;
    130    case PIPE_BLENDFACTOR_INV_CONST_COLOR:
    131    case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
    132       if(!bld->inv_const)
    133          bld->inv_const = lp_build_comp(&bld->base, bld->const_);
    134       return bld->inv_const;
    135    case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
    136    case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
    137       /* TODO */
    138       assert(0);
    139       return bld->base.zero;
    140    default:
    141       assert(0);
    142       return bld->base.zero;
    143    }
    144 }
    145 
    146 
    147 enum lp_build_blend_swizzle {
    148    LP_BUILD_BLEND_SWIZZLE_RGBA = 0,
    149    LP_BUILD_BLEND_SWIZZLE_AAAA = 1
    150 };
    151 
    152 
    153 /**
    154  * How should we shuffle the base factor.
    155  */
    156 static enum lp_build_blend_swizzle
    157 lp_build_blend_factor_swizzle(unsigned factor)
    158 {
    159    switch (factor) {
    160    case PIPE_BLENDFACTOR_ONE:
    161    case PIPE_BLENDFACTOR_ZERO:
    162    case PIPE_BLENDFACTOR_SRC_COLOR:
    163    case PIPE_BLENDFACTOR_DST_COLOR:
    164    case PIPE_BLENDFACTOR_CONST_COLOR:
    165    case PIPE_BLENDFACTOR_SRC1_COLOR:
    166    case PIPE_BLENDFACTOR_INV_SRC_COLOR:
    167    case PIPE_BLENDFACTOR_INV_DST_COLOR:
    168    case PIPE_BLENDFACTOR_INV_CONST_COLOR:
    169    case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
    170       return LP_BUILD_BLEND_SWIZZLE_RGBA;
    171    case PIPE_BLENDFACTOR_SRC_ALPHA:
    172    case PIPE_BLENDFACTOR_DST_ALPHA:
    173    case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
    174    case PIPE_BLENDFACTOR_SRC1_ALPHA:
    175    case PIPE_BLENDFACTOR_CONST_ALPHA:
    176    case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
    177    case PIPE_BLENDFACTOR_INV_DST_ALPHA:
    178    case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
    179    case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
    180       return LP_BUILD_BLEND_SWIZZLE_AAAA;
    181    default:
    182       assert(0);
    183       return LP_BUILD_BLEND_SWIZZLE_RGBA;
    184    }
    185 }
    186 
    187 
    188 static LLVMValueRef
    189 lp_build_blend_swizzle(struct lp_build_blend_aos_context *bld,
    190                        LLVMValueRef rgb,
    191                        LLVMValueRef alpha,
    192                        enum lp_build_blend_swizzle rgb_swizzle,
    193                        unsigned alpha_swizzle)
    194 {
    195    LLVMValueRef swizzled_rgb;
    196 
    197    switch (rgb_swizzle) {
    198    case LP_BUILD_BLEND_SWIZZLE_RGBA:
    199       swizzled_rgb = rgb;
    200       break;
    201    case LP_BUILD_BLEND_SWIZZLE_AAAA:
    202       swizzled_rgb = lp_build_swizzle_scalar_aos(&bld->base, rgb, alpha_swizzle);
    203       break;
    204    default:
    205       assert(0);
    206       swizzled_rgb = bld->base.undef;
    207    }
    208 
    209    if (rgb != alpha) {
    210       swizzled_rgb = lp_build_select_aos(&bld->base, 1 << alpha_swizzle,
    211                                          alpha, swizzled_rgb);
    212    }
    213 
    214    return swizzled_rgb;
    215 }
    216 
    217 
    218 /**
    219  * @sa http://www.opengl.org/sdk/docs/man/xhtml/glBlendFuncSeparate.xml
    220  */
    221 static LLVMValueRef
    222 lp_build_blend_factor(struct lp_build_blend_aos_context *bld,
    223                       unsigned rgb_factor,
    224                       unsigned alpha_factor,
    225                       unsigned alpha_swizzle)
    226 {
    227    LLVMValueRef rgb_factor_, alpha_factor_;
    228    enum lp_build_blend_swizzle rgb_swizzle;
    229 
    230    rgb_factor_ = lp_build_blend_factor_unswizzled(bld, rgb_factor, FALSE);
    231 
    232    if (alpha_swizzle != UTIL_FORMAT_SWIZZLE_NONE) {
    233       rgb_swizzle   = lp_build_blend_factor_swizzle(rgb_factor);
    234       alpha_factor_ = lp_build_blend_factor_unswizzled(bld, alpha_factor, TRUE);
    235       return lp_build_blend_swizzle(bld, rgb_factor_, alpha_factor_, rgb_swizzle, alpha_swizzle);
    236    } else {
    237       return rgb_factor_;
    238    }
    239 }
    240 
    241 
    242 /**
    243  * Performs blending of src and dst pixels
    244  *
    245  * @param blend         the blend state of the shader variant
    246  * @param cbuf_format   format of the colour buffer
    247  * @param type          data type of the pixel vector
    248  * @param rt            rt number
    249  * @param src           blend src
    250  * @param dst           blend dst
    251  * @param mask          optional mask to apply to the blending result
    252  * @param const_        const blend color
    253  * @param swizzle       swizzle values for RGBA
    254  *
    255  * @return the result of blending src and dst
    256  */
    257 LLVMValueRef
    258 lp_build_blend_aos(struct gallivm_state *gallivm,
    259                    const struct pipe_blend_state *blend,
    260                    const enum pipe_format *cbuf_format,
    261                    struct lp_type type,
    262                    unsigned rt,
    263                    LLVMValueRef src,
    264                    LLVMValueRef dst,
    265                    LLVMValueRef mask,
    266                    LLVMValueRef const_,
    267                    const unsigned char swizzle[4])
    268 {
    269    const struct pipe_rt_blend_state * state = &blend->rt[rt];
    270    struct lp_build_blend_aos_context bld;
    271    LLVMValueRef src_factor, dst_factor;
    272    LLVMValueRef result;
    273    unsigned alpha_swizzle = swizzle[3];
    274    boolean fullcolormask;
    275 
    276    /* Setup build context */
    277    memset(&bld, 0, sizeof bld);
    278    lp_build_context_init(&bld.base, gallivm, type);
    279    bld.src = src;
    280    bld.dst = dst;
    281    bld.const_ = const_;
    282 
    283    if (swizzle[3] > UTIL_FORMAT_SWIZZLE_W || swizzle[3] == swizzle[0])
    284       alpha_swizzle = UTIL_FORMAT_SWIZZLE_NONE;
    285 
    286    if (!state->blend_enable) {
    287       result = src;
    288    } else {
    289       boolean rgb_alpha_same = state->rgb_src_factor == state->rgb_dst_factor && state->alpha_src_factor == state->alpha_dst_factor;
    290       assert(rgb_alpha_same || alpha_swizzle != UTIL_FORMAT_SWIZZLE_NONE);
    291 
    292       src_factor = lp_build_blend_factor(&bld, state->rgb_src_factor,
    293                                          state->alpha_src_factor, alpha_swizzle);
    294       dst_factor = lp_build_blend_factor(&bld, state->rgb_dst_factor,
    295                                          state->alpha_dst_factor, alpha_swizzle);
    296 
    297       result = lp_build_blend(&bld.base,
    298                               state->rgb_func,
    299                               state->rgb_src_factor,
    300                               state->rgb_dst_factor,
    301                               src,
    302                               dst,
    303                               src_factor,
    304                               dst_factor,
    305                               rgb_alpha_same,
    306                               false);
    307 
    308       if(state->rgb_func != state->alpha_func && alpha_swizzle != UTIL_FORMAT_SWIZZLE_NONE) {
    309          LLVMValueRef alpha;
    310 
    311          alpha = lp_build_blend(&bld.base,
    312                                 state->alpha_func,
    313                                 state->alpha_src_factor,
    314                                 state->alpha_dst_factor,
    315                                 src,
    316                                 dst,
    317                                 src_factor,
    318                                 dst_factor,
    319                                 rgb_alpha_same,
    320                                 false);
    321 
    322          result = lp_build_blend_swizzle(&bld,
    323                                          result,
    324                                          alpha,
    325                                          LP_BUILD_BLEND_SWIZZLE_RGBA,
    326                                          alpha_swizzle);
    327       }
    328    }
    329 
    330    /* Check if color mask is necessary */
    331    fullcolormask = util_format_colormask_full(util_format_description(cbuf_format[rt]), state->colormask);
    332 
    333    if (!fullcolormask) {
    334       LLVMValueRef color_mask;
    335 
    336       color_mask = lp_build_const_mask_aos_swizzled(gallivm, bld.base.type, state->colormask, swizzle);
    337       lp_build_name(color_mask, "color_mask");
    338 
    339       /* Combine with input mask if necessary */
    340       if (mask) {
    341          mask = lp_build_and(&bld.base, color_mask, mask);
    342       } else {
    343          mask = color_mask;
    344       }
    345    }
    346 
    347    /* Apply mask, if one exists */
    348    if (mask) {
    349       result = lp_build_select(&bld.base, mask, result, dst);
    350    }
    351 
    352    return result;
    353 }
    354