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