#include <stdio.h>
#include "pan_blending.h"
+#include "pan_context.h"
+#include "gallium/auxiliary/util/u_blend.h"
+#include "util/format/u_format.h"
/*
* Implements fixed-function blending on Midgard.
*
* - negate source (for REVERSE_SUBTRACT)
* - dominant factor "source alpha"
- * - compliment dominant
+ * - complement dominant
* - source dominant
* - force destination to ONE
*
* The following routines implement this fixed function blending encoding
*/
+/* Not all formats can be blended by fixed-function hardware */
+
+bool
+panfrost_can_fixed_blend(enum pipe_format format)
+{
+ /* Fixed-function can handle sRGB */
+ format = util_format_linear(format);
+
+ switch (panfrost_pipe_format_table[format].hw) {
+ case MALI_RGB565:
+ case MALI_RGB5_A1_UNORM:
+ case MALI_RGB10_A2_UNORM:
+ case MALI_RGBA4_UNORM:
+ case MALI_R8_UNORM:
+ case MALI_RG8_UNORM:
+ case MALI_RGB8_UNORM:
+ case MALI_RGBA8_UNORM:
+ return true;
+ default:
+ return false;
+ }
+}
+
/* Helper to find the uncomplemented Gallium blend factor corresponding to a
* complemented Gallium blend factor */
* as necessary */
static bool
-panfrost_make_dominant_factor(unsigned src_factor, enum mali_dominant_factor *factor, bool *invert)
+panfrost_make_dominant_factor(unsigned src_factor, enum mali_dominant_factor *factor)
{
switch (src_factor) {
case PIPE_BLENDFACTOR_SRC_COLOR:
return false;
}
- /* Set invert flags */
-
- switch (src_factor) {
- case PIPE_BLENDFACTOR_ONE:
- case PIPE_BLENDFACTOR_INV_SRC_COLOR:
- case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
- case PIPE_BLENDFACTOR_INV_DST_ALPHA:
- case PIPE_BLENDFACTOR_INV_DST_COLOR:
- case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
- case PIPE_BLENDFACTOR_INV_CONST_COLOR:
- case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
- case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
- *invert = true;
-
- default:
- break;
- }
-
return true;
}
{
struct mali_blend_mode part = { 0 };
- /* Make sure that the blend function is representible with negate flags */
+ /* Make sure that the blend function is representible */
- if (func == PIPE_BLEND_ADD) {
- /* Default, no modifiers needed */
- } else if (func == PIPE_BLEND_SUBTRACT)
- part.negate_dest = true;
- else if (func == PIPE_BLEND_REVERSE_SUBTRACT)
- part.negate_source = true;
- else
+ switch (func) {
+ case PIPE_BLEND_ADD:
+ break;
+
+ /* TODO: Reenable subtraction modes when those fixed */
+ case PIPE_BLEND_SUBTRACT:
+ case PIPE_BLEND_REVERSE_SUBTRACT:
+ default:
return false;
+ }
part.clip_modifier = MALI_BLEND_MOD_NORMAL;
if (src_factor == PIPE_BLENDFACTOR_ONE)
part.clip_modifier = MALI_BLEND_MOD_SOURCE_ONE;
-
} else if (src_factor == dst_factor) {
- part.dominant = MALI_BLEND_DOM_DESTINATION; /* Ought to be an arbitrary choice, but we need to set destination for some reason? Align with the blob until we understand more */
+ /* XXX: Why? */
+ part.dominant = func == PIPE_BLEND_ADD ?
+ MALI_BLEND_DOM_DESTINATION : MALI_BLEND_DOM_SOURCE;
+
part.nondominant_mode = MALI_BLEND_NON_MIRROR;
} else if (src_factor == complement_factor(dst_factor)) {
/* TODO: How does this work exactly? */
part.dominant = MALI_BLEND_DOM_SOURCE;
part.nondominant_mode = MALI_BLEND_NON_MIRROR;
part.clip_modifier = MALI_BLEND_MOD_DEST_ONE;
+
+ /* The complement is handled by the clip modifier, don't set a
+ * complement flag */
+
+ dst_factor = src_factor;
} else if (dst_factor == complement_factor(src_factor)) {
part.dominant = MALI_BLEND_DOM_SOURCE;
part.nondominant_mode = MALI_BLEND_NON_MIRROR;
- part.clip_modifier = /*MALI_BLEND_MOD_SOURCE_ONE*/MALI_BLEND_MOD_DEST_ONE; /* Which modifier should it be? */
+ part.clip_modifier = MALI_BLEND_MOD_SOURCE_ONE;
+
+ src_factor = dst_factor;
} else {
- printf("Failed to find dominant factor?\n");
return false;
}
in_dominant_factor = PIPE_BLENDFACTOR_ZERO;
}
- bool invert_dominant = false;
enum mali_dominant_factor dominant_factor;
- if (!panfrost_make_dominant_factor(in_dominant_factor, &dominant_factor, &invert_dominant))
+ if (!panfrost_make_dominant_factor(in_dominant_factor, &dominant_factor))
return false;
part.dominant_factor = dominant_factor;
- part.complement_dominant = invert_dominant;
+ part.complement_dominant = util_blend_factor_is_inverted(in_dominant_factor);
+
+ /* It's not clear what this does, but fixes some ADD blending tests.
+ * More research is needed XXX */
+
+ if ((part.clip_modifier == MALI_BLEND_MOD_SOURCE_ONE) && (part.dominant == MALI_BLEND_DOM_SOURCE))
+ part.negate_dest = true;
/* Write out mode */
memcpy(out, &part, sizeof(part));
return true;
}
-/* We can upload a single constant for all of the factors. So, scan the factors
- * for constants used, and scan the constants for the constants used. If there
- * is a single unique constant, output that. If there are multiple,
- * fixed-function operation breaks down. */
+/* We can upload a single constant for all of the factors. So, scan
+ * the factors for constants used to create a mask to check later. */
-static bool
-panfrost_make_constant(unsigned *factors, unsigned num_factors, const struct pipe_blend_color *blend_color, float *out)
+static unsigned
+panfrost_constant_mask(unsigned *factors, unsigned num_factors)
{
- /* Color components used */
- bool cc[4] = { false };
+ unsigned mask = 0;
for (unsigned i = 0; i < num_factors; ++i) {
unsigned factor = uncomplement_factor(factors[i]);
if (factor == PIPE_BLENDFACTOR_CONST_COLOR)
- cc[0] = cc[1] = cc[2] = true;
+ mask |= 0b0111; /* RGB */
else if (factor == PIPE_BLENDFACTOR_CONST_ALPHA)
- cc[3] = true;
+ mask |= 0b1000; /* A */
}
- /* Find the actual constant associated with the components used*/
-
- float constant = 0.0;
- bool has_constant = false;
-
- for (unsigned i = 0; i < 4; ++i) {
- /* If the component is unused, nothing to do */
- if (!cc[i]) continue;
-
- float value = blend_color->color[i];
-
- /* Either there's a second constant, in which case we fail, or
- * there's no constant / a first constant, in which case we use
- * that constant */
-
- if (has_constant && constant != value) {
- return false;
- } else {
- has_constant = true;
- constant = value;
- }
- }
-
- /* We have the constant -- success! */
-
- *out = constant;
- return true;
+ return mask;
}
/* Create the descriptor for a fixed blend mode given the corresponding Gallium
* representating, return false to handle degenerate cases with a blend shader
*/
-static const struct pipe_rt_blend_state default_blend = {
- .blend_enable = 1,
-
- .rgb_func = PIPE_BLEND_ADD,
- .rgb_src_factor = PIPE_BLENDFACTOR_ONE,
- .rgb_dst_factor = PIPE_BLENDFACTOR_ZERO,
-
- .alpha_func = PIPE_BLEND_ADD,
- .alpha_src_factor = PIPE_BLENDFACTOR_ONE,
- .alpha_dst_factor = PIPE_BLENDFACTOR_ZERO,
-
- .colormask = PIPE_MASK_RGBA
-};
-
bool
-panfrost_make_fixed_blend_mode(const struct pipe_rt_blend_state *blend, struct mali_blend_equation *out, unsigned colormask, const struct pipe_blend_color *blend_color)
+panfrost_make_fixed_blend_mode(
+ struct pipe_rt_blend_state blend,
+ struct mali_blend_equation *out,
+ unsigned *constant_mask)
{
+ /* Gallium and Mali represent colour masks identically. XXX: Static
+ * assert for future proof */
+
+ out->color_mask = blend.colormask;
+
/* If no blending is enabled, default back on `replace` mode */
- if (!blend->blend_enable)
- return panfrost_make_fixed_blend_mode(&default_blend, out, colormask, blend_color);
+ if (!blend.blend_enable) {
+ out->rgb_mode = 0x122;
+ out->alpha_mode = 0x122;
+ return true;
+ }
- /* We have room only for a single float32 constant between the four
- * components. If we need more, spill to the programmable pipeline. */
+ /* At draw-time, we'll need to analyze the blend constant, so
+ * precompute a mask for it -- even if we don't end up able to use
+ * fixed-function blending */
unsigned factors[] = {
- blend->rgb_src_factor, blend->rgb_dst_factor,
- blend->alpha_src_factor, blend->alpha_dst_factor,
+ blend.rgb_src_factor, blend.rgb_dst_factor,
+ blend.alpha_src_factor, blend.alpha_dst_factor,
};
- if (!panfrost_make_constant(factors, ARRAY_SIZE(factors), blend_color, &out->constant))
- return false;
+ *constant_mask = panfrost_constant_mask(factors, ARRAY_SIZE(factors));
+
+ /* Try to compile the actual fixed-function blend */
unsigned rgb_mode = 0;
unsigned alpha_mode = 0;
if (!panfrost_make_fixed_blend_part(
- blend->rgb_func, blend->rgb_src_factor, blend->rgb_dst_factor,
- &rgb_mode))
+ blend.rgb_func, blend.rgb_src_factor, blend.rgb_dst_factor,
+ &rgb_mode))
return false;
if (!panfrost_make_fixed_blend_part(
- blend->alpha_func, blend->alpha_src_factor, blend->alpha_dst_factor,
- &alpha_mode))
+ blend.alpha_func, blend.alpha_src_factor, blend.alpha_dst_factor,
+ &alpha_mode))
return false;
out->rgb_mode = rgb_mode;
out->alpha_mode = alpha_mode;
- /* Gallium and Mali represent colour masks identically. XXX: Static assert for future proof */
- out->color_mask = colormask;
-
return true;
}