From 31f5a43bf0d01ea0cab54a05eadf6e6778fc570f Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Thu, 2 May 2019 02:27:04 +0000 Subject: [PATCH] panfrost: Support RGB565 FBOs Signed-off-by: Alyssa Rosenzweig --- src/gallium/drivers/panfrost/pan_context.c | 69 ++++++++++++++++----- 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, 80 insertions(+), 29 deletions(-) diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c index c50c546a399..17b5b75db92 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,38 @@ 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); + } + + return 0; } static void @@ -246,18 +290,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 +2105,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) -- 2.30.2