1 /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
2
3 /*
4 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * Authors:
26 * Rob Clark <robclark@freedesktop.org>
27 */
28
29 #include <sys/stat.h>
30
31 #include "pipe/p_context.h"
32 #include "pipe/p_state.h"
33 #include "util/u_format.h"
34 #include "util/u_memory.h"
35 #include "util/u_inlines.h"
36 #include "util/u_hash_table.h"
37 #include "os/os_thread.h"
38
39 #include "freedreno_drm_public.h"
40
41 #include "freedreno/freedreno_screen.h"
42
43 static struct util_hash_table *fd_tab = NULL;
44
45 pipe_static_mutex(fd_screen_mutex);
46
47 static void
fd_drm_screen_destroy(struct pipe_screen * pscreen)48 fd_drm_screen_destroy(struct pipe_screen *pscreen)
49 {
50 struct fd_screen *screen = fd_screen(pscreen);
51 boolean destroy;
52
53 pipe_mutex_lock(fd_screen_mutex);
54 destroy = --screen->refcnt == 0;
55 if (destroy) {
56 int fd = fd_device_fd(screen->dev);
57 util_hash_table_remove(fd_tab, intptr_to_pointer(fd));
58 }
59 pipe_mutex_unlock(fd_screen_mutex);
60
61 if (destroy) {
62 pscreen->destroy = screen->winsys_priv;
63 pscreen->destroy(pscreen);
64 }
65 }
66
hash_fd(void * key)67 static unsigned hash_fd(void *key)
68 {
69 int fd = pointer_to_intptr(key);
70 struct stat stat;
71 fstat(fd, &stat);
72
73 return stat.st_dev ^ stat.st_ino ^ stat.st_rdev;
74 }
75
compare_fd(void * key1,void * key2)76 static int compare_fd(void *key1, void *key2)
77 {
78 int fd1 = pointer_to_intptr(key1);
79 int fd2 = pointer_to_intptr(key2);
80 struct stat stat1, stat2;
81 fstat(fd1, &stat1);
82 fstat(fd2, &stat2);
83
84 return stat1.st_dev != stat2.st_dev ||
85 stat1.st_ino != stat2.st_ino ||
86 stat1.st_rdev != stat2.st_rdev;
87 }
88
89 struct pipe_screen *
fd_drm_screen_create(int fd)90 fd_drm_screen_create(int fd)
91 {
92 struct pipe_screen *pscreen = NULL;
93
94 pipe_mutex_lock(fd_screen_mutex);
95 if (!fd_tab) {
96 fd_tab = util_hash_table_create(hash_fd, compare_fd);
97 if (!fd_tab)
98 goto unlock;
99 }
100
101 pscreen = util_hash_table_get(fd_tab, intptr_to_pointer(fd));
102 if (pscreen) {
103 fd_screen(pscreen)->refcnt++;
104 } else {
105 struct fd_device *dev = fd_device_new_dup(fd);
106 if (!dev)
107 goto unlock;
108
109 pscreen = fd_screen_create(dev);
110 if (pscreen) {
111 int fd = fd_device_fd(dev);
112
113 util_hash_table_set(fd_tab, intptr_to_pointer(fd), pscreen);
114
115 /* Bit of a hack, to avoid circular linkage dependency,
116 * ie. pipe driver having to call in to winsys, we
117 * override the pipe drivers screen->destroy():
118 */
119 fd_screen(pscreen)->winsys_priv = pscreen->destroy;
120 pscreen->destroy = fd_drm_screen_destroy;
121 }
122 }
123
124 unlock:
125 pipe_mutex_unlock(fd_screen_mutex);
126 return pscreen;
127 }
128