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
lp_build_blend_func_commutative(unsigned func)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
lp_build_blend_func_reverse(unsigned rgb_func,unsigned alpha_func)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
lp_build_blend_factor_complementary(unsigned src_factor,unsigned dst_factor)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
lp_build_blend_func(struct lp_build_context * bld,unsigned func,LLVMValueRef term1,LLVMValueRef term2)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
lp_build_blend(struct lp_build_context * bld,unsigned func,unsigned factor_src,unsigned factor_dst,LLVMValueRef src,LLVMValueRef dst,LLVMValueRef src_factor,LLVMValueRef dst_factor,boolean not_alpha_dependent,boolean optimise_only)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