Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. #include <sys/stat.h>
  2. #include <unistd.h>
  3. #include "pipe/p_context.h"
  4. #include "pipe/p_state.h"
  5. #include "util/u_format.h"
  6. #include "util/u_memory.h"
  7. #include "util/u_inlines.h"
  8. #include "util/u_hash_table.h"
  9. #include "os/os_thread.h"
  10.  
  11. #include "nouveau_drm_public.h"
  12.  
  13. #include "nouveau/nouveau_winsys.h"
  14. #include "nouveau/nouveau_screen.h"
  15.  
  16. static struct util_hash_table *fd_tab = NULL;
  17.  
  18. pipe_static_mutex(nouveau_screen_mutex);
  19.  
  20. boolean nouveau_drm_screen_unref(struct nouveau_screen *screen)
  21. {
  22.         int ret;
  23.         if (screen->refcount == -1)
  24.                 return true;
  25.  
  26.         pipe_mutex_lock(nouveau_screen_mutex);
  27.         ret = --screen->refcount;
  28.         assert(ret >= 0);
  29.         if (ret == 0)
  30.                 util_hash_table_remove(fd_tab, intptr_to_pointer(screen->device->fd));
  31.         pipe_mutex_unlock(nouveau_screen_mutex);
  32.         return ret == 0;
  33. }
  34.  
  35. static unsigned hash_fd(void *key)
  36. {
  37.     int fd = pointer_to_intptr(key);
  38.     struct stat stat;
  39.     fstat(fd, &stat);
  40.  
  41.     return stat.st_dev ^ stat.st_ino ^ stat.st_rdev;
  42. }
  43.  
  44. static int compare_fd(void *key1, void *key2)
  45. {
  46.     int fd1 = pointer_to_intptr(key1);
  47.     int fd2 = pointer_to_intptr(key2);
  48.     struct stat stat1, stat2;
  49.     fstat(fd1, &stat1);
  50.     fstat(fd2, &stat2);
  51.  
  52.     return stat1.st_dev != stat2.st_dev ||
  53.            stat1.st_ino != stat2.st_ino ||
  54.            stat1.st_rdev != stat2.st_rdev;
  55. }
  56.  
  57. PUBLIC struct pipe_screen *
  58. nouveau_drm_screen_create(int fd)
  59. {
  60.         struct nouveau_device *dev = NULL;
  61.         struct pipe_screen *(*init)(struct nouveau_device *);
  62.         struct nouveau_screen *screen;
  63.         int ret, dupfd = -1;
  64.  
  65.         pipe_mutex_lock(nouveau_screen_mutex);
  66.         if (!fd_tab) {
  67.                 fd_tab = util_hash_table_create(hash_fd, compare_fd);
  68.                 if (!fd_tab)
  69.                         goto err;
  70.         }
  71.  
  72.         screen = util_hash_table_get(fd_tab, intptr_to_pointer(fd));
  73.         if (screen) {
  74.                 screen->refcount++;
  75.                 pipe_mutex_unlock(nouveau_screen_mutex);
  76.                 return &screen->base;
  77.         }
  78.  
  79.         /* Since the screen re-use is based on the device node and not the fd,
  80.          * create a copy of the fd to be owned by the device. Otherwise a
  81.          * scenario could occur where two screens are created, and the first
  82.          * one is shut down, along with the fd being closed. The second
  83.          * (identical) screen would now have a reference to the closed fd. We
  84.          * avoid this by duplicating the original fd. Note that
  85.          * nouveau_device_wrap does not close the fd in case of a device
  86.          * creation error.
  87.          */
  88.         dupfd = dup(fd);
  89.         ret = nouveau_device_wrap(dupfd, 1, &dev);
  90.         if (ret)
  91.                 goto err;
  92.  
  93.         switch (dev->chipset & ~0xf) {
  94.         case 0x30:
  95.         case 0x40:
  96.         case 0x60:
  97.                 init = nv30_screen_create;
  98.                 break;
  99.         case 0x50:
  100.         case 0x80:
  101.         case 0x90:
  102.         case 0xa0:
  103.                 init = nv50_screen_create;
  104.                 break;
  105.         case 0xc0:
  106.         case 0xd0:
  107.         case 0xe0:
  108.         case 0xf0:
  109.         case 0x100:
  110.         case 0x110:
  111.                 init = nvc0_screen_create;
  112.                 break;
  113.         default:
  114.                 debug_printf("%s: unknown chipset nv%02x\n", __func__,
  115.                              dev->chipset);
  116.                 goto err;
  117.         }
  118.  
  119.         screen = (struct nouveau_screen*)init(dev);
  120.         if (!screen)
  121.                 goto err;
  122.  
  123.         util_hash_table_set(fd_tab, intptr_to_pointer(fd), screen);
  124.         screen->refcount = 1;
  125.         pipe_mutex_unlock(nouveau_screen_mutex);
  126.         return &screen->base;
  127.  
  128. err:
  129.         if (dev)
  130.                 nouveau_device_del(&dev);
  131.         else if (dupfd >= 0)
  132.                 close(dupfd);
  133.         pipe_mutex_unlock(nouveau_screen_mutex);
  134.         return NULL;
  135. }
  136.