• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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