+/* Determines the # of bytes per pixel we need to reserve for a given format in
+ * the tilebuffer (compared to 128-bit budget, etc). Usually the same as the
+ * bytes per pixel of the format itself, but there are some special cases I
+ * don't understand. */
+
+static unsigned
+pan_bytes_per_pixel_tib(enum pipe_format format)
+{
+ const struct util_format_description *desc =
+ util_format_description(format);
+
+ if (util_format_is_unorm8(desc) || format == PIPE_FORMAT_B5G6R5_UNORM)
+ return 4;
+
+ return desc->block.bits / 8;
+}
+
+/* Determines whether a framebuffer uses too much tilebuffer space (requiring
+ * us to scale up the tile at a performance penalty). This is conservative but
+ * afaict you get 128-bits per pixel normally */
+
+static unsigned
+pan_tib_size(struct panfrost_batch *batch)
+{
+ unsigned size = 0;
+
+ for (int cb = 0; cb < batch->key.nr_cbufs; ++cb) {
+ struct pipe_surface *surf = batch->key.cbufs[cb];
+ assert(surf);
+ size += pan_bytes_per_pixel_tib(surf->format);
+ }
+
+ return size;
+}
+
+static unsigned
+pan_tib_shift(struct panfrost_batch *batch)
+{
+ unsigned size = pan_tib_size(batch);
+
+ if (size > 128)
+ return 4;
+ else if (size > 64)
+ return 5;
+ else if (size > 32)
+ return 6;
+ else if (size > 16)
+ return 7;
+ else
+ return 8;
+}
+
+static struct mali_framebuffer
+panfrost_emit_mfbd(struct panfrost_batch *batch, unsigned vertex_count)
+{
+ struct panfrost_context *ctx = batch->ctx;
+ struct pipe_context *gallium = (struct pipe_context *) ctx;
+ struct panfrost_device *dev = pan_device(gallium->screen);
+
+ unsigned width = batch->key.width;
+ unsigned height = batch->key.height;
+
+ struct mali_framebuffer mfbd = {
+ .width1 = MALI_POSITIVE(width),
+ .height1 = MALI_POSITIVE(height),
+ .width2 = MALI_POSITIVE(width),
+ .height2 = MALI_POSITIVE(height),
+
+ /* Configures tib size */
+ .unk1 = (pan_tib_shift(batch) << 9) | 0x80,
+
+ .rt_count_1 = MALI_POSITIVE(MAX2(batch->key.nr_cbufs, 1)),
+ .rt_count_2 = 4,
+ };
+
+ if (dev->quirks & IS_BIFROST) {
+ mfbd.msaa.sample_locations = panfrost_emit_sample_locations(batch);
+ mfbd.tiler_meta = panfrost_batch_get_tiler_meta(batch, vertex_count);
+ } else {
+ if (batch->stack_size) {
+ unsigned shift = panfrost_get_stack_shift(batch->stack_size);
+ struct panfrost_bo *bo = panfrost_batch_get_scratchpad(batch,
+ batch->stack_size,
+ dev->thread_tls_alloc,
+ dev->core_count);
+ mfbd.shared_memory.stack_shift = shift;
+ mfbd.shared_memory.scratchpad = bo->gpu;
+ }
+
+ mfbd.shared_memory.shared_workgroup_count = ~0;
+
+ mfbd.tiler = panfrost_emit_midg_tiler(batch, vertex_count);
+ }
+
+ return mfbd;
+}
+
+void
+panfrost_attach_mfbd(struct panfrost_batch *batch, unsigned vertex_count)
+{
+ struct mali_framebuffer mfbd =
+ panfrost_emit_mfbd(batch, vertex_count);
+
+ memcpy(batch->framebuffer.cpu, &mfbd, sizeof(mfbd));
+}
+