• 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    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