1 /**************************************************************************
2 *
3 * Copyright (C) 2020 Chromium
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 **************************************************************************/
24
25 #include "virgl_resource.h"
26
27 #include <assert.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <unistd.h>
32
33 #include "util/u_hash_table.h"
34 #include "util/u_pointer.h"
35 #include "virgl_util.h"
36
37 static struct util_hash_table *virgl_resource_table;
38 static struct virgl_resource_pipe_callbacks pipe_callbacks;
39
40 static void
virgl_resource_destroy_func(void * val)41 virgl_resource_destroy_func(void *val)
42 {
43 struct virgl_resource *res = (struct virgl_resource *)val;
44
45 if (res->pipe_resource)
46 pipe_callbacks.unref(res->pipe_resource, pipe_callbacks.data);
47 if (res->fd_type != VIRGL_RESOURCE_FD_INVALID)
48 close(res->fd);
49
50 free(res);
51 }
52
53 int
virgl_resource_table_init(const struct virgl_resource_pipe_callbacks * callbacks)54 virgl_resource_table_init(const struct virgl_resource_pipe_callbacks *callbacks)
55 {
56 virgl_resource_table = util_hash_table_create(hash_func_u32,
57 compare_func,
58 virgl_resource_destroy_func);
59 if (!virgl_resource_table)
60 return ENOMEM;
61
62 if (callbacks)
63 pipe_callbacks = *callbacks;
64
65 return 0;
66 }
67
68 void
virgl_resource_table_cleanup(void)69 virgl_resource_table_cleanup(void)
70 {
71 util_hash_table_destroy(virgl_resource_table);
72 memset(&pipe_callbacks, 0, sizeof(pipe_callbacks));
73 }
74
75 void
virgl_resource_table_reset(void)76 virgl_resource_table_reset(void)
77 {
78 util_hash_table_clear(virgl_resource_table);
79 }
80
81 static struct virgl_resource *
virgl_resource_create(uint32_t res_id)82 virgl_resource_create(uint32_t res_id)
83 {
84 struct virgl_resource *res;
85 enum pipe_error err;
86
87 res = calloc(1, sizeof(*res));
88 if (!res)
89 return NULL;
90
91 err = util_hash_table_set(virgl_resource_table,
92 uintptr_to_pointer(res_id),
93 res);
94 if (err != PIPE_OK) {
95 free(res);
96 return NULL;
97 }
98
99 res->res_id = res_id;
100 res->fd_type = VIRGL_RESOURCE_FD_INVALID;
101 res->fd = -1;
102
103 return res;
104 }
105
106 struct virgl_resource *
virgl_resource_create_from_pipe(uint32_t res_id,struct pipe_resource * pres,const struct iovec * iov,int iov_count)107 virgl_resource_create_from_pipe(uint32_t res_id,
108 struct pipe_resource *pres,
109 const struct iovec *iov,
110 int iov_count)
111 {
112 struct virgl_resource *res;
113
114 res = virgl_resource_create(res_id);
115 if (!res)
116 return NULL;
117
118 /* take ownership */
119 res->pipe_resource = pres;
120
121 res->iov = iov;
122 res->iov_count = iov_count;
123
124 return res;
125 }
126
127 struct virgl_resource *
virgl_resource_create_from_fd(uint32_t res_id,enum virgl_resource_fd_type fd_type,int fd,const struct iovec * iov,int iov_count)128 virgl_resource_create_from_fd(uint32_t res_id,
129 enum virgl_resource_fd_type fd_type,
130 int fd,
131 const struct iovec *iov,
132 int iov_count)
133 {
134 struct virgl_resource *res;
135
136 assert(fd_type != VIRGL_RESOURCE_FD_INVALID && fd >= 0);
137
138 res = virgl_resource_create(res_id);
139 if (!res)
140 return NULL;
141
142 res->fd_type = fd_type;
143 /* take ownership */
144 res->fd = fd;
145
146 res->iov = iov;
147 res->iov_count = iov_count;
148
149 return res;
150 }
151
152 struct virgl_resource *
virgl_resource_create_from_iov(uint32_t res_id,const struct iovec * iov,int iov_count)153 virgl_resource_create_from_iov(uint32_t res_id,
154 const struct iovec *iov,
155 int iov_count)
156 {
157 struct virgl_resource *res;
158
159 if (iov_count)
160 assert(iov);
161
162 res = virgl_resource_create(res_id);
163 if (!res)
164 return NULL;
165
166 res->iov = iov;
167 res->iov_count = iov_count;
168
169 return res;
170 }
171
172 void
virgl_resource_remove(uint32_t res_id)173 virgl_resource_remove(uint32_t res_id)
174 {
175 util_hash_table_remove(virgl_resource_table, uintptr_to_pointer(res_id));
176 }
177
virgl_resource_lookup(uint32_t res_id)178 struct virgl_resource *virgl_resource_lookup(uint32_t res_id)
179 {
180 return util_hash_table_get(virgl_resource_table,
181 uintptr_to_pointer(res_id));
182 }
183
184 int
virgl_resource_attach_iov(struct virgl_resource * res,const struct iovec * iov,int iov_count)185 virgl_resource_attach_iov(struct virgl_resource *res,
186 const struct iovec *iov,
187 int iov_count)
188 {
189 if (res->iov)
190 return EINVAL;
191
192 res->iov = iov;
193 res->iov_count = iov_count;
194
195 if (res->pipe_resource) {
196 pipe_callbacks.attach_iov(res->pipe_resource,
197 iov,
198 iov_count,
199 pipe_callbacks.data);
200 }
201
202 return 0;
203 }
204
205 void
virgl_resource_detach_iov(struct virgl_resource * res)206 virgl_resource_detach_iov(struct virgl_resource *res)
207 {
208 if (!res->iov)
209 return;
210
211 if (res->pipe_resource)
212 pipe_callbacks.detach_iov(res->pipe_resource, pipe_callbacks.data);
213
214 res->iov = NULL;
215 res->iov_count = 0;
216 }
217
218 enum virgl_resource_fd_type
virgl_resource_export_fd(struct virgl_resource * res,int * fd)219 virgl_resource_export_fd(struct virgl_resource *res, int *fd)
220 {
221 if (res->fd_type != VIRGL_RESOURCE_FD_INVALID) {
222 #ifdef F_DUPFD_CLOEXEC
223 *fd = fcntl(res->fd, F_DUPFD_CLOEXEC, 0);
224 if (*fd < 0)
225 *fd = dup(res->fd);
226 #else
227 *fd = dup(res->fd);
228 #endif
229 return *fd >= 0 ? res->fd_type : VIRGL_RESOURCE_FD_INVALID;
230 } else if (res->pipe_resource) {
231 return pipe_callbacks.export_fd(res->pipe_resource,
232 fd,
233 pipe_callbacks.data);
234 }
235
236 return VIRGL_RESOURCE_FD_INVALID;
237 }
238