panfrost: Simplify make_fixed_blend_mode prototype
[mesa.git] / src / gallium / drivers / panfrost / pan_blending.c
index 54e232b0a4482334fe61c38ffe95a2565f1ae78c..e1122880594b548ab720eda4ab167ab817e813cb 100644 (file)
@@ -25,6 +25,8 @@
 #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 */
 
@@ -141,7 +166,7 @@ uncomplement_factor(int 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:
@@ -181,24 +206,6 @@ panfrost_make_dominant_factor(unsigned src_factor, enum mali_dominant_factor *fa
                 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;
 }
 
@@ -220,16 +227,18 @@ panfrost_make_fixed_blend_part(unsigned func, unsigned src_factor, unsigned dst_
 {
         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;
 
@@ -250,21 +259,29 @@ panfrost_make_fixed_blend_part(unsigned func, unsigned src_factor, unsigned dst_
 
                 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;
         }
 
@@ -276,14 +293,19 @@ panfrost_make_fixed_blend_part(unsigned func, unsigned src_factor, unsigned dst_
                 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));
@@ -291,53 +313,24 @@ panfrost_make_fixed_blend_part(unsigned func, unsigned src_factor, unsigned dst_
         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, void *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! */
-
-        memcpy(out, &constant, sizeof(float));
-        return true;
+        return mask;
 }
 
 /* Create the descriptor for a fixed blend mode given the corresponding Gallium
@@ -346,59 +339,53 @@ panfrost_make_constant(unsigned *factors, unsigned num_factors, const struct pip
  * 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 panfrost_blend_state *so, 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)
 {
-        struct mali_blend_equation *out = &so->equation;
+        /* 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, so, 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, &so->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;
 }