panfrost: Add blend shader support to bifrost

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7151>
diff --git a/src/gallium/drivers/panfrost/pan_assemble.c b/src/gallium/drivers/panfrost/pan_assemble.c
index a7f2725..f2bc19d 100644
--- a/src/gallium/drivers/panfrost/pan_assemble.c
+++ b/src/gallium/drivers/panfrost/pan_assemble.c
@@ -298,6 +298,14 @@
 
                 break;
         case MESA_SHADER_FRAGMENT:
+                for (unsigned i = 0; i < ARRAY_SIZE(state->blend_ret_addrs); i++) {
+                        if (!program.blend_ret_offsets[i])
+                                continue;
+
+                        state->blend_ret_addrs[i] = (state->bo->gpu & UINT32_MAX) +
+                                                    program.blend_ret_offsets[i];
+                        assert(!(state->blend_ret_addrs[i] & 0x7));
+                }
                 varying_count = util_bitcount64(s->info.inputs_read);
                 if (s->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_DEPTH))
                         state->writes_depth = true;
diff --git a/src/gallium/drivers/panfrost/pan_blend_shaders.c b/src/gallium/drivers/panfrost/pan_blend_shaders.c
index bdefdec..470f947 100644
--- a/src/gallium/drivers/panfrost/pan_blend_shaders.c
+++ b/src/gallium/drivers/panfrost/pan_blend_shaders.c
@@ -27,6 +27,7 @@
 #include "pan_util.h"
 #include "panfrost-quirks.h"
 #include "midgard/midgard_compile.h"
+#include "bifrost/bifrost_compile.h"
 #include "compiler/nir/nir_builder.h"
 #include "nir/nir_lower_blend.h"
 #include "panfrost/util/pan_lower_framebuffer.h"
@@ -216,6 +217,84 @@
         return res;
 }
 
+static uint64_t
+bifrost_get_blend_desc(enum pipe_format fmt, unsigned rt)
+{
+        const struct util_format_description *desc = util_format_description(fmt);
+        uint64_t res;
+
+        pan_pack(&res, BIFROST_INTERNAL_BLEND, cfg) {
+                cfg.mode = MALI_BIFROST_BLEND_MODE_OPAQUE;
+                cfg.fixed_function.num_comps = desc->nr_channels;
+                cfg.fixed_function.rt = rt;
+
+                nir_alu_type T = pan_unpacked_type_for_format(desc);
+                switch (T) {
+                case nir_type_float16:
+                        cfg.fixed_function.conversion.register_format =
+                                MALI_BIFROST_REGISTER_FILE_FORMAT_F16;
+                        break;
+                case nir_type_float32:
+                        cfg.fixed_function.conversion.register_format =
+                                MALI_BIFROST_REGISTER_FILE_FORMAT_F32;
+                        break;
+                case nir_type_int16:
+                        cfg.fixed_function.conversion.register_format =
+                                MALI_BIFROST_REGISTER_FILE_FORMAT_I16;
+                        break;
+                case nir_type_int32:
+                        cfg.fixed_function.conversion.register_format =
+                                MALI_BIFROST_REGISTER_FILE_FORMAT_I32;
+                        break;
+                case nir_type_uint16:
+                        cfg.fixed_function.conversion.register_format =
+                                MALI_BIFROST_REGISTER_FILE_FORMAT_U16;
+                        break;
+                case nir_type_uint32:
+                        cfg.fixed_function.conversion.register_format =
+                                MALI_BIFROST_REGISTER_FILE_FORMAT_U32;
+                        break;
+                default:
+                        unreachable("Invalid format");
+                }
+
+                cfg.fixed_function.conversion.memory_format.srgb =
+                        desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB;
+
+                if (util_format_is_unorm8(desc)) {
+                        cfg.fixed_function.conversion.memory_format.format = MALI_RGBA8_2;
+                        continue;
+                }
+
+                enum pipe_format linearized = util_format_linear(fmt);
+                switch (linearized) {
+                case PIPE_FORMAT_B5G6R5_UNORM:
+                        cfg.fixed_function.conversion.memory_format.format = MALI_R5G6B5;
+                        break;
+                case PIPE_FORMAT_A4B4G4R4_UNORM:
+                case PIPE_FORMAT_B4G4R4A4_UNORM:
+                case PIPE_FORMAT_R4G4B4A4_UNORM:
+                        cfg.fixed_function.conversion.memory_format.format = MALI_RGBA4;
+                        break;
+                case PIPE_FORMAT_R10G10B10A2_UNORM:
+                case PIPE_FORMAT_B10G10R10A2_UNORM:
+                case PIPE_FORMAT_R10G10B10X2_UNORM:
+                case PIPE_FORMAT_B10G10R10X2_UNORM:
+                        cfg.fixed_function.conversion.memory_format.format = MALI_RGB10_A2_2;
+                        break;
+                case PIPE_FORMAT_B5G5R5A1_UNORM:
+                case PIPE_FORMAT_R5G5B5A1_UNORM:
+                case PIPE_FORMAT_B5G5R5X1_UNORM:
+                        cfg.fixed_function.conversion.memory_format.format = MALI_RGB5_A1;
+                        break;
+                default:
+                        unreachable("Invalid format");
+                }
+        }
+
+        return res;
+}
+
 void
 panfrost_compile_blend_shader(struct panfrost_blend_shader *shader,
                               const float *constants)
@@ -244,7 +323,13 @@
         if (constants)
                 memcpy(inputs.blend.constants, constants, sizeof(inputs.blend.constants));
 
-        midgard_compile_shader_nir(shader->nir, &program, &inputs);
+        if (dev->quirks & IS_BIFROST) {
+                inputs.blend.bifrost_blend_desc =
+                        bifrost_get_blend_desc(shader->key.format, shader->key.rt);
+                bifrost_compile_shader_nir(shader->nir, &program, &inputs);
+	} else {
+                midgard_compile_shader_nir(shader->nir, &program, &inputs);
+        }
 
         /* Allow us to patch later */
         shader->first_tag = program.first_tag;
diff --git a/src/gallium/drivers/panfrost/pan_cmdstream.c b/src/gallium/drivers/panfrost/pan_cmdstream.c
index e481bbb..dd99e2c 100644
--- a/src/gallium/drivers/panfrost/pan_cmdstream.c
+++ b/src/gallium/drivers/panfrost/pan_cmdstream.c
@@ -297,6 +297,8 @@
                                 assert((blend[i].shader.gpu & (0xffffffffull << 32)) ==
                                        (fs->bo->gpu & (0xffffffffull << 32)));
                                 cfg.bifrost.internal.shader.pc = (u32)blend[i].shader.gpu;
+                                assert(!(fs->blend_ret_addrs[i] & 0x7));
+                                cfg.bifrost.internal.shader.return_value = fs->blend_ret_addrs[i];
                                 cfg.bifrost.internal.mode = MALI_BIFROST_BLEND_MODE_SHADER;
                         } else {
                                 enum pipe_format format = batch->key.cbufs[i]->format;
diff --git a/src/gallium/drivers/panfrost/pan_context.h b/src/gallium/drivers/panfrost/pan_context.h
index f725113..4452328 100644
--- a/src/gallium/drivers/panfrost/pan_context.h
+++ b/src/gallium/drivers/panfrost/pan_context.h
@@ -246,6 +246,9 @@
 
         BITSET_WORD outputs_read;
         enum pipe_format rt_formats[8];
+
+        /* Blend return addresses */
+        uint32_t blend_ret_addrs[8];
 };
 
 /* A collection of varyings (the CSO) */