pan/blend: Add support for float blending

Blend equations that work on float are treated a bit differently, hence
the new is_float on pan_blend_equation.

Reviewed-by: Lars-Ivar Hesselberg Simonsen <lars-ivar.simonsen@arm.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/39171>
This commit is contained in:
Faith Ekstrand 2026-01-05 22:29:51 -05:00 committed by Marge Bot
parent c51f12cb99
commit 14889a09bc
2 changed files with 80 additions and 22 deletions

View file

@ -51,6 +51,18 @@ factor_is_supported(enum pipe_blendfactor factor)
factor != PIPE_BLENDFACTOR_SRC1_ALPHA; factor != PIPE_BLENDFACTOR_SRC1_ALPHA;
} }
/* The set of factors supported by the hardware for floats is significantly
* reduced.
*/
static bool
factor_is_supported_for_float(enum pipe_blendfactor factor)
{
return factor == PIPE_BLENDFACTOR_ZERO ||
factor == PIPE_BLENDFACTOR_ONE ||
factor == PIPE_BLENDFACTOR_SRC_ALPHA ||
factor == PIPE_BLENDFACTOR_INV_SRC_ALPHA;
}
/* OpenGL allows encoding (src*dest + dest*src) which is incompatiblle with /* OpenGL allows encoding (src*dest + dest*src) which is incompatiblle with
* Midgard style blending since there are two multiplies. However, it may be * Midgard style blending since there are two multiplies. However, it may be
* factored as 2*src*dest = dest*(2*src), which can be encoded on Bifrost as 0 * factored as 2*src*dest = dest*(2*src), which can be encoded on Bifrost as 0
@ -70,27 +82,41 @@ is_2srcdest(enum pipe_blend_func blend_func, enum pipe_blendfactor src_factor,
static bool static bool
can_fixed_function_equation(enum pipe_blend_func blend_func, can_fixed_function_equation(enum pipe_blend_func blend_func,
enum pipe_blendfactor src_factor, enum pipe_blendfactor src_factor,
enum pipe_blendfactor dest_factor, bool is_alpha, enum pipe_blendfactor dest_factor,
bool is_alpha, bool is_float,
bool supports_2src) bool supports_2src)
{ {
if (is_2srcdest(blend_func, src_factor, dest_factor, is_alpha)) /* We can only do add/subtract in hardware. No min/max. */
return supports_2src;
if (blend_func != PIPE_BLEND_ADD && blend_func != PIPE_BLEND_SUBTRACT && if (blend_func != PIPE_BLEND_ADD && blend_func != PIPE_BLEND_SUBTRACT &&
blend_func != PIPE_BLEND_REVERSE_SUBTRACT) blend_func != PIPE_BLEND_REVERSE_SUBTRACT)
return false; return false;
if (!factor_is_supported(src_factor) || !factor_is_supported(dest_factor)) if (is_float) {
return false; /* There are a couple special cases for add with zero */
if (blend_func == PIPE_BLEND_ADD &&
src_factor == PIPE_BLENDFACTOR_ZERO &&
(dest_factor == PIPE_BLENDFACTOR_INV_SRC_COLOR ||
dest_factor == PIPE_BLENDFACTOR_DST_ALPHA))
return true;
/* Fixed function requires src/dest factors to match (up to invert) or be return factor_is_supported_for_float(src_factor) &&
* zero/one. factor_is_supported_for_float(dest_factor);
*/ } else {
enum pipe_blendfactor src = util_blendfactor_without_invert(src_factor); if (is_2srcdest(blend_func, src_factor, dest_factor, is_alpha))
enum pipe_blendfactor dest = util_blendfactor_without_invert(dest_factor); return supports_2src;
return (src == dest) || (src == PIPE_BLENDFACTOR_ONE) || if (!factor_is_supported(src_factor) || !factor_is_supported(dest_factor))
(dest == PIPE_BLENDFACTOR_ONE); return false;
/* Fixed function requires src/dest factors to match (up to invert) or be
* zero/one.
*/
enum pipe_blendfactor src = util_blendfactor_without_invert(src_factor);
enum pipe_blendfactor dest = util_blendfactor_without_invert(dest_factor);
return (src == dest) || (src == PIPE_BLENDFACTOR_ONE) ||
(dest == PIPE_BLENDFACTOR_ONE);
}
} }
static unsigned static unsigned
@ -137,6 +163,9 @@ pan_pack_blend_constant(enum pipe_format format, float cons)
const struct util_format_description *format_desc = const struct util_format_description *format_desc =
util_format_description(format); util_format_description(format);
/* Mali doesn't support float blend constants */
assert(format_desc->channel[0].type != UTIL_FORMAT_TYPE_FLOAT);
/* On Bifrost, the blend constant is expressed with a UNORM of the /* On Bifrost, the blend constant is expressed with a UNORM of the
* size of the target format. The value is then shifted such that * size of the target format. The value is then shifted such that
* used bits are in the MSB. * used bits are in the MSB.
@ -159,10 +188,12 @@ pan_blend_can_fixed_function(const struct pan_blend_equation equation,
return !equation.blend_enable || return !equation.blend_enable ||
(can_fixed_function_equation( (can_fixed_function_equation(
equation.rgb_func, equation.rgb_src_factor, equation.rgb_func, equation.rgb_src_factor,
equation.rgb_dst_factor, false, supports_2src) && equation.rgb_dst_factor, false /* is_alpha */,
equation.is_float, supports_2src) &&
can_fixed_function_equation( can_fixed_function_equation(
equation.alpha_func, equation.alpha_src_factor, equation.alpha_func, equation.alpha_src_factor,
equation.alpha_dst_factor, true, supports_2src)); equation.alpha_dst_factor, true /* is_alpha */,
equation.is_float, supports_2src));
} }
static enum mali_blend_operand_c static enum mali_blend_operand_c
@ -197,11 +228,13 @@ to_c_factor(enum pipe_blendfactor factor)
static void static void
to_mali_function(enum pipe_blend_func blend_func, to_mali_function(enum pipe_blend_func blend_func,
enum pipe_blendfactor src_factor, enum pipe_blendfactor src_factor,
enum pipe_blendfactor dest_factor, bool is_alpha, enum pipe_blendfactor dest_factor,
bool is_alpha, bool is_float,
struct MALI_BLEND_FUNCTION *function) struct MALI_BLEND_FUNCTION *function)
{ {
assert(can_fixed_function_equation(blend_func, src_factor, dest_factor, assert(can_fixed_function_equation(blend_func, src_factor, dest_factor,
is_alpha, true)); is_alpha, is_float,
true /* supports_2src */));
/* We handle ZERO/ONE specially since it's the hardware has 0 and can invert /* We handle ZERO/ONE specially since it's the hardware has 0 and can invert
* to 1 but Gallium has 0 as the uninverted version. * to 1 but Gallium has 0 as the uninverted version.
@ -308,6 +341,15 @@ pan_blend_is_opaque(const struct pan_blend_equation equation)
if (!equation.blend_enable) if (!equation.blend_enable)
return true; return true;
/* NOTE (NaN/inf):
*
* Technically, we should reject this optimization for float blending
* because 0.0 * NaN/inf = NaN. However, Vulkan and OpenGL both allow us
* to drop inf/NaN pretty much at-will and the NIR blending we would fall
* back to will also drop 0.0 blend factors. One day we might want to do
* all this behind a driconf flag but today is not that day.
*/
/* Also detect open-coded opaque blending */ /* Also detect open-coded opaque blending */
return equation.rgb_src_factor == PIPE_BLENDFACTOR_ONE && return equation.rgb_src_factor == PIPE_BLENDFACTOR_ONE &&
equation.rgb_dst_factor == PIPE_BLENDFACTOR_ZERO && equation.rgb_dst_factor == PIPE_BLENDFACTOR_ZERO &&
@ -446,8 +488,22 @@ pan_blend_reads_dest(const struct pan_blend_equation equation)
if (!equation.blend_enable) if (!equation.blend_enable)
return false; return false;
return is_min_max(equation.rgb_func) || is_min_max(equation.alpha_func) || /* NOTE (NaN/inf):
is_dest_factor(equation.rgb_src_factor, false) || *
* Technically, we should reject this optimization for float blending
* because 0.0 * NaN/inf = NaN. However, Vulkan and OpenGL both allow us
* to drop inf/NaN pretty much at-will and the NIR blending we would fall
* back to will also drop 0.0 blend factors. One day we might want to do
* all this behind a driconf flag but today is not that day.
*/
/* Min/max blending ignores the factors so the destination always gets
* read verbatim.
*/
if (is_min_max(equation.rgb_func) || is_min_max(equation.alpha_func))
return true;
return is_dest_factor(equation.rgb_src_factor, false) ||
is_dest_factor(equation.alpha_src_factor, true) || is_dest_factor(equation.alpha_src_factor, true) ||
equation.rgb_dst_factor != PIPE_BLENDFACTOR_ZERO || equation.rgb_dst_factor != PIPE_BLENDFACTOR_ZERO ||
equation.alpha_dst_factor != PIPE_BLENDFACTOR_ZERO; equation.alpha_dst_factor != PIPE_BLENDFACTOR_ZERO;
@ -474,9 +530,11 @@ pan_blend_to_fixed_function_equation(const struct pan_blend_equation equation,
/* Compile the fixed-function blend */ /* Compile the fixed-function blend */
to_mali_function(equation.rgb_func, equation.rgb_src_factor, to_mali_function(equation.rgb_func, equation.rgb_src_factor,
equation.rgb_dst_factor, false, &out->rgb); equation.rgb_dst_factor, false /* is_alpha */,
equation.is_float, &out->rgb);
to_mali_function(equation.alpha_func, equation.alpha_src_factor, to_mali_function(equation.alpha_func, equation.alpha_src_factor,
equation.alpha_dst_factor, true, &out->alpha); equation.alpha_dst_factor, true /* is_alpha */,
equation.is_float, &out->alpha);
out->color_mask = equation.color_mask; out->color_mask = equation.color_mask;
} }

View file

@ -35,6 +35,7 @@ struct MALI_BLEND_EQUATION;
struct pan_blend_equation { struct pan_blend_equation {
unsigned blend_enable : 1; unsigned blend_enable : 1;
unsigned is_float : 1;
enum pipe_blend_func rgb_func : 3; enum pipe_blend_func rgb_func : 3;
enum pipe_blendfactor rgb_src_factor : 5; enum pipe_blendfactor rgb_src_factor : 5;
enum pipe_blendfactor rgb_dst_factor : 5; enum pipe_blendfactor rgb_dst_factor : 5;
@ -42,7 +43,6 @@ struct pan_blend_equation {
enum pipe_blendfactor alpha_src_factor : 5; enum pipe_blendfactor alpha_src_factor : 5;
enum pipe_blendfactor alpha_dst_factor : 5; enum pipe_blendfactor alpha_dst_factor : 5;
unsigned color_mask : 4; unsigned color_mask : 4;
unsigned padding : 1;
}; };
struct pan_blend_rt_state { struct pan_blend_rt_state {