1 /**************************************************************************
2 *
3 * Copyright (C) 2014 Red Hat Inc.
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 <stdio.h>
26 #include <time.h>
27
28 #include <epoxy/gl.h>
29
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <unistd.h>
34 #include "pipe/p_state.h"
35 #include "util/u_format.h"
36 #include "util/u_math.h"
37 #include "vrend_renderer.h"
38
39 #include "virglrenderer.h"
40
41 #ifdef HAVE_EPOXY_EGL_H
42 #include "virgl_gbm.h"
43 #include "virgl_egl.h"
44 #endif
45
46 #ifdef HAVE_EPOXY_GLX_H
47 #include "virgl_glx.h"
48 static struct virgl_glx *glx_info;
49 #endif
50
51 /* new API - just wrap internal API for now */
52
virgl_renderer_resource_create(struct virgl_renderer_resource_create_args * args,struct iovec * iov,uint32_t num_iovs)53 int virgl_renderer_resource_create(struct virgl_renderer_resource_create_args *args, struct iovec *iov, uint32_t num_iovs)
54 {
55 return vrend_renderer_resource_create((struct vrend_renderer_resource_create_args *)args, iov, num_iovs, NULL);
56 }
57
virgl_renderer_resource_import_eglimage(struct virgl_renderer_resource_create_args * args,void * image)58 int virgl_renderer_resource_import_eglimage(struct virgl_renderer_resource_create_args *args, void *image)
59 {
60 #ifdef HAVE_EPOXY_EGL_H
61 return vrend_renderer_resource_create((struct vrend_renderer_resource_create_args *)args, 0, 0, image);
62 #else
63 return EINVAL;
64 #endif
65 }
66
virgl_renderer_resource_set_priv(uint32_t res_handle,void * priv)67 void virgl_renderer_resource_set_priv(uint32_t res_handle, void *priv)
68 {
69 vrend_renderer_resource_set_priv(res_handle, priv);
70 }
71
virgl_renderer_resource_get_priv(uint32_t res_handle)72 void *virgl_renderer_resource_get_priv(uint32_t res_handle)
73 {
74 return vrend_renderer_resource_get_priv(res_handle);
75 }
76
virgl_renderer_resource_unref(uint32_t res_handle)77 void virgl_renderer_resource_unref(uint32_t res_handle)
78 {
79 vrend_renderer_resource_unref(res_handle);
80 }
81
virgl_renderer_fill_caps(uint32_t set,uint32_t version,void * caps)82 void virgl_renderer_fill_caps(uint32_t set, uint32_t version,
83 void *caps)
84 {
85 vrend_renderer_fill_caps(set, version, (union virgl_caps *)caps);
86 }
87
virgl_renderer_context_create(uint32_t handle,uint32_t nlen,const char * name)88 int virgl_renderer_context_create(uint32_t handle, uint32_t nlen, const char *name)
89 {
90 return vrend_renderer_context_create(handle, nlen, name);
91 }
92
virgl_renderer_context_destroy(uint32_t handle)93 void virgl_renderer_context_destroy(uint32_t handle)
94 {
95 vrend_renderer_context_destroy(handle);
96 }
97
virgl_renderer_submit_cmd(void * buffer,int ctx_id,int ndw)98 int virgl_renderer_submit_cmd(void *buffer,
99 int ctx_id,
100 int ndw)
101 {
102 return vrend_decode_block(ctx_id, buffer, ndw);
103 }
104
virgl_renderer_transfer_write_iov(uint32_t handle,uint32_t ctx_id,int level,uint32_t stride,uint32_t layer_stride,struct virgl_box * box,uint64_t offset,struct iovec * iovec,unsigned int iovec_cnt)105 int virgl_renderer_transfer_write_iov(uint32_t handle,
106 uint32_t ctx_id,
107 int level,
108 uint32_t stride,
109 uint32_t layer_stride,
110 struct virgl_box *box,
111 uint64_t offset,
112 struct iovec *iovec,
113 unsigned int iovec_cnt)
114 {
115 struct vrend_transfer_info transfer_info;
116
117 transfer_info.handle = handle;
118 transfer_info.ctx_id = ctx_id;
119 transfer_info.level = level;
120 transfer_info.stride = stride;
121 transfer_info.layer_stride = layer_stride;
122 transfer_info.box = (struct pipe_box *)box;
123 transfer_info.offset = offset;
124 transfer_info.iovec = iovec;
125 transfer_info.iovec_cnt = iovec_cnt;
126 transfer_info.context0 = true;
127 transfer_info.synchronized = false;
128
129 return vrend_renderer_transfer_iov(&transfer_info, VIRGL_TRANSFER_TO_HOST);
130 }
131
virgl_renderer_transfer_read_iov(uint32_t handle,uint32_t ctx_id,uint32_t level,uint32_t stride,uint32_t layer_stride,struct virgl_box * box,uint64_t offset,struct iovec * iovec,int iovec_cnt)132 int virgl_renderer_transfer_read_iov(uint32_t handle, uint32_t ctx_id,
133 uint32_t level, uint32_t stride,
134 uint32_t layer_stride,
135 struct virgl_box *box,
136 uint64_t offset, struct iovec *iovec,
137 int iovec_cnt)
138 {
139 struct vrend_transfer_info transfer_info;
140
141 transfer_info.handle = handle;
142 transfer_info.ctx_id = ctx_id;
143 transfer_info.level = level;
144 transfer_info.stride = stride;
145 transfer_info.layer_stride = layer_stride;
146 transfer_info.box = (struct pipe_box *)box;
147 transfer_info.offset = offset;
148 transfer_info.iovec = iovec;
149 transfer_info.iovec_cnt = iovec_cnt;
150 transfer_info.context0 = true;
151 transfer_info.synchronized = false;
152
153 return vrend_renderer_transfer_iov(&transfer_info, VIRGL_TRANSFER_FROM_HOST);
154 }
155
virgl_renderer_resource_attach_iov(int res_handle,struct iovec * iov,int num_iovs)156 int virgl_renderer_resource_attach_iov(int res_handle, struct iovec *iov,
157 int num_iovs)
158 {
159 return vrend_renderer_resource_attach_iov(res_handle, iov, num_iovs);
160 }
161
virgl_renderer_resource_detach_iov(int res_handle,struct iovec ** iov_p,int * num_iovs_p)162 void virgl_renderer_resource_detach_iov(int res_handle, struct iovec **iov_p, int *num_iovs_p)
163 {
164 vrend_renderer_resource_detach_iov(res_handle, iov_p, num_iovs_p);
165 }
166
virgl_renderer_create_fence(int client_fence_id,uint32_t ctx_id)167 int virgl_renderer_create_fence(int client_fence_id, uint32_t ctx_id)
168 {
169 return vrend_renderer_create_fence(client_fence_id, ctx_id);
170 }
171
virgl_renderer_force_ctx_0(void)172 void virgl_renderer_force_ctx_0(void)
173 {
174 vrend_renderer_force_ctx_0();
175 }
176
virgl_renderer_ctx_attach_resource(int ctx_id,int res_handle)177 void virgl_renderer_ctx_attach_resource(int ctx_id, int res_handle)
178 {
179 vrend_renderer_attach_res_ctx(ctx_id, res_handle);
180 }
181
virgl_renderer_ctx_detach_resource(int ctx_id,int res_handle)182 void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle)
183 {
184 vrend_renderer_detach_res_ctx(ctx_id, res_handle);
185 }
186
virgl_renderer_resource_get_info(int res_handle,struct virgl_renderer_resource_info * info)187 int virgl_renderer_resource_get_info(int res_handle,
188 struct virgl_renderer_resource_info *info)
189 {
190 int ret;
191 ret = vrend_renderer_resource_get_info(res_handle, (struct vrend_renderer_resource_info *)info);
192 #ifdef HAVE_EPOXY_EGL_H
193 if (ret == 0 && use_context == CONTEXT_EGL)
194 return virgl_egl_get_fourcc_for_texture(egl, info->tex_id, info->virgl_format, &info->drm_fourcc);
195 #endif
196
197 return ret;
198 }
199
virgl_renderer_get_cap_set(uint32_t cap_set,uint32_t * max_ver,uint32_t * max_size)200 void virgl_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver,
201 uint32_t *max_size)
202 {
203 vrend_renderer_get_cap_set(cap_set, max_ver, max_size);
204 }
205
virgl_renderer_get_rect(int resource_id,struct iovec * iov,unsigned int num_iovs,uint32_t offset,int x,int y,int width,int height)206 void virgl_renderer_get_rect(int resource_id, struct iovec *iov, unsigned int num_iovs,
207 uint32_t offset, int x, int y, int width, int height)
208 {
209 vrend_renderer_get_rect(resource_id, iov, num_iovs, offset, x, y, width, height);
210 }
211
212
213 static struct virgl_renderer_callbacks *rcbs;
214
215 static void *dev_cookie;
216
217 static struct vrend_if_cbs virgl_cbs;
218
virgl_write_fence(uint32_t fence_id)219 static void virgl_write_fence(uint32_t fence_id)
220 {
221 rcbs->write_fence(dev_cookie, fence_id);
222 }
223
create_gl_context(int scanout_idx,struct virgl_gl_ctx_param * param)224 static virgl_renderer_gl_context create_gl_context(int scanout_idx, struct virgl_gl_ctx_param *param)
225 {
226 struct virgl_renderer_gl_ctx_param vparam;
227
228 #ifdef HAVE_EPOXY_EGL_H
229 if (use_context == CONTEXT_EGL)
230 return virgl_egl_create_context(egl, param);
231 #endif
232 #ifdef HAVE_EPOXY_GLX_H
233 if (use_context == CONTEXT_GLX)
234 return virgl_glx_create_context(glx_info, param);
235 #endif
236 vparam.version = 1;
237 vparam.shared = param->shared;
238 vparam.major_ver = param->major_ver;
239 vparam.minor_ver = param->minor_ver;
240 return rcbs->create_gl_context(dev_cookie, scanout_idx, &vparam);
241 }
242
destroy_gl_context(virgl_renderer_gl_context ctx)243 static void destroy_gl_context(virgl_renderer_gl_context ctx)
244 {
245 #ifdef HAVE_EPOXY_EGL_H
246 if (use_context == CONTEXT_EGL) {
247 virgl_egl_destroy_context(egl, ctx);
248 return;
249 }
250 #endif
251 #ifdef HAVE_EPOXY_GLX_H
252 if (use_context == CONTEXT_GLX) {
253 virgl_glx_destroy_context(glx_info, ctx);
254 return;
255 }
256 #endif
257 rcbs->destroy_gl_context(dev_cookie, ctx);
258 }
259
make_current(virgl_renderer_gl_context ctx)260 static int make_current(virgl_renderer_gl_context ctx)
261 {
262 #ifdef HAVE_EPOXY_EGL_H
263 if (use_context == CONTEXT_EGL)
264 return virgl_egl_make_context_current(egl, ctx);
265 #endif
266 #ifdef HAVE_EPOXY_GLX_H
267 if (use_context == CONTEXT_GLX)
268 return virgl_glx_make_context_current(glx_info, ctx);
269 #endif
270 return rcbs->make_current(dev_cookie, 0, ctx);
271 }
272
273 static struct vrend_if_cbs virgl_cbs = {
274 virgl_write_fence,
275 create_gl_context,
276 destroy_gl_context,
277 make_current,
278 };
279
virgl_renderer_get_cursor_data(uint32_t resource_id,uint32_t * width,uint32_t * height)280 void *virgl_renderer_get_cursor_data(uint32_t resource_id, uint32_t *width, uint32_t *height)
281 {
282 vrend_renderer_force_ctx_0();
283 return vrend_renderer_get_cursor_contents(resource_id, width, height);
284 }
285
virgl_renderer_poll(void)286 void virgl_renderer_poll(void)
287 {
288 vrend_renderer_check_fences();
289 }
290
virgl_renderer_cleanup(UNUSED void * cookie)291 void virgl_renderer_cleanup(UNUSED void *cookie)
292 {
293 vrend_renderer_fini();
294 #ifdef HAVE_EPOXY_EGL_H
295 if (use_context == CONTEXT_EGL) {
296 virgl_egl_destroy(egl);
297 egl = NULL;
298 use_context = CONTEXT_NONE;
299 if (gbm) {
300 virgl_gbm_fini(gbm);
301 gbm = NULL;
302 }
303 }
304 #endif
305 #ifdef HAVE_EPOXY_GLX_H
306 if (use_context == CONTEXT_GLX) {
307 virgl_glx_destroy(glx_info);
308 glx_info = NULL;
309 use_context = CONTEXT_NONE;
310 }
311 #endif
312 }
313
virgl_renderer_init(void * cookie,int flags,struct virgl_renderer_callbacks * cbs)314 int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks *cbs)
315 {
316 uint32_t renderer_flags = 0;
317 if (!cookie || !cbs)
318 return -1;
319
320 if (cbs->version < 1 || cbs->version > VIRGL_RENDERER_CALLBACKS_VERSION)
321 return -1;
322
323 dev_cookie = cookie;
324 rcbs = cbs;
325
326 if (flags & VIRGL_RENDERER_USE_EGL) {
327 #ifdef HAVE_EPOXY_EGL_H
328 int fd = -1;
329 if (cbs->version >= 2 && cbs->get_drm_fd) {
330 fd = cbs->get_drm_fd(cookie);
331 }
332
333 /*
334 * If the user specifies a preferred DRM fd and we can't use it, fail. If the user doesn't
335 * specify an fd, it's possible to initialize EGL without one.
336 */
337 gbm = virgl_gbm_init(fd);
338 if (fd > 0 && !gbm)
339 return -1;
340
341 egl = virgl_egl_init(gbm, flags & VIRGL_RENDERER_USE_SURFACELESS,
342 flags & VIRGL_RENDERER_USE_GLES);
343 if (!egl) {
344 if (gbm) {
345 virgl_gbm_fini(gbm);
346 gbm = NULL;
347 }
348
349 return -1;
350 }
351
352 use_context = CONTEXT_EGL;
353 #else
354 vrend_printf( "EGL is not supported on this platform\n");
355 return -1;
356 #endif
357 } else if (flags & VIRGL_RENDERER_USE_GLX) {
358 #ifdef HAVE_EPOXY_GLX_H
359 glx_info = virgl_glx_init();
360 if (!glx_info)
361 return -1;
362 use_context = CONTEXT_GLX;
363 #else
364 vrend_printf( "GLX is not supported on this platform\n");
365 return -1;
366 #endif
367 }
368
369 if (flags & VIRGL_RENDERER_THREAD_SYNC)
370 renderer_flags |= VREND_USE_THREAD_SYNC;
371
372 return vrend_renderer_init(&virgl_cbs, renderer_flags);
373 }
374
virgl_renderer_get_fd_for_texture(uint32_t tex_id,int * fd)375 int virgl_renderer_get_fd_for_texture(uint32_t tex_id, int *fd)
376 {
377 #ifdef HAVE_EPOXY_EGL_H
378 if (!egl)
379 return -1;
380
381 return virgl_egl_get_fd_for_texture(egl, tex_id, fd);
382 #else
383 return -1;
384 #endif
385 }
386
virgl_renderer_get_fd_for_texture2(uint32_t tex_id,int * fd,int * stride,int * offset)387 int virgl_renderer_get_fd_for_texture2(uint32_t tex_id, int *fd, int *stride, int *offset)
388 {
389 #ifdef HAVE_EPOXY_EGL_H
390 if (!egl)
391 return -1;
392
393 return virgl_egl_get_fd_for_texture2(egl, tex_id, fd, stride, offset);
394 #else
395 return -1;
396 #endif
397 }
398
virgl_renderer_reset(void)399 void virgl_renderer_reset(void)
400 {
401 vrend_renderer_reset();
402 }
403
virgl_renderer_get_poll_fd(void)404 int virgl_renderer_get_poll_fd(void)
405 {
406 return vrend_renderer_get_poll_fd();
407 }
408
virgl_set_debug_callback(virgl_debug_callback_type cb)409 virgl_debug_callback_type virgl_set_debug_callback(virgl_debug_callback_type cb)
410 {
411 return vrend_set_debug_callback(cb);
412 }
413
virgl_renderer_execute(void * execute_args,uint32_t execute_size)414 int virgl_renderer_execute(void *execute_args, uint32_t execute_size)
415 {
416 return vrend_renderer_execute(execute_args, execute_size);
417 }
418