#include "freedreno_priv.h"
static pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER;
-static void * dev_table;
-static struct fd_device * fd_device_new_impl(int fd)
+struct fd_device * kgsl_device_new(int fd);
+struct fd_device * msm_device_new(int fd);
+
+static void
+add_bucket(struct fd_device *dev, int size)
{
- struct fd_device *dev = calloc(1, sizeof(*dev));
- if (!dev)
- return NULL;
- atomic_set(&dev->refcnt, 1);
- dev->fd = fd;
- dev->handle_table = drmHashCreate();
- dev->name_table = drmHashCreate();
- return dev;
+ 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++;
}
-/* use inode for key into dev_table, rather than fd, to avoid getting
- * confused by multiple-opens:
- */
-static int devkey(int fd)
+static void
+init_cache_buckets(struct fd_device *dev)
{
- struct stat s;
- if (fstat(fd, &s)) {
- ERROR_MSG("stat failed: %s", strerror(errno));
- return -1;
+ 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);
}
- return s.st_ino;
}
-struct fd_device * fd_device_new(int fd)
+drm_public struct fd_device * fd_device_new(int fd)
{
- struct fd_device *dev = NULL;
- int key = devkey(fd);
+ struct fd_device *dev;
+ drmVersionPtr version;
- pthread_mutex_lock(&table_lock);
-
- if (!dev_table)
- dev_table = drmHashCreate();
+ /* figure out if we are kgsl or msm drm driver: */
+ version = drmGetVersion(fd);
+ if (!version) {
+ ERROR_MSG("cannot get version: %s", strerror(errno));
+ return NULL;
+ }
- if (drmHashLookup(dev_table, key, (void **)&dev)) {
- dev = fd_device_new_impl(fd);
- drmHashInsert(dev_table, key, dev);
+ if (!strcmp(version->name, "kgsl")) {
+ DEBUG_MSG("kgsl DRM device");
+ dev = kgsl_device_new(fd);
+ } else if (!strcmp(version->name, "msm")) {
+ DEBUG_MSG("msm DRM device");
+ dev = msm_device_new(fd);
} else {
- dev = fd_device_ref(dev);
+ ERROR_MSG("unknown device: %s", version->name);
+ dev = NULL;
}
+ drmFreeVersion(version);
- pthread_mutex_unlock(&table_lock);
+ if (!dev)
+ return NULL;
+
+ atomic_set(&dev->refcnt, 1);
+ dev->fd = fd;
+ dev->handle_table = drmHashCreate();
+ dev->name_table = drmHashCreate();
+ init_cache_buckets(dev);
return dev;
}
-struct fd_device * fd_device_ref(struct fd_device *dev)
+/* 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 = fd_device_new(dup(fd));
+ if (dev)
+ dev->closefd = 1;
+ return 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, devkey(dev->fd));
+ fd_device_del_impl(dev);
pthread_mutex_unlock(&table_lock);
- free(dev);
}