panfrost: Support RGB565 FBOs

Submitted by Alyssa Rosenzweig on May 2, 2019, 3:08 a.m.

Details

Message ID 20190502030821.5194-1-alyssa@rosenzweig.io
State New
Headers show
Series "panfrost: Support RGB565 FBOs" ( rev: 1 ) in Mesa

Not browsing as part of any series.

Commit Message

Alyssa Rosenzweig May 2, 2019, 3:08 a.m.
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
---
 src/gallium/drivers/panfrost/pan_context.c  | 67 +++++++++++++++------
 src/gallium/drivers/panfrost/pan_mfbd.c     | 11 +++-
 src/gallium/drivers/panfrost/pan_resource.c | 21 +++++--
 src/gallium/drivers/panfrost/pan_screen.c   |  8 +--
 4 files changed, 78 insertions(+), 29 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c
index c50c546a399..770f6960c11 100644
--- a/src/gallium/drivers/panfrost/pan_context.c
+++ b/src/gallium/drivers/panfrost/pan_context.c
@@ -40,6 +40,7 @@ 
 #include "util/u_format.h"
 #include "indices/u_primconvert.h"
 #include "tgsi/tgsi_parse.h"
+#include "util/u_math.h"
 
 #include "pan_screen.h"
 #include "pan_blending.h"
@@ -53,6 +54,22 @@  extern const char *pan_counters_base;
 /* Do not actually send anything to the GPU; merely generate the cmdstream as fast as possible. Disables framebuffer writes */
 //#define DRY_RUN
 
+/* Can a given format support AFBC? Not all can. */
+
+static bool
+panfrost_can_afbc(enum pipe_format format)
+{
+        const struct util_format_description *desc =
+                util_format_description(format);
+
+        if (util_format_is_rgba8_variant(desc))
+                return true;
+
+        /* TODO: AFBC of other formats */
+
+        return false;
+}
+
 /* AFBC is enabled on a per-resource basis (AFBC enabling is theoretically
  * indepdent between color buffers and depth/stencil). To enable, we allocate
  * the AFBC metadata buffer and mark that it is enabled. We do -not- actually
@@ -228,11 +245,36 @@  panfrost_is_scanout(struct panfrost_context *ctx)
                ctx->pipe_framebuffer.cbufs[0]->texture->bind & PIPE_BIND_SHARED;
 }
 
-/* Maps float 0.0-1.0 to int 0x00-0xFF */
-static uint8_t
-normalised_float_to_u8(float f)
+static uint32_t
+pan_pack_color(const union pipe_color_union *color, enum pipe_format format)
 {
-        return (uint8_t) (int) (f * 255.0f);
+        /* Alpha magicked to 1.0 if there is no alpha */
+
+        bool has_alpha = util_format_has_alpha(format);
+        float clear_alpha = has_alpha ? color->f[3] : 1.0f;
+
+        /* Packed color depends on the framebuffer format */
+
+        const struct util_format_description *desc =
+                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);
+        } 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;
+                unsigned g6 = CLAMP(color->f[1], 0.0, 1.0) * 63.0;
+                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);
+        } else {
+                /* Unknown format */
+                assert(0);
+        }
 }
 
 static void
@@ -246,18 +288,8 @@  panfrost_clear(
         struct panfrost_job *job = panfrost_get_job_for_fbo(ctx);
 
         if (buffers & PIPE_CLEAR_COLOR) {
-                /* Alpha clear only meaningful without alpha channel, TODO less ad hoc */
-                bool has_alpha = util_format_has_alpha(ctx->pipe_framebuffer.cbufs[0]->format);
-                float clear_alpha = has_alpha ? color->f[3] : 1.0f;
-
-                uint32_t packed_color =
-                        (normalised_float_to_u8(clear_alpha) << 24) |
-                        (normalised_float_to_u8(color->f[2]) << 16) |
-                        (normalised_float_to_u8(color->f[1]) <<  8) |
-                        (normalised_float_to_u8(color->f[0]) <<  0);
-
-                job->clear_color = packed_color;
-
+                enum pipe_format format = ctx->pipe_framebuffer.cbufs[0]->format;
+                job->clear_color = pan_pack_color(color, format);
         }
 
         if (buffers & PIPE_CLEAR_DEPTH) {
@@ -2071,9 +2103,10 @@  panfrost_set_framebuffer_state(struct pipe_context *pctx,
                 panfrost_attach_vt_framebuffer(ctx);
 
                 struct panfrost_resource *tex = ((struct panfrost_resource *) ctx->pipe_framebuffer.cbufs[i]->texture);
+                enum pipe_format format = ctx->pipe_framebuffer.cbufs[i]->format;
                 bool is_scanout = panfrost_is_scanout(ctx);
 
-                if (!is_scanout && tex->bo->layout != PAN_AFBC) {
+                if (!is_scanout && tex->bo->layout != PAN_AFBC && panfrost_can_afbc(format)) {
                         /* The blob is aggressive about enabling AFBC. As such,
                          * it's pretty much necessary to use it here, since we
                          * have no traces of non-compressed FBO. */
diff --git a/src/gallium/drivers/panfrost/pan_mfbd.c b/src/gallium/drivers/panfrost/pan_mfbd.c
index 25286c32da5..6986992012f 100644
--- a/src/gallium/drivers/panfrost/pan_mfbd.c
+++ b/src/gallium/drivers/panfrost/pan_mfbd.c
@@ -36,7 +36,7 @@  panfrost_mfbd_format(struct pipe_surface *surf)
         const struct util_format_description *desc =
                 util_format_description(surf->texture->format);
 
-        /* Fill in accordingly */
+        /* Fill in accordingly, defaulting to RGBA8888 (UNORM) */
 
         struct mali_rt_format fmt = {
                 .unk1 = 0x4000000,
@@ -47,6 +47,14 @@  panfrost_mfbd_format(struct pipe_surface *surf)
                 .unk4 = 0x8
         };
 
+        /* Set flags for alternative formats */
+
+        if (surf->texture->format == PIPE_FORMAT_B5G6R5_UNORM) {
+                fmt.unk1 = 0x14000000;
+                fmt.nr_channels = MALI_POSITIVE(2);
+                fmt.flags |= 0x1;
+        }
+
         return fmt;
 }
 
@@ -95,7 +103,6 @@  panfrost_mfbd_set_cbuf(
                         stride = -stride;
                 }
 
-                /* MFBD specifies stride in tiles */
                 rt->framebuffer = framebuffer;
                 rt->framebuffer_stride = stride / 16;
         } else if (rsrc->bo->layout == PAN_AFBC) {
diff --git a/src/gallium/drivers/panfrost/pan_resource.c b/src/gallium/drivers/panfrost/pan_resource.c
index 73f987c45bc..6638f362855 100644
--- a/src/gallium/drivers/panfrost/pan_resource.c
+++ b/src/gallium/drivers/panfrost/pan_resource.c
@@ -416,16 +416,25 @@  panfrost_transfer_map(struct pipe_context *pctx,
 
         *out_transfer = &transfer->base;
 
-        if (resource->bind & PIPE_BIND_DISPLAY_TARGET ||
-            resource->bind & PIPE_BIND_SCANOUT ||
-            resource->bind & PIPE_BIND_SHARED) {
-                /* Mipmapped readpixels?! */
-                assert(level == 0);
+        /* Check if we're bound for rendering and this is a read pixels. If so,
+         * we need to flush */
+
+        struct panfrost_context *ctx = pan_context(pctx);
+        struct pipe_framebuffer_state *fb = &ctx->pipe_framebuffer;
+
+        bool is_bound = false;
 
-                /* Force a flush -- kill the pipeline */
+        for (unsigned c = 0; c < fb->nr_cbufs; ++c) {
+                is_bound |= fb->cbufs[c]->texture == resource;
+        }
+
+        if (is_bound && (usage & PIPE_TRANSFER_READ)) {
+                assert(level == 0);
                 panfrost_flush(pctx, NULL, PIPE_FLUSH_END_OF_FRAME);
         }
 
+        /* TODO: Respect usage flags */
+
         if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
                 /* TODO: reallocate */
                 //printf("debug: Missed reallocate\n");
diff --git a/src/gallium/drivers/panfrost/pan_screen.c b/src/gallium/drivers/panfrost/pan_screen.c
index 4f23dd5cdf0..3af82f6ae0c 100644
--- a/src/gallium/drivers/panfrost/pan_screen.c
+++ b/src/gallium/drivers/panfrost/pan_screen.c
@@ -445,11 +445,11 @@  panfrost_is_format_supported( struct pipe_screen *screen,
                 return FALSE;
 
         if (bind & PIPE_BIND_RENDER_TARGET) {
-                /* We don't support rendering into anything but RGBA8 yet. We
-                 * need more formats for spec compliance, but for now, honesty
-                 * is the best policy <3 */
+                /* TODO: Support all the formats! :) */
+                bool supported = util_format_is_rgba8_variant(format_desc);
+                supported |= format == PIPE_FORMAT_B5G6R5_UNORM;
 
-                if (!util_format_is_rgba8_variant(format_desc))
+                if (!supported)
                         return FALSE;
 
                 if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS)