X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fllvmpipe%2Flp_bld_blend.c;h=1feb415c9e5f5a3a4c5a97093d77d65d0e1c599e;hb=70048eb1e3bc155b2b6f3554e6a03fb239082f2d;hp=e070aac378df334049fe4ec2565746ff95e32235;hpb=1dd7bb17c7331f9ecd0bc830b61ada235a56fe6d;p=mesa.git diff --git a/src/gallium/drivers/llvmpipe/lp_bld_blend.c b/src/gallium/drivers/llvmpipe/lp_bld_blend.c index e070aac378d..1feb415c9e5 100644 --- a/src/gallium/drivers/llvmpipe/lp_bld_blend.c +++ b/src/gallium/drivers/llvmpipe/lp_bld_blend.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2009 VMware, Inc. + * Copyright 2012 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -25,293 +25,199 @@ * **************************************************************************/ - -/** - * @file - * Blend LLVM IR generation. - * - * This code is generic -- it should be able to cope both with floating point - * and integer inputs in AOS form. - * - * @author Jose Fonseca - */ - - #include "pipe/p_state.h" +#include "util/u_debug.h" -#include "lp_bld.h" -#include "lp_bld_type.h" -#include "lp_bld_const.h" -#include "lp_bld_arit.h" -#include "lp_bld_swizzle.h" +#include "gallivm/lp_bld_type.h" +#include "gallivm/lp_bld_arit.h" +#include "gallivm/lp_bld_const.h" +#include "gallivm/lp_bld_logic.h" +#include "gallivm/lp_bld_swizzle.h" +#include "gallivm/lp_bld_flow.h" +#include "gallivm/lp_bld_debug.h" +#include "lp_bld_blend.h" /** - * We may the same values several times, so we keep them here to avoid - * recomputing them. Also reusing the values allows us to do simplifications - * that LLVM optimization passes wouldn't normally be able to do. + * Is (a OP b) == (b OP a)? */ -struct lp_build_blend_context +boolean +lp_build_blend_func_commutative(unsigned func) { - struct lp_build_context base; - - LLVMValueRef src; - LLVMValueRef dst; - LLVMValueRef const_; - - LLVMValueRef inv_src; - LLVMValueRef inv_dst; - LLVMValueRef inv_const; - LLVMValueRef saturate; - - LLVMValueRef rgb_src_factor; - LLVMValueRef alpha_src_factor; - LLVMValueRef rgb_dst_factor; - LLVMValueRef alpha_dst_factor; -}; - - -static LLVMValueRef -lp_build_blend_factor_unswizzled(struct lp_build_blend_context *bld, - unsigned factor, - boolean alpha) -{ - switch (factor) { - case PIPE_BLENDFACTOR_ZERO: - return bld->base.zero; - case PIPE_BLENDFACTOR_ONE: - return bld->base.one; - case PIPE_BLENDFACTOR_SRC_COLOR: - case PIPE_BLENDFACTOR_SRC_ALPHA: - return bld->src; - case PIPE_BLENDFACTOR_DST_COLOR: - case PIPE_BLENDFACTOR_DST_ALPHA: - return bld->dst; - case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: - if(alpha) - return bld->base.one; - else { - if(!bld->inv_dst) - bld->inv_dst = lp_build_comp(&bld->base, bld->dst); - if(!bld->saturate) - bld->saturate = lp_build_min(&bld->base, bld->src, bld->inv_dst); - return bld->saturate; - } - case PIPE_BLENDFACTOR_CONST_COLOR: - case PIPE_BLENDFACTOR_CONST_ALPHA: - return bld->const_; - case PIPE_BLENDFACTOR_SRC1_COLOR: - case PIPE_BLENDFACTOR_SRC1_ALPHA: - /* TODO */ - assert(0); - return bld->base.zero; - case PIPE_BLENDFACTOR_INV_SRC_COLOR: - case PIPE_BLENDFACTOR_INV_SRC_ALPHA: - if(!bld->inv_src) - bld->inv_src = lp_build_comp(&bld->base, bld->src); - return bld->inv_src; - case PIPE_BLENDFACTOR_INV_DST_COLOR: - case PIPE_BLENDFACTOR_INV_DST_ALPHA: - if(!bld->inv_dst) - bld->inv_dst = lp_build_comp(&bld->base, bld->dst); - return bld->inv_dst; - case PIPE_BLENDFACTOR_INV_CONST_COLOR: - case PIPE_BLENDFACTOR_INV_CONST_ALPHA: - if(!bld->inv_const) - bld->inv_const = lp_build_comp(&bld->base, bld->const_); - return bld->inv_const; - case PIPE_BLENDFACTOR_INV_SRC1_COLOR: - case PIPE_BLENDFACTOR_INV_SRC1_ALPHA: - /* TODO */ - assert(0); - return bld->base.zero; + switch (func) { + case PIPE_BLEND_ADD: + case PIPE_BLEND_MIN: + case PIPE_BLEND_MAX: + return TRUE; + case PIPE_BLEND_SUBTRACT: + case PIPE_BLEND_REVERSE_SUBTRACT: + return FALSE; default: assert(0); - return bld->base.zero; + return TRUE; } } -enum lp_build_blend_swizzle { - LP_BUILD_BLEND_SWIZZLE_RGBA = 0, - LP_BUILD_BLEND_SWIZZLE_AAAA = 1, -}; - - /** - * How should we shuffle the base factor. + * Whether the blending functions are the reverse of each other. */ -static enum lp_build_blend_swizzle -lp_build_blend_factor_swizzle(unsigned factor) -{ - switch (factor) { - case PIPE_BLENDFACTOR_ONE: - case PIPE_BLENDFACTOR_ZERO: - case PIPE_BLENDFACTOR_SRC_COLOR: - case PIPE_BLENDFACTOR_DST_COLOR: - case PIPE_BLENDFACTOR_CONST_COLOR: - case PIPE_BLENDFACTOR_SRC1_COLOR: - case PIPE_BLENDFACTOR_INV_SRC_COLOR: - case PIPE_BLENDFACTOR_INV_DST_COLOR: - case PIPE_BLENDFACTOR_INV_CONST_COLOR: - case PIPE_BLENDFACTOR_INV_SRC1_COLOR: - return LP_BUILD_BLEND_SWIZZLE_RGBA; - case PIPE_BLENDFACTOR_SRC_ALPHA: - case PIPE_BLENDFACTOR_DST_ALPHA: - case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: - case PIPE_BLENDFACTOR_SRC1_ALPHA: - case PIPE_BLENDFACTOR_CONST_ALPHA: - case PIPE_BLENDFACTOR_INV_SRC_ALPHA: - case PIPE_BLENDFACTOR_INV_DST_ALPHA: - case PIPE_BLENDFACTOR_INV_CONST_ALPHA: - case PIPE_BLENDFACTOR_INV_SRC1_ALPHA: - return LP_BUILD_BLEND_SWIZZLE_AAAA; - default: - assert(0); - return LP_BUILD_BLEND_SWIZZLE_RGBA; - } -} - - -static LLVMValueRef -lp_build_blend_swizzle(struct lp_build_blend_context *bld, - LLVMValueRef rgb, - LLVMValueRef alpha, - enum lp_build_blend_swizzle rgb_swizzle, - unsigned alpha_swizzle) +boolean +lp_build_blend_func_reverse(unsigned rgb_func, unsigned alpha_func) { - if(rgb == alpha) { - if(rgb_swizzle == LP_BUILD_BLEND_SWIZZLE_RGBA) - return rgb; - if(rgb_swizzle == LP_BUILD_BLEND_SWIZZLE_AAAA) - return lp_build_broadcast_aos(&bld->base, rgb, alpha_swizzle); - } - else { - if(rgb_swizzle == LP_BUILD_BLEND_SWIZZLE_RGBA) { - boolean cond[4] = {0, 0, 0, 0}; - cond[alpha_swizzle] = 1; - return lp_build_select_aos(&bld->base, alpha, rgb, cond); - } - if(rgb_swizzle == LP_BUILD_BLEND_SWIZZLE_AAAA) { - unsigned char swizzle[4]; - swizzle[0] = alpha_swizzle; - swizzle[1] = alpha_swizzle; - swizzle[2] = alpha_swizzle; - swizzle[3] = alpha_swizzle; - swizzle[alpha_swizzle] += 4; - return lp_build_swizzle2_aos(&bld->base, rgb, alpha, swizzle); - } - } - assert(0); - return bld->base.undef; + if(rgb_func == alpha_func) + return FALSE; + if(rgb_func == PIPE_BLEND_SUBTRACT && alpha_func == PIPE_BLEND_REVERSE_SUBTRACT) + return TRUE; + if(rgb_func == PIPE_BLEND_REVERSE_SUBTRACT && alpha_func == PIPE_BLEND_SUBTRACT) + return TRUE; + return FALSE; } /** - * @sa http://www.opengl.org/sdk/docs/man/xhtml/glBlendFuncSeparate.xml + * Whether the blending factors are complementary of each other. */ -static LLVMValueRef -lp_build_blend_factor(struct lp_build_blend_context *bld, - LLVMValueRef factor1, - unsigned rgb_factor, - unsigned alpha_factor, - unsigned alpha_swizzle) +static inline boolean +lp_build_blend_factor_complementary(unsigned src_factor, unsigned dst_factor) { - LLVMValueRef rgb_factor_; - LLVMValueRef alpha_factor_; - LLVMValueRef factor2; - enum lp_build_blend_swizzle rgb_swizzle; - - rgb_factor_ = lp_build_blend_factor_unswizzled(bld, rgb_factor, FALSE); - alpha_factor_ = lp_build_blend_factor_unswizzled(bld, alpha_factor, TRUE); - - rgb_swizzle = lp_build_blend_factor_swizzle(rgb_factor); - - factor2 = lp_build_blend_swizzle(bld, rgb_factor_, alpha_factor_, rgb_swizzle, alpha_swizzle); - - return lp_build_mul(&bld->base, factor1, factor2); + return dst_factor == (src_factor ^ 0x10); } /** * @sa http://www.opengl.org/sdk/docs/man/xhtml/glBlendEquationSeparate.xml */ -static LLVMValueRef -lp_build_blend_func(struct lp_build_blend_context *bld, +LLVMValueRef +lp_build_blend_func(struct lp_build_context *bld, unsigned func, - LLVMValueRef term1, + LLVMValueRef term1, LLVMValueRef term2) { switch (func) { case PIPE_BLEND_ADD: - return lp_build_add(&bld->base, term1, term2); - break; + return lp_build_add(bld, term1, term2); case PIPE_BLEND_SUBTRACT: - return lp_build_sub(&bld->base, term1, term2); + return lp_build_sub(bld, term1, term2); case PIPE_BLEND_REVERSE_SUBTRACT: - return lp_build_sub(&bld->base, term2, term1); + return lp_build_sub(bld, term2, term1); case PIPE_BLEND_MIN: - return lp_build_min(&bld->base, term1, term2); + return lp_build_min(bld, term1, term2); case PIPE_BLEND_MAX: - return lp_build_max(&bld->base, term1, term2); + return lp_build_max(bld, term1, term2); default: assert(0); - return bld->base.zero; + return bld->zero; } } +/** + * Performs optimisations and blending independent of SoA/AoS + * + * @param func the blend function + * @param factor_src PIPE_BLENDFACTOR_xxx + * @param factor_dst PIPE_BLENDFACTOR_xxx + * @param src source rgba + * @param dst dest rgba + * @param src_factor src factor computed value + * @param dst_factor dst factor computed value + * @param not_alpha_dependent same factors accross all channels of src/dst + * + * not_alpha_dependent should be: + * SoA: always true as it is only one channel at a time + * AoS: rgb_src_factor == alpha_src_factor && rgb_dst_factor == alpha_dst_factor + * + * Note that pretty much every possible optimisation can only be done on non-unorm targets + * due to unorm values not going above 1.0 meaning factorisation can change results. + * e.g. (0.9 * 0.9) + (0.9 * 0.9) != 0.9 * (0.9 + 0.9) as result of + is always <= 1. + */ LLVMValueRef -lp_build_blend(LLVMBuilderRef builder, - const struct pipe_blend_state *blend, - union lp_type type, +lp_build_blend(struct lp_build_context *bld, + unsigned func, + unsigned factor_src, + unsigned factor_dst, LLVMValueRef src, LLVMValueRef dst, - LLVMValueRef const_, - unsigned alpha_swizzle) + LLVMValueRef src_factor, + LLVMValueRef dst_factor, + boolean not_alpha_dependent, + boolean optimise_only) { - struct lp_build_blend_context bld; - LLVMValueRef src_term; - LLVMValueRef dst_term; + LLVMValueRef result, src_term, dst_term; + + /* If we are not alpha dependent we can mess with the src/dst factors */ + if (not_alpha_dependent) { + if (lp_build_blend_factor_complementary(factor_src, factor_dst)) { + if (func == PIPE_BLEND_ADD) { + if (factor_src < factor_dst) { + return lp_build_lerp(bld, src_factor, dst, src, 0); + } else { + return lp_build_lerp(bld, dst_factor, src, dst, 0); + } + } else if(bld->type.floating && func == PIPE_BLEND_SUBTRACT) { + result = lp_build_add(bld, src, dst); + + if (factor_src < factor_dst) { + result = lp_build_mul(bld, result, src_factor); + return lp_build_sub(bld, result, dst); + } else { + result = lp_build_mul(bld, result, dst_factor); + return lp_build_sub(bld, src, result); + } + } else if(bld->type.floating && func == PIPE_BLEND_REVERSE_SUBTRACT) { + result = lp_build_add(bld, src, dst); + + if (factor_src < factor_dst) { + result = lp_build_mul(bld, result, src_factor); + return lp_build_sub(bld, dst, result); + } else { + result = lp_build_mul(bld, result, dst_factor); + return lp_build_sub(bld, result, src); + } + } + } - /* It makes no sense to blend unless values are normalized */ - assert(type.norm); + if (bld->type.floating && factor_src == factor_dst) { + if (func == PIPE_BLEND_ADD || + func == PIPE_BLEND_SUBTRACT || + func == PIPE_BLEND_REVERSE_SUBTRACT) { + LLVMValueRef result; + result = lp_build_blend_func(bld, func, src, dst); + return lp_build_mul(bld, result, src_factor); + } + } + } + + if (optimise_only) + return NULL; - /* Setup build context */ - memset(&bld, 0, sizeof bld); - bld.base.builder = builder; - bld.base.type = type; - bld.base.undef = lp_build_undef(type); - bld.base.zero = lp_build_zero(type); - bld.base.one = lp_build_one(type); - bld.src = src; - bld.dst = dst; - bld.const_ = const_; + src_term = lp_build_mul(bld, src, src_factor); + dst_term = lp_build_mul(bld, dst, dst_factor); + return lp_build_blend_func(bld, func, src_term, dst_term); +} - /* TODO: There are still a few optimization oportunities here. For certain - * combinations it is possible to reorder the operations and therefor saving - * some instructions. */ +void +lp_build_alpha_to_coverage(struct gallivm_state *gallivm, + struct lp_type type, + struct lp_build_mask_context *mask, + LLVMValueRef alpha, + boolean do_branch) +{ + struct lp_build_context bld; + LLVMValueRef test; + LLVMValueRef alpha_ref_value; - src_term = lp_build_blend_factor(&bld, src, blend->rgb_src_factor, blend->alpha_src_factor, alpha_swizzle); - dst_term = lp_build_blend_factor(&bld, dst, blend->rgb_dst_factor, blend->alpha_dst_factor, alpha_swizzle); + lp_build_context_init(&bld, gallivm, type); -#ifdef DEBUG - LLVMSetValueName(src_term, "src_term"); - LLVMSetValueName(dst_term, "dst_term"); -#endif + alpha_ref_value = lp_build_const_vec(gallivm, type, 0.5); - if(blend->rgb_func == blend->alpha_func) { - return lp_build_blend_func(&bld, blend->rgb_func, src_term, dst_term); - } - else { - /* Seperate RGB / A functions */ + test = lp_build_cmp(&bld, PIPE_FUNC_GREATER, alpha, alpha_ref_value); - LLVMValueRef rgb; - LLVMValueRef alpha; + lp_build_name(test, "alpha_to_coverage"); - rgb = lp_build_blend_func(&bld, blend->rgb_func, src_term, dst_term); - alpha = lp_build_blend_func(&bld, blend->alpha_func, src_term, dst_term); + lp_build_mask_update(mask, test); - return lp_build_blend_swizzle(&bld, rgb, alpha, LP_BUILD_BLEND_SWIZZLE_RGBA, alpha_swizzle); - } + if (do_branch) + lp_build_mask_check(mask); }