[Mesa-dev] [PATCH v3 09/25] panfrost: Rework the panfrost_bo API

Boris Brezillon boris.brezillon at collabora.com
Thu Sep 5 19:41:34 UTC 2019


* BO related functions/structs are now exposed in pan_bo.h instead of
  being spread in pan_screen.h/pan_resource.h
* cache related functions are no longer exposed
* panfrost_bo now has a ->screen field to avoid passing screen around
* the function names are made consistent (all BO related functions are
  prefixed with panfrost_bo_)
* release functions are no longer exposed, existing users are converted
  to use panfrost_bo_unreference() instead

Signed-off-by: Boris Brezillon <boris.brezillon at collabora.com>
---
 src/gallium/drivers/panfrost/pan_allocate.c   |   5 +-
 src/gallium/drivers/panfrost/pan_allocate.h   |  20 --
 src/gallium/drivers/panfrost/pan_assemble.c   |   3 +-
 src/gallium/drivers/panfrost/pan_blend_cso.c  |   5 +-
 src/gallium/drivers/panfrost/pan_bo.c         | 236 +++++++++++++++++-
 src/gallium/drivers/panfrost/pan_bo.h         |  78 ++++++
 src/gallium/drivers/panfrost/pan_context.c    |  16 +-
 src/gallium/drivers/panfrost/pan_drm.c        | 187 +-------------
 src/gallium/drivers/panfrost/pan_instancing.c |   1 +
 src/gallium/drivers/panfrost/pan_job.c        |   7 +-
 src/gallium/drivers/panfrost/pan_mfbd.c       |   1 +
 src/gallium/drivers/panfrost/pan_resource.c   |  38 +--
 src/gallium/drivers/panfrost/pan_resource.h   |   8 +-
 src/gallium/drivers/panfrost/pan_screen.c     |   1 +
 src/gallium/drivers/panfrost/pan_screen.h     |  24 --
 src/gallium/drivers/panfrost/pan_sfbd.c       |   1 +
 src/gallium/drivers/panfrost/pan_varyings.c   |   1 +
 17 files changed, 338 insertions(+), 294 deletions(-)
 create mode 100644 src/gallium/drivers/panfrost/pan_bo.h

diff --git a/src/gallium/drivers/panfrost/pan_allocate.c b/src/gallium/drivers/panfrost/pan_allocate.c
index a22b1a5a88d6..beebb0bc6d7e 100644
--- a/src/gallium/drivers/panfrost/pan_allocate.c
+++ b/src/gallium/drivers/panfrost/pan_allocate.c
@@ -29,6 +29,7 @@
 #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? */
@@ -66,12 +67,12 @@ panfrost_allocate_transient(struct panfrost_context *ctx, size_t sz)
                                TRANSIENT_SLAB_SIZE : ALIGN_POT(sz, 4096);
 
                 /* We can't reuse the current BO, but we can create a new one. */
-                bo = panfrost_drm_create_bo(screen, bo_sz, 0);
+                bo = panfrost_bo_create(screen, bo_sz, 0);
                 panfrost_batch_add_bo(batch, bo);
 
                 /* 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(&screen->base, bo);
+                panfrost_bo_unreference(bo);
 
                 if (sz < TRANSIENT_SLAB_SIZE) {
                         batch->transient_bo = bo;
diff --git a/src/gallium/drivers/panfrost/pan_allocate.h b/src/gallium/drivers/panfrost/pan_allocate.h
index c0aff62df4a1..91c2af9c4f17 100644
--- a/src/gallium/drivers/panfrost/pan_allocate.h
+++ b/src/gallium/drivers/panfrost/pan_allocate.h
@@ -43,26 +43,6 @@ struct panfrost_transfer {
         mali_ptr gpu;
 };
 
-struct panfrost_bo {
-        /* Must be first for casting */
-        struct list_head link;
-
-        struct pipe_reference reference;
-
-        /* Mapping for the entire object (all levels) */
-        uint8_t *cpu;
-
-        /* GPU address for the object */
-        mali_ptr gpu;
-
-        /* Size of all entire trees */
-        size_t size;
-
-        int gem_handle;
-
-        uint32_t flags;
-};
-
 struct panfrost_transfer
 panfrost_allocate_transient(struct panfrost_context *ctx, size_t sz);
 
diff --git a/src/gallium/drivers/panfrost/pan_assemble.c b/src/gallium/drivers/panfrost/pan_assemble.c
index b57cd5ef6ad2..79c000367632 100644
--- a/src/gallium/drivers/panfrost/pan_assemble.c
+++ b/src/gallium/drivers/panfrost/pan_assemble.c
@@ -25,6 +25,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "pan_bo.h"
 #include "pan_context.h"
 
 #include "compiler/nir/nir.h"
@@ -82,7 +83,7 @@ panfrost_shader_compile(
          * I bet someone just thought that would be a cute pun. At least,
          * that's how I'd do it. */
 
-        state->bo = panfrost_drm_create_bo(screen, size, PAN_ALLOCATE_EXECUTE);
+        state->bo = panfrost_bo_create(screen, size, PAN_ALLOCATE_EXECUTE);
         memcpy(state->bo->cpu, dst, size);
         meta->shader = state->bo->gpu | program.first_tag;
 
diff --git a/src/gallium/drivers/panfrost/pan_blend_cso.c b/src/gallium/drivers/panfrost/pan_blend_cso.c
index ab49772f3ba3..69897be4f007 100644
--- a/src/gallium/drivers/panfrost/pan_blend_cso.c
+++ b/src/gallium/drivers/panfrost/pan_blend_cso.c
@@ -29,6 +29,7 @@
 #include "util/u_memory.h"
 #include "pan_blend_shaders.h"
 #include "pan_blending.h"
+#include "pan_bo.h"
 
 /* A given Gallium blend state can be encoded to the hardware in numerous,
  * dramatically divergent ways due to the interactions of blending with
@@ -272,12 +273,12 @@ panfrost_get_blend_for_context(struct panfrost_context *ctx, unsigned rti)
         final.shader.first_tag = shader->first_tag;
 
         /* Upload the shader */
-        final.shader.bo = panfrost_drm_create_bo(screen, shader->size, PAN_ALLOCATE_EXECUTE);
+        final.shader.bo = panfrost_bo_create(screen, shader->size, PAN_ALLOCATE_EXECUTE);
         memcpy(final.shader.bo->cpu, shader->buffer, shader->size);
 
         /* Pass BO ownership to job */
         panfrost_batch_add_bo(batch, final.shader.bo);
-        panfrost_bo_unreference(ctx->base.screen, final.shader.bo);
+        panfrost_bo_unreference(final.shader.bo);
 
         if (shader->patch_index) {
                 /* We have to specialize the blend shader to use constants, so
diff --git a/src/gallium/drivers/panfrost/pan_bo.c b/src/gallium/drivers/panfrost/pan_bo.c
index f2f49437a89f..1f87c18e9ad5 100644
--- a/src/gallium/drivers/panfrost/pan_bo.c
+++ b/src/gallium/drivers/panfrost/pan_bo.c
@@ -23,11 +23,20 @@
  * Authors (Collabora):
  *   Alyssa Rosenzweig <alyssa.rosenzweig at collabora.com>
  */
+#include <stdio.h>
+#include <fcntl.h>
 #include <xf86drm.h>
 #include <pthread.h>
 #include "drm-uapi/panfrost_drm.h"
 
+#include "pan_bo.h"
 #include "pan_screen.h"
+#include "pan_util.h"
+#include "pandecode/decode.h"
+
+#include "os/os_mman.h"
+
+#include "util/u_inlines.h"
 #include "util/u_math.h"
 
 /* This file implements a userspace BO cache. Allocating and freeing
@@ -45,6 +54,51 @@
  * around the linked list.
  */
 
+static struct panfrost_bo *
+panfrost_bo_alloc(struct panfrost_screen *screen, size_t size,
+                  uint32_t flags)
+{
+        struct drm_panfrost_create_bo create_bo = { .size = size };
+        struct panfrost_bo *bo;
+        int ret;
+
+        if (screen->kernel_version->version_major > 1 ||
+            screen->kernel_version->version_minor >= 1) {
+                if (flags & PAN_ALLOCATE_GROWABLE)
+                        create_bo.flags |= PANFROST_BO_HEAP;
+                if (!(flags & PAN_ALLOCATE_EXECUTE))
+                        create_bo.flags |= PANFROST_BO_NOEXEC;
+        }
+
+        ret = drmIoctl(screen->fd, DRM_IOCTL_PANFROST_CREATE_BO, &create_bo);
+        if (ret)
+                return NULL;
+
+        bo = rzalloc(screen, struct panfrost_bo);
+        assert(bo);
+        bo->size = create_bo.size;
+        bo->gpu = create_bo.offset;
+        bo->gem_handle = create_bo.handle;
+        bo->flags = flags;
+        bo->screen = screen;
+        return bo;
+}
+
+static void
+panfrost_bo_free(struct panfrost_bo *bo)
+{
+        struct drm_gem_close gem_close = { .handle = bo->gem_handle };
+        int ret;
+
+        ret = drmIoctl(bo->screen->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
+        if (ret) {
+                fprintf(stderr, "DRM_IOCTL_GEM_CLOSE failed: %m\n");
+                assert(0);
+        }
+
+        ralloc_free(bo);
+}
+
 /* Helper to calculate the bucket index of a BO */
 
 static unsigned
@@ -80,10 +134,9 @@ pan_bucket(struct panfrost_screen *screen, unsigned size)
  * cache. If it fails, it returns NULL signaling the caller to allocate a new
  * BO. */
 
-struct panfrost_bo *
-panfrost_bo_cache_fetch(
-                struct panfrost_screen *screen,
-                size_t size, uint32_t flags)
+static struct panfrost_bo *
+panfrost_bo_cache_fetch(struct panfrost_screen *screen,
+                        size_t size, uint32_t flags)
 {
         pthread_mutex_lock(&screen->bo_cache_lock);
         struct list_head *bucket = pan_bucket(screen, size);
@@ -105,7 +158,7 @@ panfrost_bo_cache_fetch(
 
                         ret = drmIoctl(screen->fd, DRM_IOCTL_PANFROST_MADVISE, &madv);
                         if (!ret && !madv.retained) {
-                                panfrost_drm_release_bo(screen, entry, false);
+                                panfrost_bo_free(entry);
                                 continue;
                         }
                         /* Let's go! */
@@ -121,11 +174,14 @@ panfrost_bo_cache_fetch(
 /* Tries to add a BO to the cache. Returns if it was
  * successful */
 
-bool
-panfrost_bo_cache_put(
-                struct panfrost_screen *screen,
-                struct panfrost_bo *bo)
+static bool
+panfrost_bo_cache_put(struct panfrost_bo *bo)
 {
+        struct panfrost_screen *screen = bo->screen;
+
+        if (bo->dont_reuse)
+                return false;
+
         pthread_mutex_lock(&screen->bo_cache_lock);
         struct list_head *bucket = pan_bucket(screen, bo->size);
         struct drm_panfrost_madvise madv;
@@ -150,8 +206,7 @@ panfrost_bo_cache_put(
  * OS) */
 
 void
-panfrost_bo_cache_evict_all(
-                struct panfrost_screen *screen)
+panfrost_bo_cache_evict_all(struct panfrost_screen *screen)
 {
         pthread_mutex_lock(&screen->bo_cache_lock);
         for (unsigned i = 0; i < ARRAY_SIZE(screen->bo_cache); ++i) {
@@ -159,9 +214,166 @@ panfrost_bo_cache_evict_all(
 
                 list_for_each_entry_safe(struct panfrost_bo, entry, bucket, link) {
                         list_del(&entry->link);
-                        panfrost_drm_release_bo(screen, entry, false);
+                        panfrost_bo_free(entry);
                 }
         }
         pthread_mutex_unlock(&screen->bo_cache_lock);
 }
 
+void
+panfrost_bo_mmap(struct panfrost_bo *bo)
+{
+        struct drm_panfrost_mmap_bo mmap_bo = { .handle = bo->gem_handle };
+        int ret;
+
+        if (bo->cpu)
+                return;
+
+        ret = drmIoctl(bo->screen->fd, DRM_IOCTL_PANFROST_MMAP_BO, &mmap_bo);
+        if (ret) {
+                fprintf(stderr, "DRM_IOCTL_PANFROST_MMAP_BO failed: %m\n");
+                assert(0);
+        }
+
+        bo->cpu = os_mmap(NULL, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                          bo->screen->fd, mmap_bo.offset);
+        if (bo->cpu == MAP_FAILED) {
+                fprintf(stderr, "mmap failed: %p %m\n", bo->cpu);
+                assert(0);
+        }
+
+        /* Record the mmap if we're tracing */
+        if (pan_debug & PAN_DBG_TRACE)
+                pandecode_inject_mmap(bo->gpu, bo->cpu, bo->size, NULL);
+}
+
+void
+panfrost_bo_munmap(struct panfrost_bo *bo)
+{
+        if (!bo->cpu)
+                return;
+
+        if (os_munmap((void *) (uintptr_t)bo->cpu, bo->size)) {
+                perror("munmap");
+                abort();
+        }
+
+        bo->cpu = NULL;
+}
+
+struct panfrost_bo *
+panfrost_bo_create(struct panfrost_screen *screen, size_t size,
+                   uint32_t flags)
+{
+        struct panfrost_bo *bo;
+
+        /* Kernel will fail (confusingly) with EPERM otherwise */
+        assert(size > 0);
+
+        /* To maximize BO cache usage, don't allocate tiny BOs */
+        size = MAX2(size, 4096);
+
+        /* GROWABLE BOs cannot be mmapped */
+        if (flags & PAN_ALLOCATE_GROWABLE)
+                assert(flags & PAN_ALLOCATE_INVISIBLE);
+
+        /* Before creating a BO, we first want to check the cache, otherwise,
+         * the cache misses and we need to allocate a BO fresh from the kernel
+         */
+        bo = panfrost_bo_cache_fetch(screen, size, flags);
+        if (!bo)
+                bo = panfrost_bo_alloc(screen, size, flags);
+
+        assert(bo);
+
+        /* Only mmap now if we know we need to. For CPU-invisible buffers, we
+         * never map since we don't care about their contents; they're purely
+         * for GPU-internal use. But we do trace them anyway.
+         */
+        if (!(flags & (PAN_ALLOCATE_INVISIBLE | PAN_ALLOCATE_DELAY_MMAP)))
+                panfrost_bo_mmap(bo);
+	else if ((flags & PAN_ALLOCATE_INVISIBLE) && (pan_debug & PAN_DBG_TRACE))
+                pandecode_inject_mmap(bo->gpu, NULL, bo->size, NULL);
+
+        pipe_reference_init(&bo->reference, 1);
+        return bo;
+}
+
+static void
+panfrost_bo_release(struct panfrost_bo *bo)
+{
+        if (!bo)
+                return;
+
+        /* Rather than freeing the BO now, we'll cache the BO for later
+         * allocations if we're allowed to */
+
+        panfrost_bo_munmap(bo);
+
+        if (panfrost_bo_cache_put(bo))
+                return;
+
+        panfrost_bo_free(bo);
+}
+
+void
+panfrost_bo_reference(struct panfrost_bo *bo)
+{
+        if (bo)
+                pipe_reference(NULL, &bo->reference);
+}
+
+void
+panfrost_bo_unreference(struct panfrost_bo *bo)
+{
+        if (!bo)
+                return;
+
+        /* When the reference count goes to zero, we need to cleanup */
+        if (pipe_reference(&bo->reference, NULL))
+                panfrost_bo_release(bo);
+}
+
+struct panfrost_bo *
+panfrost_bo_import(struct panfrost_screen *screen, int fd)
+{
+        struct panfrost_bo *bo = rzalloc(screen, struct panfrost_bo);
+        struct drm_panfrost_get_bo_offset get_bo_offset = {0,};
+        ASSERTED int ret;
+        unsigned gem_handle;
+
+        ret = drmPrimeFDToHandle(screen->fd, fd, &gem_handle);
+        assert(!ret);
+
+        get_bo_offset.handle = gem_handle;
+        ret = drmIoctl(screen->fd, DRM_IOCTL_PANFROST_GET_BO_OFFSET, &get_bo_offset);
+        assert(!ret);
+
+        bo->screen = screen;
+        bo->gem_handle = gem_handle;
+        bo->gpu = (mali_ptr)get_bo_offset.offset;
+        bo->size = lseek(fd, 0, SEEK_END);
+        bo->dont_reuse = true;
+        assert(bo->size > 0);
+        pipe_reference_init(&bo->reference, 1);
+
+        // TODO map and unmap on demand?
+        panfrost_bo_mmap(bo);
+        return bo;
+}
+
+int
+panfrost_bo_export(struct panfrost_bo *bo)
+{
+        struct drm_prime_handle args = {
+                .handle = bo->gem_handle,
+                .flags = DRM_CLOEXEC,
+        };
+
+        int ret = drmIoctl(bo->screen->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
+        if (ret == -1)
+                return -1;
+
+        bo->dont_reuse = true;
+        return args.fd;
+}
diff --git a/src/gallium/drivers/panfrost/pan_bo.h b/src/gallium/drivers/panfrost/pan_bo.h
new file mode 100644
index 000000000000..b4bff645e257
--- /dev/null
+++ b/src/gallium/drivers/panfrost/pan_bo.h
@@ -0,0 +1,78 @@
+/*
+ * © Copyright 2019 Alyssa Rosenzweig
+ * © Copyright 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef __PAN_BO_H__
+#define __PAN_BO_H__
+
+#include <panfrost-misc.h>
+#include "pipe/p_state.h"
+#include "util/list.h"
+
+struct panfrost_bo {
+        /* Must be first for casting */
+        struct list_head link;
+
+        struct pipe_reference reference;
+
+        struct panfrost_screen *screen;
+
+        /* Mapping for the entire object (all levels) */
+        uint8_t *cpu;
+
+        /* GPU address for the object */
+        mali_ptr gpu;
+
+        /* Size of all entire trees */
+        size_t size;
+
+        int gem_handle;
+
+        /* The BO should not be added to the re-use cache when released. Should
+         * be true for imported/exported BOs.
+         */
+        bool dont_reuse;
+
+        uint32_t flags;
+};
+
+void
+panfrost_bo_mmap(struct panfrost_bo *bo);
+void
+panfrost_bo_munmap(struct panfrost_bo *bo);
+void
+panfrost_bo_reference(struct panfrost_bo *bo);
+void
+panfrost_bo_unreference(struct panfrost_bo *bo);
+struct panfrost_bo *
+panfrost_bo_create(struct panfrost_screen *screen, size_t size,
+                   uint32_t flags);
+struct panfrost_bo *
+panfrost_bo_import(struct panfrost_screen *screen, int fd);
+int
+panfrost_bo_export(struct panfrost_bo *bo);
+void
+panfrost_bo_cache_evict_all(struct panfrost_screen *screen);
+
+#endif /* __PAN_BO_H__ */
diff --git a/src/gallium/drivers/panfrost/pan_context.c b/src/gallium/drivers/panfrost/pan_context.c
index 0fb4c2584e40..f0cd8cdb12ea 100644
--- a/src/gallium/drivers/panfrost/pan_context.c
+++ b/src/gallium/drivers/panfrost/pan_context.c
@@ -27,6 +27,7 @@
 #include <sys/poll.h>
 #include <errno.h>
 
+#include "pan_bo.h"
 #include "pan_context.h"
 #include "pan_format.h"
 
@@ -1889,7 +1890,7 @@ panfrost_delete_shader_state(
 
         for (unsigned i = 0; i < cso->variant_count; ++i) {
                 struct panfrost_shader_state *shader_state = &cso->variants[i];
-                panfrost_bo_unreference(pctx->screen, shader_state->bo);
+                panfrost_bo_unreference(shader_state->bo);
                 shader_state->bo = NULL;
         }
 
@@ -2556,7 +2557,6 @@ static void
 panfrost_destroy(struct pipe_context *pipe)
 {
         struct panfrost_context *panfrost = pan_context(pipe);
-        struct panfrost_screen *screen = pan_screen(pipe->screen);
 
         if (panfrost->blitter)
                 util_blitter_destroy(panfrost->blitter);
@@ -2564,9 +2564,9 @@ panfrost_destroy(struct pipe_context *pipe)
         if (panfrost->blitter_wallpaper)
                 util_blitter_destroy(panfrost->blitter_wallpaper);
 
-        panfrost_drm_release_bo(screen, panfrost->scratchpad, false);
-        panfrost_drm_release_bo(screen, panfrost->tiler_heap, false);
-        panfrost_drm_release_bo(screen, panfrost->tiler_dummy, false);
+        panfrost_bo_unreference(panfrost->scratchpad);
+        panfrost_bo_unreference(panfrost->tiler_heap);
+        panfrost_bo_unreference(panfrost->tiler_dummy);
 
         ralloc_free(pipe);
 }
@@ -2749,11 +2749,11 @@ panfrost_setup_hardware(struct panfrost_context *ctx)
         struct pipe_context *gallium = (struct pipe_context *) ctx;
         struct panfrost_screen *screen = pan_screen(gallium->screen);
 
-        ctx->scratchpad = panfrost_drm_create_bo(screen, 64 * 4 * 4096, 0);
-        ctx->tiler_heap = panfrost_drm_create_bo(screen, 4096 * 4096,
+        ctx->scratchpad = panfrost_bo_create(screen, 64 * 4 * 4096, 0);
+        ctx->tiler_heap = panfrost_bo_create(screen, 4096 * 4096,
                                                  PAN_ALLOCATE_INVISIBLE |
                                                  PAN_ALLOCATE_GROWABLE);
-        ctx->tiler_dummy = panfrost_drm_create_bo(screen, 4096,
+        ctx->tiler_dummy = panfrost_bo_create(screen, 4096,
                                                   PAN_ALLOCATE_INVISIBLE);
         assert(ctx->scratchpad && ctx->tiler_heap && ctx->tiler_dummy);
 }
diff --git a/src/gallium/drivers/panfrost/pan_drm.c b/src/gallium/drivers/panfrost/pan_drm.c
index e7dcd2e58751..e4b75fad4078 100644
--- a/src/gallium/drivers/panfrost/pan_drm.c
+++ b/src/gallium/drivers/panfrost/pan_drm.c
@@ -32,198 +32,13 @@
 #include "util/os_time.h"
 #include "os/os_mman.h"
 
+#include "pan_bo.h"
 #include "pan_screen.h"
 #include "pan_resource.h"
 #include "pan_context.h"
 #include "pan_util.h"
 #include "pandecode/decode.h"
 
-void
-panfrost_drm_mmap_bo(struct panfrost_screen *screen, struct panfrost_bo *bo)
-{
-        struct drm_panfrost_mmap_bo mmap_bo = { .handle = bo->gem_handle };
-        int ret;
-
-        if (bo->cpu)
-                return;
-
-        ret = drmIoctl(screen->fd, DRM_IOCTL_PANFROST_MMAP_BO, &mmap_bo);
-        if (ret) {
-                fprintf(stderr, "DRM_IOCTL_PANFROST_MMAP_BO failed: %m\n");
-                assert(0);
-        }
-
-        bo->cpu = os_mmap(NULL, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
-                          screen->fd, mmap_bo.offset);
-        if (bo->cpu == MAP_FAILED) {
-                fprintf(stderr, "mmap failed: %p %m\n", bo->cpu);
-                assert(0);
-        }
-
-        /* Record the mmap if we're tracing */
-        if (pan_debug & PAN_DBG_TRACE)
-                pandecode_inject_mmap(bo->gpu, bo->cpu, bo->size, NULL);
-}
-
-static void
-panfrost_drm_munmap_bo(struct panfrost_screen *screen, struct panfrost_bo *bo)
-{
-        if (!bo->cpu)
-                return;
-
-        if (os_munmap((void *) (uintptr_t)bo->cpu, bo->size)) {
-                perror("munmap");
-                abort();
-        }
-
-        bo->cpu = NULL;
-}
-
-struct panfrost_bo *
-panfrost_drm_create_bo(struct panfrost_screen *screen, size_t size,
-                       uint32_t flags)
-{
-        struct panfrost_bo *bo;
-
-        /* Kernel will fail (confusingly) with EPERM otherwise */
-        assert(size > 0);
-
-        /* To maximize BO cache usage, don't allocate tiny BOs */
-        size = MAX2(size, 4096);
-
-        /* GROWABLE BOs cannot be mmapped */
-        if (flags & PAN_ALLOCATE_GROWABLE)
-                assert(flags & PAN_ALLOCATE_INVISIBLE);
-
-        unsigned translated_flags = 0;
-
-        if (screen->kernel_version->version_major > 1 ||
-            screen->kernel_version->version_minor >= 1) {
-                if (flags & PAN_ALLOCATE_GROWABLE)
-                        translated_flags |= PANFROST_BO_HEAP;
-                if (!(flags & PAN_ALLOCATE_EXECUTE))
-                        translated_flags |= PANFROST_BO_NOEXEC;
-        }
-
-        struct drm_panfrost_create_bo create_bo = {
-                .size = size,
-                .flags = translated_flags,
-        };
-
-        /* Before creating a BO, we first want to check the cache */
-
-        bo = panfrost_bo_cache_fetch(screen, size, flags);
-
-        if (bo == NULL) {
-                /* Otherwise, the cache misses and we need to allocate a BO fresh from
-                 * the kernel */
-
-                int ret;
-
-                ret = drmIoctl(screen->fd, DRM_IOCTL_PANFROST_CREATE_BO, &create_bo);
-                if (ret) {
-                        fprintf(stderr, "DRM_IOCTL_PANFROST_CREATE_BO failed: %m\n");
-                        assert(0);
-                }
-
-                /* We have a BO allocated from the kernel; fill in the userspace
-                 * version */
-
-                bo = rzalloc(screen, struct panfrost_bo);
-                bo->size = create_bo.size;
-                bo->gpu = create_bo.offset;
-                bo->gem_handle = create_bo.handle;
-                bo->flags = flags;
-        }
-
-        /* Only mmap now if we know we need to. For CPU-invisible buffers, we
-         * never map since we don't care about their contents; they're purely
-         * for GPU-internal use. But we do trace them anyway. */
-
-        if (!(flags & (PAN_ALLOCATE_INVISIBLE | PAN_ALLOCATE_DELAY_MMAP)))
-                panfrost_drm_mmap_bo(screen, bo);
-        else if (flags & PAN_ALLOCATE_INVISIBLE) {
-                if (pan_debug & PAN_DBG_TRACE)
-                        pandecode_inject_mmap(bo->gpu, NULL, bo->size, NULL);
-        }
-
-        pipe_reference_init(&bo->reference, 1);
-        return bo;
-}
-
-void
-panfrost_drm_release_bo(struct panfrost_screen *screen, struct panfrost_bo *bo, bool cacheable)
-{
-        if (!bo)
-                return;
-
-        struct drm_gem_close gem_close = { .handle = bo->gem_handle };
-        int ret;
-
-        /* Rather than freeing the BO now, we'll cache the BO for later
-         * allocations if we're allowed to */
-
-        panfrost_drm_munmap_bo(screen, bo);
-
-        if (cacheable) {
-                bool cached = panfrost_bo_cache_put(screen, bo);
-
-                if (cached)
-                        return;
-        }
-
-        /* Otherwise, if the BO wasn't cached, we'll legitimately free the BO */
-
-        ret = drmIoctl(screen->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
-        if (ret) {
-                fprintf(stderr, "DRM_IOCTL_GEM_CLOSE failed: %m\n");
-                assert(0);
-        }
-
-        ralloc_free(bo);
-}
-
-struct panfrost_bo *
-panfrost_drm_import_bo(struct panfrost_screen *screen, int fd)
-{
-        struct panfrost_bo *bo = rzalloc(screen, struct panfrost_bo);
-        struct drm_panfrost_get_bo_offset get_bo_offset = {0,};
-        ASSERTED int ret;
-        unsigned gem_handle;
-
-        ret = drmPrimeFDToHandle(screen->fd, fd, &gem_handle);
-        assert(!ret);
-
-        get_bo_offset.handle = gem_handle;
-        ret = drmIoctl(screen->fd, DRM_IOCTL_PANFROST_GET_BO_OFFSET, &get_bo_offset);
-        assert(!ret);
-
-        bo->gem_handle = gem_handle;
-        bo->gpu = (mali_ptr) get_bo_offset.offset;
-        bo->size = lseek(fd, 0, SEEK_END);
-        assert(bo->size > 0);
-        pipe_reference_init(&bo->reference, 1);
-
-        // TODO map and unmap on demand?
-        panfrost_drm_mmap_bo(screen, bo);
-        return bo;
-}
-
-int
-panfrost_drm_export_bo(struct panfrost_screen *screen, const struct panfrost_bo *bo)
-{
-        struct drm_prime_handle args = {
-                .handle = bo->gem_handle,
-                .flags = DRM_CLOEXEC,
-        };
-
-        int ret = drmIoctl(screen->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
-        if (ret == -1)
-                return -1;
-
-        return args.fd;
-}
-
 static int
 panfrost_drm_submit_batch(struct panfrost_batch *batch, u64 first_job_desc,
                           int reqs)
diff --git a/src/gallium/drivers/panfrost/pan_instancing.c b/src/gallium/drivers/panfrost/pan_instancing.c
index 44fe0a344aab..bcdcbe429394 100644
--- a/src/gallium/drivers/panfrost/pan_instancing.c
+++ b/src/gallium/drivers/panfrost/pan_instancing.c
@@ -23,6 +23,7 @@
  *
  */
 
+#include "pan_bo.h"
 #include "pan_context.h"
 
 /* See mali_job for notes on how this works. But basically, for small vertex
diff --git a/src/gallium/drivers/panfrost/pan_job.c b/src/gallium/drivers/panfrost/pan_job.c
index 58b494108e2d..7c40bcee0fca 100644
--- a/src/gallium/drivers/panfrost/pan_job.c
+++ b/src/gallium/drivers/panfrost/pan_job.c
@@ -25,6 +25,7 @@
 
 #include <assert.h>
 
+#include "pan_bo.h"
 #include "pan_context.h"
 #include "util/hash_table.h"
 #include "util/ralloc.h"
@@ -62,11 +63,11 @@ panfrost_free_batch(struct panfrost_batch *batch)
 
         set_foreach(batch->bos, entry) {
                 struct panfrost_bo *bo = (struct panfrost_bo *)entry->key;
-                panfrost_bo_unreference(ctx->base.screen, bo);
+                panfrost_bo_unreference(bo);
         }
 
         /* Unreference the polygon list */
-        panfrost_bo_unreference(ctx->base.screen, batch->polygon_list);
+        panfrost_bo_unreference(batch->polygon_list);
 
         _mesa_hash_table_remove_key(ctx->batches, &batch->key);
 
@@ -170,7 +171,7 @@ panfrost_batch_get_polygon_list(struct panfrost_batch *batch, unsigned size)
 
                 /* Create the BO as invisible, as there's no reason to map */
 
-                batch->polygon_list = panfrost_drm_create_bo(screen,
+                batch->polygon_list = panfrost_bo_create(screen,
                                 size, PAN_ALLOCATE_INVISIBLE);
         }
 
diff --git a/src/gallium/drivers/panfrost/pan_mfbd.c b/src/gallium/drivers/panfrost/pan_mfbd.c
index 3ad22f82c4ab..618ebd3c4a19 100644
--- a/src/gallium/drivers/panfrost/pan_mfbd.c
+++ b/src/gallium/drivers/panfrost/pan_mfbd.c
@@ -22,6 +22,7 @@
  *
  */
 
+#include "pan_bo.h"
 #include "pan_context.h"
 #include "pan_util.h"
 #include "pan_format.h"
diff --git a/src/gallium/drivers/panfrost/pan_resource.c b/src/gallium/drivers/panfrost/pan_resource.c
index 0be6b2b1c330..a5869768f9de 100644
--- a/src/gallium/drivers/panfrost/pan_resource.c
+++ b/src/gallium/drivers/panfrost/pan_resource.c
@@ -41,6 +41,7 @@
 #include "util/u_transfer_helper.h"
 #include "util/u_gen_mipmap.h"
 
+#include "pan_bo.h"
 #include "pan_context.h"
 #include "pan_screen.h"
 #include "pan_resource.h"
@@ -81,7 +82,7 @@ panfrost_resource_from_handle(struct pipe_screen *pscreen,
         pipe_reference_init(&prsc->reference, 1);
         prsc->screen = pscreen;
 
-        rsc->bo = panfrost_drm_import_bo(screen, whandle->handle);
+        rsc->bo = panfrost_bo_import(screen, whandle->handle);
         rsc->slices[0].stride = whandle->stride;
         rsc->slices[0].initialized = true;
         panfrost_resource_reset_damage(rsc);
@@ -133,7 +134,7 @@ panfrost_resource_get_handle(struct pipe_screen *pscreen,
 
                         return true;
                 } else {
-                        int fd = panfrost_drm_export_bo(screen, rsrc->bo);
+                        int fd = panfrost_bo_export(rsrc->bo);
 
                         if (fd < 0)
                                 return false;
@@ -412,7 +413,7 @@ panfrost_resource_create_bo(struct panfrost_screen *screen, struct panfrost_reso
 
         /* We create a BO immediately but don't bother mapping, since we don't
          * care to map e.g. FBOs which the CPU probably won't touch */
-        pres->bo = panfrost_drm_create_bo(screen, bo_size, PAN_ALLOCATE_DELAY_MMAP);
+        pres->bo = panfrost_bo_create(screen, bo_size, PAN_ALLOCATE_DELAY_MMAP);
 }
 
 void
@@ -521,25 +522,6 @@ panfrost_resource_create(struct pipe_screen *screen,
         return (struct pipe_resource *)so;
 }
 
-void
-panfrost_bo_reference(struct panfrost_bo *bo)
-{
-        if (bo)
-                pipe_reference(NULL, &bo->reference);
-}
-
-void
-panfrost_bo_unreference(struct pipe_screen *screen, struct panfrost_bo *bo)
-{
-        if (!bo)
-                return;
-
-        /* When the reference count goes to zero, we need to cleanup */
-
-        if (pipe_reference(&bo->reference, NULL))
-                panfrost_drm_release_bo(pan_screen(screen), bo, true);
-}
-
 static void
 panfrost_resource_destroy(struct pipe_screen *screen,
                           struct pipe_resource *pt)
@@ -551,7 +533,7 @@ panfrost_resource_destroy(struct pipe_screen *screen,
                 renderonly_scanout_destroy(rsrc->scanout, pscreen->ro);
 
         if (rsrc->bo)
-                panfrost_bo_unreference(screen, rsrc->bo);
+                panfrost_bo_unreference(rsrc->bo);
 
         util_range_destroy(&rsrc->valid_buffer_range);
         ralloc_free(rsrc);
@@ -579,11 +561,7 @@ panfrost_transfer_map(struct pipe_context *pctx,
         *out_transfer = &transfer->base;
 
         /* If we haven't already mmaped, now's the time */
-
-        if (!bo->cpu) {
-                struct panfrost_screen *screen = pan_screen(pctx->screen);
-                panfrost_drm_mmap_bo(screen, bo);
-        }
+        panfrost_bo_mmap(bo);
 
         /* Check if we're bound for rendering and this is a read pixels. If so,
          * we need to flush */
@@ -861,8 +839,8 @@ panfrost_resource_hint_layout(
 
         /* If we grew in size, reallocate the BO */
         if (new_size > rsrc->bo->size) {
-                panfrost_drm_release_bo(screen, rsrc->bo, true);
-                rsrc->bo = panfrost_drm_create_bo(screen, new_size, PAN_ALLOCATE_DELAY_MMAP);
+                panfrost_bo_unreference(rsrc->bo);
+                rsrc->bo = panfrost_bo_create(screen, new_size, PAN_ALLOCATE_DELAY_MMAP);
         }
 }
 
diff --git a/src/gallium/drivers/panfrost/pan_resource.h b/src/gallium/drivers/panfrost/pan_resource.h
index 6ed3d1fd60e8..aca3c70952b1 100644
--- a/src/gallium/drivers/panfrost/pan_resource.h
+++ b/src/gallium/drivers/panfrost/pan_resource.h
@@ -32,6 +32,8 @@
 #include "drm-uapi/drm.h"
 #include "util/u_range.h"
 
+struct panfrost_bo;
+
 /* Describes the memory layout of a BO */
 
 enum panfrost_memory_layout {
@@ -57,12 +59,6 @@ struct panfrost_slice {
         bool initialized;
 };
 
-void
-panfrost_bo_reference(struct panfrost_bo *bo);
-
-void
-panfrost_bo_unreference(struct pipe_screen *screen, struct panfrost_bo *bo);
-
 struct panfrost_resource {
         struct pipe_resource base;
         struct {
diff --git a/src/gallium/drivers/panfrost/pan_screen.c b/src/gallium/drivers/panfrost/pan_screen.c
index 5dcceac370d5..50a27bad1767 100644
--- a/src/gallium/drivers/panfrost/pan_screen.c
+++ b/src/gallium/drivers/panfrost/pan_screen.c
@@ -42,6 +42,7 @@
 
 #include "drm-uapi/drm_fourcc.h"
 
+#include "pan_bo.h"
 #include "pan_screen.h"
 #include "pan_resource.h"
 #include "pan_public.h"
diff --git a/src/gallium/drivers/panfrost/pan_screen.h b/src/gallium/drivers/panfrost/pan_screen.h
index 96044b8c8b90..aab141a563c2 100644
--- a/src/gallium/drivers/panfrost/pan_screen.h
+++ b/src/gallium/drivers/panfrost/pan_screen.h
@@ -120,17 +120,6 @@ pan_screen(struct pipe_screen *p)
         return (struct panfrost_screen *)p;
 }
 
-struct panfrost_bo *
-panfrost_drm_create_bo(struct panfrost_screen *screen, size_t size,
-                       uint32_t flags);
-void
-panfrost_drm_mmap_bo(struct panfrost_screen *screen, struct panfrost_bo *bo);
-void
-panfrost_drm_release_bo(struct panfrost_screen *screen, struct panfrost_bo *bo, bool cacheable);
-struct panfrost_bo *
-panfrost_drm_import_bo(struct panfrost_screen *screen, int fd);
-int
-panfrost_drm_export_bo(struct panfrost_screen *screen, const struct panfrost_bo *bo);
 int
 panfrost_drm_submit_vs_fs_batch(struct panfrost_batch *batch, bool has_draws);
 void
@@ -149,18 +138,5 @@ panfrost_drm_fence_finish(struct pipe_screen *pscreen,
                           struct pipe_context *ctx,
                           struct pipe_fence_handle *fence,
                           uint64_t timeout);
-struct panfrost_bo *
-panfrost_bo_cache_fetch(
-                struct panfrost_screen *screen,
-                size_t size, uint32_t flags);
-
-bool
-panfrost_bo_cache_put(
-                struct panfrost_screen *screen,
-                struct panfrost_bo *bo);
-
-void
-panfrost_bo_cache_evict_all(
-                struct panfrost_screen *screen);
 
 #endif /* PAN_SCREEN_H */
diff --git a/src/gallium/drivers/panfrost/pan_sfbd.c b/src/gallium/drivers/panfrost/pan_sfbd.c
index f58c054c8f24..2d12904e9393 100644
--- a/src/gallium/drivers/panfrost/pan_sfbd.c
+++ b/src/gallium/drivers/panfrost/pan_sfbd.c
@@ -22,6 +22,7 @@
  *
  */
 
+#include "pan_bo.h"
 #include "pan_context.h"
 #include "pan_util.h"
 #include "pan_format.h"
diff --git a/src/gallium/drivers/panfrost/pan_varyings.c b/src/gallium/drivers/panfrost/pan_varyings.c
index 12760109b7cb..02f2e670eaf6 100644
--- a/src/gallium/drivers/panfrost/pan_varyings.c
+++ b/src/gallium/drivers/panfrost/pan_varyings.c
@@ -23,6 +23,7 @@
  *
  */
 
+#include "pan_bo.h"
 #include "pan_context.h"
 #include "util/u_prim.h"
 
-- 
2.21.0



More information about the mesa-dev mailing list