svga/winsys: implement GBS support
[mesa.git] / src / gallium / winsys / svga / drm / vmw_screen.c
index f7799cec32d113712dfbedb31dd2640a9b9caa45..0c343cc7bdd47b601ba9e1820e361c771c422b99 100644 (file)
 
 
 #include "vmw_screen.h"
-
+#include "vmw_fence.h"
 #include "vmw_context.h"
 
 #include "util/u_memory.h"
 #include "pipe/p_compiler.h"
+#include "util/u_hash_table.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
+static struct util_hash_table *dev_hash = NULL;
+
+static int vmw_dev_compare(void *key1, void *key2)
+{
+   return (major(*(dev_t *)key1) == major(*(dev_t *)key2) &&
+           minor(*(dev_t *)key1) == minor(*(dev_t *)key2)) ? 0 : 1;
+}
+
+static unsigned vmw_dev_hash(void *key)
+{
+   return (major(*(dev_t *) key) << 16) | minor(*(dev_t *) key);
+}
 
 /* Called from vmw_drm_create_screen(), creates and initializes the
  * vmw_winsys_screen structure, which is the main entity in this
  * module.
+ * First, check whether a vmw_winsys_screen object already exists for
+ * this device, and in that case return that one, making sure that we
+ * have our own file descriptor open to DRM.
  */
+
 struct vmw_winsys_screen *
 vmw_winsys_create( int fd, boolean use_old_scanout_flag )
 {
-   struct vmw_winsys_screen *vws = CALLOC_STRUCT(vmw_winsys_screen);
+   struct vmw_winsys_screen *vws;
+   struct stat stat_buf;
+
+   if (dev_hash == NULL) {
+      dev_hash = util_hash_table_create(vmw_dev_hash, vmw_dev_compare);
+      if (dev_hash == NULL)
+         return NULL;
+   }
+
+   if (fstat(fd, &stat_buf))
+      return NULL;
+
+   vws = util_hash_table_get(dev_hash, &stat_buf.st_rdev);
+   if (vws) {
+      vws->open_count++;
+      return vws;
+   }
+
+   vws = CALLOC_STRUCT(vmw_winsys_screen);
    if (!vws)
       goto out_no_vws;
 
-   vws->ioctl.drm_fd = fd;
+   vws->device = stat_buf.st_rdev;
+   vws->open_count = 1;
+   vws->ioctl.drm_fd = dup(fd);
    vws->use_old_scanout_flag = use_old_scanout_flag;
+   vws->base.have_gb_dma = TRUE;
 
    if (!vmw_ioctl_init(vws))
       goto out_no_ioctl;
 
+   vws->fence_ops = vmw_fence_ops_create(vws);
+   if (!vws->fence_ops)
+      goto out_no_fence_ops;
+
    if(!vmw_pools_init(vws))
       goto out_no_pools;
 
    if (!vmw_winsys_screen_init_svga(vws))
       goto out_no_svga;
 
+   if (util_hash_table_set(dev_hash, &vws->device, vws) != PIPE_OK)
+      goto out_no_hash_insert;
+
    return vws;
+out_no_hash_insert:
 out_no_svga:
    vmw_pools_cleanup(vws);
 out_no_pools:
+   vws->fence_ops->destroy(vws->fence_ops);
+out_no_fence_ops:
    vmw_ioctl_cleanup(vws);
 out_no_ioctl:
+   close(vws->ioctl.drm_fd);
    FREE(vws);
 out_no_vws:
    return NULL;
@@ -69,7 +121,12 @@ out_no_vws:
 void
 vmw_winsys_destroy(struct vmw_winsys_screen *vws)
 {
-   vmw_pools_cleanup(vws);
-   vmw_ioctl_cleanup(vws);
-   FREE(vws);
+   if (--vws->open_count == 0) {
+      util_hash_table_remove(dev_hash, &vws->device);
+      vmw_pools_cleanup(vws);
+      vws->fence_ops->destroy(vws->fence_ops);
+      vmw_ioctl_cleanup(vws);
+      close(vws->ioctl.drm_fd);
+      FREE(vws);
+   }
 }