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