Path: blob/21.2-virgl/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c
4573 views
#include <sys/stat.h>1#include <unistd.h>2#include <fcntl.h>3#include "pipe/p_context.h"4#include "pipe/p_state.h"5#include "util/format/u_format.h"6#include "util/os_file.h"7#include "util/u_memory.h"8#include "util/u_inlines.h"9#include "util/u_hash_table.h"10#include "util/u_pointer.h"11#include "os/os_thread.h"1213#include "nouveau_drm_public.h"1415#include "nouveau/nouveau_winsys.h"16#include "nouveau/nouveau_screen.h"1718#include <nvif/class.h>19#include <nvif/cl0080.h>2021static struct hash_table *fd_tab = NULL;2223static mtx_t nouveau_screen_mutex = _MTX_INITIALIZER_NP;2425bool nouveau_drm_screen_unref(struct nouveau_screen *screen)26{27int ret;28if (screen->refcount == -1)29return true;3031mtx_lock(&nouveau_screen_mutex);32ret = --screen->refcount;33assert(ret >= 0);34if (ret == 0)35_mesa_hash_table_remove_key(fd_tab, intptr_to_pointer(screen->drm->fd));36mtx_unlock(&nouveau_screen_mutex);37return ret == 0;38}3940PUBLIC struct pipe_screen *41nouveau_drm_screen_create(int fd)42{43struct nouveau_drm *drm = NULL;44struct nouveau_device *dev = NULL;45struct nouveau_screen *(*init)(struct nouveau_device *);46struct nouveau_screen *screen = NULL;47int ret, dupfd;4849mtx_lock(&nouveau_screen_mutex);50if (!fd_tab) {51fd_tab = util_hash_table_create_fd_keys();52if (!fd_tab) {53mtx_unlock(&nouveau_screen_mutex);54return NULL;55}56}5758screen = util_hash_table_get(fd_tab, intptr_to_pointer(fd));59if (screen) {60screen->refcount++;61mtx_unlock(&nouveau_screen_mutex);62return &screen->base;63}6465/* Since the screen re-use is based on the device node and not the fd,66* create a copy of the fd to be owned by the device. Otherwise a67* scenario could occur where two screens are created, and the first68* one is shut down, along with the fd being closed. The second69* (identical) screen would now have a reference to the closed fd. We70* avoid this by duplicating the original fd. Note that71* nouveau_device_wrap does not close the fd in case of a device72* creation error.73*/74dupfd = os_dupfd_cloexec(fd);7576ret = nouveau_drm_new(dupfd, &drm);77if (ret)78goto err;7980ret = nouveau_device_new(&drm->client, NV_DEVICE,81&(struct nv_device_v0) {82.device = ~0ULL,83}, sizeof(struct nv_device_v0), &dev);84if (ret)85goto err;8687switch (dev->chipset & ~0xf) {88case 0x30:89case 0x40:90case 0x60:91init = nv30_screen_create;92break;93case 0x50:94case 0x80:95case 0x90:96case 0xa0:97init = nv50_screen_create;98break;99case 0xc0:100case 0xd0:101case 0xe0:102case 0xf0:103case 0x100:104case 0x110:105case 0x120:106case 0x130:107case 0x140:108case 0x160:109init = nvc0_screen_create;110break;111default:112debug_printf("%s: unknown chipset nv%02x\n", __func__,113dev->chipset);114goto err;115}116117screen = init(dev);118if (!screen || !screen->base.context_create)119goto err;120121/* Use dupfd in hash table, to avoid errors if the original fd gets122* closed by its owner. The hash key needs to live at least as long as123* the screen.124*/125_mesa_hash_table_insert(fd_tab, intptr_to_pointer(dupfd), screen);126screen->refcount = 1;127mtx_unlock(&nouveau_screen_mutex);128return &screen->base;129130err:131if (screen) {132screen->base.destroy(&screen->base);133} else {134nouveau_device_del(&dev);135nouveau_drm_del(&drm);136close(dupfd);137}138mtx_unlock(&nouveau_screen_mutex);139return NULL;140}141142143