Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / drivers / llvmpipe / lp_bld_blend_aos.c
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@vmware.com>
43  */
44
45
46 #include "pipe/p_state.h"
47 #include "util/u_debug.h"
48
49 #include "gallivm/lp_bld_type.h"
50 #include "gallivm/lp_bld_const.h"
51 #include "gallivm/lp_bld_arit.h"
52 #include "gallivm/lp_bld_logic.h"
53 #include "gallivm/lp_bld_swizzle.h"
54 #include "gallivm/lp_bld_debug.h"
55
56 #include "lp_bld_blend.h"
57
58
59 /**
60  * We may the same values several times, so we keep them here to avoid
61  * recomputing them. Also reusing the values allows us to do simplifications
62  * that LLVM optimization passes wouldn't normally be able to do.
63  */
64 struct lp_build_blend_aos_context
65 {
66    struct lp_build_context base;
67    
68    LLVMValueRef src;
69    LLVMValueRef dst;
70    LLVMValueRef const_;
71
72    LLVMValueRef inv_src;
73    LLVMValueRef inv_dst;
74    LLVMValueRef inv_const;
75    LLVMValueRef saturate;
76
77    LLVMValueRef rgb_src_factor;
78    LLVMValueRef alpha_src_factor;
79    LLVMValueRef rgb_dst_factor;
80    LLVMValueRef alpha_dst_factor;
81 };
82
83
84 static LLVMValueRef
85 lp_build_blend_factor_unswizzled(struct lp_build_blend_aos_context *bld,
86                                  unsigned factor,
87                                  boolean alpha)
88 {
89    switch (factor) {
90    case PIPE_BLENDFACTOR_ZERO:
91       return bld->base.zero;
92    case PIPE_BLENDFACTOR_ONE:
93       return bld->base.one;
94    case PIPE_BLENDFACTOR_SRC_COLOR:
95    case PIPE_BLENDFACTOR_SRC_ALPHA:
96       return bld->src;
97    case PIPE_BLENDFACTOR_DST_COLOR:
98    case PIPE_BLENDFACTOR_DST_ALPHA:
99       return bld->dst;
100    case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
101       if(alpha)
102          return bld->base.one;
103       else {
104          if(!bld->inv_dst)
105             bld->inv_dst = lp_build_comp(&bld->base, bld->dst);
106          if(!bld->saturate)
107             bld->saturate = lp_build_min(&bld->base, bld->src, bld->inv_dst);
108          return bld->saturate;
109       }
110    case PIPE_BLENDFACTOR_CONST_COLOR:
111    case PIPE_BLENDFACTOR_CONST_ALPHA:
112       return bld->const_;
113    case PIPE_BLENDFACTOR_SRC1_COLOR:
114    case PIPE_BLENDFACTOR_SRC1_ALPHA:
115       /* TODO */
116       assert(0);
117       return bld->base.zero;
118    case PIPE_BLENDFACTOR_INV_SRC_COLOR:
119    case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
120       if(!bld->inv_src)
121          bld->inv_src = lp_build_comp(&bld->base, bld->src);
122       return bld->inv_src;
123    case PIPE_BLENDFACTOR_INV_DST_COLOR:
124    case PIPE_BLENDFACTOR_INV_DST_ALPHA:
125       if(!bld->inv_dst)
126          bld->inv_dst = lp_build_comp(&bld->base, bld->dst);
127       return bld->inv_dst;
128    case PIPE_BLENDFACTOR_INV_CONST_COLOR:
129    case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
130       if(!bld->inv_const)
131          bld->inv_const = lp_build_comp(&bld->base, bld->const_);
132       return bld->inv_const;
133    case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
134    case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
135       /* TODO */
136       assert(0);
137       return bld->base.zero;
138    default:
139       assert(0);
140       return bld->base.zero;
141    }
142 }
143
144
145 enum lp_build_blend_swizzle {
146    LP_BUILD_BLEND_SWIZZLE_RGBA = 0,
147    LP_BUILD_BLEND_SWIZZLE_AAAA = 1
148 };
149
150
151 /**
152  * How should we shuffle the base factor.
153  */
154 static enum lp_build_blend_swizzle
155 lp_build_blend_factor_swizzle(unsigned factor)
156 {
157    switch (factor) {
158    case PIPE_BLENDFACTOR_ONE:
159    case PIPE_BLENDFACTOR_ZERO:
160    case PIPE_BLENDFACTOR_SRC_COLOR:
161    case PIPE_BLENDFACTOR_DST_COLOR:
162    case PIPE_BLENDFACTOR_CONST_COLOR:
163    case PIPE_BLENDFACTOR_SRC1_COLOR:
164    case PIPE_BLENDFACTOR_INV_SRC_COLOR:
165    case PIPE_BLENDFACTOR_INV_DST_COLOR:
166    case PIPE_BLENDFACTOR_INV_CONST_COLOR:
167    case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
168       return LP_BUILD_BLEND_SWIZZLE_RGBA;
169    case PIPE_BLENDFACTOR_SRC_ALPHA:
170    case PIPE_BLENDFACTOR_DST_ALPHA:
171    case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
172    case PIPE_BLENDFACTOR_SRC1_ALPHA:
173    case PIPE_BLENDFACTOR_CONST_ALPHA:
174    case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
175    case PIPE_BLENDFACTOR_INV_DST_ALPHA:
176    case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
177    case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
178       return LP_BUILD_BLEND_SWIZZLE_AAAA;
179    default:
180       assert(0);
181       return LP_BUILD_BLEND_SWIZZLE_RGBA;
182    }
183 }
184
185
186 static LLVMValueRef
187 lp_build_blend_swizzle(struct lp_build_blend_aos_context *bld,
188                        LLVMValueRef rgb, 
189                        LLVMValueRef alpha, 
190                        enum lp_build_blend_swizzle rgb_swizzle,
191                        unsigned alpha_swizzle)
192 {
193    LLVMValueRef swizzled_rgb;
194
195    switch (rgb_swizzle) {
196    case LP_BUILD_BLEND_SWIZZLE_RGBA:
197       swizzled_rgb = rgb;
198       break;
199    case LP_BUILD_BLEND_SWIZZLE_AAAA:
200       swizzled_rgb = lp_build_swizzle_scalar_aos(&bld->base, rgb, alpha_swizzle);
201       break;
202    default:
203       assert(0);
204       swizzled_rgb = bld->base.undef;
205    }
206
207    if (rgb != alpha) {
208       swizzled_rgb = lp_build_select_aos(&bld->base, 1 << alpha_swizzle,
209                                          alpha, swizzled_rgb);
210    }
211
212    return swizzled_rgb;
213 }
214
215
216 /**
217  * @sa http://www.opengl.org/sdk/docs/man/xhtml/glBlendFuncSeparate.xml
218  */
219 static LLVMValueRef
220 lp_build_blend_factor(struct lp_build_blend_aos_context *bld,
221                       LLVMValueRef factor1,
222                       unsigned rgb_factor,
223                       unsigned alpha_factor,
224                       unsigned alpha_swizzle)
225 {
226    LLVMValueRef rgb_factor_;
227    LLVMValueRef alpha_factor_;
228    LLVMValueRef factor2;
229    enum lp_build_blend_swizzle rgb_swizzle;
230
231    rgb_factor_   = lp_build_blend_factor_unswizzled(bld, rgb_factor,   FALSE);
232    alpha_factor_ = lp_build_blend_factor_unswizzled(bld, alpha_factor, TRUE);
233
234    rgb_swizzle = lp_build_blend_factor_swizzle(rgb_factor);
235
236    factor2 = lp_build_blend_swizzle(bld, rgb_factor_, alpha_factor_, rgb_swizzle, alpha_swizzle);
237
238    return lp_build_mul(&bld->base, factor1, factor2);
239 }
240
241
242 /**
243  * Is (a OP b) == (b OP a)?
244  */
245 boolean
246 lp_build_blend_func_commutative(unsigned func)
247 {
248    switch (func) {
249    case PIPE_BLEND_ADD:
250    case PIPE_BLEND_MIN:
251    case PIPE_BLEND_MAX:
252       return TRUE;
253    case PIPE_BLEND_SUBTRACT:
254    case PIPE_BLEND_REVERSE_SUBTRACT:
255       return FALSE;
256    default:
257       assert(0);
258       return TRUE;
259    }
260 }
261
262
263 boolean
264 lp_build_blend_func_reverse(unsigned rgb_func, unsigned alpha_func)
265 {
266    if(rgb_func == alpha_func)
267       return FALSE;
268    if(rgb_func == PIPE_BLEND_SUBTRACT && alpha_func == PIPE_BLEND_REVERSE_SUBTRACT)
269       return TRUE;
270    if(rgb_func == PIPE_BLEND_REVERSE_SUBTRACT && alpha_func == PIPE_BLEND_SUBTRACT)
271       return TRUE;
272    return FALSE;
273 }
274
275
276 /**
277  * @sa http://www.opengl.org/sdk/docs/man/xhtml/glBlendEquationSeparate.xml
278  */
279 LLVMValueRef
280 lp_build_blend_func(struct lp_build_context *bld,
281                     unsigned func,
282                     LLVMValueRef term1, 
283                     LLVMValueRef term2)
284 {
285    switch (func) {
286    case PIPE_BLEND_ADD:
287       return lp_build_add(bld, term1, term2);
288    case PIPE_BLEND_SUBTRACT:
289       return lp_build_sub(bld, term1, term2);
290    case PIPE_BLEND_REVERSE_SUBTRACT:
291       return lp_build_sub(bld, term2, term1);
292    case PIPE_BLEND_MIN:
293       return lp_build_min(bld, term1, term2);
294    case PIPE_BLEND_MAX:
295       return lp_build_max(bld, term1, term2);
296    default:
297       assert(0);
298       return bld->zero;
299    }
300 }
301
302
303 LLVMValueRef
304 lp_build_blend_aos(struct gallivm_state *gallivm,
305                    const struct pipe_blend_state *blend,
306                    struct lp_type type,
307                    unsigned rt,
308                    LLVMValueRef src,
309                    LLVMValueRef dst,
310                    LLVMValueRef const_,
311                    unsigned alpha_swizzle)
312 {
313    struct lp_build_blend_aos_context bld;
314    LLVMValueRef src_term;
315    LLVMValueRef dst_term;
316
317    /* FIXME: color masking not implemented yet */
318    assert(blend->rt[rt].colormask == 0xf);
319
320    if(!blend->rt[rt].blend_enable)
321       return src;
322
323    /* Setup build context */
324    memset(&bld, 0, sizeof bld);
325    lp_build_context_init(&bld.base, gallivm, type);
326    bld.src = src;
327    bld.dst = dst;
328    bld.const_ = const_;
329
330    /* TODO: There are still a few optimization opportunities here. For certain
331     * combinations it is possible to reorder the operations and therefore saving
332     * some instructions. */
333
334    src_term = lp_build_blend_factor(&bld, src, blend->rt[rt].rgb_src_factor,
335                                     blend->rt[rt].alpha_src_factor, alpha_swizzle);
336    dst_term = lp_build_blend_factor(&bld, dst, blend->rt[rt].rgb_dst_factor,
337                                     blend->rt[rt].alpha_dst_factor, alpha_swizzle);
338
339    lp_build_name(src_term, "src_term");
340    lp_build_name(dst_term, "dst_term");
341
342    if(blend->rt[rt].rgb_func == blend->rt[rt].alpha_func) {
343       return lp_build_blend_func(&bld.base, blend->rt[rt].rgb_func, src_term, dst_term);
344    }
345    else {
346       /* Seperate RGB / A functions */
347
348       LLVMValueRef rgb;
349       LLVMValueRef alpha;
350
351       rgb   = lp_build_blend_func(&bld.base, blend->rt[rt].rgb_func,   src_term, dst_term);
352       alpha = lp_build_blend_func(&bld.base, blend->rt[rt].alpha_func, src_term, dst_term);
353
354       return lp_build_blend_swizzle(&bld, rgb, alpha, LP_BUILD_BLEND_SWIZZLE_RGBA, alpha_swizzle);
355    }
356 }