panfrost: XML-ify the single target framebuffer descriptor

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/6797>
diff --git a/src/gallium/drivers/panfrost/pan_job.c b/src/gallium/drivers/panfrost/pan_job.c
index 62394f5..ac3ac15 100644
--- a/src/gallium/drivers/panfrost/pan_job.c
+++ b/src/gallium/drivers/panfrost/pan_job.c
@@ -741,7 +741,7 @@
 
         if (!batch->framebuffer.gpu) {
                 unsigned size = (dev->quirks & MIDGARD_SFBD) ?
-                        sizeof(struct mali_single_framebuffer) :
+                        MALI_SINGLE_TARGET_FRAMEBUFFER_LENGTH :
                         sizeof(struct mali_framebuffer);
 
                 batch->framebuffer = panfrost_pool_alloc_aligned(&batch->pool, size, 64);
diff --git a/src/gallium/drivers/panfrost/pan_sfbd.c b/src/gallium/drivers/panfrost/pan_sfbd.c
index 889841b..3bbfda3 100644
--- a/src/gallium/drivers/panfrost/pan_sfbd.c
+++ b/src/gallium/drivers/panfrost/pan_sfbd.c
@@ -28,8 +28,9 @@
 
 #include "util/format/u_format.h"
 
-static struct mali_sfbd_format
-panfrost_sfbd_format(struct pipe_surface *surf)
+static void
+panfrost_sfbd_format(struct pipe_surface *surf,
+                     struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS *fb)
 {
         /* Explode details on the format */
 
@@ -41,90 +42,77 @@
         unsigned char swizzle[4];
         panfrost_invert_swizzle(desc->swizzle, swizzle);
 
-        struct mali_sfbd_format fmt = {
-                .unk1 = 0x1,
-                .swizzle = panfrost_translate_swizzle_4(swizzle),
-                .nr_channels = MALI_POSITIVE(desc->nr_channels),
-                .unk2 = 0x4,
-                .unk3 = 0xb,
-        };
+        fb->swizzle = panfrost_translate_swizzle_4(swizzle);
 
         if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB)
-                fmt.unk2 |= MALI_SFBD_FORMAT_SRGB;
+                fb->srgb = true;
+
+        if (util_format_is_unorm8(desc)) {
+                fb->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_R8G8B8A8;
+                switch (desc->nr_channels) {
+                case 1:
+                        fb->color_writeback_format = MALI_SFBD_COLOR_FORMAT_R8;
+                        break;
+                case 2:
+                        fb->color_writeback_format = MALI_SFBD_COLOR_FORMAT_R8G8;
+                        break;
+                case 3:
+                        fb->color_writeback_format = MALI_SFBD_COLOR_FORMAT_R8G8B8;
+                        break;
+                case 4:
+                        fb->color_writeback_format = MALI_SFBD_COLOR_FORMAT_R8G8B8A8;
+                        break;
+                default:
+                        unreachable("Invalid number of components");
+                }
+
+                /* If 8b RGB variant, we're good to go */
+                return;
+        }
 
         /* sRGB handled as a dedicated flag */
         enum pipe_format linearized = util_format_linear(surf->format);
 
-        /* If RGB, we're good to go */
-        if (util_format_is_unorm8(desc))
-                return fmt;
-
         switch (linearized) {
         case PIPE_FORMAT_B5G6R5_UNORM:
-                fmt.unk1 = 0x5;
-                fmt.nr_channels = MALI_POSITIVE(2);
-                fmt.unk2 = 0x5;
+                fb->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_R5G6B5A0;
+                fb->color_writeback_format = MALI_SFBD_COLOR_FORMAT_R5G6B5;
                 break;
 
         case PIPE_FORMAT_A4B4G4R4_UNORM:
         case PIPE_FORMAT_B4G4R4A4_UNORM:
         case PIPE_FORMAT_R4G4B4A4_UNORM:
-                fmt.unk1 = 0x4;
-                fmt.nr_channels = MALI_POSITIVE(1);
-                fmt.unk2 = 0x5;
+                fb->internal_format = MALI_COLOR_BUFFER_INTERNAL_FORMAT_R4G4B4A4;
+                fb->color_writeback_format = MALI_SFBD_COLOR_FORMAT_R4G4B4A4;
                 break;
 
         default:
                 unreachable("Invalid format rendering");
         }
-
-        return fmt;
 }
 
 static void
 panfrost_sfbd_clear(
         struct panfrost_batch *batch,
-        struct mali_single_framebuffer *sfbd)
+        struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS *sfbd)
 {
         if (batch->clear & PIPE_CLEAR_COLOR) {
-                sfbd->clear_color_1 = batch->clear_color[0][0];
-                sfbd->clear_color_2 = batch->clear_color[0][1];
-                sfbd->clear_color_3 = batch->clear_color[0][2];
-                sfbd->clear_color_4 = batch->clear_color[0][3];
+                sfbd->clear_color_0 = batch->clear_color[0][0];
+                sfbd->clear_color_1 = batch->clear_color[0][1];
+                sfbd->clear_color_2 = batch->clear_color[0][2];
+                sfbd->clear_color_3 = batch->clear_color[0][3];
         }
 
-        if (batch->clear & PIPE_CLEAR_DEPTH) {
-                sfbd->clear_depth_1 = batch->clear_depth;
-                sfbd->clear_depth_2 = batch->clear_depth;
-                sfbd->clear_depth_3 = batch->clear_depth;
-                sfbd->clear_depth_4 = batch->clear_depth;
-        }
+        if (batch->clear & PIPE_CLEAR_DEPTH)
+                sfbd->z_clear = batch->clear_depth;
 
-        if (batch->clear & PIPE_CLEAR_STENCIL) {
-                sfbd->clear_stencil = batch->clear_stencil;
-        }
-
-        /* Set flags based on what has been cleared, for the SFBD case */
-        /* XXX: What do these flags mean? */
-        int clear_flags = 0x101100;
-
-        if (!(batch->clear & ~(PIPE_CLEAR_COLOR | PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) {
-                /* On a tiler like this, it's fastest to clear all three buffers at once */
-
-                clear_flags |= MALI_CLEAR_FAST;
-        } else {
-                clear_flags |= MALI_CLEAR_SLOW;
-
-                if (batch->clear & PIPE_CLEAR_STENCIL)
-                        clear_flags |= MALI_CLEAR_SLOW_STENCIL;
-        }
-
-        sfbd->clear_flags = clear_flags;
+        if (batch->clear & PIPE_CLEAR_STENCIL)
+                sfbd->s_clear = batch->clear_stencil & 0xff;
 }
 
 static void
 panfrost_sfbd_set_cbuf(
-        struct mali_single_framebuffer *fb,
+        struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS *fb,
         struct pipe_surface *surf)
 {
         struct panfrost_resource *rsrc = pan_resource(surf->texture);
@@ -136,16 +124,17 @@
 
         mali_ptr base = panfrost_get_texture_address(rsrc, level, first_layer, 0);
 
-        fb->format = panfrost_sfbd_format(surf);
+        panfrost_sfbd_format(surf, fb);
 
-        fb->framebuffer = base;
-        fb->stride = stride;
+        fb->color_write_enable = true;
+        fb->color_writeback.base = base;
+        fb->color_writeback.row_stride = stride;
 
         if (rsrc->modifier == DRM_FORMAT_MOD_LINEAR)
-                fb->format.block = MALI_BLOCK_FORMAT_LINEAR;
+                fb->color_block_format = MALI_BLOCK_FORMAT_LINEAR;
         else if (rsrc->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
-                fb->format.block = MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED;
-                fb->stride *= 16;
+                fb->color_block_format = MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED;
+                fb->color_writeback.row_stride *= 16;
         } else {
                 fprintf(stderr, "Invalid render modifier\n");
                 assert(0);
@@ -154,11 +143,10 @@
 
 static void
 panfrost_sfbd_set_zsbuf(
-        struct mali_single_framebuffer *fb,
+        struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS *fb,
         struct pipe_surface *surf)
 {
         struct panfrost_resource *rsrc = pan_resource(surf->texture);
-        struct panfrost_context *ctx = pan_context(surf->context);
 
         unsigned level = surf->u.tex.level;
         assert(surf->u.tex.first_layer == 0);
@@ -166,59 +154,47 @@
         if (rsrc->modifier != DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED)
                 unreachable("Invalid render modifier.");
 
-        fb->depth_buffer = rsrc->bo->gpu + rsrc->slices[level].offset;
-        fb->depth_stride = rsrc->slices[level].stride;
-
-        /* No stencil? Job done. */
-        if (!ctx->depth_stencil || !ctx->depth_stencil->base.stencil[0].enabled)
-                return;
-
-        if (panfrost_is_z24s8_variant(surf->format)) {
-                /* Stencil data is interleaved with depth */
-                fb->stencil_buffer = fb->depth_buffer;
-                fb->stencil_stride = fb->depth_stride;
-        } else if (surf->format == PIPE_FORMAT_Z32_FLOAT) {
-                /* No stencil, nothing to do */
-        } else if (surf->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
-                /* Stencil data in separate buffer */
-                struct panfrost_resource *stencil = rsrc->separate_stencil;
-                struct panfrost_slice stencil_slice = stencil->slices[level];
-
-                fb->stencil_buffer = stencil->bo->gpu + stencil_slice.offset;
-                fb->stencil_stride = stencil_slice.stride;
-        } else
+        fb->zs_block_format = MALI_BLOCK_FORMAT_TILED_U_INTERLEAVED;
+        fb->zs_writeback.base = rsrc->bo->gpu + rsrc->slices[level].offset;
+        fb->zs_writeback.row_stride = rsrc->slices[level].stride * 16;
+        switch (surf->format) {
+        case PIPE_FORMAT_Z24_UNORM_S8_UINT:
+                fb->zs_format = MALI_ZS_FORMAT_D24S8;
+                break;
+        case PIPE_FORMAT_Z24X8_UNORM:
+                fb->zs_format = MALI_ZS_FORMAT_D24X8;
+                break;
+        case PIPE_FORMAT_Z32_FLOAT:
+                fb->zs_format = MALI_ZS_FORMAT_D32;
+                break;
+        case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT:
+                fb->zs_format = MALI_ZS_FORMAT_D32_S8X24;
+                break;
+        default:
                 unreachable("Unsupported depth/stencil format.");
+        }
 }
 
-
-static struct mali_single_framebuffer
-panfrost_emit_sfbd(struct panfrost_batch *batch, unsigned vertex_count)
+static void
+panfrost_init_sfbd_params(struct panfrost_batch *batch,
+                          struct MALI_SINGLE_TARGET_FRAMEBUFFER_PARAMETERS *sfbd)
 {
-        struct panfrost_context *ctx = batch->ctx;
-        struct pipe_context *gallium = (struct pipe_context *) ctx;
-        struct panfrost_device *dev = pan_device(gallium->screen);
+        sfbd->bound_max_x = batch->key.width - 1;
+        sfbd->bound_max_y = batch->key.height - 1;
+        sfbd->dithering_enable = true;
+        sfbd->clean_pixel_write_enable = true;
+        sfbd->tie_break_rule = MALI_TIE_BREAK_RULE_MINUS_180_IN_0_OUT;
+}
 
-        unsigned width = batch->key.width;
-        unsigned height = batch->key.height;
-
+static void
+panfrost_emit_sfdb_local_storage(struct panfrost_batch *batch, void *sfbd,
+                                 unsigned vertex_count)
+{
+        struct panfrost_device *dev = pan_device(batch->ctx->base.screen);
         /* TODO: Why do we need to make the stack bigger than other platforms? */
         unsigned shift = panfrost_get_stack_shift(MAX2(batch->stack_size, 512));
 
-        struct mali_single_framebuffer framebuffer = {
-                .width = MALI_POSITIVE(width),
-                .height = MALI_POSITIVE(height),
-                .format = {
-                        .unk3 = 0x3,
-                },
-                .clear_flags = 0x1000,
-        };
-
-        struct mali_midgard_tiler_packed t;
-        panfrost_emit_midg_tiler(batch, &t, vertex_count);
-        framebuffer.tiler = t;
-
-        struct mali_local_storage_packed lsp;
-        pan_pack(&lsp, LOCAL_STORAGE, ls) {
+        pan_section_pack(sfbd, SINGLE_TARGET_FRAMEBUFFER, LOCAL_STORAGE, ls) {
                 ls.tls_size = shift;
                 ls.wls_instances = MALI_LOCAL_STORAGE_NO_WORKGROUP_MEM;
                 ls.tls_base_pointer =
@@ -227,18 +203,32 @@
                                                       dev->thread_tls_alloc,
                                                       dev->core_count)->gpu;
         }
-        framebuffer.shared_memory = lsp;
+}
 
-        return framebuffer;
+static void
+panfrost_emit_sfdb_tiler(struct panfrost_batch *batch, void *sfbd,
+                         unsigned vertex_count)
+{
+        void *tiler = pan_section_ptr(sfbd, SINGLE_TARGET_FRAMEBUFFER, TILER);
+
+        panfrost_emit_midg_tiler(batch, tiler, vertex_count);
+
+        /* All weights set to 0, nothing to do here */
+        pan_section_pack(sfbd, SINGLE_TARGET_FRAMEBUFFER, PADDING_1, padding) {}
+        pan_section_pack(sfbd, SINGLE_TARGET_FRAMEBUFFER, TILER_WEIGHTS, w) {}
 }
 
 void
 panfrost_attach_sfbd(struct panfrost_batch *batch, unsigned vertex_count)
 {
-        struct mali_single_framebuffer sfbd =
-                panfrost_emit_sfbd(batch, vertex_count);
+        void *sfbd = batch->framebuffer.cpu;
 
-        memcpy(batch->framebuffer.cpu, &sfbd, sizeof(sfbd));
+        panfrost_emit_sfdb_local_storage(batch, sfbd, vertex_count);
+        pan_section_pack(sfbd, SINGLE_TARGET_FRAMEBUFFER, PARAMETERS, params) {
+                panfrost_init_sfbd_params(batch, &params);
+        }
+        panfrost_emit_sfdb_tiler(batch, sfbd, vertex_count);
+        pan_section_pack(sfbd, SINGLE_TARGET_FRAMEBUFFER, PADDING_2, padding) {}
 }
 
 /* Creates an SFBD for the FRAGMENT section of the bound framebuffer */
@@ -246,35 +236,46 @@
 mali_ptr
 panfrost_sfbd_fragment(struct panfrost_batch *batch, bool has_draws)
 {
-        struct mali_single_framebuffer fb = panfrost_emit_sfbd(batch, has_draws);
+        struct panfrost_transfer t =
+                panfrost_pool_alloc_aligned(&batch->pool,
+                                            MALI_SINGLE_TARGET_FRAMEBUFFER_LENGTH,
+                                            64);
+        void *sfbd = t.cpu;
 
-        panfrost_sfbd_clear(batch, &fb);
+        panfrost_emit_sfdb_local_storage(batch, sfbd, has_draws);
+        pan_section_pack(sfbd, SINGLE_TARGET_FRAMEBUFFER, PARAMETERS, params) {
+                panfrost_init_sfbd_params(batch, &params);
+                panfrost_sfbd_clear(batch, &params);
 
-        /* SFBD does not support MRT natively; sanity check */
-        assert(batch->key.nr_cbufs <= 1);
-        if (batch->key.nr_cbufs) {
-                struct pipe_surface *surf = batch->key.cbufs[0];
-                struct panfrost_resource *rsrc = pan_resource(surf->texture);
-                struct panfrost_bo *bo = rsrc->bo;
+                /* SFBD does not support MRT natively; sanity check */
+                assert(batch->key.nr_cbufs <= 1);
+                if (batch->key.nr_cbufs) {
+                        struct pipe_surface *surf = batch->key.cbufs[0];
+                        struct panfrost_resource *rsrc = pan_resource(surf->texture);
+                        struct panfrost_bo *bo = rsrc->bo;
 
-                panfrost_sfbd_set_cbuf(&fb, surf);
+                        panfrost_sfbd_set_cbuf(&params, surf);
 
-                if (rsrc->checksummed) {
-                        unsigned level = surf->u.tex.level;
-                        struct panfrost_slice *slice = &rsrc->slices[level];
+                        if (rsrc->checksummed) {
+                                unsigned level = surf->u.tex.level;
+                                struct panfrost_slice *slice = &rsrc->slices[level];
 
-                        fb.checksum_stride = slice->checksum_stride;
-                        fb.checksum = bo->gpu + slice->checksum_offset;
+                                params.crc_buffer.row_stride = slice->checksum_stride;
+                                params.crc_buffer.base = bo->gpu + slice->checksum_offset;
+                        }
+                }
+
+                if (batch->key.zsbuf)
+                        panfrost_sfbd_set_zsbuf(&params, batch->key.zsbuf);
+
+                if (batch->requirements & PAN_REQ_MSAA) {
+                        /* Only 4x MSAA supported right now. */
+                        params.sample_count = 4;
+                        params.msaa = MALI_MSAA_MULTIPLE;
                 }
         }
+        panfrost_emit_sfdb_tiler(batch, sfbd, has_draws);
+        pan_section_pack(sfbd, SINGLE_TARGET_FRAMEBUFFER, PADDING_2, padding) {}
 
-        if (batch->key.zsbuf)
-                panfrost_sfbd_set_zsbuf(&fb, batch->key.zsbuf);
-
-        if (batch->requirements & PAN_REQ_MSAA) {
-                fb.format.unk1 |= MALI_SFBD_FORMAT_MSAA_A;
-                fb.format.unk2 |= MALI_SFBD_FORMAT_MSAA_B;
-        }
-
-        return panfrost_pool_upload_aligned(&batch->pool, &fb, sizeof(fb), 64);
+        return t.gpu;
 }
diff --git a/src/panfrost/include/panfrost-job.h b/src/panfrost/include/panfrost-job.h
index 4ab5637..52dc696 100644
--- a/src/panfrost/include/panfrost-job.h
+++ b/src/panfrost/include/panfrost-job.h
@@ -545,41 +545,6 @@
         mali_ptr framebuffer;
 } __attribute__((packed));
 
-/* Single Framebuffer Descriptor */
-
-/* Flags apply to format. With just MSAA_A and MSAA_B, the framebuffer is
- * configured for 4x. With MSAA_8, it is configured for 8x. */
-
-#define MALI_SFBD_FORMAT_MSAA_8 (1 << 3)
-#define MALI_SFBD_FORMAT_MSAA_A (1 << 4)
-#define MALI_SFBD_FORMAT_MSAA_B (1 << 4)
-#define MALI_SFBD_FORMAT_SRGB 	(1 << 5)
-
-/* Fast/slow based on whether all three buffers are cleared at once */
-
-#define MALI_CLEAR_FAST         (1 << 18)
-#define MALI_CLEAR_SLOW         (1 << 28)
-#define MALI_CLEAR_SLOW_STENCIL (1 << 31)
-
-struct mali_sfbd_format {
-        /* 0x1 */
-        unsigned unk1 : 6;
-
-        /* mali_channel_swizzle */
-        unsigned swizzle : 12;
-
-        /* MALI_POSITIVE */
-        unsigned nr_channels : 2;
-
-        /* 0x4 */
-        unsigned unk2 : 6;
-
-        enum mali_block_format block : 2;
-
-        /* 0xb */
-        unsigned unk3 : 4;
-};
-
 /* Configures multisampling on Bifrost fragment jobs */
 
 struct bifrost_multisampling {
@@ -589,72 +554,6 @@
         u64 zero4;
 } __attribute__((packed));
 
-struct mali_single_framebuffer {
-        struct mali_local_storage_packed shared_memory;
-        struct mali_sfbd_format format;
-
-        u32 clear_flags;
-        u32 zero2;
-
-        /* Purposeful off-by-one in these fields should be accounted for by the
-         * MALI_DIMENSION macro */
-
-        u16 width;
-        u16 height;
-
-        u32 zero3[4];
-        mali_ptr checksum;
-        u32 checksum_stride;
-        u32 zero5;
-
-        /* By default, the framebuffer is upside down from OpenGL's
-         * perspective. Set framebuffer to the end and negate the stride to
-         * flip in the Y direction */
-
-        mali_ptr framebuffer;
-        int32_t stride;
-
-        u32 zero4;
-
-        /* Depth and stencil buffers are interleaved, it appears, as they are
-         * set to the same address in captures. Both fields set to zero if the
-         * buffer is not being cleared. Depending on GL_ENABLE magic, you might
-         * get a zero enable despite the buffer being present; that still is
-         * disabled. */
-
-        mali_ptr depth_buffer; // not SAME_VA
-        u32 depth_stride_zero : 4;
-        u32 depth_stride : 28;
-        u32 zero7;
-
-        mali_ptr stencil_buffer; // not SAME_VA
-        u32 stencil_stride_zero : 4;
-        u32 stencil_stride : 28;
-        u32 zero8;
-
-        u32 clear_color_1; // RGBA8888 from glClear, actually used by hardware
-        u32 clear_color_2; // always equal, but unclear function?
-        u32 clear_color_3; // always equal, but unclear function?
-        u32 clear_color_4; // always equal, but unclear function?
-
-        /* Set to zero if not cleared */
-
-        float clear_depth_1; // float32, ditto
-        float clear_depth_2; // float32, ditto
-        float clear_depth_3; // float32, ditto
-        float clear_depth_4; // float32, ditto
-
-        u32 clear_stencil; // Exactly as it appears in OpenGL
-
-        u32 zero6[7];
-
-        struct mali_midgard_tiler_packed tiler;
-        struct mali_midgard_tiler_weights_packed tiler_weights;
-
-        /* More below this, maybe */
-} __attribute__((packed));
-
-
 #define MALI_MFBD_FORMAT_SRGB 	  (1 << 0)
 
 struct mali_rt_format {
diff --git a/src/panfrost/lib/decode.c b/src/panfrost/lib/decode.c
index 43a8ff0..c0aac7e 100644
--- a/src/panfrost/lib/decode.c
+++ b/src/panfrost/lib/decode.c
@@ -67,6 +67,12 @@
         DUMP_UNPACKED(T, temp, __VA_ARGS__); \
 }
 
+#define DUMP_SECTION(A, S, cl, ...) { \
+        pan_section_unpack(cl, A, S, temp); \
+        pandecode_log(__VA_ARGS__); \
+        pan_section_print(pandecode_dump_stream, A, S, temp, (pandecode_indent + 1) * 2); \
+}
+
 #define MAP_ADDR(T, addr, cl) \
         const uint8_t *cl = 0; \
         { \
@@ -211,15 +217,6 @@
         }
 }
 
-#define FLAG_INFO(flag) { MALI_CLEAR_##flag, "MALI_CLEAR_" #flag }
-static const struct pandecode_flag_info clear_flag_info[] = {
-        FLAG_INFO(FAST),
-        FLAG_INFO(SLOW),
-        FLAG_INFO(SLOW_STENCIL),
-        {}
-};
-#undef FLAG_INFO
-
 #define FLAG_INFO(flag) { MALI_MFBD_FORMAT_##flag, "MALI_MFBD_FORMAT_" #flag }
 static const struct pandecode_flag_info mfbd_fmt_flag_info[] = {
         FLAG_INFO(SRGB),
@@ -256,22 +253,6 @@
 };
 #undef FLAG_INFO
 
-#define FLAG_INFO(flag) { MALI_SFBD_FORMAT_##flag, "MALI_SFBD_FORMAT_" #flag }
-static const struct pandecode_flag_info sfbd_unk1_info [] = {
-        FLAG_INFO(MSAA_8),
-        FLAG_INFO(MSAA_A),
-        {}
-};
-#undef FLAG_INFO
-
-#define FLAG_INFO(flag) { MALI_SFBD_FORMAT_##flag, "MALI_SFBD_FORMAT_" #flag }
-static const struct pandecode_flag_info sfbd_unk2_info [] = {
-        FLAG_INFO(MSAA_B),
-        FLAG_INFO(SRGB),
-        {}
-};
-#undef FLAG_INFO
-
 /* Midgard's tiler descriptor is embedded within the
  * larger FBD */
 
@@ -403,141 +384,38 @@
         bool has_extra;
 };
 
-static void
-pandecode_sfbd_format(struct mali_sfbd_format format)
-{
-        pandecode_log(".format = {\n");
-        pandecode_indent++;
-
-        pandecode_log(".unk1 = ");
-        pandecode_log_decoded_flags(sfbd_unk1_info, format.unk1);
-        pandecode_log_cont(",\n");
-
-        /* TODO: Map formats so we can check swizzles and print nicely */
-        pandecode_log("swizzle");
-        pandecode_swizzle(format.swizzle, MALI_RGBA8_UNORM);
-        pandecode_log_cont(",\n");
-
-        pandecode_prop("nr_channels = MALI_POSITIVE(%d)",
-                       (format.nr_channels + 1));
-
-        pandecode_log(".unk2 = ");
-        pandecode_log_decoded_flags(sfbd_unk2_info, format.unk2);
-        pandecode_log_cont(",\n");
-
-        pandecode_prop("block = %s", mali_block_format_as_str(format.block));
-
-        pandecode_prop("unk3 = 0x%" PRIx32, format.unk3);
-
-        pandecode_indent--;
-        pandecode_log("},\n");
-}
-
 static struct pandecode_fbd
 pandecode_sfbd(uint64_t gpu_va, int job_no, bool is_fragment, unsigned gpu_id)
 {
         struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing(gpu_va);
-        const struct mali_single_framebuffer *PANDECODE_PTR_VAR(s, mem, (mali_ptr) gpu_va);
+        const void *PANDECODE_PTR_VAR(s, mem, (mali_ptr) gpu_va);
 
         struct pandecode_fbd info = {
                 .has_extra = false,
                 .rt_count = 1
         };
 
-        pandecode_log("struct mali_single_framebuffer framebuffer_%"PRIx64"_%d = {\n", gpu_va, job_no);
+        pandecode_log("Single-Target Framebuffer:\n");
         pandecode_indent++;
-        DUMP_CL(LOCAL_STORAGE, &s->shared_memory, "Local Storage:\n");
-        pandecode_sfbd_format(s->format);
 
-        info.width = s->width + 1;
-        info.height = s->height + 1;
+        DUMP_SECTION(SINGLE_TARGET_FRAMEBUFFER, LOCAL_STORAGE, s, "Local Storage:\n");
+        pan_section_unpack(s, SINGLE_TARGET_FRAMEBUFFER, PARAMETERS, p);
+        DUMP_UNPACKED(SINGLE_TARGET_FRAMEBUFFER_PARAMETERS, p, "Parameters:\n");
 
-        pandecode_prop("width = MALI_POSITIVE(%" PRId16 ")", info.width);
-        pandecode_prop("height = MALI_POSITIVE(%" PRId16 ")", info.height);
-
-        MEMORY_PROP(s, checksum);
-
-        if (s->checksum_stride)
-                pandecode_prop("checksum_stride = %d", s->checksum_stride);
-
-        MEMORY_PROP(s, framebuffer);
-        pandecode_prop("stride = %d", s->stride);
-
-        /* Earlier in the actual commandstream -- right before width -- but we
-         * delay to flow nicer */
-
-        pandecode_log(".clear_flags = ");
-        pandecode_log_decoded_flags(clear_flag_info, s->clear_flags);
-        pandecode_log_cont(",\n");
-
-        if (s->depth_buffer) {
-                MEMORY_PROP(s, depth_buffer);
-                pandecode_prop("depth_stride = %d", s->depth_stride);
-        }
-
-        if (s->stencil_buffer) {
-                MEMORY_PROP(s, stencil_buffer);
-                pandecode_prop("stencil_stride = %d", s->stencil_stride);
-        }
-
-        if (s->depth_stride_zero ||
-            s->stencil_stride_zero ||
-            s->zero7 || s->zero8) {
-                pandecode_msg("XXX: Depth/stencil zeros tripped\n");
-                pandecode_prop("depth_stride_zero = 0x%x",
-                               s->depth_stride_zero);
-                pandecode_prop("stencil_stride_zero = 0x%x",
-                               s->stencil_stride_zero);
-                pandecode_prop("zero7 = 0x%" PRIx32,
-                               s->zero7);
-                pandecode_prop("zero8 = 0x%" PRIx32,
-                               s->zero8);
-        }
-
-        if (s->clear_color_1 | s->clear_color_2 | s->clear_color_3 | s->clear_color_4) {
-                pandecode_prop("clear_color_1 = 0x%" PRIx32, s->clear_color_1);
-                pandecode_prop("clear_color_2 = 0x%" PRIx32, s->clear_color_2);
-                pandecode_prop("clear_color_3 = 0x%" PRIx32, s->clear_color_3);
-                pandecode_prop("clear_color_4 = 0x%" PRIx32, s->clear_color_4);
-        }
-
-        if (s->clear_depth_1 != 0 || s->clear_depth_2 != 0 || s->clear_depth_3 != 0 || s->clear_depth_4 != 0) {
-                pandecode_prop("clear_depth_1 = %f", s->clear_depth_1);
-                pandecode_prop("clear_depth_2 = %f", s->clear_depth_2);
-                pandecode_prop("clear_depth_3 = %f", s->clear_depth_3);
-                pandecode_prop("clear_depth_4 = %f", s->clear_depth_4);
-        }
-
-        if (s->clear_stencil) {
-                pandecode_prop("clear_stencil = 0x%x", s->clear_stencil);
-        }
-
-        const struct mali_midgard_tiler_packed t = s->tiler;
-        const struct mali_midgard_tiler_weights_packed w = s->tiler_weights;
+        const void *t = pan_section_ptr(s, SINGLE_TARGET_FRAMEBUFFER, TILER);
+        const void *w = pan_section_ptr(s, SINGLE_TARGET_FRAMEBUFFER, TILER_WEIGHTS);
 
         bool has_hierarchy = !(gpu_id == 0x0720 || gpu_id == 0x0820 || gpu_id == 0x0830);
-        pandecode_midgard_tiler_descriptor(&t, &w, s->width + 1, s->height + 1, is_fragment, has_hierarchy);
+        pandecode_midgard_tiler_descriptor(t, w, p.bound_max_x + 1, p.bound_max_y + 1, is_fragment, has_hierarchy);
 
         pandecode_indent--;
-        pandecode_log("};\n");
 
-        pandecode_prop("zero2 = 0x%" PRIx32, s->zero2);
-        pandecode_prop("zero4 = 0x%" PRIx32, s->zero4);
-        pandecode_prop("zero5 = 0x%" PRIx32, s->zero5);
-
-        pandecode_log_cont(".zero3 = {");
-
-        for (int i = 0; i < sizeof(s->zero3) / sizeof(s->zero3[0]); ++i)
-                pandecode_log_cont("%X, ", s->zero3[i]);
-
-        pandecode_log_cont("},\n");
-
-        pandecode_log_cont(".zero6 = {");
-
-        for (int i = 0; i < sizeof(s->zero6) / sizeof(s->zero6[0]); ++i)
-                pandecode_log_cont("%X, ", s->zero6[i]);
-
-        pandecode_log_cont("},\n");
+        /* Dummy unpack of the padding section to make sure all words are 0.
+         * No need to call print here since the section is supposed to be empty.
+         */
+        pan_section_unpack(s, SINGLE_TARGET_FRAMEBUFFER, PADDING_1, padding1);
+        pan_section_unpack(s, SINGLE_TARGET_FRAMEBUFFER, PADDING_2, padding2);
+        pandecode_log("\n");
 
         return info;
 }
diff --git a/src/panfrost/lib/midgard.xml b/src/panfrost/lib/midgard.xml
index 119e93c..0514b86 100644
--- a/src/panfrost/lib/midgard.xml
+++ b/src/panfrost/lib/midgard.xml
@@ -574,7 +574,7 @@
     <field name="WLS Base Pointer" size="64" start="4:0" type="address"/>
   </struct>
 
-  <struct name="Midgard Tiler">
+  <struct name="Midgard Tiler" size="10">
     <field name="Polygon List Size" size="32" start="0:0" type="uint" prefix="MALI_MIDGARD_TILER">
       <value name="Minimum Header Size" value="512"/>
     </field>
@@ -599,4 +599,156 @@
     <field name="Weight6" size="32" start="6:0" type="uint"/>
     <field name="Weight7" size="32" start="7:0" type="uint"/>
   </struct>
+
+  <enum name="Color Buffer Internal Format">
+    <value name="Raw Value" value="0"/>
+    <value name="R8G8B8A8" value="1"/>
+    <value name="R10G10B10A2" value="2"/>
+    <value name="R8G8B8A2" value="3"/>
+    <value name="R4G4B4A4" value="4"/>
+    <value name="R5G6B5A0" value="5"/>
+    <value name="R5G5B5A1" value="6"/>
+    <value name="RAW8" value="32"/>
+    <value name="RAW16" value="33"/>
+    <value name="RAW32" value="34"/>
+    <value name="RAW64" value="35"/>
+    <value name="RAW128" value="36"/>
+  </enum>
+
+  <enum name="SFBD Color Format">
+    <value name="4_32B_CHANNELS" value="0"/>
+    <value name="3_32B_CHANNELS" value="1"/>
+    <value name="2_32B_CHANNELS" value="2"/>
+    <value name="1_32B_CHANNEL" value="3"/>
+    <value name="4_16B_CHANNELS" value="4"/>
+    <value name="3_16B_CHANNELS" value="5"/>
+    <value name="2_16B_CHANNELS" value="6"/>
+    <value name="1_16B_CHANNEL" value="7"/>
+    <value name="R8" value="16"/>
+    <value name="R8G8" value="17"/>
+    <value name="R8G8B8" value="18"/>
+    <value name="R8G8B8A8" value="19"/>
+    <value name="R4G4B4A4" value="20"/>
+    <value name="R5G6B5" value="21"/>
+    <value name="R8G8B8_FROM_R8G8B8A2" value="22"/>
+    <value name="R10G10B10A2" value="24"/>
+    <value name="A2B10G10R10" value="25"/>
+    <value name="R5G5B5A1" value="28"/>
+    <value name="A1B5G5R5" value="29"/>
+  </enum>
+
+  <enum name="Downsampling Accumulation Mode">
+    <value name="Unsigned normalized integer" value="0"/>
+    <value name="Signed normalized integer" value="1"/>
+  </enum>
+
+  <enum name="Sample Layout">
+    <value name="Ordered 4x Grid" value="0"/>
+    <value name="Rotated 4x Grid" value="1"/>
+    <value name="D3D 8x Grid" value="2"/>
+    <value name="D3D 16x Grid" value="3"/>
+  </enum>
+
+  <enum name="ZS Format">
+    <value name="D16" value="1"/>
+    <value name="D24" value="2"/>
+    <value name="D24X8" value="4"/>
+    <value name="D24S8" value="5"/>
+    <value name="X8D24" value="6"/>
+    <value name="S8D24" value="7"/>
+    <value name="D32_X8X24" value="13"/>
+    <value name="D32" value="14"/>
+    <value name="D32_S8X24" value="15"/>
+  </enum>
+
+  <enum name="S Format">
+    <value name="S8" value="1"/>
+    <value name="S8X8" value="2"/>
+    <value name="S8X24" value="3"/>
+    <value name="X24S8" value="4"/>
+    <value name="X8S8" value="5"/>
+    <value name="X32_S8X24" value="6"/>
+  </enum>
+
+  <enum name="Tie-Break Rule">
+    <value name="0_IN_180_OUT" value="0"/>
+    <value name="0_OUT_180_IN" value="1"/>
+    <value name="MINUS_180_IN_0_OUT" value="2"/>
+    <value name="MINUS_180_OUT_0_IN" value="3"/>
+    <value name="90_IN_270_OUT" value="4"/>
+    <value name="90_OUT_270_IN" value="5"/>
+    <value name="MINUS_90_IN_90_OUT" value="6"/>
+    <value name="MINUS_90_OUT_90_IN" value="7"/>
+  </enum>
+
+  <struct name="RT Buffer">
+    <field name="Base" size="64" start="0:0" type="address"/>
+    <field name="Row Stride" size="32" start="2:0" type="uint"/>
+    <field name="Surface Stride" size="32" start="3:0" type="uint"/>
+  </struct>
+
+  <struct name="Single-Target Framebuffer Parameters" size="40">
+    <field name="Internal Format" size="3" start="0:0" default="Raw Value" type="Color Buffer Internal Format"/>
+    <field name="Sample Count" size="3" start="0:3" type="uint" default="1" modifier="log2"/>
+    <field name="Swizzle" size="12" start="0:6" type="uint"/>
+    <field name="Color Writeback Format" size="5" start="0:18" default="4_32B_CHANNELS" type="SFBD Color Format"/>
+    <field name="MSAA" size="2" start="0:23" default="Single" type="MSAA"/>
+    <field name="sRGB" size="1" start="0:25" type="bool"/>
+    <field name="Color Block Format" size="2" start="0:26" type="Block Format"/>
+    <field name="Dithering Enable" size="1" start="0:28" type="bool"/>
+    <field name="Clean Pixel Write Enable" size="1" start="0:29" type="bool"/>
+    <field name="Color Preload Enable" size="1" start="0:30" type="bool"/>
+    <field name="Color Write Enable" size="1" start="0:31" type="bool"/>
+    <field name="X Downsampling Scale" size="3" start="1:0" type="uint"/>
+    <field name="Y Downsampling Scale" size="3" start="1:3" type="uint"/>
+    <field name="Downsampling Accumulation Mode" size="2" start="1:6" type="Downsampling Accumulation Mode"/>
+    <field name="Sample Layout" size="2" start="1:8" type="Sample Layout"/>
+    <field name="Big Endian" size="1" start="1:10" type="bool"/>
+    <field name="Tie-Break Rule" size="3" start="1:11" type="Tie-Break Rule"/>
+    <field name="CRC Read Enable" size="1" start="1:14" type="bool"/>
+    <field name="CRC Write Enable" size="1" start="1:15" type="bool"/>
+    <field name="ZS Block Format" size="2" start="1:16" type="Block Format"/>
+    <field name="ZS Format" size="4" start="1:18" type="ZS Format" default="D24S8"/>
+    <field name="ZS Preload Enable" size="1" start="1:22" type="bool"/>
+    <field name="ZS Write Enable" size="1" start="1:23" type="bool"/>
+    <field name="S Block Format" size="2" start="1:24" type="Block Format"/>
+    <field name="S Format" size="4" start="1:26" type="S Format"/>
+    <field name="S Write Enable" size="1" start="1:31" type="bool"/>
+    <field name="Bound Min X" size="16" start="2:0" type="uint"/>
+    <field name="Bound Min Y" size="16" start="2:16" type="uint"/>
+    <field name="Bound Max X" size="16" start="3:0" type="uint"/>
+    <field name="Bound Max Y" size="16" start="3:16" type="uint"/>
+    <field name="DCD Offset" size="32" start="4:0" type="uint"/>
+    <field name="CRC Buffer" size="128" start="8:0" type="RT Buffer"/>
+    <field name="Color Writeback" size="128" start="12:0" type="RT Buffer"/>
+    <field name="ZS Writeback" size="128" start="16:0" type="RT Buffer"/>
+    <field name="S Writeback" size="128" start="20:0" type="RT Buffer"/>
+    <field name="Color Load Address" size="64" start="24:0" type="address"/>
+    <field name="Color Load Row Stride" size="32" start="26:0" type="uint"/>
+    <field name="Color Load Surface Stride" size="32" start="27:0" type="uint"/>
+    <field name="Clear Color 0" size="32" start="24:0" type="uint"/>
+    <field name="Clear Color 1" size="32" start="25:0" type="uint"/>
+    <field name="Clear Color 2" size="32" start="26:0" type="uint"/>
+    <field name="Clear Color 3" size="32" start="27:0" type="uint"/>
+    <field name="ZS Load Address" size="64" start="28:0" type="address"/>
+    <field name="ZS Load Row Stride" size="32" start="30:0" type="uint"/>
+    <field name="ZS Load Surface Stride" size="32" start="31:0" type="uint"/>
+    <field name="Z Clear" size="32" start="28:0" type="float"/>
+    <field name="S Clear" size="8" start="32:0" type="uint"/>
+  </struct>
+
+  <struct name="Single-Target Framebuffer Padding 1" size="6">
+  </struct>
+
+  <struct name="Single-Target Framebuffer Padding 2" size="8">
+  </struct>
+
+  <aggregate name="Single-Target Framebuffer" size="320">
+    <section name="Local Storage" offset="0" type="Local Storage"/>
+    <section name="Parameters" offset="32" type="Single-Target Framebuffer Parameters"/>
+    <section name="Tiler" offset="192" type="Midgard Tiler"/>
+    <section name="Padding 1" offset="232" type="Single-Target Framebuffer Padding 1"/>
+    <section name="Tiler Weights" offset="256" type="Midgard Tiler Weights"/>
+    <section name="Padding 2" offset="288" type="Single-Target Framebuffer Padding 2"/>
+  </aggregate>
 </panxml>