#include "freedreno_priv.h"
static pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER;
-static void * dev_table;
struct fd_device * kgsl_device_new(int fd);
struct fd_device * msm_device_new(int fd);
-static struct fd_device * fd_device_new_impl(int fd)
+static void
+add_bucket(struct fd_device *dev, int size)
+{
+ unsigned int i = dev->num_buckets;
+
+ assert(i < ARRAY_SIZE(dev->cache_bucket));
+
+ list_inithead(&dev->cache_bucket[i].list);
+ dev->cache_bucket[i].size = size;
+ dev->num_buckets++;
+}
+
+static void
+init_cache_buckets(struct fd_device *dev)
+{
+ unsigned long size, cache_max_size = 64 * 1024 * 1024;
+
+ /* OK, so power of two buckets was too wasteful of memory.
+ * Give 3 other sizes between each power of two, to hopefully
+ * cover things accurately enough. (The alternative is
+ * probably to just go for exact matching of sizes, and assume
+ * that for things like composited window resize the tiled
+ * width/height alignment and rounding of sizes to pages will
+ * get us useful cache hit rates anyway)
+ */
+ add_bucket(dev, 4096);
+ add_bucket(dev, 4096 * 2);
+ add_bucket(dev, 4096 * 3);
+
+ /* Initialize the linked lists for BO reuse cache. */
+ for (size = 4 * 4096; size <= cache_max_size; size *= 2) {
+ add_bucket(dev, size);
+ add_bucket(dev, size + size * 1 / 4);
+ add_bucket(dev, size + size * 2 / 4);
+ add_bucket(dev, size + size * 3 / 4);
+ }
+}
+
+drm_public struct fd_device * fd_device_new(int fd)
{
struct fd_device *dev;
drmVersionPtr version;
ERROR_MSG("unknown device: %s", version->name);
dev = NULL;
}
+ drmFreeVersion(version);
if (!dev)
return NULL;
dev->fd = fd;
dev->handle_table = drmHashCreate();
dev->name_table = drmHashCreate();
+ init_cache_buckets(dev);
return dev;
}
-struct fd_device * fd_device_new(int fd)
+/* like fd_device_new() but creates it's own private dup() of the fd
+ * which is close()d when the device is finalized.
+ */
+drm_public struct fd_device * fd_device_new_dup(int fd)
{
- struct fd_device *dev = NULL;
- int key = fd;
-
- pthread_mutex_lock(&table_lock);
-
- if (!dev_table)
- dev_table = drmHashCreate();
-
- if (drmHashLookup(dev_table, key, (void **)&dev)) {
- dev = fd_device_new_impl(fd);
- if (dev)
- drmHashInsert(dev_table, key, dev);
- } else {
- dev = fd_device_ref(dev);
- }
-
- pthread_mutex_unlock(&table_lock);
-
+ struct fd_device *dev = fd_device_new(dup(fd));
+ if (dev)
+ dev->closefd = 1;
return dev;
}
-struct fd_device * fd_device_ref(struct fd_device *dev)
+drm_public struct fd_device * fd_device_ref(struct fd_device *dev)
{
atomic_inc(&dev->refcnt);
return dev;
}
-void fd_device_del(struct fd_device *dev)
+static void fd_device_del_impl(struct fd_device *dev)
+{
+ fd_cleanup_bo_cache(dev, 0);
+ drmHashDestroy(dev->handle_table);
+ drmHashDestroy(dev->name_table);
+ if (dev->closefd)
+ close(dev->fd);
+ dev->funcs->destroy(dev);
+}
+
+void fd_device_del_locked(struct fd_device *dev)
+{
+ if (!atomic_dec_and_test(&dev->refcnt))
+ return;
+ fd_device_del_impl(dev);
+}
+
+drm_public void fd_device_del(struct fd_device *dev)
{
if (!atomic_dec_and_test(&dev->refcnt))
return;
pthread_mutex_lock(&table_lock);
- drmHashDestroy(dev->handle_table);
- drmHashDestroy(dev->name_table);
- drmHashDelete(dev_table, dev->fd);
+ fd_device_del_impl(dev);
pthread_mutex_unlock(&table_lock);
- dev->funcs->destroy(dev);
}