summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk@arm.linux.org.uk>2015-05-29 21:04:37 +0100
committerRussell King <rmk@arm.linux.org.uk>2015-06-29 12:58:32 +0100
commit3a0f0de67cebabbd5de5e2cf5d7eaf34aaf95a42 (patch)
tree2a3d661c0397ea63fb074b2bb65eb8f8e197737e
parent0b106007a0499afbe1346fef78147b69696d953f (diff)
etnaviv: add bo caching support to etnadrm
Add bo caching support to etnadrm. Signed-off-by: Russell King <rmk@arm.linux.org.uk>
-rw-r--r--etnaviv/etnadrm.c107
1 files changed, 95 insertions, 12 deletions
diff --git a/etnaviv/etnadrm.c b/etnaviv/etnadrm.c
index c6f26fe..38fbe06 100644
--- a/etnaviv/etnadrm.c
+++ b/etnaviv/etnadrm.c
@@ -16,6 +16,7 @@
#include <etnaviv/state.xml.h>
+#include "bo-cache.h"
#include "etnadrm.h"
#include "etnaviv_drm.h"
#include "compat-list.h"
@@ -23,6 +24,13 @@
#define etnadrm_pipe last_fence_id
+struct etna_viv_conn {
+ struct viv_conn conn;
+ struct bo_cache cache;
+};
+
+static void etna_bo_cache_free(struct bo_entry *be);
+
struct chip_specs {
uint32_t param;
uint32_t offset;
@@ -130,15 +138,20 @@ int etnadrm_open_render(const char *name)
int viv_open(enum viv_hw_type hw_type, struct viv_conn **out)
{
+ struct etna_viv_conn *ec;
struct viv_conn *conn;
drmVersionPtr version;
Bool found = FALSE;
int pipe, err = -1;
- conn = calloc(1, sizeof *conn);
- if (!conn)
+ ec = calloc(1, sizeof *ec);
+ if (!ec)
return -1;
+ bo_cache_init(&ec->cache, etna_bo_cache_free);
+
+ conn = &ec->conn;
+
conn->fd = etnadrm_open_render("etnaviv");
if (conn->fd == -1)
goto error;
@@ -231,9 +244,13 @@ error:
int viv_close(struct viv_conn *conn)
{
+ struct etna_viv_conn *ec = container_of(conn, struct etna_viv_conn, conn);
+
if (conn->fd < 0)
return -1;
+ bo_cache_fini(&ec->cache);
+
close(conn->fd);
free(conn);
return 0;
@@ -271,20 +288,51 @@ struct etna_bo {
int ref;
int bo_idx;
struct xorg_list node;
+ struct bo_entry cache;
};
-int etna_bo_del(struct viv_conn *conn, struct etna_bo *mem, struct etna_queue *queue)
+static void etna_bo_free(struct etna_bo *bo)
{
- if (--mem->ref == 0) {
- struct drm_gem_close req = {
- .handle = mem->handle,
- };
+ struct viv_conn *conn = bo->conn;
+ struct drm_gem_close req = {
+ .handle = bo->handle,
+ };
- if (mem->logical)
- munmap(mem->logical, mem->size);
+ if (bo->logical)
+ munmap(bo->logical, bo->size);
- drmIoctl(conn->fd, DRM_IOCTL_GEM_CLOSE, &req);
- free(mem);
+ drmIoctl(conn->fd, DRM_IOCTL_GEM_CLOSE, &req);
+ free(bo);
+}
+
+static void etna_bo_cache_free(struct bo_entry *be)
+{
+ etna_bo_free(container_of(be, struct etna_bo, cache));
+}
+
+static struct etna_bo *etna_bo_bucket_get(struct bo_bucket *bucket)
+{
+ struct bo_entry *be = bo_cache_bucket_get(bucket);
+ struct etna_bo *bo = NULL;
+
+ if (be) {
+ bo = container_of(be, struct etna_bo, cache);
+ bo->ref = 1;
+ bo->bo_idx = -1;
+ }
+
+ return bo;
+}
+
+int etna_bo_del(struct viv_conn *conn, struct etna_bo *mem, struct etna_queue *queue)
+{
+ struct etna_viv_conn *ec = container_of(conn, struct etna_viv_conn, conn);
+
+ if (--mem->ref == 0) {
+ if (mem->cache.bucket)
+ bo_cache_put(&ec->cache, &mem->cache);
+ else
+ etna_bo_free(mem);
return 0;
}
return -1;
@@ -303,7 +351,8 @@ static struct etna_bo *etna_bo_alloc(struct viv_conn *conn)
return mem;
}
-struct etna_bo *etna_bo_new(struct viv_conn *conn, size_t bytes, uint32_t flags)
+static struct etna_bo *etna_bo_get(struct viv_conn *conn, size_t bytes,
+ uint32_t flags)
{
struct etna_bo *mem;
struct drm_etnaviv_gem_new req = {
@@ -332,6 +381,35 @@ struct etna_bo *etna_bo_new(struct viv_conn *conn, size_t bytes, uint32_t flags)
return mem;
}
+struct etna_bo *etna_bo_new(struct viv_conn *conn, size_t bytes, uint32_t flags)
+{
+ struct etna_viv_conn *ec = container_of(conn, struct etna_viv_conn, conn);
+ struct bo_bucket *bucket = NULL;
+ struct etna_bo *bo;
+
+ do {
+ if ((flags & DRM_ETNA_GEM_TYPE_MASK) == DRM_ETNA_GEM_TYPE_CMD)
+ break;
+
+ bucket = bo_cache_bucket_find(&ec->cache, bytes);
+ if (!bucket)
+ break;
+
+ /* We must allocate the bucket size for it to be re-usable */
+ bytes = bucket->size;
+
+ bo = etna_bo_bucket_get(bucket);
+ if (bo)
+ return bo;
+ } while (0);
+
+ bo = etna_bo_get(conn, bytes, flags);
+ if (bo)
+ bo->cache.bucket = bucket;
+
+ return bo;
+}
+
struct etna_bo *etna_bo_from_dmabuf(struct viv_conn *conn, int fd, int prot)
{
struct etna_bo *mem;
@@ -418,6 +496,11 @@ uint32_t etna_bo_gpu_address(struct etna_bo *bo)
uint32_t etna_bo_handle(struct etna_bo *bo)
{
+ /*
+ * If we're wanting the handle, we're more than likely
+ * exporting it, which means we must not re-use this bo.
+ */
+ bo->cache.bucket = NULL;
return bo->handle;
}