virgl: reuse screen when fd is already open

It is necessary to share the screen between mesa and gralloc to
properly ref count resources. This implements a hash lookup on
the file description to re-use an already created screen. This is
a similar implementation as freedreno and radeon.

Signed-off-by: Rob Herring <robh@kernel.org>
Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
Rob Herring 2016-01-29 16:36:28 -06:00 committed by Dave Airlie
parent 6711592c2f
commit f87330dbce
5 changed files with 97 additions and 8 deletions

View file

@ -226,14 +226,9 @@ pipe_freedreno_create_screen(int fd)
struct pipe_screen *
pipe_virgl_create_screen(int fd)
{
struct virgl_winsys *vws;
struct pipe_screen *screen;
vws = virgl_drm_winsys_create(fd);
if (!vws)
return NULL;
screen = virgl_create_screen(vws);
screen = virgl_drm_screen_create(fd);
return screen ? debug_screen_wrap(screen) : NULL;
}

View file

@ -557,6 +557,7 @@ virgl_create_screen(struct virgl_winsys *vws)
vws->get_caps(vws, &screen->caps);
screen->refcnt = 1;
util_format_s3tc_init();
return &screen->base;

View file

@ -28,6 +28,12 @@
struct virgl_screen {
struct pipe_screen base;
int refcnt;
/* place for winsys to stash it's own stuff: */
void *winsys_priv;
struct virgl_winsys *vws;
struct virgl_drm_caps caps;

View file

@ -23,8 +23,8 @@
#ifndef VIRGL_DRM_PUBLIC_H
#define VIRGL_DRM_PUBLIC_H
struct virgl_winsys;
struct pipe_screen;
struct virgl_winsys *virgl_drm_winsys_create(int drmFD);
struct pipe_screen *virgl_drm_screen_create(int fd);
#endif

View file

@ -25,6 +25,7 @@
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include "os/os_mman.h"
#include "os/os_time.h"
@ -33,6 +34,8 @@
#include "util/u_hash_table.h"
#include "util/u_inlines.h"
#include "state_tracker/drm_driver.h"
#include "virgl/virgl_screen.h"
#include "virgl/virgl_public.h"
#include <xf86drm.h>
#include "virtgpu_drm.h"
@ -772,3 +775,87 @@ virgl_drm_winsys_create(int drmFD)
return &qdws->base;
}
static struct util_hash_table *fd_tab = NULL;
pipe_static_mutex(virgl_screen_mutex);
static void
virgl_drm_screen_destroy(struct pipe_screen *pscreen)
{
struct virgl_screen *screen = virgl_screen(pscreen);
boolean destroy;
pipe_mutex_lock(virgl_screen_mutex);
destroy = --screen->refcnt == 0;
if (destroy) {
int fd = virgl_drm_winsys(screen->vws)->fd;
util_hash_table_remove(fd_tab, intptr_to_pointer(fd));
}
pipe_mutex_unlock(virgl_screen_mutex);
if (destroy) {
pscreen->destroy = screen->winsys_priv;
pscreen->destroy(pscreen);
}
}
static unsigned hash_fd(void *key)
{
int fd = pointer_to_intptr(key);
struct stat stat;
fstat(fd, &stat);
return stat.st_dev ^ stat.st_ino ^ stat.st_rdev;
}
static int compare_fd(void *key1, void *key2)
{
int fd1 = pointer_to_intptr(key1);
int fd2 = pointer_to_intptr(key2);
struct stat stat1, stat2;
fstat(fd1, &stat1);
fstat(fd2, &stat2);
return stat1.st_dev != stat2.st_dev ||
stat1.st_ino != stat2.st_ino ||
stat1.st_rdev != stat2.st_rdev;
}
struct pipe_screen *
virgl_drm_screen_create(int fd)
{
struct pipe_screen *pscreen = NULL;
pipe_mutex_lock(virgl_screen_mutex);
if (!fd_tab) {
fd_tab = util_hash_table_create(hash_fd, compare_fd);
if (!fd_tab)
goto unlock;
}
pscreen = util_hash_table_get(fd_tab, intptr_to_pointer(fd));
if (pscreen) {
virgl_screen(pscreen)->refcnt++;
} else {
struct virgl_winsys *vws;
int dup_fd = dup(fd);
vws = virgl_drm_winsys_create(dup_fd);
pscreen = virgl_create_screen(vws);
if (pscreen) {
util_hash_table_set(fd_tab, intptr_to_pointer(dup_fd), pscreen);
/* Bit of a hack, to avoid circular linkage dependency,
* ie. pipe driver having to call in to winsys, we
* override the pipe drivers screen->destroy():
*/
virgl_screen(pscreen)->winsys_priv = pscreen->destroy;
pscreen->destroy = virgl_drm_screen_destroy;
}
}
unlock:
pipe_mutex_unlock(virgl_screen_mutex);
return pscreen;
}