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 pipe_callbacks = *callbacks;
63
64 return 0;
65 }
66
67 void
virgl_resource_table_cleanup(void)68 virgl_resource_table_cleanup(void)
69 {
70 util_hash_table_destroy(virgl_resource_table);
71 memset(&pipe_callbacks, 0, sizeof(pipe_callbacks));
72 }
73
74 void
virgl_resource_table_reset(void)75 virgl_resource_table_reset(void)
76 {
77 util_hash_table_clear(virgl_resource_table);
78 }
79
80 static struct virgl_resource *
virgl_resource_create(uint32_t res_id)81 virgl_resource_create(uint32_t res_id)
82 {
83 struct virgl_resource *res;
84 enum pipe_error err;
85
86 res = calloc(1, sizeof(*res));
87 if (!res)
88 return NULL;
89
90 err = util_hash_table_set(virgl_resource_table,
91 uintptr_to_pointer(res_id),
92 res);
93 if (err != PIPE_OK) {
94 free(res);
95 return NULL;
96 }
97
98 res->res_id = res_id;
99 res->fd_type = VIRGL_RESOURCE_FD_INVALID;
100 res->fd = -1;
101
102 return res;
103 }
104
105 struct virgl_resource *
virgl_resource_create_from_pipe(uint32_t res_id,struct pipe_resource * pres,const struct iovec * iov,int iov_count)106 virgl_resource_create_from_pipe(uint32_t res_id,
107 struct pipe_resource *pres,
108 const struct iovec *iov,
109 int iov_count)
110 {
111 struct virgl_resource *res;
112
113 res = virgl_resource_create(res_id);
114 if (!res)
115 return NULL;
116
117 /* take ownership */
118 res->pipe_resource = pres;
119
120 res->iov = iov;
121 res->iov_count = iov_count;
122
123 return res;
124 }
125
126 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)127 virgl_resource_create_from_fd(uint32_t res_id,
128 enum virgl_resource_fd_type fd_type,
129 int fd,
130 const struct iovec *iov,
131 int iov_count)
132 {
133 struct virgl_resource *res;
134
135 assert(fd_type != VIRGL_RESOURCE_FD_INVALID && fd >= 0);
136
137 res = virgl_resource_create(res_id);
138 if (!res)
139 return NULL;
140
141 res->fd_type = fd_type;
142 /* take ownership */
143 res->fd = fd;
144
145 res->iov = iov;
146 res->iov_count = iov_count;
147
148 return res;
149 }
150
151 struct virgl_resource *
virgl_resource_create_from_iov(uint32_t res_id,const struct iovec * iov,int iov_count)152 virgl_resource_create_from_iov(uint32_t res_id,
153 const struct iovec *iov,
154 int iov_count)
155 {
156 struct virgl_resource *res;
157
158 if (iov_count)
159 assert(iov);
160
161 res = virgl_resource_create(res_id);
162 if (!res)
163 return NULL;
164
165 res->iov = iov;
166 res->iov_count = iov_count;
167
168 return res;
169 }
170
171 void
virgl_resource_remove(uint32_t res_id)172 virgl_resource_remove(uint32_t res_id)
173 {
174 util_hash_table_remove(virgl_resource_table, uintptr_to_pointer(res_id));
175 }
176
virgl_resource_lookup(uint32_t res_id)177 struct virgl_resource *virgl_resource_lookup(uint32_t res_id)
178 {
179 return util_hash_table_get(virgl_resource_table,
180 uintptr_to_pointer(res_id));
181 }
182
183 int
virgl_resource_attach_iov(struct virgl_resource * res,const struct iovec * iov,int iov_count)184 virgl_resource_attach_iov(struct virgl_resource *res,
185 const struct iovec *iov,
186 int iov_count)
187 {
188 if (res->iov)
189 return EINVAL;
190
191 res->iov = iov;
192 res->iov_count = iov_count;
193
194 if (res->pipe_resource) {
195 pipe_callbacks.attach_iov(res->pipe_resource,
196 iov,
197 iov_count,
198 pipe_callbacks.data);
199 }
200
201 return 0;
202 }
203
204 void
virgl_resource_detach_iov(struct virgl_resource * res)205 virgl_resource_detach_iov(struct virgl_resource *res)
206 {
207 if (!res->iov)
208 return;
209
210 if (res->pipe_resource)
211 pipe_callbacks.detach_iov(res->pipe_resource, pipe_callbacks.data);
212
213 res->iov = NULL;
214 res->iov_count = 0;
215 }
216
217 enum virgl_resource_fd_type
virgl_resource_export_fd(struct virgl_resource * res,int * fd)218 virgl_resource_export_fd(struct virgl_resource *res, int *fd)
219 {
220 if (res->fd_type != VIRGL_RESOURCE_FD_INVALID) {
221 #ifdef F_DUPFD_CLOEXEC
222 *fd = fcntl(res->fd, F_DUPFD_CLOEXEC, 0);
223 if (*fd < 0)
224 *fd = dup(res->fd);
225 #else
226 *fd = dup(res->fd);
227 #endif
228 return *fd >= 0 ? res->fd_type : VIRGL_RESOURCE_FD_INVALID;
229 } else if (res->pipe_resource) {
230 return pipe_callbacks.export_fd(res->pipe_resource,
231 fd,
232 pipe_callbacks.data);
233 }
234
235 return VIRGL_RESOURCE_FD_INVALID;
236 }
237