panfrost: Extend clear colour packing
authorAlyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Mon, 1 Jul 2019 18:49:06 +0000 (11:49 -0700)
committerAlyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Wed, 10 Jul 2019 13:12:03 +0000 (06:12 -0700)
Eventually, this will allow packing clear colours for all formats,
including floating-point framebuffers, pure integer buffers, and special
formats. Currently, a few of these formats are supported, and many more
are handled through a generic Gallium colour packing path (which is not
a perfect fit for the hardware, but works for many formats and is a sane
default for the moment.)

Signed-off-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
src/gallium/drivers/panfrost/pan_job.c
src/gallium/drivers/panfrost/pan_job.h
src/gallium/drivers/panfrost/pan_mfbd.c
src/gallium/drivers/panfrost/pan_sfbd.c

index 2f7fe9e3cc3d39160ee60e7820ab5208273fbbfb..6838050e57575d0ed636dec999deaeb324948eae 100644 (file)
@@ -184,8 +184,26 @@ panfrost_job_set_requirements(struct panfrost_context *ctx,
                 job->requirements |= PAN_REQ_DEPTH_WRITE;
 }
 
-static uint32_t
-pan_pack_color(const union pipe_color_union *color, enum pipe_format format)
+/* Helper to smear a 32-bit color across 128-bit components */
+
+static void
+pan_pack_color_32(uint32_t *packed, uint32_t v)
+{
+        for (unsigned i = 0; i < 4; ++i)
+                packed[i] = v;
+}
+
+static void
+pan_pack_color_64(uint32_t *packed, uint32_t lo, uint32_t hi)
+{
+        for (unsigned i = 0; i < 4; i += 2) {
+                packed[i + 0] = lo;
+                packed[i + 1] = hi;
+        }
+}
+
+static void
+pan_pack_color(uint32_t *packed, const union pipe_color_union *color, enum pipe_format format)
 {
         /* Alpha magicked to 1.0 if there is no alpha */
 
@@ -198,10 +216,11 @@ pan_pack_color(const union pipe_color_union *color, enum pipe_format format)
                 util_format_description(format);
 
         if (util_format_is_rgba8_variant(desc)) {
-                return (float_to_ubyte(clear_alpha) << 24) |
-                       (float_to_ubyte(color->f[2]) << 16) |
-                       (float_to_ubyte(color->f[1]) <<  8) |
-                       (float_to_ubyte(color->f[0]) <<  0);
+                pan_pack_color_32(packed,
+                        (float_to_ubyte(clear_alpha) << 24) |
+                        (float_to_ubyte(color->f[2]) << 16) |
+                        (float_to_ubyte(color->f[1]) <<  8) |
+                        (float_to_ubyte(color->f[0]) <<  0));
         } else if (format == PIPE_FORMAT_B5G6R5_UNORM) {
                 /* First, we convert the components to R5, G6, B5 separately */
                 unsigned r5 = CLAMP(color->f[0], 0.0, 1.0) * 31.0;
@@ -209,17 +228,53 @@ pan_pack_color(const union pipe_color_union *color, enum pipe_format format)
                 unsigned b5 = CLAMP(color->f[2], 0.0, 1.0) * 31.0;
 
                 /* Then we pack into a sparse u32. TODO: Why these shifts? */
-                return (b5 << 25) | (g6 << 14) | (r5 << 5);
+                pan_pack_color_32(packed, (b5 << 25) | (g6 << 14) | (r5 << 5));
+        } else if (format == PIPE_FORMAT_B4G4R4A4_UNORM) {
+                /* We scale the components against 0xF0 (=240.0), rather than 0xFF */
+                unsigned r4 = CLAMP(color->f[0], 0.0, 1.0) * 240.0;
+                unsigned g4 = CLAMP(color->f[1], 0.0, 1.0) * 240.0;
+                unsigned b4 = CLAMP(color->f[2], 0.0, 1.0) * 240.0;
+                unsigned a4 = CLAMP(clear_alpha, 0.0, 1.0) * 240.0;
+
+                /* Pack on *byte* intervals */
+                pan_pack_color_32(packed, (a4 << 24) | (b4 << 16) | (g4 << 8) | r4);
+        } else if (format == PIPE_FORMAT_B5G5R5A1_UNORM) {
+                /* Scale as expected but shift oddly */
+                unsigned r5 = round(CLAMP(color->f[0], 0.0, 1.0)) * 31.0;
+                unsigned g5 = round(CLAMP(color->f[1], 0.0, 1.0)) * 31.0;
+                unsigned b5 = round(CLAMP(color->f[2], 0.0, 1.0)) * 31.0;
+                unsigned a1 = round(CLAMP(clear_alpha, 0.0, 1.0)) * 1.0;
+
+                pan_pack_color_32(packed, (a1 << 31) | (b5 << 25) | (g5 << 15) | (r5 << 5));
         } else {
                 /* Try Gallium's generic default path. Doesn't work for all
                  * formats but it's a good guess. */
 
                 union util_color out;
-                util_pack_color(color->f, format, &out);
-                return out.ui[0];
-        }
 
-        return 0;
+                if (util_format_is_pure_integer(format)) {
+                        memcpy(out.ui, color->ui, 16);
+                } else {
+                        util_pack_color(color->f, format, &out);
+                }
+
+                unsigned size = util_format_get_blocksize(format);
+
+                if (size == 1) {
+                        unsigned b = out.ui[0];
+                        unsigned s = b | (b << 8);
+                        pan_pack_color_32(packed, s | (s << 16));
+                } else if (size == 2)
+                        pan_pack_color_32(packed, out.ui[0] | (out.ui[0] << 16));
+                else if (size == 4)
+                        pan_pack_color_32(packed, out.ui[0]);
+                else if (size == 8)
+                        pan_pack_color_64(packed, out.ui[0], out.ui[1]);
+                else if (size == 16)
+                        memcpy(packed, out.ui, 16);
+                else
+                        unreachable("Unknown generic format size packing clear colour");
+        }
 }
 
 void
@@ -231,8 +286,13 @@ panfrost_job_clear(struct panfrost_context *ctx,
 
 {
         if (buffers & PIPE_CLEAR_COLOR) {
-                enum pipe_format format = ctx->pipe_framebuffer.cbufs[0]->format;
-                job->clear_color = pan_pack_color(color, format);
+                for (unsigned i = 0; i < PIPE_MAX_COLOR_BUFS; ++i) {
+                        if (!(buffers & (PIPE_CLEAR_COLOR0 << i)))
+                                continue;
+
+                        enum pipe_format format = ctx->pipe_framebuffer.cbufs[i]->format;
+                        pan_pack_color(job->clear_color[i], color, format);
+                }
         }
 
         if (buffers & PIPE_CLEAR_DEPTH) {
index b4c9db9828e28c702585b6c14f9033ec437d1245..95478279d62c1d361720378f99bafffcfedf92ec 100644 (file)
@@ -51,8 +51,12 @@ struct panfrost_job {
         /* Buffers cleared (PIPE_CLEAR_* bitmask) */
         unsigned clear;
 
-        /* Packed clear values */
-        uint32_t clear_color;
+        /* Packed clear values, indexed by both render target as well as word.
+         * Essentially, a single pixel is packed, with some padding to bring it
+         * up to a 32-bit interval; that pixel is then duplicated over to fill
+         * all 16-bytes */
+
+        uint32_t clear_color[PIPE_MAX_COLOR_BUFS][4];
         float clear_depth;
         unsigned clear_stencil;
 
index 72f938713b181014d6e6fb68f6007ac85106e462..d14fb4269dbe85e9bf091c10a5315f1f8d935a1c 100644 (file)
@@ -127,13 +127,17 @@ panfrost_mfbd_clear(
                 struct panfrost_job *job,
                 struct bifrost_framebuffer *fb,
                 struct bifrost_fb_extra *fbx,
-                struct bifrost_render_target *rt)
+                struct bifrost_render_target *rts,
+                unsigned rt_count)
 {
-        if (job->clear & PIPE_CLEAR_COLOR) {
-                rt->clear_color_1 = job->clear_color;
-                rt->clear_color_2 = job->clear_color;
-                rt->clear_color_3 = job->clear_color;
-                rt->clear_color_4 = job->clear_color;
+        for (unsigned i = 0; i < rt_count; ++i) {
+                if (!(job->clear & (PIPE_CLEAR_COLOR0 << i)))
+                        continue;
+
+                rts[i].clear_color_1 = job->clear_color[i][0];
+                rts[i].clear_color_2 = job->clear_color[i][1];
+                rts[i].clear_color_3 = job->clear_color[i][2];
+                rts[i].clear_color_4 = job->clear_color[i][3];
         }
 
         if (job->clear & PIPE_CLEAR_DEPTH) {
@@ -299,7 +303,7 @@ panfrost_mfbd_fragment(struct panfrost_context *ctx, bool has_draws)
         fb.mfbd_flags = 0x100;
 
         /* TODO: MRT clear */
-        panfrost_mfbd_clear(job, &fb, &fbx, &rts[0]);
+        panfrost_mfbd_clear(job, &fb, &fbx, rts, fb.rt_count_2);
 
         for (int cb = 0; cb < ctx->pipe_framebuffer.nr_cbufs; ++cb) {
                 struct pipe_surface *surf = ctx->pipe_framebuffer.cbufs[cb];
index 76267b746ac0315bee1ea84c0478c84a05424857..03a9d7adfb0c072d737f9ac10cba57fd0d9fc2b1 100644 (file)
@@ -43,10 +43,10 @@ panfrost_sfbd_clear(
         struct panfrost_context *ctx = job->ctx;
 
         if (job->clear & PIPE_CLEAR_COLOR) {
-                sfbd->clear_color_1 = job->clear_color;
-                sfbd->clear_color_2 = job->clear_color;
-                sfbd->clear_color_3 = job->clear_color;
-                sfbd->clear_color_4 = job->clear_color;
+                sfbd->clear_color_1 = job->clear_color[0][0];
+                sfbd->clear_color_2 = job->clear_color[0][1];
+                sfbd->clear_color_3 = job->clear_color[0][2];
+                sfbd->clear_color_4 = job->clear_color[0][3];
         }
 
         if (job->clear & PIPE_CLEAR_DEPTH) {