Home | History | Annotate | Download | only in llvmpipe
      1 /**************************************************************************
      2  *
      3  * Copyright 2012 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 "pipe/p_state.h"
     29 #include "util/u_debug.h"
     30 
     31 #include "gallivm/lp_bld_type.h"
     32 #include "gallivm/lp_bld_arit.h"
     33 
     34 #include "lp_bld_blend.h"
     35 
     36 /**
     37  * Is (a OP b) == (b OP a)?
     38  */
     39 boolean
     40 lp_build_blend_func_commutative(unsigned func)
     41 {
     42    switch (func) {
     43    case PIPE_BLEND_ADD:
     44    case PIPE_BLEND_MIN:
     45    case PIPE_BLEND_MAX:
     46       return TRUE;
     47    case PIPE_BLEND_SUBTRACT:
     48    case PIPE_BLEND_REVERSE_SUBTRACT:
     49       return FALSE;
     50    default:
     51       assert(0);
     52       return TRUE;
     53    }
     54 }
     55 
     56 
     57 /**
     58  * Whether the blending functions are the reverse of each other.
     59  */
     60 boolean
     61 lp_build_blend_func_reverse(unsigned rgb_func, unsigned alpha_func)
     62 {
     63    if(rgb_func == alpha_func)
     64       return FALSE;
     65    if(rgb_func == PIPE_BLEND_SUBTRACT && alpha_func == PIPE_BLEND_REVERSE_SUBTRACT)
     66       return TRUE;
     67    if(rgb_func == PIPE_BLEND_REVERSE_SUBTRACT && alpha_func == PIPE_BLEND_SUBTRACT)
     68       return TRUE;
     69    return FALSE;
     70 }
     71 
     72 
     73 /**
     74  * Whether the blending factors are complementary of each other.
     75  */
     76 static INLINE boolean
     77 lp_build_blend_factor_complementary(unsigned src_factor, unsigned dst_factor)
     78 {
     79    return dst_factor == (src_factor ^ 0x10);
     80 }
     81 
     82 
     83 /**
     84  * @sa http://www.opengl.org/sdk/docs/man/xhtml/glBlendEquationSeparate.xml
     85  */
     86 LLVMValueRef
     87 lp_build_blend_func(struct lp_build_context *bld,
     88                     unsigned func,
     89                     LLVMValueRef term1,
     90                     LLVMValueRef term2)
     91 {
     92    switch (func) {
     93    case PIPE_BLEND_ADD:
     94       return lp_build_add(bld, term1, term2);
     95    case PIPE_BLEND_SUBTRACT:
     96       return lp_build_sub(bld, term1, term2);
     97    case PIPE_BLEND_REVERSE_SUBTRACT:
     98       return lp_build_sub(bld, term2, term1);
     99    case PIPE_BLEND_MIN:
    100       return lp_build_min(bld, term1, term2);
    101    case PIPE_BLEND_MAX:
    102       return lp_build_max(bld, term1, term2);
    103    default:
    104       assert(0);
    105       return bld->zero;
    106    }
    107 }
    108 
    109 
    110 /**
    111  * Performs optimisations and blending independent of SoA/AoS
    112  *
    113  * @param func                   the blend function
    114  * @param factor_src             PIPE_BLENDFACTOR_xxx
    115  * @param factor_dst             PIPE_BLENDFACTOR_xxx
    116  * @param src                    source rgba
    117  * @param dst                    dest rgba
    118  * @param src_factor             src factor computed value
    119  * @param dst_factor             dst factor computed value
    120  * @param not_alpha_dependent    same factors accross all channels of src/dst
    121  *
    122  * not_alpha_dependent should be:
    123  *  SoA: always true as it is only one channel at a time
    124  *  AoS: rgb_src_factor == alpha_src_factor && rgb_dst_factor == alpha_dst_factor
    125  *
    126  * Note that pretty much every possible optimisation can only be done on non-unorm targets
    127  * due to unorm values not going above 1.0 meaning factorisation can change results.
    128  * e.g. (0.9 * 0.9) + (0.9 * 0.9) != 0.9 * (0.9 + 0.9) as result of + is always <= 1.
    129  */
    130 LLVMValueRef
    131 lp_build_blend(struct lp_build_context *bld,
    132                unsigned func,
    133                unsigned factor_src,
    134                unsigned factor_dst,
    135                LLVMValueRef src,
    136                LLVMValueRef dst,
    137                LLVMValueRef src_factor,
    138                LLVMValueRef dst_factor,
    139                boolean not_alpha_dependent,
    140                boolean optimise_only)
    141 {
    142    LLVMValueRef result, src_term, dst_term;
    143 
    144    /* If we are not alpha dependent we can mess with the src/dst factors */
    145    if (not_alpha_dependent) {
    146       if (lp_build_blend_factor_complementary(factor_src, factor_dst)) {
    147          if (func == PIPE_BLEND_ADD) {
    148             if (factor_src < factor_dst) {
    149                return lp_build_lerp(bld, src_factor, dst, src);
    150             } else {
    151                return lp_build_lerp(bld, dst_factor, src, dst);
    152             }
    153          } else if(bld->type.floating && func == PIPE_BLEND_SUBTRACT) {
    154             result = lp_build_add(bld, src, dst);
    155 
    156             if (factor_src < factor_dst) {
    157                result = lp_build_mul(bld, result, src_factor);
    158                return lp_build_sub(bld, result, dst);
    159             } else {
    160                result = lp_build_mul(bld, result, dst_factor);
    161                return lp_build_sub(bld, src, result);
    162             }
    163          } else if(bld->type.floating && func == PIPE_BLEND_REVERSE_SUBTRACT) {
    164             result = lp_build_add(bld, src, dst);
    165 
    166             if (factor_src < factor_dst) {
    167                result = lp_build_mul(bld, result, src_factor);
    168                return lp_build_sub(bld, dst, result);
    169             } else {
    170                result = lp_build_mul(bld, result, dst_factor);
    171                return lp_build_sub(bld, result, src);
    172             }
    173          }
    174       }
    175 
    176       if (bld->type.floating && factor_src == factor_dst) {
    177          if (func == PIPE_BLEND_ADD ||
    178              func == PIPE_BLEND_SUBTRACT ||
    179              func == PIPE_BLEND_REVERSE_SUBTRACT) {
    180             LLVMValueRef result;
    181             result = lp_build_blend_func(bld, func, src, dst);
    182             return lp_build_mul(bld, result, src_factor);
    183          }
    184       }
    185    }
    186 
    187    if (optimise_only)
    188       return NULL;
    189 
    190    src_term = lp_build_mul(bld, src, src_factor);
    191    dst_term = lp_build_mul(bld, dst, dst_factor);
    192    return lp_build_blend_func(bld, func, src_term, dst_term);
    193 }
    194