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#include "util/u_format.h"
49
50#include "gallivm/lp_bld_type.h"
51#include "gallivm/lp_bld_const.h"
52#include "gallivm/lp_bld_arit.h"
53#include "gallivm/lp_bld_logic.h"
54#include "gallivm/lp_bld_swizzle.h"
55#include "gallivm/lp_bld_bitarit.h"
56#include "gallivm/lp_bld_debug.h"
57
58#include "lp_bld_blend.h"
59
60
61/**
62 * We may the same values several times, so we keep them here to avoid
63 * recomputing them. Also reusing the values allows us to do simplifications
64 * that LLVM optimization passes wouldn't normally be able to do.
65 */
66struct lp_build_blend_aos_context
67{
68   struct lp_build_context base;
69
70   LLVMValueRef src;
71   LLVMValueRef dst;
72   LLVMValueRef const_;
73
74   LLVMValueRef inv_src;
75   LLVMValueRef inv_dst;
76   LLVMValueRef inv_const;
77   LLVMValueRef saturate;
78
79   LLVMValueRef rgb_src_factor;
80   LLVMValueRef alpha_src_factor;
81   LLVMValueRef rgb_dst_factor;
82   LLVMValueRef alpha_dst_factor;
83};
84
85
86static LLVMValueRef
87lp_build_blend_factor_unswizzled(struct lp_build_blend_aos_context *bld,
88                                 unsigned factor,
89                                 boolean alpha)
90{
91   switch (factor) {
92   case PIPE_BLENDFACTOR_ZERO:
93      return bld->base.zero;
94   case PIPE_BLENDFACTOR_ONE:
95      return bld->base.one;
96   case PIPE_BLENDFACTOR_SRC_COLOR:
97   case PIPE_BLENDFACTOR_SRC_ALPHA:
98      return bld->src;
99   case PIPE_BLENDFACTOR_DST_COLOR:
100   case PIPE_BLENDFACTOR_DST_ALPHA:
101      return bld->dst;
102   case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
103      if(alpha)
104         return bld->base.one;
105      else {
106         if(!bld->inv_dst)
107            bld->inv_dst = lp_build_comp(&bld->base, bld->dst);
108         if(!bld->saturate)
109            bld->saturate = lp_build_min(&bld->base, bld->src, bld->inv_dst);
110         return bld->saturate;
111      }
112   case PIPE_BLENDFACTOR_CONST_COLOR:
113   case PIPE_BLENDFACTOR_CONST_ALPHA:
114      return bld->const_;
115   case PIPE_BLENDFACTOR_SRC1_COLOR:
116   case PIPE_BLENDFACTOR_SRC1_ALPHA:
117      /* TODO */
118      assert(0);
119      return bld->base.zero;
120   case PIPE_BLENDFACTOR_INV_SRC_COLOR:
121   case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
122      if(!bld->inv_src)
123         bld->inv_src = lp_build_comp(&bld->base, bld->src);
124      return bld->inv_src;
125   case PIPE_BLENDFACTOR_INV_DST_COLOR:
126   case PIPE_BLENDFACTOR_INV_DST_ALPHA:
127      if(!bld->inv_dst)
128         bld->inv_dst = lp_build_comp(&bld->base, bld->dst);
129      return bld->inv_dst;
130   case PIPE_BLENDFACTOR_INV_CONST_COLOR:
131   case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
132      if(!bld->inv_const)
133         bld->inv_const = lp_build_comp(&bld->base, bld->const_);
134      return bld->inv_const;
135   case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
136   case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
137      /* TODO */
138      assert(0);
139      return bld->base.zero;
140   default:
141      assert(0);
142      return bld->base.zero;
143   }
144}
145
146
147enum lp_build_blend_swizzle {
148   LP_BUILD_BLEND_SWIZZLE_RGBA = 0,
149   LP_BUILD_BLEND_SWIZZLE_AAAA = 1
150};
151
152
153/**
154 * How should we shuffle the base factor.
155 */
156static enum lp_build_blend_swizzle
157lp_build_blend_factor_swizzle(unsigned factor)
158{
159   switch (factor) {
160   case PIPE_BLENDFACTOR_ONE:
161   case PIPE_BLENDFACTOR_ZERO:
162   case PIPE_BLENDFACTOR_SRC_COLOR:
163   case PIPE_BLENDFACTOR_DST_COLOR:
164   case PIPE_BLENDFACTOR_CONST_COLOR:
165   case PIPE_BLENDFACTOR_SRC1_COLOR:
166   case PIPE_BLENDFACTOR_INV_SRC_COLOR:
167   case PIPE_BLENDFACTOR_INV_DST_COLOR:
168   case PIPE_BLENDFACTOR_INV_CONST_COLOR:
169   case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
170      return LP_BUILD_BLEND_SWIZZLE_RGBA;
171   case PIPE_BLENDFACTOR_SRC_ALPHA:
172   case PIPE_BLENDFACTOR_DST_ALPHA:
173   case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
174   case PIPE_BLENDFACTOR_SRC1_ALPHA:
175   case PIPE_BLENDFACTOR_CONST_ALPHA:
176   case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
177   case PIPE_BLENDFACTOR_INV_DST_ALPHA:
178   case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
179   case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
180      return LP_BUILD_BLEND_SWIZZLE_AAAA;
181   default:
182      assert(0);
183      return LP_BUILD_BLEND_SWIZZLE_RGBA;
184   }
185}
186
187
188static LLVMValueRef
189lp_build_blend_swizzle(struct lp_build_blend_aos_context *bld,
190                       LLVMValueRef rgb,
191                       LLVMValueRef alpha,
192                       enum lp_build_blend_swizzle rgb_swizzle,
193                       unsigned alpha_swizzle)
194{
195   LLVMValueRef swizzled_rgb;
196
197   switch (rgb_swizzle) {
198   case LP_BUILD_BLEND_SWIZZLE_RGBA:
199      swizzled_rgb = rgb;
200      break;
201   case LP_BUILD_BLEND_SWIZZLE_AAAA:
202      swizzled_rgb = lp_build_swizzle_scalar_aos(&bld->base, rgb, alpha_swizzle);
203      break;
204   default:
205      assert(0);
206      swizzled_rgb = bld->base.undef;
207   }
208
209   if (rgb != alpha) {
210      swizzled_rgb = lp_build_select_aos(&bld->base, 1 << alpha_swizzle,
211                                         alpha, swizzled_rgb);
212   }
213
214   return swizzled_rgb;
215}
216
217
218/**
219 * @sa http://www.opengl.org/sdk/docs/man/xhtml/glBlendFuncSeparate.xml
220 */
221static LLVMValueRef
222lp_build_blend_factor(struct lp_build_blend_aos_context *bld,
223                      unsigned rgb_factor,
224                      unsigned alpha_factor,
225                      unsigned alpha_swizzle)
226{
227   LLVMValueRef rgb_factor_, alpha_factor_;
228   enum lp_build_blend_swizzle rgb_swizzle;
229
230   rgb_factor_ = lp_build_blend_factor_unswizzled(bld, rgb_factor, FALSE);
231
232   if (alpha_swizzle != UTIL_FORMAT_SWIZZLE_NONE) {
233      rgb_swizzle   = lp_build_blend_factor_swizzle(rgb_factor);
234      alpha_factor_ = lp_build_blend_factor_unswizzled(bld, alpha_factor, TRUE);
235      return lp_build_blend_swizzle(bld, rgb_factor_, alpha_factor_, rgb_swizzle, alpha_swizzle);
236   } else {
237      return rgb_factor_;
238   }
239}
240
241
242/**
243 * Performs blending of src and dst pixels
244 *
245 * @param blend         the blend state of the shader variant
246 * @param cbuf_format   format of the colour buffer
247 * @param type          data type of the pixel vector
248 * @param rt            rt number
249 * @param src           blend src
250 * @param dst           blend dst
251 * @param mask          optional mask to apply to the blending result
252 * @param const_        const blend color
253 * @param swizzle       swizzle values for RGBA
254 *
255 * @return the result of blending src and dst
256 */
257LLVMValueRef
258lp_build_blend_aos(struct gallivm_state *gallivm,
259                   const struct pipe_blend_state *blend,
260                   const enum pipe_format *cbuf_format,
261                   struct lp_type type,
262                   unsigned rt,
263                   LLVMValueRef src,
264                   LLVMValueRef dst,
265                   LLVMValueRef mask,
266                   LLVMValueRef const_,
267                   const unsigned char swizzle[4])
268{
269   const struct pipe_rt_blend_state * state = &blend->rt[rt];
270   struct lp_build_blend_aos_context bld;
271   LLVMValueRef src_factor, dst_factor;
272   LLVMValueRef result;
273   unsigned alpha_swizzle = swizzle[3];
274   boolean fullcolormask;
275
276   /* Setup build context */
277   memset(&bld, 0, sizeof bld);
278   lp_build_context_init(&bld.base, gallivm, type);
279   bld.src = src;
280   bld.dst = dst;
281   bld.const_ = const_;
282
283   if (swizzle[3] > UTIL_FORMAT_SWIZZLE_W || swizzle[3] == swizzle[0])
284      alpha_swizzle = UTIL_FORMAT_SWIZZLE_NONE;
285
286   if (!state->blend_enable) {
287      result = src;
288   } else {
289      boolean rgb_alpha_same = state->rgb_src_factor == state->rgb_dst_factor && state->alpha_src_factor == state->alpha_dst_factor;
290      assert(rgb_alpha_same || alpha_swizzle != UTIL_FORMAT_SWIZZLE_NONE);
291
292      src_factor = lp_build_blend_factor(&bld, state->rgb_src_factor,
293                                         state->alpha_src_factor, alpha_swizzle);
294      dst_factor = lp_build_blend_factor(&bld, state->rgb_dst_factor,
295                                         state->alpha_dst_factor, alpha_swizzle);
296
297      result = lp_build_blend(&bld.base,
298                              state->rgb_func,
299                              state->rgb_src_factor,
300                              state->rgb_dst_factor,
301                              src,
302                              dst,
303                              src_factor,
304                              dst_factor,
305                              rgb_alpha_same,
306                              false);
307
308      if(state->rgb_func != state->alpha_func && alpha_swizzle != UTIL_FORMAT_SWIZZLE_NONE) {
309         LLVMValueRef alpha;
310
311         alpha = lp_build_blend(&bld.base,
312                                state->alpha_func,
313                                state->alpha_src_factor,
314                                state->alpha_dst_factor,
315                                src,
316                                dst,
317                                src_factor,
318                                dst_factor,
319                                rgb_alpha_same,
320                                false);
321
322         result = lp_build_blend_swizzle(&bld,
323                                         result,
324                                         alpha,
325                                         LP_BUILD_BLEND_SWIZZLE_RGBA,
326                                         alpha_swizzle);
327      }
328   }
329
330   /* Check if color mask is necessary */
331   fullcolormask = util_format_colormask_full(util_format_description(cbuf_format[rt]), state->colormask);
332
333   if (!fullcolormask) {
334      LLVMValueRef color_mask;
335
336      color_mask = lp_build_const_mask_aos_swizzled(gallivm, bld.base.type, state->colormask, swizzle);
337      lp_build_name(color_mask, "color_mask");
338
339      /* Combine with input mask if necessary */
340      if (mask) {
341         mask = lp_build_and(&bld.base, color_mask, mask);
342      } else {
343         mask = color_mask;
344      }
345   }
346
347   /* Apply mask, if one exists */
348   if (mask) {
349      result = lp_build_select(&bld.base, mask, result, dst);
350   }
351
352   return result;
353}
354