panfrost: Allocate extra data for depth buffer
[mesa.git] / src / gallium / drivers / panfrost / pan_resource.c
index a38ab5e9928c380e1f946f02c1b2bb0374718f87..89be07871a515ee394f30ea2c3cde93cd1f66a9e 100644 (file)
@@ -42,6 +42,7 @@
 #include "pan_screen.h"
 #include "pan_resource.h"
 #include "pan_swizzle.h"
+#include "pan_util.h"
 
 static struct pipe_resource *
 panfrost_resource_from_handle(struct pipe_screen *pscreen,
@@ -68,6 +69,12 @@ panfrost_resource_from_handle(struct pipe_screen *pscreen,
 
        rsc->bo = screen->driver->import_bo(screen, whandle);
 
+       if (screen->ro) {
+               rsc->scanout =
+                       renderonly_create_gpu_import_for_resource(prsc, screen->ro, NULL);
+               /* failure is expected in some cases.. */
+       }
+
         return prsc;
 }
 
@@ -87,17 +94,15 @@ panfrost_resource_get_handle(struct pipe_screen *pscreen,
         handle->stride = stride;
         handle->modifier = DRM_FORMAT_MOD_INVALID;
 
-        if (handle->type == WINSYS_HANDLE_TYPE_SHARED) {
-                printf("Missed shared handle\n");
-                return FALSE;
-        } else if (handle->type == WINSYS_HANDLE_TYPE_KMS) {
-                if (renderonly_get_handle(scanout, handle)) {
-                        return TRUE;
-                } else {
-                        printf("Missed nonrenderonly KMS handle for resource %p with scanout %p\n", pt, scanout);
-                        return FALSE;
-                }
-        } else if (handle->type == WINSYS_HANDLE_TYPE_FD) {
+       if (handle->type == WINSYS_HANDLE_TYPE_SHARED) {
+               return FALSE;
+       } else if (handle->type == WINSYS_HANDLE_TYPE_KMS) {
+               if (renderonly_get_handle(scanout, handle))
+                       return TRUE;
+
+               handle->handle = rsrc->bo->gem_handle;
+               return TRUE;
+       } else if (handle->type == WINSYS_HANDLE_TYPE_FD) {
                 if (scanout) {
                         struct drm_prime_handle args = {
                                 .handle = scanout->handle,
@@ -111,20 +116,17 @@ panfrost_resource_get_handle(struct pipe_screen *pscreen,
                         handle->handle = args.fd;
 
                         return TRUE;
-                } else {
-                        printf("Missed nonscanout FD handle\n");
-                        assert(0);
-                        return FALSE;
-                }
-        }
+                } else
+                       return screen->driver->export_bo(screen, rsrc->bo->gem_handle, handle);
+       }
 
-        return FALSE;
+       return FALSE;
 }
 
 static void
 panfrost_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
 {
-        //fprintf(stderr, "TODO %s\n", __func__);
+        //DBG("TODO %s\n", __func__);
 }
 
 static void
@@ -132,7 +134,7 @@ panfrost_blit(struct pipe_context *pipe,
               const struct pipe_blit_info *info)
 {
         /* STUB */
-        printf("Skipping blit XXX\n");
+        DBG("Skipping blit XXX\n");
         return;
 }
 
@@ -185,52 +187,65 @@ static struct panfrost_bo *
 panfrost_create_bo(struct panfrost_screen *screen, const struct pipe_resource *template)
 {
        struct panfrost_bo *bo = CALLOC_STRUCT(panfrost_bo);
+
+        /* Calculate the size of the bo */
+
         int bytes_per_pixel = util_format_get_blocksize(template->format);
         int stride = bytes_per_pixel * template->width0; /* TODO: Alignment? */
         size_t sz = stride;
 
         if (template->height0) sz *= template->height0;
-
         if (template->depth0) sz *= template->depth0;
 
-        if ((template->bind & PIPE_BIND_RENDER_TARGET) || (template->bind & PIPE_BIND_DEPTH_STENCIL)) {
-               /* TODO: Mipmapped RTs */
-               //assert(template->last_level == 0);
-
-               /* Allocate the framebuffer as its own slab of GPU-accessible memory */
-               struct panfrost_memory slab;
-               screen->driver->allocate_slab(screen, &slab, (sz / 4096) + 1, false, 0, 0, 0);
-
-               /* Make the resource out of the slab */
-               bo->cpu[0] = slab.cpu;
-               bo->gpu[0] = slab.gpu;
-       } else {
-                /* TODO: For linear resources, allocate straight on the cmdstream for
-                 * zero-copy operation */
-
-                /* Tiling textures is almost always faster, unless we only use it once */
-                bo->tiled = (template->usage != PIPE_USAGE_STREAM) && (template->bind & PIPE_BIND_SAMPLER_VIEW);
+        /* Depth buffers require extra space for unknown reasons */
+
+        if (template->bind & PIPE_BIND_DEPTH_STENCIL)
+                sz = sz + sz/256;
+
+        /* Based on the usage, figure out what storing will be used. There are
+         * various tradeoffs:
+         *
+         * Linear: the basic format, bad for memory bandwidth, bad for cache
+         * use. Zero-copy, though. Renderable.
+         *
+         * Tiled: Not compressed, but cache-optimized. Expensive to write into
+         * (due to software tiling), but cheap to sample from. Ideal for most
+         * textures. 
+         *
+         * AFBC: Compressed and renderable (so always desirable for non-scanout
+         * rendertargets). Cheap to sample from. The format is black box, so we
+         * can't read/write from software.
+         */
+
+        /* Tiling textures is almost always faster, unless we only use it once */
+        bool should_tile = (template->usage != PIPE_USAGE_STREAM) && (template->bind & PIPE_BIND_SAMPLER_VIEW);
+
+        /* Set the layout appropriately */
+        bo->layout = should_tile ? PAN_TILED : PAN_LINEAR;
+
+        if (bo->layout == PAN_TILED) {
+                /* For tiled, we don't map directly, so just malloc any old buffer */
+
+                for (int l = 0; l < (template->last_level + 1); ++l) {
+                        bo->cpu[l] = malloc(sz);
+                        bo->size[l] = sz;
+                        sz >>= 2;
+                }
+        } else {
+                /* For a linear resource, allocate a block of memory from
+                 * kernel space */
 
-                if (bo->tiled) {
-                        /* For tiled, we don't map directly, so just malloc any old buffer */
+                struct panfrost_memory mem;
 
-                        for (int l = 0; l < (template->last_level + 1); ++l) {
-                                bo->cpu[l] = malloc(sz);
-                                //sz >>= 2;
-                        }
-                } else {
-                        /* But for linear, we can! */
+                bo->size[0] = ALIGN(sz, 4096);
+                screen->driver->allocate_slab(screen, &mem, bo->size[0] / 4096, true, 0, 0, 0);
 
-                        struct pb_slab_entry *entry = pb_slab_alloc(&screen->slabs, sz, HEAP_TEXTURE);
-                        struct panfrost_memory_entry *p_entry = (struct panfrost_memory_entry *) entry;
-                        struct panfrost_memory *backing = (struct panfrost_memory *) entry->slab;
-                        bo->entry[0] = p_entry;
-                        bo->cpu[0] = backing->cpu + p_entry->offset;
-                        bo->gpu[0] = backing->gpu + p_entry->offset;
+                bo->cpu[0] = mem.cpu;
+                bo->gpu[0] = mem.gpu;
+                bo->gem_handle = mem.gem_handle;
 
-                        /* TODO: Mipmap */
-                }
-       }
+                /* TODO: Mipmap */
+        }
 
         return bo;
 }
@@ -256,45 +271,39 @@ panfrost_resource_create(struct pipe_screen *screen,
                 case PIPE_TEXTURE_RECT:
                         break;
                 default:
-                        fprintf(stderr, "Unknown texture target %d\n", template->target);
+                        DBG("Unknown texture target %d\n", template->target);
                         assert(0);
         }
 
-        if ((template->bind & PIPE_BIND_RENDER_TARGET) || (template->bind & PIPE_BIND_DEPTH_STENCIL)) {
-                if (template->bind & PIPE_BIND_DISPLAY_TARGET ||
-                    template->bind & PIPE_BIND_SCANOUT ||
-                    template->bind & PIPE_BIND_SHARED) {
-                        struct pipe_resource scanout_templat = *template;
-                        struct renderonly_scanout *scanout;
-                        struct winsys_handle handle;
-
-                        /* TODO: align width0 and height0? */
-
-                        scanout = renderonly_scanout_for_resource(&scanout_templat,
-                                                                  pscreen->ro, &handle);
-                        if (!scanout)
-                                return NULL;
-
-                        assert(handle.type == WINSYS_HANDLE_TYPE_FD);
-                        /* TODO: handle modifiers? */
-                        so = pan_resource(screen->resource_from_handle(screen, template,
-                                                                         &handle,
-                                                                         PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE));
-                        close(handle.handle);
-                        if (!so)
-                                return NULL;
-
-                        so->scanout = scanout;
-                        pscreen->display_target = so;
-                } else {
-                       so->bo = panfrost_create_bo(pscreen, template);
-                }
+        if (template->bind & PIPE_BIND_DISPLAY_TARGET ||
+            template->bind & PIPE_BIND_SCANOUT ||
+            template->bind & PIPE_BIND_SHARED) {
+                struct pipe_resource scanout_templat = *template;
+                struct renderonly_scanout *scanout;
+                struct winsys_handle handle;
+
+                /* TODO: align width0 and height0? */
+
+                scanout = renderonly_scanout_for_resource(&scanout_templat,
+                                                          pscreen->ro, &handle);
+                if (!scanout)
+                        return NULL;
+
+                assert(handle.type == WINSYS_HANDLE_TYPE_FD);
+                /* TODO: handle modifiers? */
+                so = pan_resource(screen->resource_from_handle(screen, template,
+                                                                 &handle,
+                                                                 PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE));
+                close(handle.handle);
+                if (!so)
+                        return NULL;
+
+                so->scanout = scanout;
+                pscreen->display_target = so;
         } else {
-               so->bo = panfrost_create_bo(pscreen, template);
+                so->bo = panfrost_create_bo(pscreen, template);
         }
 
-        printf("Created resource %p with scanout %p\n", so, so->scanout);
-
         return (struct pipe_resource *)so;
 }
 
@@ -303,28 +312,39 @@ panfrost_destroy_bo(struct panfrost_screen *screen, struct panfrost_bo *pbo)
 {
        struct panfrost_bo *bo = (struct panfrost_bo *)pbo;
 
-        if (bo->tiled) {
-                /* CPU is all malloc'ed, so just plain ol' free needed */
+        if (bo->layout == PAN_LINEAR && !bo->imported) {
+                /* Construct a memory object for all mip levels */
+
+                struct panfrost_memory mem = {
+                        .cpu = bo->cpu[0],
+                        .gpu = bo->gpu[0],
+                        .size = bo->size[0],
+                        .gem_handle = bo->gem_handle,
+                };
+
+                screen->driver->free_slab(screen, &mem);
+        }
+
+        if (bo->layout == PAN_TILED) {
+                /* Tiled has a malloc'd CPU, so just plain ol' free needed */
 
-                for (int l = 0; bo->cpu[l]; l++) {
+                for (int l = 0; l < MAX_MIP_LEVELS; ++l) {
                         free(bo->cpu[l]);
                 }
-        } else if (bo->entry[0] != NULL) {
-                bo->entry[0]->freed = true;
-                pb_slab_free(&screen->slabs, &bo->entry[0]->base);
-        } else {
-                /* TODO */
-                printf("--leaking main allocation--\n");
         }
 
-        if (bo->has_afbc) {
+        if (bo->layout == PAN_AFBC) {
                 /* TODO */
-                printf("--leaking afbc--\n");
+                DBG("--leaking afbc (%d bytes)--\n", bo->afbc_metadata_size);
         }
 
         if (bo->has_checksum) {
                 /* TODO */
-                printf("--leaking checksum--\n");
+                DBG("--leaking checksum (%zd bytes)--\n", bo->checksum_slab.size);
+        }
+
+        if (bo->imported) {
+                screen->driver->free_imported_bo(screen, bo);
         }
 }
 
@@ -332,7 +352,7 @@ static void
 panfrost_resource_destroy(struct pipe_screen *screen,
                           struct pipe_resource *pt)
 {
-        struct panfrost_screen *pscreen = panfrost_screen(screen);
+        struct panfrost_screen *pscreen = pan_screen(screen);
         struct panfrost_resource *rsrc = (struct panfrost_resource *) pt;
 
        if (rsrc->scanout)
@@ -352,8 +372,8 @@ panfrost_map_bo(struct panfrost_context *ctx, struct pipe_transfer *transfer)
         /* If non-zero level, it's a mipmapped resource and needs to be treated as such */
         bo->is_mipmap |= transfer->level;
 
-        if (transfer->usage & PIPE_TRANSFER_MAP_DIRECTLY && bo->tiled) {
-                /* We cannot directly map tiled textures */
+        if (transfer->usage & PIPE_TRANSFER_MAP_DIRECTLY && bo->layout != PAN_LINEAR) {
+                /* We can only directly map linear resources */
                 return NULL;
         }
 
@@ -424,12 +444,6 @@ panfrost_tile_texture(struct panfrost_screen *screen, struct panfrost_resource *
 
         int swizzled_sz = panfrost_swizzled_size(width, height, bytes_per_pixel);
 
-        /* Allocate the transfer given that known size but do not copy */
-        struct pb_slab_entry *entry = pb_slab_alloc(&screen->slabs, swizzled_sz, HEAP_TEXTURE);
-        struct panfrost_memory_entry *p_entry = (struct panfrost_memory_entry *) entry;
-        struct panfrost_memory *backing = (struct panfrost_memory *) entry->slab;
-        uint8_t *swizzled = backing->cpu + p_entry->offset;
-
         /* Save the entry. But if there was already an entry here (from a
          * previous upload of the resource), free that one so we don't leak */
 
@@ -438,6 +452,12 @@ panfrost_tile_texture(struct panfrost_screen *screen, struct panfrost_resource *
                 pb_slab_free(&screen->slabs, &bo->entry[level]->base);
         }
 
+        /* Allocate the transfer given that known size but do not copy */
+        struct pb_slab_entry *entry = pb_slab_alloc(&screen->slabs, swizzled_sz, HEAP_TEXTURE);
+        struct panfrost_memory_entry *p_entry = (struct panfrost_memory_entry *) entry;
+        struct panfrost_memory *backing = (struct panfrost_memory *) entry->slab;
+        uint8_t *swizzled = backing->cpu + p_entry->offset;
+
         bo->entry[level] = p_entry;
         bo->gpu[level] = backing->gpu + p_entry->offset;
 
@@ -458,9 +478,9 @@ panfrost_unmap_bo(struct panfrost_context *ctx,
                         struct panfrost_resource *prsrc = (struct panfrost_resource *) transfer->resource;
 
                         /* Gallium thinks writeback happens here; instead, this is our cue to tile */
-                        if (bo->has_afbc) {
-                                printf("Warning: writes to afbc surface can't possibly work out well for you...\n");
-                        } else if (bo->tiled) {
+                        if (bo->layout == PAN_AFBC) {
+                                DBG("Warning: writes to afbc surface can't possibly work out well for you...\n");
+                        } else if (bo->layout == PAN_TILED) {
                                 struct pipe_context *gallium = (struct pipe_context *) ctx;
                                 struct panfrost_screen *screen = pan_screen(gallium->screen);
                                 panfrost_tile_texture(screen, prsrc, transfer->level);
@@ -525,15 +545,35 @@ panfrost_slab_can_reclaim(void *priv, struct pb_slab_entry *entry)
 static void
 panfrost_slab_free(void *priv, struct pb_slab *slab)
 {
-        /* STUB */
-        //struct panfrost_memory *mem = (struct panfrost_memory *) slab;
-        printf("stub: Tried to free slab\n");
+        struct panfrost_memory *mem = (struct panfrost_memory *) slab;
+        struct panfrost_screen *screen = (struct panfrost_screen *) priv;
+
+        screen->driver->free_slab(screen, mem);
 }
 
 static void
 panfrost_invalidate_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
 {
-        //fprintf(stderr, "TODO %s\n", __func__);
+        //DBG("TODO %s\n", __func__);
+}
+
+static enum pipe_format
+panfrost_resource_get_internal_format(struct pipe_resource *prsrc)
+{
+        return prsrc->format;
+}
+
+static void
+panfrost_resource_set_stencil(struct pipe_resource *prsrc,
+                              struct pipe_resource *stencil)
+{
+        pan_resource(prsrc)->separate_stencil = pan_resource(stencil);
+}
+
+static struct pipe_resource *
+panfrost_resource_get_stencil(struct pipe_resource *prsrc)
+{
+        return &pan_resource(prsrc)->separate_stencil->base;
 }
 
 static const struct u_transfer_vtbl transfer_vtbl = {
@@ -542,9 +582,9 @@ static const struct u_transfer_vtbl transfer_vtbl = {
         .transfer_map             = panfrost_transfer_map,
         .transfer_unmap           = panfrost_transfer_unmap,
         .transfer_flush_region    = u_default_transfer_flush_region,
-        //.get_internal_format      = panfrost_resource_get_internal_format,
-        //.set_stencil              = panfrost_resource_set_stencil,
-        //.get_stencil              = panfrost_resource_get_stencil,
+        .get_internal_format      = panfrost_resource_get_internal_format,
+        .set_stencil              = panfrost_resource_set_stencil,
+        .get_stencil              = panfrost_resource_get_stencil,
 };
 
 void
@@ -557,7 +597,7 @@ panfrost_resource_screen_init(struct panfrost_screen *pscreen)
         pscreen->base.resource_from_handle = panfrost_resource_from_handle;
         pscreen->base.resource_get_handle = panfrost_resource_get_handle;
         pscreen->base.transfer_helper = u_transfer_helper_create(&transfer_vtbl,
-                                                            true, true,
+                                                            true, false,
                                                             true, true);
 
         pb_slabs_init(&pscreen->slabs,