panfrost: Move the blend logic out of the gallium driver
authorBoris Brezillon <boris.brezillon@collabora.com>
Wed, 10 Feb 2021 07:47:39 +0000 (08:47 +0100)
committerMarge Bot <eric+marge@anholt.net>
Mon, 15 Feb 2021 11:23:46 +0000 (11:23 +0000)
Most of it is API-independent, so let's move it out of the gallium
driver so it can be shared with the Vulkan driver.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Acked-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8963>

13 files changed:
src/gallium/drivers/panfrost/Makefile.sources
src/gallium/drivers/panfrost/meson.build
src/gallium/drivers/panfrost/pan_blend_cso.c
src/gallium/drivers/panfrost/pan_blend_cso.h
src/gallium/drivers/panfrost/pan_blend_shaders.c
src/gallium/drivers/panfrost/pan_blending.c [deleted file]
src/gallium/drivers/panfrost/pan_blending.h [deleted file]
src/gallium/drivers/panfrost/pan_context.c
src/gallium/drivers/panfrost/pan_job.c
src/panfrost/Makefile.sources
src/panfrost/lib/meson.build
src/panfrost/lib/pan_blend.c [new file with mode: 0644]
src/panfrost/lib/pan_blend.h [new file with mode: 0644]

index d858d47..81e9884 100644 (file)
@@ -2,8 +2,6 @@ C_SOURCES := \
        pan_assemble.c \
        pan_blend_cso.c \
        pan_blend_cso.h \
-       pan_blending.c \
-       pan_blending.h \
        pan_blend_shaders.c \
        pan_blend_shaders.h \
        pan_blit.c \
index 66647c9..0e4a70b 100644 (file)
@@ -29,7 +29,6 @@ files_panfrost = files(
   'pan_blit.c',
   'pan_job.c',
   'pan_assemble.c',
-  'pan_blending.c',
   'pan_blend_shaders.c',
   'pan_blend_cso.c',
   'pan_cmdstream.c',
index 553df21..32ccab4 100644 (file)
@@ -29,7 +29,6 @@
 #include "util/u_memory.h"
 #include "gallium/auxiliary/util/u_blend.h"
 #include "pan_blend_shaders.h"
-#include "pan_blending.h"
 #include "pan_bo.h"
 #include "panfrost-quirks.h"
 
@@ -115,50 +114,38 @@ static void *
 panfrost_create_blend_state(struct pipe_context *pipe,
                             const struct pipe_blend_state *blend)
 {
-        struct panfrost_device *dev = pan_device(pipe->screen);
         struct panfrost_context *ctx = pan_context(pipe);
         struct panfrost_blend_state *so = rzalloc(ctx, struct panfrost_blend_state);
         so->base = *blend;
 
+        so->pan.dither = blend->dither;
+        so->pan.logicop_enable = blend->logicop_enable;
+        so->pan.logicop_func = blend->logicop_func;
+        so->pan.rt_count = blend->max_rt + 1;
+
         /* TODO: The following features are not yet implemented */
         assert(!blend->alpha_to_one);
 
-        for (unsigned c = 0; c < PIPE_MAX_COLOR_BUFS; ++c) {
+        for (unsigned c = 0; c < so->pan.rt_count; ++c) {
                 unsigned g = blend->independent_blend_enable ? c : 0;
-                struct pipe_rt_blend_state pipe = blend->rt[g];
-
-                struct panfrost_blend_rt *rt = &so->rt[c];
+                const struct pipe_rt_blend_state *pipe = &blend->rt[g];
+                struct pan_blend_equation *equation = &so->pan.rts[c].equation;
 
-                /* Logic ops are always shader */
-                if (blend->logicop_enable) {
-                        rt->load_dest = true;
+                equation->color_mask = pipe->colormask;
+                equation->blend_enable = pipe->blend_enable;
+                if (!equation->blend_enable)
                         continue;
-                }
-
-                rt->constant_mask = panfrost_blend_constant_mask(&pipe);
-                rt->has_fixed_function =
-                        panfrost_make_fixed_blend_mode(pipe, &rt->equation);
-
-                /* v6 doesn't support blend constants in FF blend equations. */
-                if (rt->has_fixed_function && dev->arch == 6 && rt->constant_mask)
-                        rt->has_fixed_function = false;
-
-                if (rt->has_fixed_function) {
-                        rt->opaque = pipe.rgb_src_factor == PIPE_BLENDFACTOR_ONE &&
-                                     pipe.rgb_dst_factor == PIPE_BLENDFACTOR_ZERO &&
-                                     (pipe.rgb_func == PIPE_BLEND_ADD ||
-                                      pipe.rgb_func == PIPE_BLEND_SUBTRACT) &&
-                                     pipe.alpha_src_factor == PIPE_BLENDFACTOR_ONE &&
-                                     pipe.alpha_dst_factor == PIPE_BLENDFACTOR_ZERO &&
-                                     (pipe.alpha_func == PIPE_BLEND_ADD ||
-                                      pipe.alpha_func == PIPE_BLEND_SUBTRACT) &&
-                                     pipe.colormask == 0xf;
-                }
-
-                rt->load_dest = util_blend_uses_dest(pipe)
-                        || pipe.colormask != 0xF;
-
-                rt->no_colour = pipe.colormask == 0x0;
+
+                equation->rgb_func = util_blend_func_to_shader(pipe->rgb_func);
+                equation->rgb_src_factor = util_blend_factor_to_shader(pipe->rgb_src_factor);
+                equation->rgb_invert_src_factor = util_blend_factor_is_inverted(pipe->rgb_src_factor);
+                equation->rgb_dst_factor = util_blend_factor_to_shader(pipe->rgb_dst_factor);
+                equation->rgb_invert_dst_factor = util_blend_factor_is_inverted(pipe->rgb_dst_factor);
+                equation->alpha_func = util_blend_func_to_shader(pipe->alpha_func);
+                equation->alpha_src_factor = util_blend_factor_to_shader(pipe->alpha_src_factor);
+                equation->alpha_invert_src_factor = util_blend_factor_is_inverted(pipe->alpha_src_factor);
+                equation->alpha_dst_factor = util_blend_factor_to_shader(pipe->alpha_dst_factor);
+                equation->alpha_invert_dst_factor = util_blend_factor_is_inverted(pipe->alpha_dst_factor);
         }
 
         return so;
@@ -190,77 +177,47 @@ panfrost_set_blend_color(struct pipe_context *pipe,
                 ctx->blend_color = *blend_color;
 }
 
-/* Given a vec4 of constants, reduce it to just a single constant according to
- * the mask (if we can) */
-
-static bool
-panfrost_blend_constant(float *out, float *in, unsigned mask)
-{
-        /* If there is no components used, it automatically works */
-
-        if (!mask)
-                return true;
-
-        /* Find some starter mask */
-        unsigned first = ffs(mask) - 1;
-        float cons = in[first];
-        mask ^= (1 << first);
-
-        /* Ensure the rest are equal */
-        while (mask) {
-                unsigned i = u_bit_scan(&mask);
-
-                if (in[i] != cons)
-                        return false;
-        }
-
-        /* Otherwise, we're good to go */
-        *out = cons;
-        return true;
-}
-
 /* Create a final blend given the context */
 
 struct panfrost_blend_final
 panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rti, struct panfrost_bo **bo, unsigned *shader_offset)
 {
+        struct panfrost_device *dev = pan_device(ctx->base.screen);
         struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx);
         struct pipe_framebuffer_state *fb = &ctx->pipe_framebuffer;
         enum pipe_format fmt = fb->cbufs[rti]->format;
+        unsigned nr_samples = fb->cbufs[rti]->nr_samples ? :
+                              fb->cbufs[rti]->texture->nr_samples;
 
         /* Grab the blend state */
         struct panfrost_blend_state *blend = ctx->blend;
-        struct panfrost_blend_rt *rt = &blend->rt[rti];
+        struct pan_blend_state pan_blend = blend->pan;
+
+        pan_blend.rts[rti].format = fmt;
+        pan_blend.rts[rti].nr_samples = nr_samples;
+        memcpy(pan_blend.constants, ctx->blend_color.color,
+               sizeof(pan_blend.constants));
 
         /* First, we'll try fixed function, matching equation and constant */
-        if (rt->has_fixed_function && panfrost_can_fixed_blend(fmt)) {
-                float constant = 0.0;
-
-                if (panfrost_blend_constant(
-                            &constant,
-                            ctx->blend_color.color,
-                            rt->constant_mask)) {
-                        struct panfrost_blend_final final = {
-                                .equation = {
-                                        .equation = rt->equation,
-                                        .constant = constant
-                                },
-                                .load_dest = rt->load_dest,
-                                .opaque = rt->opaque,
-                                .no_colour = rt->no_colour
-                        };
-
-                        return final;
-                }
+        if (pan_blend_can_fixed_function(dev, &pan_blend, rti)) {
+                struct panfrost_blend_final final = {
+                        .load_dest = pan_blend_reads_dest(&pan_blend, rti),
+                        .equation.constant = pan_blend_get_constant(dev, &pan_blend, rti),
+                        .opaque = pan_blend_is_opaque(&pan_blend, rti),
+                        .no_colour = pan_blend.rts[rti].equation.color_mask == 0,
+                };
+
+                pan_blend_to_fixed_function_equation(dev, &pan_blend, rti,
+                                                     &final.equation.equation);
+                return final;
         }
 
-        unsigned nr_samples = fb->cbufs[rti]->nr_samples ? :
-                              fb->cbufs[rti]->texture->nr_samples;
 
         /* Otherwise, we need to grab a shader */
+        unsigned constant_mask = pan_blend_constant_mask(&pan_blend, rti);
         struct panfrost_blend_shader *shader =
                 panfrost_get_blend_shader(ctx, blend, fmt, nr_samples, rti,
-                                          rt->constant_mask ?
+                                          constant_mask ?
                                           ctx->blend_color.color : NULL);
 
         /* Upload the shader, sharing a BO */
@@ -284,7 +241,7 @@ panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rti, struc
                         .first_tag = shader->first_tag,
                         .gpu = (*bo)->ptr.gpu + *shader_offset,
                 },
-                .load_dest = rt->load_dest,
+                .load_dest = pan_blend_reads_dest(&pan_blend, rti),
         };
 
         *shader_offset += shader->size;
index 433f94a..71b4001 100644 (file)
@@ -28,6 +28,7 @@
 #ifndef __PAN_BLEND_CSO_H
 #define __PAN_BLEND_CSO_H
 
+#include "pan_blend.h"
 #include "util/hash_table.h"
 #include "nir.h"
 
@@ -95,24 +96,9 @@ struct panfrost_blend_equation_final {
         float constant;
 };
 
-struct panfrost_blend_rt {
-        /* If has_fixed_function is set, equation is the
-         * fixed-function configuration for this blend state */
-
-        bool has_fixed_function;
-        struct MALI_BLEND_EQUATION equation;
-
-        /* Mask of blend color components read */
-        unsigned constant_mask;
-
-        /* Properties of the blend mode */
-        bool opaque, load_dest, no_colour;
-};
-
 struct panfrost_blend_state {
         struct pipe_blend_state base;
-
-        struct panfrost_blend_rt rt[PIPE_MAX_COLOR_BUFS];
+        struct pan_blend_state pan;
 };
 
 /* Container for a final blend state, specialized to constants and a
index 4d0166e..f2ad5c3 100644 (file)
  * (compilation).
  */
 
-static nir_lower_blend_options
-nir_make_options(const struct pipe_blend_state *blend, unsigned i)
-{
-        nir_lower_blend_options options = { 0 };
-
-        if (blend->logicop_enable) {
-            options.logicop_enable = true;
-            options.logicop_func = blend->logicop_func;
-            return options;
-        }
-
-        options.logicop_enable = false;
-
-        if (!blend->independent_blend_enable)
-                i = 0;
-
-        /* If blend is disabled, we just use replace mode */
-
-        nir_lower_blend_channel rgb = {
-                .func = BLEND_FUNC_ADD,
-                .src_factor = BLEND_FACTOR_ZERO,
-                .invert_src_factor = true,
-                .dst_factor = BLEND_FACTOR_ZERO,
-                .invert_dst_factor = false
-        };
-
-        nir_lower_blend_channel alpha = rgb;
-
-        if (blend->rt[i].blend_enable) {
-                rgb.func = util_blend_func_to_shader(blend->rt[i].rgb_func);
-                rgb.src_factor = util_blend_factor_to_shader(blend->rt[i].rgb_src_factor);
-                rgb.dst_factor = util_blend_factor_to_shader(blend->rt[i].rgb_dst_factor);
-                rgb.invert_src_factor = util_blend_factor_is_inverted(blend->rt[i].rgb_src_factor);
-                rgb.invert_dst_factor = util_blend_factor_is_inverted(blend->rt[i].rgb_dst_factor);
-
-                alpha.func = util_blend_func_to_shader(blend->rt[i].alpha_func);
-                alpha.src_factor = util_blend_factor_to_shader(blend->rt[i].alpha_src_factor);
-                alpha.dst_factor = util_blend_factor_to_shader(blend->rt[i].alpha_dst_factor);
-                alpha.invert_src_factor = util_blend_factor_is_inverted(blend->rt[i].alpha_src_factor);
-                alpha.invert_dst_factor = util_blend_factor_is_inverted(blend->rt[i].alpha_dst_factor);
-        }
-
-        options.rgb = rgb;
-        options.alpha = alpha;
-
-        options.colormask = blend->rt[i].colormask;
-
-        return options;
-}
-
-static nir_ssa_def *
-nir_iclamp(nir_builder *b, nir_ssa_def *v, int32_t lo, int32_t hi)
-{
-        return nir_imin(b, nir_imax(b, v, nir_imm_int(b, lo)), nir_imm_int(b, hi));
-}
-
 struct panfrost_blend_shader *
 panfrost_create_blend_shader(struct panfrost_context *ctx,
                              struct panfrost_blend_state *state,
@@ -138,82 +82,16 @@ panfrost_create_blend_shader(struct panfrost_context *ctx,
 {
         struct panfrost_device *dev = pan_device(ctx->base.screen);
         struct panfrost_blend_shader *res = rzalloc(ctx, struct panfrost_blend_shader);
+        struct pan_blend_state pan_blend = state->pan;
 
         res->ctx = ctx;
         res->key = *key;
 
         /* Build the shader */
+        pan_blend.rts[key->rt].format = key->format;
+        pan_blend.rts[key->rt].nr_samples = key->nr_samples;
+        res->nir = pan_blend_create_shader(dev, &pan_blend, key->rt);
 
-        nir_shader *shader = nir_shader_create(ctx, MESA_SHADER_FRAGMENT, &midgard_nir_options, NULL);
-        nir_function *fn = nir_function_create(shader, "main");
-        fn->is_entrypoint = true;
-        nir_function_impl *impl = nir_function_impl_create(fn);
-
-        const struct util_format_description *format_desc =
-                util_format_description(key->format);
-
-        nir_alu_type T = pan_unpacked_type_for_format(format_desc);
-        enum glsl_base_type g =
-                (T == nir_type_float16) ? GLSL_TYPE_FLOAT16 :
-                (T == nir_type_float32) ? GLSL_TYPE_FLOAT :
-                (T == nir_type_int8) ? GLSL_TYPE_INT8 :
-                (T == nir_type_int16) ? GLSL_TYPE_INT16 :
-                (T == nir_type_int32) ? GLSL_TYPE_INT :
-                (T == nir_type_uint8) ? GLSL_TYPE_UINT8 :
-                (T == nir_type_uint16) ? GLSL_TYPE_UINT16 :
-                (T == nir_type_uint32) ? GLSL_TYPE_UINT :
-                GLSL_TYPE_FLOAT;
-
-        /* Create the blend variables */
-
-        nir_variable *c_src = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_Color");
-        nir_variable *c_src1 = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_Color1");
-        nir_variable *c_out = nir_variable_create(shader, nir_var_shader_out, glsl_vector_type(g, 4), "gl_FragColor");
-
-        c_src->data.location = VARYING_SLOT_COL0;
-        c_src1->data.location = VARYING_SLOT_VAR0;
-        c_out->data.location = FRAG_RESULT_COLOR;
-
-        c_src1->data.driver_location = 1;
-
-        /* Setup nir_builder */
-
-        nir_builder _b;
-        nir_builder *b = &_b;
-        nir_builder_init(b, impl);
-        b->cursor = nir_before_block(nir_start_block(impl));
-
-        /* Setup inputs */
-
-        nir_ssa_def *s_src[] = {nir_load_var(b, c_src), nir_load_var(b, c_src1)};
-
-        for (int i = 0; i < ARRAY_SIZE(s_src); ++i) {
-                if (T == nir_type_float16)
-                        s_src[i] = nir_f2f16(b, s_src[i]);
-                else if (T == nir_type_int16)
-                        s_src[i] = nir_i2i16(b, nir_iclamp(b, s_src[i], -32768, 32767));
-                else if (T == nir_type_uint16)
-                        s_src[i] = nir_u2u16(b, nir_umin(b, s_src[i], nir_imm_int(b, 65535)));
-                else if (T == nir_type_int8)
-                        s_src[i] = nir_i2i8(b, nir_iclamp(b, s_src[i], -128, 127));
-                else if (T == nir_type_uint8)
-                        s_src[i] = nir_u2u8(b, nir_umin(b, s_src[i], nir_imm_int(b, 255)));
-        }
-
-        /* Build a trivial blend shader */
-        nir_store_var(b, c_out, s_src[0], 0xFF);
-
-        nir_lower_blend_options options = nir_make_options(&state->base, key->rt);
-        options.format = key->format;
-        options.is_bifrost = pan_is_bifrost(dev);
-        options.src1 = s_src[1];
-
-        if (T == nir_type_float16)
-                options.half = true;
-
-        NIR_PASS_V(shader, nir_lower_blend, options);
-
-        res->nir = shader;
         return res;
 }
 
diff --git a/src/gallium/drivers/panfrost/pan_blending.c b/src/gallium/drivers/panfrost/pan_blending.c
deleted file mode 100644 (file)
index bc76fac..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Â© Copyright 2018 Alyssa Rosenzweig
- * Copyright (C) 2019-2020 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#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. */
-
-/* Not all formats can be blended by fixed-function hardware */
-
-bool
-panfrost_can_fixed_blend(enum pipe_format format)
-{
-        return panfrost_blend_format(format).internal != 0;
-}
-
-/* Helper to find the uncomplemented Gallium blend factor corresponding to a
- * complemented Gallium blend factor */
-
-static int
-complement_factor(int factor)
-{
-        switch (factor) {
-        case PIPE_BLENDFACTOR_INV_SRC_COLOR:
-                return PIPE_BLENDFACTOR_SRC_COLOR;
-
-        case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
-                return PIPE_BLENDFACTOR_SRC_ALPHA;
-
-        case PIPE_BLENDFACTOR_INV_DST_ALPHA:
-                return PIPE_BLENDFACTOR_DST_ALPHA;
-
-        case PIPE_BLENDFACTOR_INV_DST_COLOR:
-                return PIPE_BLENDFACTOR_DST_COLOR;
-
-        case PIPE_BLENDFACTOR_INV_CONST_COLOR:
-                return PIPE_BLENDFACTOR_CONST_COLOR;
-
-        case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
-                return PIPE_BLENDFACTOR_CONST_ALPHA;
-
-        default:
-                return -1;
-        }
-}
-
-/* Helper to strip the complement from any Gallium blend factor */
-
-static int
-uncomplement_factor(int factor)
-{
-        int complement = complement_factor(factor);
-        return (complement == -1) ? factor : complement;
-}
-
-/* Check if this is a special edge case blend factor, which may require the use
- * of clip modifiers */
-
-static bool
-is_edge_blendfactor(unsigned factor)
-{
-        return factor == PIPE_BLENDFACTOR_ONE || factor == PIPE_BLENDFACTOR_ZERO;
-}
-
-static bool
-factor_is_supported(unsigned factor)
-{
-        return factor != PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE &&
-               factor != PIPE_BLENDFACTOR_SRC1_COLOR &&
-               factor != PIPE_BLENDFACTOR_SRC1_ALPHA &&
-               factor != PIPE_BLENDFACTOR_INV_SRC1_COLOR &&
-               factor != PIPE_BLENDFACTOR_INV_SRC1_ALPHA;
-}
-
-static bool
-can_use_fixed_function_blend(unsigned blend_func,
-                             unsigned src_factor,
-                             unsigned dest_factor)
-{
-        if (blend_func != PIPE_BLEND_ADD &&
-            blend_func != PIPE_BLEND_SUBTRACT &&
-            blend_func != PIPE_BLEND_REVERSE_SUBTRACT)
-                return false;
-
-        if (!factor_is_supported(src_factor) ||
-            !factor_is_supported(dest_factor))
-                return false;
-
-        if (src_factor != dest_factor &&
-            src_factor != complement_factor(dest_factor) &&
-            complement_factor(src_factor) != dest_factor &&
-            !is_edge_blendfactor(src_factor) &&
-            !is_edge_blendfactor(dest_factor))
-                return false;
-
-        return true;
-}
-
-static void to_c_factor(unsigned factor, struct MALI_BLEND_FUNCTION *function)
-{
-        if (complement_factor(factor) >= 0)
-                function->invert_c = true;
-
-        switch (uncomplement_factor(factor)) {
-        case PIPE_BLENDFACTOR_ONE:
-        case PIPE_BLENDFACTOR_ZERO:
-                function->invert_c = factor == PIPE_BLENDFACTOR_ONE;
-                function->c = MALI_BLEND_OPERAND_C_ZERO;
-                break;
-
-        case PIPE_BLENDFACTOR_SRC_ALPHA:
-                function->c = MALI_BLEND_OPERAND_C_SRC_ALPHA;
-                break;
-
-        case PIPE_BLENDFACTOR_DST_ALPHA:
-                function->c = MALI_BLEND_OPERAND_C_DEST_ALPHA;
-                break;
-
-        case PIPE_BLENDFACTOR_SRC_COLOR:
-                function->c = MALI_BLEND_OPERAND_C_SRC;
-                break;
-
-        case PIPE_BLENDFACTOR_DST_COLOR:
-                function->c = MALI_BLEND_OPERAND_C_DEST;
-                break;
-
-        case PIPE_BLENDFACTOR_CONST_COLOR:
-        case PIPE_BLENDFACTOR_CONST_ALPHA:
-                function->c = MALI_BLEND_OPERAND_C_CONSTANT;
-                break;
-        default:
-                unreachable("Invalid blend factor");
-        }
-
-}
-
-static bool
-to_panfrost_function(unsigned blend_func,
-                     unsigned src_factor,
-                     unsigned dest_factor,
-                     struct MALI_BLEND_FUNCTION *function)
-{
-        if (!can_use_fixed_function_blend(blend_func, src_factor, dest_factor))
-                return false;
-
-        if (src_factor == PIPE_BLENDFACTOR_ZERO) {
-                function->a = MALI_BLEND_OPERAND_A_ZERO;
-                function->b = MALI_BLEND_OPERAND_B_DEST;
-                if (blend_func == PIPE_BLEND_SUBTRACT)
-                        function->negate_b = true;
-                to_c_factor(dest_factor, function);
-        } else if (src_factor == PIPE_BLENDFACTOR_ONE) {
-                function->a = MALI_BLEND_OPERAND_A_SRC;
-                function->b = MALI_BLEND_OPERAND_B_DEST;
-                if (blend_func == PIPE_BLEND_SUBTRACT)
-                        function->negate_b = true;
-                else if (blend_func == PIPE_BLEND_REVERSE_SUBTRACT)
-                        function->negate_a = true;
-                to_c_factor(dest_factor, function);
-        } else if (dest_factor == PIPE_BLENDFACTOR_ZERO) {
-                function->a = MALI_BLEND_OPERAND_A_ZERO;
-                function->b = MALI_BLEND_OPERAND_B_SRC;
-                if (blend_func == PIPE_BLEND_REVERSE_SUBTRACT)
-                        function->negate_b = true;
-                to_c_factor(src_factor, function);
-        } else if (dest_factor == PIPE_BLENDFACTOR_ONE) {
-                function->a = MALI_BLEND_OPERAND_A_DEST;
-                function->b = MALI_BLEND_OPERAND_B_SRC;
-                if (blend_func == PIPE_BLEND_SUBTRACT)
-                        function->negate_a = true;
-                else if (blend_func == PIPE_BLEND_REVERSE_SUBTRACT)
-                        function->negate_b = true;
-                to_c_factor(src_factor, function);
-        } else if (src_factor == dest_factor) {
-                function->a = MALI_BLEND_OPERAND_A_ZERO;
-                to_c_factor(src_factor, function);
-
-                switch (blend_func) {
-                case PIPE_BLEND_ADD:
-                        function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;
-                        break;
-                case PIPE_BLEND_REVERSE_SUBTRACT:
-                        function->negate_b = true;
-                        /* fall-through */
-                case PIPE_BLEND_SUBTRACT:
-                        function->b = MALI_BLEND_OPERAND_B_SRC_MINUS_DEST;
-                        break;
-                default:
-                        unreachable("Invalid blend function");
-                }
-        } else {
-                assert(src_factor == complement_factor(dest_factor) ||
-                       complement_factor(src_factor) == dest_factor);
-
-                function->a = MALI_BLEND_OPERAND_A_DEST;
-                to_c_factor(src_factor, function);
-
-                switch (blend_func) {
-                case PIPE_BLEND_ADD:
-                        function->b = MALI_BLEND_OPERAND_B_SRC_MINUS_DEST;
-                        break;
-                case PIPE_BLEND_REVERSE_SUBTRACT:
-                        function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;
-                        function->negate_b = true;
-                        break;
-                case PIPE_BLEND_SUBTRACT:
-                        function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;
-                        function->negate_a = true;
-                        break;
-                }
-        }
-
-        return true;
-}
-
-/* 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 unsigned
-panfrost_blend_factor_constant_mask(enum pipe_blendfactor factor)
-{
-        unsigned mask = 0;
-
-        factor = uncomplement_factor(factor);
-        if (factor == PIPE_BLENDFACTOR_CONST_COLOR)
-                mask |= 0b0111; /* RGB */
-        else if (factor == PIPE_BLENDFACTOR_CONST_ALPHA)
-                mask |= 0b1000; /* A */
-
-        return mask;
-}
-
-unsigned
-panfrost_blend_constant_mask(const struct pipe_rt_blend_state *blend)
-{
-        return panfrost_blend_factor_constant_mask(blend->rgb_src_factor) |
-               panfrost_blend_factor_constant_mask(blend->rgb_dst_factor) |
-               panfrost_blend_factor_constant_mask(blend->alpha_src_factor) |
-               panfrost_blend_factor_constant_mask(blend->alpha_dst_factor);
-}
-
-/* Create the descriptor for a fixed blend mode given the corresponding Gallium
- * state, if possible. Return true and write out the blend descriptor into
- * blend_equation. If it is not possible with the fixed function
- * representation, return false to handle degenerate cases with a blend shader
- */
-
-bool
-panfrost_make_fixed_blend_mode(const struct pipe_rt_blend_state blend,
-                               struct MALI_BLEND_EQUATION *equation)
-{
-        /* If no blending is enabled, default back on `replace` mode */
-
-        if (!blend.blend_enable) {
-                equation->color_mask = blend.colormask;
-                equation->rgb.a = MALI_BLEND_OPERAND_A_SRC;
-                equation->rgb.b = MALI_BLEND_OPERAND_B_SRC;
-                equation->rgb.c = MALI_BLEND_OPERAND_C_ZERO;
-                equation->alpha.a = MALI_BLEND_OPERAND_A_SRC;
-                equation->alpha.b = MALI_BLEND_OPERAND_B_SRC;
-                equation->alpha.c = MALI_BLEND_OPERAND_C_ZERO;
-                return true;
-        }
-
-        /* Try to compile the actual fixed-function blend */
-        if (!to_panfrost_function(blend.rgb_func, blend.rgb_src_factor,
-                                  blend.rgb_dst_factor,
-                                  &equation->rgb))
-                return false;
-
-        if (!to_panfrost_function(blend.alpha_func, blend.alpha_src_factor,
-                                  blend.alpha_dst_factor,
-                                  &equation->alpha))
-                return false;
-
-        equation->color_mask = blend.colormask;
-        return true;
-}
diff --git a/src/gallium/drivers/panfrost/pan_blending.h b/src/gallium/drivers/panfrost/pan_blending.h
deleted file mode 100644 (file)
index ccc4025..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Â© Copyright 2018 Alyssa Rosenzweig
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#ifndef __PAN_BLENDING_H__
-#define __PAN_BLENDING_H__
-
-#include "pipe/p_state.h"
-#include "pipe/p_defines.h"
-#include <midgard_pack.h>
-#include "pan_blend_cso.h"
-
-struct panfrost_blend_state;
-
-unsigned
-panfrost_blend_constant_mask(const struct pipe_rt_blend_state *blend);
-
-bool
-panfrost_make_fixed_blend_mode(const struct pipe_rt_blend_state blend,
-                               struct MALI_BLEND_EQUATION *equation);
-
-bool
-panfrost_can_fixed_blend(enum pipe_format format);
-
-#endif
index d324dd7..7fb9f0f 100644 (file)
@@ -51,7 +51,6 @@
 
 #include "midgard_pack.h"
 #include "pan_screen.h"
-#include "pan_blending.h"
 #include "pan_blend_shaders.h"
 #include "pan_cmdstream.h"
 #include "pan_util.h"
index 25f664a..f469c38 100644 (file)
@@ -37,7 +37,6 @@
 #include "util/rounding.h"
 #include "util/u_framebuffer.h"
 #include "pan_util.h"
-#include "pan_blending.h"
 #include "pan_cmdstream.h"
 #include "decode.h"
 #include "panfrost-quirks.h"
@@ -829,7 +828,8 @@ panfrost_load_surface(struct panfrost_batch *batch, struct pipe_surface *surf, u
 
         mali_ptr blend_shader = 0;
 
-        if (loc >= FRAG_RESULT_DATA0 && !panfrost_can_fixed_blend(rsrc->base.format)) {
+        if (loc >= FRAG_RESULT_DATA0 &&
+            !panfrost_blend_format(rsrc->base.format).internal) {
                 struct panfrost_blend_shader *b =
                         panfrost_get_blend_shader(batch->ctx, batch->ctx->blit_blend,
                                                   rsrc->base.format,
index fcf9682..2793c19 100644 (file)
@@ -31,6 +31,8 @@ lib_FILES := \
         lib/pan_attributes.c \
         lib/pan_bo.c \
         lib/pan_bo.h \
+        lib/pan_blend.c \
+        lib/pan_blend.h \
         lib/pan_blit.c \
         lib/pan_device.h \
         lib/pan_encoder.h \
index a32b7de..1c3f435 100644 (file)
@@ -25,6 +25,7 @@ libpanfrost_lib_files = files(
   'pan_afbc.c',
   'pan_attributes.c',
   'pan_bo.c',
+  'pan_blend.c',
   'pan_blit.c',
   'pan_format.c',
   'pan_invocation.c',
diff --git a/src/panfrost/lib/pan_blend.c b/src/panfrost/lib/pan_blend.c
new file mode 100644 (file)
index 0000000..3f955b0
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+ * Copyright (C) 2018 Alyssa Rosenzweig
+ * Copyright (C) 2019-2021 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "pan_blend.h"
+#include "pan_shader.h"
+#include "pan_texture.h"
+#include "panfrost/util/pan_lower_framebuffer.h"
+#include "panfrost/util/nir_lower_blend.h"
+#include "util/format/u_format.h"
+#include "compiler/nir/nir.h"
+#include "compiler/nir/nir_builder.h"
+
+/* Implements fixed-function blending on Midgard. */
+
+/* Check if this is a special edge case blend factor, which may require the use
+ * of clip modifiers */
+
+static bool
+factor_is_supported(enum blend_factor factor)
+{
+        return factor != BLEND_FACTOR_SRC_ALPHA_SATURATE &&
+               factor != BLEND_FACTOR_SRC1_COLOR &&
+               factor != BLEND_FACTOR_SRC1_ALPHA;
+}
+
+static bool
+can_fixed_function_equation(enum blend_func blend_func,
+                            enum blend_factor src_factor,
+                            enum blend_factor dest_factor)
+{
+        if (blend_func != BLEND_FUNC_ADD &&
+            blend_func != BLEND_FUNC_SUBTRACT &&
+            blend_func != BLEND_FUNC_REVERSE_SUBTRACT)
+                return false;
+
+        if (!factor_is_supported(src_factor) ||
+            !factor_is_supported(dest_factor))
+                return false;
+
+        if (src_factor != dest_factor &&
+            src_factor != BLEND_FACTOR_ZERO &&
+            dest_factor != BLEND_FACTOR_ZERO)
+                return false;
+
+        return true;
+}
+
+static unsigned
+blend_factor_constant_mask(enum blend_factor factor)
+{
+        unsigned mask = 0;
+
+        if (factor == BLEND_FACTOR_CONSTANT_COLOR)
+                mask |= 0b0111; /* RGB */
+        else if (factor == BLEND_FACTOR_CONSTANT_ALPHA)
+                mask |= 0b1000; /* A */
+
+        return mask;
+}
+
+unsigned
+pan_blend_constant_mask(const struct pan_blend_state *state,
+                        unsigned rt)
+{
+        const struct pan_blend_equation *e = &state->rts[rt].equation;
+
+        return blend_factor_constant_mask(e->rgb_src_factor) |
+               blend_factor_constant_mask(e->rgb_dst_factor) |
+               blend_factor_constant_mask(e->alpha_src_factor) |
+               blend_factor_constant_mask(e->alpha_dst_factor);
+}
+
+static bool
+can_blend_constant(const struct panfrost_device *dev,
+                   const struct pan_blend_state *state,
+                   unsigned rt)
+{
+        unsigned constant_mask = pan_blend_constant_mask(state, rt);
+        if (!constant_mask)
+                return true;
+
+        /* v6 doesn't support blend constants in FF blend equations. */
+        if (dev->arch == 6)
+                return false;
+
+        unsigned first_constant = ffs(constant_mask) - 1;
+        float constant = state->constants[first_constant];
+
+        for (unsigned i = first_constant + 1; i < ARRAY_SIZE(state->constants); i++) {
+                if (((1 << i) & constant_mask) &&
+                    state->constants[i] != constant)
+                        return false;
+        }
+
+        return true;
+}
+
+float
+pan_blend_get_constant(ASSERTED const struct panfrost_device *dev,
+                       const struct pan_blend_state *state,
+                       unsigned rt)
+{
+        assert(can_blend_constant(dev, state, rt));
+
+        unsigned constant_mask = pan_blend_constant_mask(state, rt);
+
+        if (!constant_mask)
+                return 0.0f;
+
+        return state->constants[ffs(constant_mask) - 1];
+}
+
+bool
+pan_blend_can_fixed_function(const struct panfrost_device *dev,
+                             const struct pan_blend_state *state,
+                             unsigned rt)
+{
+        const struct pan_blend_rt_state *rt_state = &state->rts[rt];
+
+        /* LogicOp requires a blend shader */
+        if (state->logicop_enable)
+                return false;
+
+        /* Not all formats can be blended by fixed-function hardware */
+        if (!panfrost_blend_format(rt_state->format).internal)
+                return false;
+
+        if (!rt_state->equation.blend_enable)
+                return true;
+
+        if (!can_blend_constant(dev, state, rt))
+                return false;
+
+        return can_fixed_function_equation(rt_state->equation.rgb_func,
+                                           rt_state->equation.rgb_src_factor,
+                                           rt_state->equation.rgb_dst_factor) &&
+               can_fixed_function_equation(rt_state->equation.alpha_func,
+                                           rt_state->equation.alpha_src_factor,
+                                           rt_state->equation.alpha_dst_factor);
+}
+
+static void
+to_c_factor(enum blend_factor factor, bool invert_factor,
+            struct MALI_BLEND_FUNCTION *function)
+{
+        function->invert_c = invert_factor;
+
+        switch (factor) {
+        case BLEND_FACTOR_ZERO:
+                function->c = MALI_BLEND_OPERAND_C_ZERO;
+                break;
+
+        case BLEND_FACTOR_SRC_ALPHA:
+                function->c = MALI_BLEND_OPERAND_C_SRC_ALPHA;
+                break;
+
+        case BLEND_FACTOR_DST_ALPHA:
+                function->c = MALI_BLEND_OPERAND_C_DEST_ALPHA;
+                break;
+
+        case BLEND_FACTOR_SRC_COLOR:
+                function->c = MALI_BLEND_OPERAND_C_SRC;
+                break;
+
+        case BLEND_FACTOR_DST_COLOR:
+                function->c = MALI_BLEND_OPERAND_C_DEST;
+                break;
+
+        case BLEND_FACTOR_CONSTANT_COLOR:
+        case BLEND_FACTOR_CONSTANT_ALPHA:
+                function->c = MALI_BLEND_OPERAND_C_CONSTANT;
+                break;
+        default:
+                unreachable("Invalid blend factor");
+        }
+
+}
+
+static void
+to_panfrost_function(enum blend_func blend_func,
+                     enum blend_factor src_factor,
+                     bool invert_src,
+                     enum blend_factor dest_factor,
+                     bool invert_dest,
+                     struct MALI_BLEND_FUNCTION *function)
+{
+        assert(can_fixed_function_equation(blend_func, src_factor, dest_factor));
+
+        if (src_factor == BLEND_FACTOR_ZERO && !invert_src) {
+                function->a = MALI_BLEND_OPERAND_A_ZERO;
+                function->b = MALI_BLEND_OPERAND_B_DEST;
+                if (blend_func == BLEND_FUNC_SUBTRACT)
+                        function->negate_b = true;
+                to_c_factor(dest_factor, invert_dest, function);
+        } else if (src_factor == BLEND_FACTOR_ZERO && invert_src) {
+                function->a = MALI_BLEND_OPERAND_A_SRC;
+                function->b = MALI_BLEND_OPERAND_B_DEST;
+                if (blend_func == BLEND_FUNC_SUBTRACT)
+                        function->negate_b = true;
+                else if (blend_func == BLEND_FUNC_REVERSE_SUBTRACT)
+                        function->negate_a = true;
+                to_c_factor(dest_factor, invert_dest, function);
+        } else if (dest_factor == BLEND_FACTOR_ZERO && !invert_dest) {
+                function->a = MALI_BLEND_OPERAND_A_ZERO;
+                function->b = MALI_BLEND_OPERAND_B_SRC;
+                if (blend_func == BLEND_FUNC_REVERSE_SUBTRACT)
+                        function->negate_b = true;
+                to_c_factor(src_factor, invert_src, function);
+        } else if (dest_factor == BLEND_FACTOR_ZERO && invert_dest) {
+                function->a = MALI_BLEND_OPERAND_A_DEST;
+                function->b = MALI_BLEND_OPERAND_B_SRC;
+                if (blend_func == BLEND_FUNC_SUBTRACT)
+                        function->negate_a = true;
+                else if (blend_func == BLEND_FUNC_REVERSE_SUBTRACT)
+                        function->negate_b = true;
+                to_c_factor(src_factor, invert_src, function);
+        } else if (src_factor == dest_factor && invert_src == invert_dest) {
+                function->a = MALI_BLEND_OPERAND_A_ZERO;
+                to_c_factor(src_factor, invert_src, function);
+
+                switch (blend_func) {
+                case BLEND_FUNC_ADD:
+                        function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;
+                        break;
+                case BLEND_FUNC_REVERSE_SUBTRACT:
+                        function->negate_b = true;
+                        /* fall-through */
+                case BLEND_FUNC_SUBTRACT:
+                        function->b = MALI_BLEND_OPERAND_B_SRC_MINUS_DEST;
+                        break;
+                default:
+                        unreachable("Invalid blend function");
+                }
+        } else {
+                assert(src_factor == dest_factor && invert_src != invert_dest);
+
+                function->a = MALI_BLEND_OPERAND_A_DEST;
+                to_c_factor(src_factor, invert_src, function);
+
+                switch (blend_func) {
+                case BLEND_FUNC_ADD:
+                        function->b = MALI_BLEND_OPERAND_B_SRC_MINUS_DEST;
+                        break;
+                case BLEND_FUNC_REVERSE_SUBTRACT:
+                        function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;
+                        function->negate_b = true;
+                        break;
+                case BLEND_FUNC_SUBTRACT:
+                        function->b = MALI_BLEND_OPERAND_B_SRC_PLUS_DEST;
+                        function->negate_a = true;
+                        break;
+                default:
+                        unreachable("Invalid blend function\n");
+                }
+        }
+}
+
+bool
+pan_blend_is_opaque(const struct pan_blend_state *state, unsigned rt)
+{
+        const struct pan_blend_equation *equation = &state->rts[rt].equation;
+
+        return equation->rgb_src_factor == BLEND_FACTOR_ZERO &&
+               equation->rgb_invert_src_factor &&
+               equation->rgb_dst_factor == BLEND_FACTOR_ZERO &&
+               !equation->rgb_invert_dst_factor &&
+               (equation->rgb_func == BLEND_FUNC_ADD ||
+                equation->rgb_func == BLEND_FUNC_SUBTRACT) &&
+               equation->alpha_src_factor == BLEND_FACTOR_ZERO &&
+               equation->alpha_invert_src_factor &&
+               equation->alpha_dst_factor == BLEND_FACTOR_ZERO &&
+               !equation->alpha_invert_dst_factor &&
+               (equation->alpha_func == BLEND_FUNC_ADD ||
+                equation->alpha_func == BLEND_FUNC_SUBTRACT) &&
+               equation->color_mask == 0xf;
+}
+
+static bool
+is_dest_factor(enum blend_factor factor, bool alpha)
+{
+      return factor == BLEND_FACTOR_DST_ALPHA ||
+             factor == BLEND_FACTOR_DST_COLOR ||
+             (factor == BLEND_FACTOR_SRC_ALPHA_SATURATE && !alpha);
+}
+
+bool
+pan_blend_reads_dest(const struct pan_blend_state *state, unsigned rt)
+{
+        const struct pan_blend_rt_state *rt_state = &state->rts[rt];
+
+        if (state->logicop_enable ||
+            (rt_state->equation.color_mask &&
+             rt_state->equation.color_mask != 0xF))
+                return true;
+
+        if (is_dest_factor(rt_state->equation.rgb_src_factor, false) ||
+            is_dest_factor(rt_state->equation.alpha_src_factor, true) ||
+            rt_state->equation.rgb_dst_factor != BLEND_FACTOR_ZERO ||
+            rt_state->equation.rgb_invert_dst_factor ||
+            rt_state->equation.alpha_dst_factor != BLEND_FACTOR_ZERO ||
+            rt_state->equation.alpha_invert_dst_factor)
+                return true;
+
+        return false;
+}
+
+/* Create the descriptor for a fixed blend mode given the corresponding Gallium
+ * state, if possible. Return true and write out the blend descriptor into
+ * blend_equation. If it is not possible with the fixed function
+ * representation, return false to handle degenerate cases with a blend shader
+ */
+
+void
+pan_blend_to_fixed_function_equation(ASSERTED const struct panfrost_device *dev,
+                                     const struct pan_blend_state *state,
+                                     unsigned rt,
+                                     struct MALI_BLEND_EQUATION *equation)
+{
+        const struct pan_blend_rt_state *rt_state = &state->rts[rt];
+
+        assert(pan_blend_can_fixed_function(dev, state, rt));
+
+        /* If no blending is enabled, default back on `replace` mode */
+        if (!rt_state->equation.blend_enable) {
+                equation->color_mask = rt_state->equation.color_mask;
+                equation->rgb.a = MALI_BLEND_OPERAND_A_SRC;
+                equation->rgb.b = MALI_BLEND_OPERAND_B_SRC;
+                equation->rgb.c = MALI_BLEND_OPERAND_C_ZERO;
+                equation->alpha.a = MALI_BLEND_OPERAND_A_SRC;
+                equation->alpha.b = MALI_BLEND_OPERAND_B_SRC;
+                equation->alpha.c = MALI_BLEND_OPERAND_C_ZERO;
+                return;
+        }
+
+        /* Try to compile the actual fixed-function blend */
+        to_panfrost_function(rt_state->equation.rgb_func,
+                             rt_state->equation.rgb_src_factor,
+                             rt_state->equation.rgb_invert_src_factor,
+                             rt_state->equation.rgb_dst_factor,
+                             rt_state->equation.rgb_invert_dst_factor,
+                             &equation->rgb);
+
+        to_panfrost_function(rt_state->equation.alpha_func,
+                             rt_state->equation.alpha_src_factor,
+                             rt_state->equation.alpha_invert_src_factor,
+                             rt_state->equation.alpha_dst_factor,
+                             rt_state->equation.alpha_invert_dst_factor,
+                             &equation->alpha);
+        equation->color_mask = rt_state->equation.color_mask;
+}
+
+static const char *
+logicop_str(enum pipe_logicop logicop)
+{
+        switch (logicop) {
+        case PIPE_LOGICOP_CLEAR: return "clear";
+        case PIPE_LOGICOP_NOR: return "nor";
+        case PIPE_LOGICOP_AND_INVERTED: return "and-inverted";
+        case PIPE_LOGICOP_COPY_INVERTED: return "copy-inverted";
+        case PIPE_LOGICOP_AND_REVERSE: return "and-reverse";
+        case PIPE_LOGICOP_INVERT: return "invert";
+        case PIPE_LOGICOP_XOR: return "xor";
+        case PIPE_LOGICOP_NAND: return "nand";
+        case PIPE_LOGICOP_AND: return "and";
+        case PIPE_LOGICOP_EQUIV: return "equiv";
+        case PIPE_LOGICOP_NOOP: return "noop";
+        case PIPE_LOGICOP_OR_INVERTED: return "or-inverted";
+        case PIPE_LOGICOP_COPY: return "copy";
+        case PIPE_LOGICOP_OR_REVERSE: return "or-reverse";
+        case PIPE_LOGICOP_OR: return "or";
+        case PIPE_LOGICOP_SET: return "set";
+        default: unreachable("Invalid logicop\n");
+        }
+}
+
+static void
+get_equation_str(const struct pan_blend_rt_state *rt_state,
+                 char *str, unsigned len)
+{
+        const char *funcs[] = {
+                "add", "sub", "reverse_sub", "min", "max",
+        };
+        const char *factors[] = {
+                "zero", "src_color", "src1_color", "dst_color",
+                "src_alpha", "src1_alpha", "dst_alpha",
+                "const_color", "const_alpha", "src_alpha_sat",
+        };
+        int ret;
+
+        if (!rt_state->equation.blend_enable) {
+               ret = snprintf(str, len, "replace");
+                assert(ret > 0);
+                return;
+        }
+
+        if (rt_state->equation.color_mask & 7) {
+                assert(rt_state->equation.rgb_func < ARRAY_SIZE(funcs));
+                assert(rt_state->equation.rgb_src_factor < ARRAY_SIZE(factors));
+                assert(rt_state->equation.rgb_dst_factor < ARRAY_SIZE(factors));
+                ret = snprintf(str, len, "%s%s%s(func=%s,src_factor=%s%s,dst_factor=%s%s)%s",
+                               (rt_state->equation.color_mask & 1) ? "R" : "",
+                               (rt_state->equation.color_mask & 2) ? "G" : "",
+                               (rt_state->equation.color_mask & 4) ? "B" : "",
+                               funcs[rt_state->equation.rgb_func],
+                               rt_state->equation.rgb_invert_src_factor ? "-" : "",
+                               factors[rt_state->equation.rgb_src_factor],
+                               rt_state->equation.rgb_invert_dst_factor ? "-" : "",
+                               factors[rt_state->equation.rgb_dst_factor],
+                               rt_state->equation.color_mask & 8 ? ";" : "");
+                assert(ret > 0);
+                str += ret;
+                len -= ret;
+         }
+
+        if (rt_state->equation.color_mask & 8) {
+                assert(rt_state->equation.alpha_func < ARRAY_SIZE(funcs));
+                assert(rt_state->equation.alpha_src_factor < ARRAY_SIZE(factors));
+                assert(rt_state->equation.alpha_dst_factor < ARRAY_SIZE(factors));
+                ret = snprintf(str, len, "A(func=%s,src_factor=%s%s,dst_factor=%s%s)",
+                               funcs[rt_state->equation.alpha_func],
+                               rt_state->equation.alpha_invert_src_factor ? "-" : "",
+                               factors[rt_state->equation.alpha_src_factor],
+                               rt_state->equation.alpha_invert_dst_factor ? "-" : "",
+                               factors[rt_state->equation.alpha_dst_factor]);
+                assert(ret > 0);
+                str += ret;
+                len -= ret;
+         }
+}
+
+static nir_ssa_def *
+nir_iclamp(nir_builder *b, nir_ssa_def *v, int32_t lo, int32_t hi)
+{
+        return nir_imin(b, nir_imax(b, v, nir_imm_int(b, lo)), nir_imm_int(b, hi));
+}
+
+nir_shader *
+pan_blend_create_shader(const struct panfrost_device *dev,
+                        const struct pan_blend_state *state,
+                        unsigned rt)
+{
+        const struct pan_blend_rt_state *rt_state = &state->rts[rt];
+        char equation_str[128] = { 0 };
+
+        get_equation_str(rt_state, equation_str, sizeof(equation_str));
+
+        nir_builder b =
+                nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT,
+                                               pan_shader_get_compiler_options(dev),
+                                               "pan_blend(rt=%d,fmt=%s,nr_samples=%d,%s=%s)",
+                                               rt, util_format_name(rt_state->format),
+                                               rt_state->nr_samples,
+                                               state->logicop_enable ? "logicop" : "equation",
+                                               state->logicop_enable ?
+                                               logicop_str(state->logicop_func) : equation_str);
+
+        const struct util_format_description *format_desc =
+                util_format_description(rt_state->format);
+        nir_alu_type nir_type = pan_unpacked_type_for_format(format_desc);
+        enum glsl_base_type glsl_type = nir_get_glsl_base_type_for_nir_type(nir_type);
+
+        nir_lower_blend_options options = {
+                .logicop_enable = state->logicop_enable,
+                .logicop_func = state->logicop_func,
+                .colormask = rt_state->equation.color_mask,
+                .half = nir_type == nir_type_float16,
+                .format = rt_state->format,
+                .is_bifrost = pan_is_bifrost(dev),
+        };
+
+        if (!rt_state->equation.blend_enable) {
+                static const nir_lower_blend_channel replace = {
+                        .func = BLEND_FUNC_ADD,
+                        .src_factor = BLEND_FACTOR_ZERO,
+                        .invert_src_factor = true,
+                        .dst_factor = BLEND_FACTOR_ZERO,
+                        .invert_dst_factor = false,
+                };
+
+                options.rgb = replace;
+                options.alpha = replace;
+        } else {
+                options.rgb.func = rt_state->equation.rgb_func;
+                options.rgb.src_factor = rt_state->equation.rgb_src_factor;
+                options.rgb.invert_src_factor = rt_state->equation.rgb_invert_src_factor;
+                options.rgb.dst_factor = rt_state->equation.rgb_dst_factor;
+                options.rgb.invert_dst_factor = rt_state->equation.rgb_invert_dst_factor;
+                options.alpha.func = rt_state->equation.alpha_func;
+                options.alpha.src_factor = rt_state->equation.alpha_src_factor;
+                options.alpha.invert_src_factor = rt_state->equation.alpha_invert_src_factor;
+                options.alpha.dst_factor = rt_state->equation.alpha_dst_factor;
+                options.alpha.invert_dst_factor = rt_state->equation.alpha_invert_dst_factor;
+        }
+
+       nir_variable *c_src =
+                nir_variable_create(b.shader, nir_var_shader_in,
+                                    glsl_vector_type(GLSL_TYPE_FLOAT, 4),
+                                    "gl_Color");
+        c_src->data.location = VARYING_SLOT_COL0;
+        nir_variable *c_src1 =
+                nir_variable_create(b.shader, nir_var_shader_in,
+                                    glsl_vector_type(GLSL_TYPE_FLOAT, 4),
+                                    "gl_Color1");
+        c_src1->data.location = VARYING_SLOT_VAR0;
+        c_src1->data.driver_location = 1;
+        nir_variable *c_out =
+                nir_variable_create(b.shader, nir_var_shader_out,
+                                    glsl_vector_type(glsl_type, 4),
+                                    "gl_FragColor");
+        c_out->data.location = FRAG_RESULT_COLOR;
+
+        nir_ssa_def *s_src[] = {nir_load_var(&b, c_src), nir_load_var(&b, c_src1)};
+
+        for (int i = 0; i < ARRAY_SIZE(s_src); ++i) {
+                switch (nir_type) {
+                case nir_type_float16:
+                        s_src[i] = nir_f2f16(&b, s_src[i]);
+                        break;
+                case nir_type_int16:
+                        s_src[i] = nir_i2i16(&b, nir_iclamp(&b, s_src[i], -32768, 32767));
+                        break;
+                case nir_type_uint16:
+                        s_src[i] = nir_u2u16(&b, nir_umin(&b, s_src[i], nir_imm_int(&b, 65535)));
+                        break;
+                case nir_type_int8:
+                        s_src[i] = nir_i2i8(&b, nir_iclamp(&b, s_src[i], -128, 127));
+                        break;
+                case nir_type_uint8:
+                        s_src[i] = nir_u2u8(&b, nir_umin(&b, s_src[i], nir_imm_int(&b, 255)));
+                        break;
+                default:
+                        break;
+                }
+        }
+
+        /* Build a trivial blend shader */
+        nir_store_var(&b, c_out, s_src[0], 0xFF);
+
+        options.src1 = s_src[1];
+
+        NIR_PASS_V(b.shader, nir_lower_blend, options);
+
+        return b.shader;
+}
diff --git a/src/panfrost/lib/pan_blend.h b/src/panfrost/lib/pan_blend.h
new file mode 100644 (file)
index 0000000..d460c1e
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2018 Alyssa Rosenzweig
+ * Copyright (C) 2019-2021 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __PAN_BLEND_H__
+#define __PAN_BLEND_H__
+
+#include "util/u_dynarray.h"
+#include "util/format/u_format.h"
+#include "compiler/shader_enums.h"
+#include "compiler/nir/nir.h"
+
+#include "panfrost/util/pan_ir.h"
+
+struct MALI_BLEND_EQUATION;
+struct panfrost_device;
+
+struct pan_blend_equation {
+        unsigned blend_enable : 1;
+        enum blend_func rgb_func : 3;
+        unsigned rgb_invert_src_factor : 1;
+        enum blend_factor rgb_src_factor : 4;
+        unsigned rgb_invert_dst_factor : 1;
+        enum blend_factor rgb_dst_factor : 4;
+        enum blend_func alpha_func : 3;
+        unsigned alpha_invert_src_factor : 1;
+        enum blend_factor alpha_src_factor : 4;
+        unsigned alpha_invert_dst_factor : 1;
+        enum blend_factor alpha_dst_factor : 4;
+        unsigned color_mask : 4;
+};
+
+struct pan_blend_rt_state {
+        /* RT format */
+        enum pipe_format format;
+
+        /* Number of samples */
+        unsigned nr_samples;
+
+        struct pan_blend_equation equation;
+};
+
+struct pan_blend_state {
+        bool dither;
+        bool logicop_enable;
+        enum pipe_logicop logicop_func;
+        float constants[4];
+        unsigned rt_count;
+        struct pan_blend_rt_state rts[8];
+};
+
+bool
+pan_blend_reads_dest(const struct pan_blend_state *state, unsigned rt);
+
+bool
+pan_blend_can_fixed_function(const struct panfrost_device *dev,
+                             const struct pan_blend_state *state,
+                             unsigned rt);
+
+bool
+pan_blend_is_opaque(const struct pan_blend_state *state,
+                    unsigned rt);
+
+unsigned
+pan_blend_constant_mask(const struct pan_blend_state *state,
+                        unsigned rt);
+
+float
+pan_blend_get_constant(const struct panfrost_device *dev,
+                       const struct pan_blend_state *state,
+                       unsigned rt);
+
+void
+pan_blend_to_fixed_function_equation(const struct panfrost_device *dev,
+                                     const struct pan_blend_state *state,
+                                     unsigned rt,
+                                     struct MALI_BLEND_EQUATION *equation);
+
+nir_shader *
+pan_blend_create_shader(const struct panfrost_device *dev,
+                        const struct pan_blend_state *state,
+                        unsigned rt);
+
+#endif