xref: /aosp_15_r20/external/virglrenderer/src/virgl_resource.c (revision bbecb9d118dfdb95f99bd754f8fa9be01f189df3)
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/os_file.h"
34 #include "util/u_hash_table.h"
35 #include "util/u_pointer.h"
36 #include "virgl_util.h"
37 #include "virgl_context.h"
38 
39 static struct util_hash_table *virgl_resource_table;
40 static struct virgl_resource_pipe_callbacks pipe_callbacks;
41 
42 static void
virgl_resource_destroy_func(void * val)43 virgl_resource_destroy_func(void *val)
44 {
45    struct virgl_resource *res = (struct virgl_resource *)val;
46 
47    if (res->pipe_resource)
48       pipe_callbacks.unref(res->pipe_resource, pipe_callbacks.data);
49    if ((res->fd_type != VIRGL_RESOURCE_FD_INVALID) &&
50        (res->fd_type != VIRGL_RESOURCE_OPAQUE_HANDLE))
51       close(res->fd);
52 
53    free(res);
54 }
55 
56 int
virgl_resource_table_init(const struct virgl_resource_pipe_callbacks * callbacks)57 virgl_resource_table_init(const struct virgl_resource_pipe_callbacks *callbacks)
58 {
59    virgl_resource_table = util_hash_table_create(hash_func_u32,
60                                                  equal_func,
61                                                  virgl_resource_destroy_func);
62    if (!virgl_resource_table)
63       return ENOMEM;
64 
65    if (callbacks)
66       pipe_callbacks = *callbacks;
67 
68    return 0;
69 }
70 
71 void
virgl_resource_table_cleanup(void)72 virgl_resource_table_cleanup(void)
73 {
74    util_hash_table_destroy(virgl_resource_table);
75    virgl_resource_table = NULL;
76    memset(&pipe_callbacks, 0, sizeof(pipe_callbacks));
77 }
78 
79 void
virgl_resource_table_reset(void)80 virgl_resource_table_reset(void)
81 {
82    util_hash_table_clear(virgl_resource_table);
83 }
84 
85 static struct virgl_resource *
virgl_resource_create(uint32_t res_id)86 virgl_resource_create(uint32_t res_id)
87 {
88    struct virgl_resource *res;
89    enum pipe_error err;
90 
91    res = calloc(1, sizeof(*res));
92    if (!res)
93       return NULL;
94 
95    err = util_hash_table_set(virgl_resource_table,
96                              uintptr_to_pointer(res_id),
97                              res);
98    if (err != PIPE_OK) {
99       free(res);
100       return NULL;
101    }
102 
103    res->res_id = res_id;
104    res->fd_type = VIRGL_RESOURCE_FD_INVALID;
105    res->fd = -1;
106 
107    return res;
108 }
109 
110 struct virgl_resource *
virgl_resource_create_from_pipe(uint32_t res_id,struct pipe_resource * pres,const struct iovec * iov,int iov_count)111 virgl_resource_create_from_pipe(uint32_t res_id,
112                                 struct pipe_resource *pres,
113                                 const struct iovec *iov,
114                                 int iov_count)
115 {
116    struct virgl_resource *res;
117 
118    res = virgl_resource_create(res_id);
119    if (!res)
120       return NULL;
121 
122    /* take ownership */
123    res->pipe_resource = pres;
124 
125    res->iov = iov;
126    res->iov_count = iov_count;
127 
128    return res;
129 }
130 
131 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,const struct virgl_resource_opaque_fd_metadata * opaque_fd_metadata)132 virgl_resource_create_from_fd(uint32_t res_id,
133                               enum virgl_resource_fd_type fd_type,
134                               int fd,
135                               const struct iovec *iov,
136                               int iov_count,
137                               const struct virgl_resource_opaque_fd_metadata *opaque_fd_metadata)
138 {
139    struct virgl_resource *res;
140 
141    assert(fd_type != VIRGL_RESOURCE_FD_INVALID  && fd >= 0);
142 
143    res = virgl_resource_create(res_id);
144    if (!res)
145       return NULL;
146 
147    res->fd_type = fd_type;
148    /* take ownership */
149    res->fd = fd;
150 
151    res->iov = iov;
152    res->iov_count = iov_count;
153 
154    if (opaque_fd_metadata && fd_type == VIRGL_RESOURCE_FD_OPAQUE)
155       res->opaque_fd_metadata = *opaque_fd_metadata;
156 
157    return res;
158 }
159 
160 struct virgl_resource *
virgl_resource_create_from_opaque_handle(struct virgl_context * ctx,uint32_t res_id,uint32_t opaque_handle)161 virgl_resource_create_from_opaque_handle(struct virgl_context *ctx,
162                                          uint32_t res_id,
163                                          uint32_t opaque_handle)
164 {
165    struct virgl_resource *res;
166 
167    res = virgl_resource_create(res_id);
168    if (!res)
169       return NULL;
170 
171    res->fd_type = VIRGL_RESOURCE_OPAQUE_HANDLE;
172    res->opaque_handle = opaque_handle;
173 
174    /* We need the ctx to get an fd from handle (which we don't want to do
175     * until asked, to avoid file descriptor limits)
176     *
177     * Shareable resources should not use OPAQUE_HANDLE, to avoid lifetime
178     * issues (ie. resource outliving the context which created it).
179     */
180    res->opaque_handle_context_id = ctx->ctx_id;
181 
182    return res;
183 }
184 
185 struct virgl_resource *
virgl_resource_create_from_iov(uint32_t res_id,const struct iovec * iov,int iov_count)186 virgl_resource_create_from_iov(uint32_t res_id,
187                                const struct iovec *iov,
188                                int iov_count)
189 {
190    struct virgl_resource *res;
191 
192    if (iov_count)
193       assert(iov);
194 
195    res = virgl_resource_create(res_id);
196    if (!res)
197       return NULL;
198 
199    res->iov = iov;
200    res->iov_count = iov_count;
201 
202    return res;
203 }
204 
205 void
virgl_resource_remove(uint32_t res_id)206 virgl_resource_remove(uint32_t res_id)
207 {
208    util_hash_table_remove(virgl_resource_table, uintptr_to_pointer(res_id));
209 }
210 
virgl_resource_lookup(uint32_t res_id)211 struct virgl_resource *virgl_resource_lookup(uint32_t res_id)
212 {
213    return util_hash_table_get(virgl_resource_table,
214                               uintptr_to_pointer(res_id));
215 }
216 
217 int
virgl_resource_attach_iov(struct virgl_resource * res,const struct iovec * iov,int iov_count)218 virgl_resource_attach_iov(struct virgl_resource *res,
219                           const struct iovec *iov,
220                           int iov_count)
221 {
222    if (res->iov)
223       return EINVAL;
224 
225    res->iov = iov;
226    res->iov_count = iov_count;
227 
228    if (res->pipe_resource) {
229       pipe_callbacks.attach_iov(res->pipe_resource,
230                                 iov,
231                                 iov_count,
232                                 pipe_callbacks.data);
233    }
234 
235    return 0;
236 }
237 
238 void
virgl_resource_detach_iov(struct virgl_resource * res)239 virgl_resource_detach_iov(struct virgl_resource *res)
240 {
241    if (!res->iov)
242       return;
243 
244    if (res->pipe_resource)
245       pipe_callbacks.detach_iov(res->pipe_resource, pipe_callbacks.data);
246 
247    res->iov = NULL;
248    res->iov_count = 0;
249 }
250 
251 enum virgl_resource_fd_type
virgl_resource_export_fd(struct virgl_resource * res,int * fd)252 virgl_resource_export_fd(struct virgl_resource *res, int *fd)
253 {
254    if (res->fd_type == VIRGL_RESOURCE_OPAQUE_HANDLE) {
255       struct virgl_context *ctx;
256 
257       ctx = virgl_context_lookup(res->opaque_handle_context_id);
258       if (!ctx)
259          return VIRGL_RESOURCE_FD_INVALID;
260 
261       return ctx->export_opaque_handle(ctx, res, fd);
262    } else if (res->fd_type != VIRGL_RESOURCE_FD_INVALID) {
263       *fd = os_dupfd_cloexec(res->fd);
264       return *fd >= 0 ? res->fd_type : VIRGL_RESOURCE_FD_INVALID;
265    } else if (res->pipe_resource) {
266       return pipe_callbacks.export_fd(res->pipe_resource,
267                                       fd,
268                                       pipe_callbacks.data);
269    }
270 
271    return VIRGL_RESOURCE_FD_INVALID;
272 }
273 
274 uint64_t
virgl_resource_get_size(struct virgl_resource * res)275 virgl_resource_get_size(struct virgl_resource *res)
276 {
277    if (res->map_size)
278       return res->map_size;
279 
280    if (res->pipe_resource)
281       return pipe_callbacks.get_size(res->pipe_resource, pipe_callbacks.data);
282 
283    return 0;
284 }
285