panfrost: Stop passing screen around for BO operations
[mesa.git] / src / gallium / drivers / panfrost / pan_allocate.c
index dff8373cbd5785ce36e43bf10f2a3d0e11fb8e0e..7938196e3e4f321329a4feb4e4deecb302ea5e7a 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * © Copyright 2018 Alyssa Rosenzweig
+ * Copyright (C) 2019 Collabora, Ltd.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
 #include <assert.h>
 #include <panfrost-misc.h>
 #include <panfrost-job.h>
+#include "pan_bo.h"
 #include "pan_context.h"
 
 /* TODO: What does this actually have to be? */
 #define ALIGNMENT 128
 
-/* Allocate a mapped chunk directly from a heap */
-
-struct panfrost_transfer
-panfrost_allocate_chunk(struct panfrost_context *ctx, size_t size, unsigned heap_id)
-{
-        size = ALIGN_POT(size, ALIGNMENT);
-
-        struct pipe_context *gallium = (struct pipe_context *) ctx;
-        struct panfrost_screen *screen = pan_screen(gallium->screen);
-
-        struct pb_slab_entry *entry = pb_slab_alloc(&screen->slabs, size, heap_id);
-        struct panfrost_memory_entry *p_entry = (struct panfrost_memory_entry *) entry;
-        struct panfrost_memory *backing = (struct panfrost_memory *) entry->slab;
-
-        struct panfrost_transfer transfer = {
-                .cpu = backing->bo->cpu + p_entry->offset,
-                .gpu = backing->bo->gpu + p_entry->offset
-        };
-
-        return transfer;
-}
-
 /* Transient command stream pooling: command stream uploads try to simply copy
  * into whereever we left off. If there isn't space, we allocate a new entry
  * into the pool and copy there */
 
 struct panfrost_transfer
-panfrost_allocate_transient(struct panfrost_context *ctx, size_t sz)
+panfrost_allocate_transient(struct panfrost_batch *batch, size_t sz)
 {
+        struct panfrost_screen *screen = pan_screen(batch->ctx->base.screen);
+
         /* Pad the size */
         sz = ALIGN_POT(sz, ALIGNMENT);
 
-        /* Check if there is room in the current entry */
-        struct panfrost_transient_pool *pool = &ctx->transient_pools[ctx->cmdstream_i];
+        /* Find or create a suitable BO */
+        struct panfrost_bo *bo = NULL;
+
+        unsigned offset = 0;
 
-        if ((pool->entry_offset + sz) > pool->entry_size) {
-                /* Don't overflow this entry -- advance to the next */
+        bool fits_in_current = (batch->transient_offset + sz) < TRANSIENT_SLAB_SIZE;
 
-                pool->entry_offset = 0;
+        if (likely(batch->transient_bo && fits_in_current)) {
+                /* We can reuse the current BO, so get it */
+                bo = batch->transient_bo;
 
-                pool->entry_index++;
-                assert(pool->entry_index < PANFROST_MAX_TRANSIENT_ENTRIES);
+                /* Use the specified offset */
+                offset = batch->transient_offset;
+                batch->transient_offset = offset + sz;
+        } else {
+                size_t bo_sz = sz < TRANSIENT_SLAB_SIZE ?
+                               TRANSIENT_SLAB_SIZE : ALIGN_POT(sz, 4096);
 
-                /* Check if this entry exists */
-                
-                if (pool->entry_index >= pool->entry_count) {
-                        /* Don't overflow the pool -- allocate a new one */
-                        struct pipe_context *gallium = (struct pipe_context *) ctx;
-                        struct panfrost_screen *screen = pan_screen(gallium->screen);
-                        struct pb_slab_entry *entry = pb_slab_alloc(&screen->slabs, pool->entry_size, HEAP_TRANSIENT);
+                /* We can't reuse the current BO, but we can create a new one. */
+                bo = panfrost_bo_create(screen, bo_sz, 0);
+                panfrost_batch_add_bo(batch, bo);
 
-                        pool->entry_count++;
-                        pool->entries[pool->entry_index] = (struct panfrost_memory_entry *) entry;
-                }
+                /* Creating a BO adds a reference, and then the job adds a
+                 * second one. So we need to pop back one reference */
+                panfrost_bo_unreference(bo);
 
-                /* Make sure we -still- won't overflow */
-                assert(sz < pool->entry_size);
+                if (sz < TRANSIENT_SLAB_SIZE) {
+                        batch->transient_bo = bo;
+                        batch->transient_offset = offset + sz;
+                }
         }
 
-        /* We have an entry we can write to, so do the upload! */
-        struct panfrost_memory_entry *p_entry = pool->entries[pool->entry_index];
-        struct panfrost_memory *backing = (struct panfrost_memory *) p_entry->base.slab;
-
         struct panfrost_transfer ret = {
-                .cpu = backing->bo->cpu + p_entry->offset + pool->entry_offset,
-                .gpu = backing->bo->gpu + p_entry->offset + pool->entry_offset
+                .cpu = bo->cpu + offset,
+                .gpu = bo->gpu + offset,
         };
 
-        /* Advance the pointer */
-        pool->entry_offset += sz;
-
         return ret;
 
 }
 
 mali_ptr
-panfrost_upload_transient(struct panfrost_context *ctx, const void *data, size_t sz)
+panfrost_upload_transient(struct panfrost_batch *batch, const void *data,
+                          size_t sz)
 {
-        struct panfrost_transfer transfer = panfrost_allocate_transient(ctx, sz);
+        struct panfrost_transfer transfer = panfrost_allocate_transient(batch, sz);
         memcpy(transfer.cpu, data, sz);
         return transfer.gpu;
 }
-
-// TODO: An actual allocator, perhaps
-// TODO: Multiple stacks for multiple bases?
-
-int hack_stack_bottom = 4096; /* Don't interfere with constant offsets */
-int last_offset = 0;
-
-static inline int
-pandev_allocate_offset(int *stack, size_t sz)
-{
-        /* First, align the stack bottom to something nice; it's not critical
-         * at this point if we waste a little space to do so. */
-
-        int excess = *stack & (ALIGNMENT - 1);
-
-        /* Add the secret of my */
-        if (excess)
-                *stack += ALIGNMENT - excess;
-
-        /* Finally, use the new bottom for the allocation and move down the
-         * stack */
-
-        int ret = *stack;
-        *stack += sz;
-        return ret;
-}
-
-inline mali_ptr
-pandev_upload(int cheating_offset, int *stack_bottom, mali_ptr base, void *base_map, const void *data, size_t sz, bool no_pad)
-{
-        int offset;
-
-        /* We're not positive about the sizes of all objects, but we don't want
-         * them to crash against each other either. Let the caller disable
-         * padding if they so choose, though. */
-
-        size_t padded_size = no_pad ? sz : sz * 2;
-
-        /* If no specific bottom is specified, use a global one... don't do
-         * this in production, kids */
-
-        if (!stack_bottom)
-                stack_bottom = &hack_stack_bottom;
-
-        /* Allocate space for the new GPU object, if required */
-
-        if (cheating_offset == -1) {
-                offset = pandev_allocate_offset(stack_bottom, padded_size);
-        } else {
-                offset = cheating_offset;
-                *stack_bottom = offset + sz;
-        }
-
-        /* Save last offset for sequential uploads (job descriptors) */
-        last_offset = offset + padded_size;
-
-        /* Upload it */
-        memcpy((uint8_t *) base_map + offset, data, sz);
-
-        /* Return the GPU address */
-        return base + offset;
-}
-
-/* Upload immediately after the last allocation */
-
-mali_ptr
-pandev_upload_sequential(mali_ptr base, void *base_map, const void *data, size_t sz)
-{
-        return pandev_upload(last_offset, NULL, base, base_map, data, sz, /* false */ true);
-}
-
-/* Simplified APIs for the real driver, rather than replays */
-
-mali_ptr
-panfrost_upload(struct panfrost_memory *mem, const void *data, size_t sz, bool no_pad)
-{
-        /* Bounds check */
-        if ((mem->stack_bottom + sz) >= mem->bo->size) {
-                printf("Out of memory, tried to upload %zd but only %zd available\n",
-                       sz, mem->bo->size - mem->stack_bottom);
-                assert(0);
-        }
-
-        return pandev_upload(-1, &mem->stack_bottom, mem->bo->gpu, mem->bo->cpu, data, sz, no_pad);
-}
-
-mali_ptr
-panfrost_upload_sequential(struct panfrost_memory *mem, const void *data, size_t sz)
-{
-        return pandev_upload(last_offset, &mem->stack_bottom, mem->bo->gpu, mem->bo->cpu, data, sz, true);
-}
-
-/* Simplified interface to allocate a chunk without any upload, to allow
- * zero-copy uploads. This is particularly useful when the copy would happen
- * anyway, for instance with texture swizzling. */
-
-void *
-panfrost_allocate_transfer(struct panfrost_memory *mem, size_t sz, mali_ptr *gpu)
-{
-        int offset = pandev_allocate_offset(&mem->stack_bottom, sz);
-
-        *gpu = mem->bo->gpu + offset;
-        return mem->bo->cpu + offset;
-}