• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2007 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   * Authors:
30   *   Keith Whitwell <keithw@vmware.com>
31   *   Brian Paul
32   */
33 
34 
35 #include "st_context.h"
36 #include "st_atom.h"
37 
38 #include "pipe/p_context.h"
39 #include "pipe/p_defines.h"
40 #include "cso_cache/cso_context.h"
41 
42 #include "framebuffer.h"
43 #include "main/blend.h"
44 #include "main/glformats.h"
45 #include "main/macros.h"
46 
47 /**
48  * Convert GLenum blend tokens to pipe tokens.
49  * Both blend factors and blend funcs are accepted.
50  */
51 static GLuint
translate_blend(GLenum blend)52 translate_blend(GLenum blend)
53 {
54    switch (blend) {
55    /* blend functions */
56    case GL_FUNC_ADD:
57       return PIPE_BLEND_ADD;
58    case GL_FUNC_SUBTRACT:
59       return PIPE_BLEND_SUBTRACT;
60    case GL_FUNC_REVERSE_SUBTRACT:
61       return PIPE_BLEND_REVERSE_SUBTRACT;
62    case GL_MIN:
63       return PIPE_BLEND_MIN;
64    case GL_MAX:
65       return PIPE_BLEND_MAX;
66 
67    /* blend factors */
68    case GL_ONE:
69       return PIPE_BLENDFACTOR_ONE;
70    case GL_SRC_COLOR:
71       return PIPE_BLENDFACTOR_SRC_COLOR;
72    case GL_SRC_ALPHA:
73       return PIPE_BLENDFACTOR_SRC_ALPHA;
74    case GL_DST_ALPHA:
75       return PIPE_BLENDFACTOR_DST_ALPHA;
76    case GL_DST_COLOR:
77       return PIPE_BLENDFACTOR_DST_COLOR;
78    case GL_SRC_ALPHA_SATURATE:
79       return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE;
80    case GL_CONSTANT_COLOR:
81       return PIPE_BLENDFACTOR_CONST_COLOR;
82    case GL_CONSTANT_ALPHA:
83       return PIPE_BLENDFACTOR_CONST_ALPHA;
84    case GL_SRC1_COLOR:
85       return PIPE_BLENDFACTOR_SRC1_COLOR;
86    case GL_SRC1_ALPHA:
87       return PIPE_BLENDFACTOR_SRC1_ALPHA;
88    case GL_ZERO:
89       return PIPE_BLENDFACTOR_ZERO;
90    case GL_ONE_MINUS_SRC_COLOR:
91       return PIPE_BLENDFACTOR_INV_SRC_COLOR;
92    case GL_ONE_MINUS_SRC_ALPHA:
93       return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
94    case GL_ONE_MINUS_DST_COLOR:
95       return PIPE_BLENDFACTOR_INV_DST_COLOR;
96    case GL_ONE_MINUS_DST_ALPHA:
97       return PIPE_BLENDFACTOR_INV_DST_ALPHA;
98    case GL_ONE_MINUS_CONSTANT_COLOR:
99       return PIPE_BLENDFACTOR_INV_CONST_COLOR;
100    case GL_ONE_MINUS_CONSTANT_ALPHA:
101       return PIPE_BLENDFACTOR_INV_CONST_ALPHA;
102    case GL_ONE_MINUS_SRC1_COLOR:
103       return PIPE_BLENDFACTOR_INV_SRC1_COLOR;
104    case GL_ONE_MINUS_SRC1_ALPHA:
105       return PIPE_BLENDFACTOR_INV_SRC1_ALPHA;
106    default:
107       assert("invalid GL token in translate_blend()" == NULL);
108       return 0;
109    }
110 }
111 
112 /**
113  * Figure out if colormasks are different per rt.
114  */
115 static GLboolean
colormask_per_rt(const struct gl_context * ctx,unsigned num_cb)116 colormask_per_rt(const struct gl_context *ctx, unsigned num_cb)
117 {
118    GLbitfield full_mask = _mesa_replicate_colormask(0xf, num_cb);
119    GLbitfield repl_mask0 =
120       _mesa_replicate_colormask(GET_COLORMASK(ctx->Color.ColorMask, 0),
121                                 num_cb);
122 
123    return (ctx->Color.ColorMask & full_mask) != repl_mask0;
124 }
125 
126 /**
127  * Figure out if blend enables/state are different per rt.
128  */
129 static GLboolean
blend_per_rt(const struct st_context * st,unsigned num_cb)130 blend_per_rt(const struct st_context *st, unsigned num_cb)
131 {
132    const struct gl_context *ctx = st->ctx;
133    GLbitfield cb_mask = u_bit_consecutive(0, num_cb);
134    GLbitfield blend_enabled = ctx->Color.BlendEnabled & cb_mask;
135 
136    if (blend_enabled && blend_enabled != cb_mask) {
137       /* This can only happen if GL_EXT_draw_buffers2 is enabled */
138       return GL_TRUE;
139    }
140    if (ctx->Color._BlendFuncPerBuffer || ctx->Color._BlendEquationPerBuffer) {
141       /* this can only happen if GL_ARB_draw_buffers_blend is enabled */
142       return GL_TRUE;
143    }
144    if (ctx->DrawBuffer->_IntegerBuffers &&
145        (ctx->DrawBuffer->_IntegerBuffers != cb_mask)) {
146       /* If there is a mix of integer/non-integer buffers then blending
147        * must be handled on a per buffer basis. */
148       return GL_TRUE;
149    }
150 
151    if (st->needs_rgb_dst_alpha_override && ctx->DrawBuffer->_RGBBuffers) {
152       /* Overriding requires independent blend functions (not just enables),
153        * require drivers exposing PIPE_CAP_RGB_OVERRIDE_DST_ALPHA_BLEND to
154        * also expose PIPE_CAP_INDEP_BLEND_FUNC.
155        */
156       assert(st->has_indep_blend_func);
157 
158       /* If some of the buffers are RGB, we may need to override blend
159        * factors that reference destination-alpha to constants.  We may
160        * need different blend factor overrides per buffer (say one uses
161        * a DST_ALPHA factor and another uses INV_DST_ALPHA), so we flip
162        * on independent blending.  This may not be required in all cases,
163        * but burning the CPU to figure it out is probably not worthwhile.
164        */
165       return GL_TRUE;
166    }
167 
168    return GL_FALSE;
169 }
170 
171 /**
172  * Modify blend function to force destination alpha to 1.0
173  *
174  * If \c function specifies a blend function that uses destination alpha,
175  * replace it with a function that hard-wires destination alpha to 1.0.
176  * This is useful when emulating a GL RGB format with an RGBA pipe_format.
177  */
178 static enum pipe_blendfactor
fix_xrgb_alpha(enum pipe_blendfactor factor)179 fix_xrgb_alpha(enum pipe_blendfactor factor)
180 {
181    switch (factor) {
182    case PIPE_BLENDFACTOR_DST_ALPHA:
183       return PIPE_BLENDFACTOR_ONE;
184 
185    case PIPE_BLENDFACTOR_INV_DST_ALPHA:
186    case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
187       return PIPE_BLENDFACTOR_ZERO;
188    default:
189       return factor;
190    }
191 }
192 
193 void
st_update_blend(struct st_context * st)194 st_update_blend( struct st_context *st )
195 {
196    struct pipe_blend_state *blend = &st->state.blend;
197    const struct gl_context *ctx = st->ctx;
198    unsigned num_cb = st->state.fb_num_cb;
199    unsigned num_state = 1;
200    unsigned i, j;
201 
202    memset(blend, 0, sizeof(*blend));
203 
204    blend->max_rt = MAX2(1, num_cb) - 1;
205 
206    if (num_cb > 1 &&
207        (blend_per_rt(st, num_cb) || colormask_per_rt(ctx, num_cb))) {
208       num_state = num_cb;
209       blend->independent_blend_enable = 1;
210    }
211 
212    for (i = 0; i < num_state; i++)
213       blend->rt[i].colormask = GET_COLORMASK(ctx->Color.ColorMask, i);
214 
215    if (ctx->Color.ColorLogicOpEnabled) {
216       /* logicop enabled */
217       blend->logicop_enable = 1;
218       blend->logicop_func = ctx->Color._LogicOp;
219    }
220    else if (ctx->Color.BlendEnabled &&
221             ctx->Color._AdvancedBlendMode != BLEND_NONE) {
222       blend->advanced_blend_func = ctx->Color._AdvancedBlendMode;
223    }
224    else if (ctx->Color.BlendEnabled &&
225             ctx->Color._AdvancedBlendMode == BLEND_NONE) {
226       /* blending enabled */
227       for (i = 0, j = 0; i < num_state; i++) {
228          if (!(ctx->Color.BlendEnabled & (1 << i)) ||
229              (ctx->DrawBuffer->_IntegerBuffers & (1 << i)) ||
230              !blend->rt[i].colormask)
231             continue;
232 
233          if (ctx->Extensions.ARB_draw_buffers_blend)
234             j = i;
235 
236          blend->rt[i].blend_enable = 1;
237          blend->rt[i].rgb_func =
238             translate_blend(ctx->Color.Blend[j].EquationRGB);
239 
240          if (ctx->Color.Blend[i].EquationRGB == GL_MIN ||
241              ctx->Color.Blend[i].EquationRGB == GL_MAX) {
242             /* Min/max are special */
243             blend->rt[i].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
244             blend->rt[i].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
245          }
246          else {
247             blend->rt[i].rgb_src_factor =
248                translate_blend(ctx->Color.Blend[j].SrcRGB);
249             blend->rt[i].rgb_dst_factor =
250                translate_blend(ctx->Color.Blend[j].DstRGB);
251          }
252 
253          blend->rt[i].alpha_func =
254             translate_blend(ctx->Color.Blend[j].EquationA);
255 
256          if (ctx->Color.Blend[i].EquationA == GL_MIN ||
257              ctx->Color.Blend[i].EquationA == GL_MAX) {
258             /* Min/max are special */
259             blend->rt[i].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
260             blend->rt[i].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
261          }
262          else {
263             blend->rt[i].alpha_src_factor =
264                translate_blend(ctx->Color.Blend[j].SrcA);
265             blend->rt[i].alpha_dst_factor =
266                translate_blend(ctx->Color.Blend[j].DstA);
267          }
268 
269          const struct gl_renderbuffer *rb =
270             ctx->DrawBuffer->_ColorDrawBuffers[i];
271 
272          if (st->needs_rgb_dst_alpha_override && rb &&
273              (ctx->DrawBuffer->_RGBBuffers & (1 << i))) {
274             struct pipe_rt_blend_state *rt = &blend->rt[i];
275             rt->rgb_src_factor = fix_xrgb_alpha(rt->rgb_src_factor);
276             rt->rgb_dst_factor = fix_xrgb_alpha(rt->rgb_dst_factor);
277             rt->alpha_src_factor = fix_xrgb_alpha(rt->alpha_src_factor);
278             rt->alpha_dst_factor = fix_xrgb_alpha(rt->alpha_dst_factor);
279          }
280       }
281    }
282    else {
283       /* no blending / logicop */
284    }
285 
286    blend->dither = ctx->Color.DitherFlag;
287 
288    if (_mesa_is_multisample_enabled(ctx) &&
289        !(ctx->DrawBuffer->_IntegerBuffers & 0x1)) {
290       /* Unlike in gallium/d3d10 these operations are only performed
291        * if both msaa is enabled and we have a multisample buffer.
292        */
293       blend->alpha_to_coverage = ctx->Multisample.SampleAlphaToCoverage;
294       blend->alpha_to_one = ctx->Multisample.SampleAlphaToOne;
295       blend->alpha_to_coverage_dither =
296          ctx->Multisample.SampleAlphaToCoverageDitherControl !=
297          GL_ALPHA_TO_COVERAGE_DITHER_DISABLE_NV;
298    }
299 
300    cso_set_blend(st->cso_context, blend);
301 }
302 
303 void
st_update_blend_color(struct st_context * st)304 st_update_blend_color(struct st_context *st)
305 {
306    struct pipe_context *pipe = st->pipe;
307    struct pipe_blend_color *bc =
308       (struct pipe_blend_color *)st->ctx->Color.BlendColorUnclamped;
309 
310    pipe->set_blend_color(pipe, bc);
311 }
312