panfrost: Use pack for XFB varying
[mesa.git] / src / gallium / drivers / panfrost / pan_sfbd.c
index 563e4269b8df31a2988e5340a7e2307f0e6def5b..58d33dcddde32b488fb8360a621618e81f7f312c 100644 (file)
  *
  */
 
+#include "pan_bo.h"
 #include "pan_context.h"
 #include "pan_util.h"
-#include "pan_format.h"
 
-#include "util/u_format.h"
+#include "util/format/u_format.h"
 
-static unsigned
+static struct mali_sfbd_format
 panfrost_sfbd_format(struct pipe_surface *surf)
 {
-        /* TODO */
-        return 0xb84e0281; /* RGB32, no MSAA */
+        /* Explode details on the format */
+
+        const struct util_format_description *desc =
+                util_format_description(surf->format);
+
+        /* The swizzle for rendering is inverted from texturing */
+
+        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,
+        };
+
+        if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB)
+                fmt.unk2 |= MALI_SFBD_FORMAT_SRGB;
+
+        /* 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;
+                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;
+                break;
+
+        default:
+                unreachable("Invalid format rendering");
+        }
+
+        return fmt;
 }
 
 static void
 panfrost_sfbd_clear(
-        struct panfrost_job *job,
+        struct panfrost_batch *batch,
         struct mali_single_framebuffer *sfbd)
 {
-        struct panfrost_context *ctx = job->ctx;
-
-        if (job->clear & PIPE_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 (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];
         }
 
-        if (job->clear & PIPE_CLEAR_DEPTH) {
-                sfbd->clear_depth_1 = job->clear_depth;
-                sfbd->clear_depth_2 = job->clear_depth;
-                sfbd->clear_depth_3 = job->clear_depth;
-                sfbd->clear_depth_4 = job->clear_depth;
-
-                sfbd->depth_buffer = ctx->depth_stencil_buffer.bo->gpu;
-                sfbd->depth_buffer_enable = MALI_DEPTH_STENCIL_ENABLE;
+        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 (job->clear & PIPE_CLEAR_STENCIL) {
-                sfbd->clear_stencil = job->clear_stencil;
-
-                sfbd->stencil_buffer = ctx->depth_stencil_buffer.bo->gpu;
-                sfbd->stencil_buffer_enable = MALI_DEPTH_STENCIL_ENABLE;
+        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 (!(job->clear & ~(PIPE_CLEAR_COLOR | PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) {
+        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 (job->clear & PIPE_CLEAR_STENCIL)
+                if (batch->clear & PIPE_CLEAR_STENCIL)
                         clear_flags |= MALI_CLEAR_SLOW_STENCIL;
         }
 
@@ -91,39 +129,142 @@ panfrost_sfbd_set_cbuf(
 {
         struct panfrost_resource *rsrc = pan_resource(surf->texture);
 
-        signed stride = rsrc->slices[0].stride;
+        unsigned level = surf->u.tex.level;
+        unsigned first_layer = surf->u.tex.first_layer;
+        assert(surf->u.tex.last_layer == first_layer);
+        signed stride = rsrc->slices[level].stride;
+
+        mali_ptr base = panfrost_get_texture_address(rsrc, level, first_layer, 0);
 
         fb->format = panfrost_sfbd_format(surf);
 
-        if (rsrc->layout == PAN_LINEAR) {
-                fb->framebuffer = rsrc->bo->gpu;
-                fb->stride = stride;
+        fb->framebuffer = base;
+        fb->stride = stride;
+
+        if (rsrc->modifier == DRM_FORMAT_MOD_LINEAR)
+                fb->format.block = MALI_BLOCK_FORMAT_LINEAR;
+        else if (rsrc->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
+                fb->format.block = MALI_BLOCK_FORMAT_TILED;
+                fb->stride *= 16;
         } else {
-                fprintf(stderr, "Invalid render layout\n");
+                fprintf(stderr, "Invalid render modifier\n");
                 assert(0);
         }
 }
 
+static void
+panfrost_sfbd_set_zsbuf(
+        struct mali_single_framebuffer *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);
+
+        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
+                unreachable("Unsupported depth/stencil format.");
+}
+
+
+static struct mali_single_framebuffer
+panfrost_emit_sfbd(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;
+
+        /* 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),
+                .shared_memory = {
+                        .stack_shift = shift,
+                        .shared_workgroup_count = ~0,
+                        .scratchpad = panfrost_batch_get_scratchpad(batch, shift, dev->thread_tls_alloc, dev->core_count)->gpu,
+                },
+                .format = {
+                        .unk3 = 0x3,
+                },
+                .clear_flags = 0x1000,
+                .tiler = panfrost_emit_midg_tiler(batch, vertex_count),
+        };
+
+        return framebuffer;
+}
+
+void
+panfrost_attach_sfbd(struct panfrost_batch *batch, unsigned vertex_count)
+{
+        struct mali_single_framebuffer sfbd =
+                panfrost_emit_sfbd(batch, vertex_count);
+
+        memcpy(batch->framebuffer.cpu, &sfbd, sizeof(sfbd));
+}
+
 /* Creates an SFBD for the FRAGMENT section of the bound framebuffer */
 
 mali_ptr
-panfrost_sfbd_fragment(struct panfrost_context *ctx, bool has_draws)
+panfrost_sfbd_fragment(struct panfrost_batch *batch, bool has_draws)
 {
-        struct panfrost_job *job = panfrost_get_job_for_fbo(ctx);
-        struct mali_single_framebuffer fb = panfrost_emit_sfbd(ctx, has_draws);
+        struct mali_single_framebuffer fb = panfrost_emit_sfbd(batch, has_draws);
 
-        panfrost_sfbd_clear(job, &fb);
+        panfrost_sfbd_clear(batch, &fb);
 
         /* SFBD does not support MRT natively; sanity check */
-        assert(ctx->pipe_framebuffer.nr_cbufs == 1);
-        panfrost_sfbd_set_cbuf(&fb, ctx->pipe_framebuffer.cbufs[0]);
+        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);
+
+                if (rsrc->checksummed) {
+                        unsigned level = surf->u.tex.level;
+                        struct panfrost_slice *slice = &rsrc->slices[level];
 
-        if (ctx->pipe_framebuffer.zsbuf) {
-                /* TODO */
+                        fb.checksum_stride = slice->checksum_stride;
+                        fb.checksum = bo->gpu + slice->checksum_offset;
+                }
         }
 
-        if (job->requirements & PAN_REQ_MSAA)
-                fb.format |= MALI_FRAMEBUFFER_MSAA_A | MALI_FRAMEBUFFER_MSAA_B;
+        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_upload_transient(ctx, &fb, sizeof(fb)) | MALI_SFBD;
+        return panfrost_pool_upload(&batch->pool, &fb, sizeof(fb));
 }