xref: /aosp_15_r20/external/mesa3d/src/mesa/state_tracker/st_atom_blend.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 <[email protected]>
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  * Decide whether to allow promotion of RGB colormasks (0x7) to RGBA (0xf).
128  */
129 static bool
allow_rgb_colormask_promotion(const struct st_context * st,unsigned num_cb,bool * need_independent_blend)130 allow_rgb_colormask_promotion(const struct st_context *st,
131                               unsigned num_cb,
132                               bool *need_independent_blend)
133 {
134    const struct gl_context *ctx = st->ctx;
135 
136    if (num_cb == 1)
137       return true;
138 
139    GLbitfield rgb_mask = _mesa_replicate_colormask(0x7, num_cb);
140    GLbitfield full_mask = _mesa_replicate_colormask(0xf, num_cb);
141 
142    /* True if all colormasks should be promoted.  If so, we can do so
143     * without needing independent blending.  (If none should be promoted,
144     * we can just skip this optimization as it doesn't do anything.)
145     */
146    bool same = ctx->DrawBuffer->_IsRGB == u_bit_consecutive(0, num_cb) &&
147                (ctx->Color.ColorMask & full_mask) == rgb_mask;
148 
149    /* We can support different per-RT promotion decisions if we driver
150     * supports independent blending (but we must actually enable it).
151     */
152    if (st->has_indep_blend_enable && !same) {
153       *need_independent_blend = true;
154       return true;
155    }
156 
157    return same;
158 }
159 
160 /**
161  * Figure out if blend enables/state are different per rt.
162  */
163 static GLboolean
blend_per_rt(const struct st_context * st,unsigned num_cb)164 blend_per_rt(const struct st_context *st, unsigned num_cb)
165 {
166    const struct gl_context *ctx = st->ctx;
167    GLbitfield cb_mask = u_bit_consecutive(0, num_cb);
168    GLbitfield blend_enabled = ctx->Color.BlendEnabled & cb_mask;
169 
170    if (blend_enabled && blend_enabled != cb_mask) {
171       /* This can only happen if GL_EXT_draw_buffers2 is enabled */
172       return GL_TRUE;
173    }
174    if (ctx->Color._BlendFuncPerBuffer || ctx->Color._BlendEquationPerBuffer) {
175       /* this can only happen if GL_ARB_draw_buffers_blend is enabled */
176       return GL_TRUE;
177    }
178    if (ctx->DrawBuffer->_IntegerBuffers &&
179        (ctx->DrawBuffer->_IntegerBuffers != cb_mask)) {
180       /* If there is a mix of integer/non-integer buffers then blending
181        * must be handled on a per buffer basis. */
182       return GL_TRUE;
183    }
184 
185    if (ctx->DrawBuffer->_BlendForceAlphaToOne) {
186       /* Overriding requires independent blend functions (not just enables),
187        * requiring drivers to expose PIPE_CAP_INDEP_BLEND_FUNC.
188        */
189       assert(st->has_indep_blend_func);
190 
191       /* If some of the buffers are RGB or emulated L/I, we may need to override blend
192        * factors that reference destination-alpha to constants.  We may
193        * need different blend factor overrides per buffer (say one uses
194        * a DST_ALPHA factor and another uses INV_DST_ALPHA), so we flip
195        * on independent blending.  This may not be required in all cases,
196        * but burning the CPU to figure it out is probably not worthwhile.
197        */
198       return GL_TRUE;
199    }
200 
201    return GL_FALSE;
202 }
203 
204 /**
205  * Modify blend function to force destination alpha to 1.0
206  *
207  * If \c function specifies a blend function that uses destination alpha,
208  * replace it with a function that hard-wires destination alpha to 1.0.
209  * This is useful when emulating a GL RGB format with an RGBA pipe_format.
210  */
211 static enum pipe_blendfactor
fix_xrgb_alpha(enum pipe_blendfactor factor)212 fix_xrgb_alpha(enum pipe_blendfactor factor)
213 {
214    switch (factor) {
215    case PIPE_BLENDFACTOR_DST_ALPHA:
216       return PIPE_BLENDFACTOR_ONE;
217 
218    case PIPE_BLENDFACTOR_INV_DST_ALPHA:
219    case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
220       return PIPE_BLENDFACTOR_ZERO;
221    default:
222       return factor;
223    }
224 }
225 
226 void
st_update_blend(struct st_context * st)227 st_update_blend( struct st_context *st )
228 {
229    struct pipe_blend_state *blend = &st->state.blend;
230    const struct gl_context *ctx = st->ctx;
231    unsigned num_cb = st->state.fb_num_cb;
232    unsigned num_state = 1;
233    unsigned i, j;
234 
235    memset(blend, 0, sizeof(*blend));
236 
237    blend->max_rt = MAX2(1, num_cb) - 1;
238 
239    bool need_independent_blend = num_cb > 1 &&
240       (blend_per_rt(st, num_cb) || colormask_per_rt(ctx, num_cb));
241 
242    bool promote_rgb_colormasks =
243       allow_rgb_colormask_promotion(st, num_cb, &need_independent_blend);
244 
245    if (need_independent_blend) {
246       num_state = num_cb;
247       blend->independent_blend_enable = 1;
248    }
249 
250    for (i = 0; i < num_state; i++) {
251       unsigned colormask = GET_COLORMASK(ctx->Color.ColorMask, i);
252 
253       /* When faking RGB as RGBA and writing every real channel, also enable
254        * writes to the A channel as well.  Some GPUs are able to render more
255        * efficiently if they know whole pixels are being overwritten, whereas
256        * partial writes may require preserving/combining new and old data.
257        */
258       if (promote_rgb_colormasks &&
259           colormask == 0x7 && (ctx->DrawBuffer->_IsRGB & (1 << i)))
260          colormask = 0xf;
261 
262       blend->rt[i].colormask = colormask;
263    }
264 
265    if (ctx->Color._AdvancedBlendMode != BLEND_NONE) {
266       blend->blend_coherent = ctx->Color.BlendCoherent;
267    }
268 
269    if (ctx->Color.ColorLogicOpEnabled) {
270       /* logicop enabled */
271       blend->logicop_enable = 1;
272       blend->logicop_func = ctx->Color._LogicOp;
273    }
274    else if (ctx->Color.BlendEnabled &&
275             ctx->Color._AdvancedBlendMode != BLEND_NONE) {
276       blend->advanced_blend_func = ctx->Color._AdvancedBlendMode;
277    }
278    else if (ctx->Color.BlendEnabled &&
279             ctx->Color._AdvancedBlendMode == BLEND_NONE) {
280       /* blending enabled */
281       for (i = 0, j = 0; i < num_state; i++) {
282          if (!(ctx->Color.BlendEnabled & (1 << i)) ||
283              (ctx->DrawBuffer->_IntegerBuffers & (1 << i)) ||
284              !blend->rt[i].colormask)
285             continue;
286 
287          if (ctx->Extensions.ARB_draw_buffers_blend)
288             j = i;
289 
290          blend->rt[i].blend_enable = 1;
291          blend->rt[i].rgb_func =
292             translate_blend(ctx->Color.Blend[j].EquationRGB);
293 
294          if (ctx->Color.Blend[i].EquationRGB == GL_MIN ||
295              ctx->Color.Blend[i].EquationRGB == GL_MAX) {
296             /* Min/max are special */
297             blend->rt[i].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
298             blend->rt[i].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
299          }
300          else {
301             blend->rt[i].rgb_src_factor =
302                translate_blend(ctx->Color.Blend[j].SrcRGB);
303             blend->rt[i].rgb_dst_factor =
304                translate_blend(ctx->Color.Blend[j].DstRGB);
305          }
306 
307          blend->rt[i].alpha_func =
308             translate_blend(ctx->Color.Blend[j].EquationA);
309 
310          if (ctx->Color.Blend[i].EquationA == GL_MIN ||
311              ctx->Color.Blend[i].EquationA == GL_MAX) {
312             /* Min/max are special */
313             blend->rt[i].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
314             blend->rt[i].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
315          }
316          else {
317             blend->rt[i].alpha_src_factor =
318                translate_blend(ctx->Color.Blend[j].SrcA);
319             blend->rt[i].alpha_dst_factor =
320                translate_blend(ctx->Color.Blend[j].DstA);
321          }
322 
323          const struct gl_renderbuffer *rb =
324             ctx->DrawBuffer->_ColorDrawBuffers[i];
325 
326          if (rb && (ctx->DrawBuffer->_BlendForceAlphaToOne & (1 << i))) {
327             struct pipe_rt_blend_state *rt = &blend->rt[i];
328             rt->rgb_src_factor = fix_xrgb_alpha(rt->rgb_src_factor);
329             rt->rgb_dst_factor = fix_xrgb_alpha(rt->rgb_dst_factor);
330             rt->alpha_src_factor = fix_xrgb_alpha(rt->alpha_src_factor);
331             rt->alpha_dst_factor = fix_xrgb_alpha(rt->alpha_dst_factor);
332          }
333       }
334    }
335    else {
336       /* no blending / logicop */
337    }
338 
339    if (st->can_dither)
340       blend->dither = ctx->Color.DitherFlag;
341 
342    if (_mesa_is_multisample_enabled(ctx) &&
343        !(ctx->DrawBuffer->_IntegerBuffers & 0x1)) {
344       /* Unlike in gallium/d3d10 these operations are only performed
345        * if both msaa is enabled and we have a multisample buffer.
346        */
347       blend->alpha_to_coverage = ctx->Multisample.SampleAlphaToCoverage;
348       blend->alpha_to_one = ctx->Multisample.SampleAlphaToOne;
349       blend->alpha_to_coverage_dither =
350          ctx->Multisample.SampleAlphaToCoverageDitherControl !=
351          GL_ALPHA_TO_COVERAGE_DITHER_DISABLE_NV;
352    }
353 
354    cso_set_blend(st->cso_context, blend);
355 }
356 
357 void
st_update_blend_color(struct st_context * st)358 st_update_blend_color(struct st_context *st)
359 {
360    struct pipe_context *pipe = st->pipe;
361    struct pipe_blend_color *bc =
362       (struct pipe_blend_color *)st->ctx->Color.BlendColorUnclamped;
363 
364    pipe->set_blend_color(pipe, bc);
365 }
366