2 * © Copyright 2018 Alyssa Rosenzweig
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 #include "pan_blending.h"
27 #include "pan_context.h"
28 #include "gallium/auxiliary/util/u_blend.h"
29 #include "util/u_format.h"
32 * Implements fixed-function blending on Midgard.
34 * Midgard splits blending into a fixed-function fast path and a programmable
35 * slow path. The fixed function blending architecture is based on "dominant"
36 * blend factors. Blending is encoded separately (but identically) between RGB
37 * and alpha functions.
39 * Essentially, for a given blending operation, there is a single dominant
40 * factor. The following dominant factors are possible:
49 * Further, a dominant factor's arithmetic compliment could be used. For
50 * instance, to encode GL_ONE_MINUS_SOURCE_ALPHA, the dominant factor would be
51 * MALI_DOMINANT_SRC_ALPHA with the complement_dominant bit set.
53 * A single constant float can be passed to the fixed-function hardware,
54 * allowing CONSTANT_ALPHA support. Further, if all components of the constant
55 * glBlendColor are identical, CONSTANT_COLOR can be implemented with the
56 * constant float mode. If the components differ, programmable blending is
59 * The nondominant factor can be either:
61 * - the same as the dominant factor (MALI_BLEND_NON_MIRROR)
62 * - zero (MALI_BLEND_NON_ZERO)
64 * Exactly one of the blend operation's source or destination can be used as
65 * the dominant factor; this is selected by the
66 * MALI_BLEND_DOM_SOURCE/DESTINATION flag.
68 * By default, all blending follows the standard OpenGL addition equation:
70 * out = source_value * source_factor + destination_value * destination_factor
72 * By setting the negate_source or negate_dest bits, other blend functions can
73 * be created. For instance, for SUBTRACT mode, set the "negate destination"
74 * flag, and similarly for REVERSE_SUBTRACT with "negate source".
76 * Finally, there is a "clip modifier" controlling the final blending
77 * behaviour, allowing for the following modes:
80 * - force source factor to one (MALI_BLEND_MODE_SOURCE_ONE)
81 * - force destination factor to one (MALI_BLEND_MODE_DEST_ONE)
83 * The clipping flags can be used to encode blend modes where the nondominant
86 * As an example putting it all together, to encode the following blend state:
88 * glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
89 * glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE);
91 * We need the following configuration:
93 * - negate source (for REVERSE_SUBTRACT)
94 * - dominant factor "source alpha"
95 * - complement dominant
97 * - force destination to ONE
99 * The following routines implement this fixed function blending encoding
102 /* Not all formats can be blended by fixed-function hardware */
105 panfrost_can_fixed_blend(enum pipe_format format
)
107 /* Fixed-function can handle sRGB */
108 format
= util_format_linear(format
);
110 /* Decompose the format */
111 const struct util_format_description
*desc
=
112 util_format_description(format
);
114 /* Any 8-bit unorm is supported */
115 if (util_format_is_unorm8(desc
))
118 /* Certain special formats are, too */
120 case PIPE_FORMAT_B5G6R5_UNORM
:
121 case PIPE_FORMAT_B4G4R4A4_UNORM
:
122 case PIPE_FORMAT_B5G5R5A1_UNORM
:
123 case PIPE_FORMAT_R10G10B10A2_UNORM
:
130 /* Helper to find the uncomplemented Gallium blend factor corresponding to a
131 * complemented Gallium blend factor */
134 complement_factor(int factor
)
137 case PIPE_BLENDFACTOR_INV_SRC_COLOR
:
138 return PIPE_BLENDFACTOR_SRC_COLOR
;
140 case PIPE_BLENDFACTOR_INV_SRC_ALPHA
:
141 return PIPE_BLENDFACTOR_SRC_ALPHA
;
143 case PIPE_BLENDFACTOR_INV_DST_ALPHA
:
144 return PIPE_BLENDFACTOR_DST_ALPHA
;
146 case PIPE_BLENDFACTOR_INV_DST_COLOR
:
147 return PIPE_BLENDFACTOR_DST_COLOR
;
149 case PIPE_BLENDFACTOR_INV_CONST_COLOR
:
150 return PIPE_BLENDFACTOR_CONST_COLOR
;
152 case PIPE_BLENDFACTOR_INV_CONST_ALPHA
:
153 return PIPE_BLENDFACTOR_CONST_ALPHA
;
160 /* Helper to strip the complement from any Gallium blend factor */
163 uncomplement_factor(int factor
)
165 int complement
= complement_factor(factor
);
166 return (complement
== -1) ? factor
: complement
;
170 /* Attempt to find the dominant factor given a particular factor, complementing
174 panfrost_make_dominant_factor(unsigned src_factor
, enum mali_dominant_factor
*factor
)
176 switch (src_factor
) {
177 case PIPE_BLENDFACTOR_SRC_COLOR
:
178 case PIPE_BLENDFACTOR_INV_SRC_COLOR
:
179 *factor
= MALI_DOMINANT_SRC_COLOR
;
182 case PIPE_BLENDFACTOR_SRC_ALPHA
:
183 case PIPE_BLENDFACTOR_INV_SRC_ALPHA
:
184 *factor
= MALI_DOMINANT_SRC_ALPHA
;
187 case PIPE_BLENDFACTOR_DST_COLOR
:
188 case PIPE_BLENDFACTOR_INV_DST_COLOR
:
189 *factor
= MALI_DOMINANT_DST_COLOR
;
192 case PIPE_BLENDFACTOR_DST_ALPHA
:
193 case PIPE_BLENDFACTOR_INV_DST_ALPHA
:
194 *factor
= MALI_DOMINANT_DST_ALPHA
;
197 case PIPE_BLENDFACTOR_ONE
:
198 case PIPE_BLENDFACTOR_ZERO
:
199 *factor
= MALI_DOMINANT_ZERO
;
202 case PIPE_BLENDFACTOR_CONST_ALPHA
:
203 case PIPE_BLENDFACTOR_INV_CONST_ALPHA
:
204 case PIPE_BLENDFACTOR_CONST_COLOR
:
205 case PIPE_BLENDFACTOR_INV_CONST_COLOR
:
206 *factor
= MALI_DOMINANT_CONSTANT
;
210 /* Fancy blend modes not supported */
217 /* Check if this is a special edge case blend factor, which may require the use
218 * of clip modifiers */
221 is_edge_blendfactor(unsigned factor
)
223 return factor
== PIPE_BLENDFACTOR_ONE
|| factor
== PIPE_BLENDFACTOR_ZERO
;
226 /* Perform the actual fixed function encoding. Encode the function with negate
227 * bits. Check for various cases to work out the dominant/nondominant split and
228 * accompanying flags. */
231 panfrost_make_fixed_blend_part(unsigned func
, unsigned src_factor
, unsigned dst_factor
, unsigned *out
)
233 struct mali_blend_mode part
= { 0 };
235 /* Make sure that the blend function is representible */
241 /* TODO: Reenable subtraction modes when those fixed */
242 case PIPE_BLEND_SUBTRACT
:
243 case PIPE_BLEND_REVERSE_SUBTRACT
:
248 part
.clip_modifier
= MALI_BLEND_MOD_NORMAL
;
250 /* Decide which is dominant, source or destination. If one is an edge
251 * case, use the other as a factor. If they're the same, it doesn't
252 * matter; we just mirror. If they're different non-edge-cases, you
253 * need a blend shader (don't do that). */
255 if (is_edge_blendfactor(dst_factor
)) {
256 part
.dominant
= MALI_BLEND_DOM_SOURCE
;
257 part
.nondominant_mode
= MALI_BLEND_NON_ZERO
;
259 if (dst_factor
== PIPE_BLENDFACTOR_ONE
)
260 part
.clip_modifier
= MALI_BLEND_MOD_DEST_ONE
;
261 } else if (is_edge_blendfactor(src_factor
)) {
262 part
.dominant
= MALI_BLEND_DOM_DESTINATION
;
263 part
.nondominant_mode
= MALI_BLEND_NON_ZERO
;
265 if (src_factor
== PIPE_BLENDFACTOR_ONE
)
266 part
.clip_modifier
= MALI_BLEND_MOD_SOURCE_ONE
;
267 } else if (src_factor
== dst_factor
) {
269 part
.dominant
= func
== PIPE_BLEND_ADD
?
270 MALI_BLEND_DOM_DESTINATION
: MALI_BLEND_DOM_SOURCE
;
272 part
.nondominant_mode
= MALI_BLEND_NON_MIRROR
;
273 } else if (src_factor
== complement_factor(dst_factor
)) {
274 /* TODO: How does this work exactly? */
275 part
.dominant
= MALI_BLEND_DOM_SOURCE
;
276 part
.nondominant_mode
= MALI_BLEND_NON_MIRROR
;
277 part
.clip_modifier
= MALI_BLEND_MOD_DEST_ONE
;
279 /* The complement is handled by the clip modifier, don't set a
282 dst_factor
= src_factor
;
283 } else if (dst_factor
== complement_factor(src_factor
)) {
284 part
.dominant
= MALI_BLEND_DOM_SOURCE
;
285 part
.nondominant_mode
= MALI_BLEND_NON_MIRROR
;
286 part
.clip_modifier
= MALI_BLEND_MOD_SOURCE_ONE
;
288 src_factor
= dst_factor
;
293 unsigned in_dominant_factor
=
294 part
.dominant
== MALI_BLEND_DOM_SOURCE
? src_factor
: dst_factor
;
296 if (part
.clip_modifier
== MALI_BLEND_MOD_NORMAL
&& in_dominant_factor
== PIPE_BLENDFACTOR_ONE
) {
297 part
.clip_modifier
= part
.dominant
== MALI_BLEND_DOM_SOURCE
? MALI_BLEND_MOD_SOURCE_ONE
: MALI_BLEND_MOD_DEST_ONE
;
298 in_dominant_factor
= PIPE_BLENDFACTOR_ZERO
;
301 enum mali_dominant_factor dominant_factor
;
303 if (!panfrost_make_dominant_factor(in_dominant_factor
, &dominant_factor
))
306 part
.dominant_factor
= dominant_factor
;
307 part
.complement_dominant
= util_blend_factor_is_inverted(in_dominant_factor
);
309 /* It's not clear what this does, but fixes some ADD blending tests.
310 * More research is needed XXX */
312 if ((part
.clip_modifier
== MALI_BLEND_MOD_SOURCE_ONE
) && (part
.dominant
== MALI_BLEND_DOM_SOURCE
))
313 part
.negate_dest
= true;
316 memcpy(out
, &part
, sizeof(part
));
321 /* We can upload a single constant for all of the factors. So, scan
322 * the factors for constants used to create a mask to check later. */
325 panfrost_constant_mask(unsigned *factors
, unsigned num_factors
)
329 for (unsigned i
= 0; i
< num_factors
; ++i
) {
330 unsigned factor
= uncomplement_factor(factors
[i
]);
332 if (factor
== PIPE_BLENDFACTOR_CONST_COLOR
)
333 mask
|= 0b0111; /* RGB */
334 else if (factor
== PIPE_BLENDFACTOR_CONST_ALPHA
)
335 mask
|= 0b1000; /* A */
341 /* Create the descriptor for a fixed blend mode given the corresponding Gallium
342 * state, if possible. Return true and write out the blend descriptor into
343 * blend_equation. If it is not possible with the fixed function
344 * representating, return false to handle degenerate cases with a blend shader
348 panfrost_make_fixed_blend_mode(
349 const struct pipe_rt_blend_state
*blend
,
350 struct mali_blend_equation
*out
,
351 unsigned *constant_mask
,
354 /* Gallium and Mali represent colour masks identically. XXX: Static
355 * assert for future proof */
357 out
->color_mask
= colormask
;
359 /* If no blending is enabled, default back on `replace` mode */
361 if (!blend
->blend_enable
) {
362 out
->rgb_mode
= 0x122;
363 out
->alpha_mode
= 0x122;
367 /* At draw-time, we'll need to analyze the blend constant, so
368 * precompute a mask for it -- even if we don't end up able to use
369 * fixed-function blending */
371 unsigned factors
[] = {
372 blend
->rgb_src_factor
, blend
->rgb_dst_factor
,
373 blend
->alpha_src_factor
, blend
->alpha_dst_factor
,
376 *constant_mask
= panfrost_constant_mask(factors
, ARRAY_SIZE(factors
));
378 /* Try to compile the actual fixed-function blend */
380 unsigned rgb_mode
= 0;
381 unsigned alpha_mode
= 0;
383 if (!panfrost_make_fixed_blend_part(
384 blend
->rgb_func
, blend
->rgb_src_factor
, blend
->rgb_dst_factor
,
388 if (!panfrost_make_fixed_blend_part(
389 blend
->alpha_func
, blend
->alpha_src_factor
, blend
->alpha_dst_factor
,
393 out
->rgb_mode
= rgb_mode
;
394 out
->alpha_mode
= alpha_mode
;