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_egl.h"
43 static struct virgl_egl *egl_info;
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 enum {
52 CONTEXT_NONE,
53 CONTEXT_EGL,
54 CONTEXT_GLX
55 };
56
57 static int use_context = CONTEXT_NONE;
58
59 /* new API - just wrap internal API for now */
60
virgl_renderer_resource_create(struct virgl_renderer_resource_create_args * args,struct iovec * iov,uint32_t num_iovs)61 int virgl_renderer_resource_create(struct virgl_renderer_resource_create_args *args, struct iovec *iov, uint32_t num_iovs)
62 {
63 return vrend_renderer_resource_create((struct vrend_renderer_resource_create_args *)args, iov, num_iovs, NULL);
64 }
65
virgl_renderer_resource_import_eglimage(struct virgl_renderer_resource_create_args * args,void * image)66 int virgl_renderer_resource_import_eglimage(struct virgl_renderer_resource_create_args *args, void *image)
67 {
68 #ifdef HAVE_EPOXY_EGL_H
69 return vrend_renderer_resource_create((struct vrend_renderer_resource_create_args *)args, 0, 0, image);
70 #else
71 return EINVAL;
72 #endif
73 }
74
virgl_renderer_resource_unref(uint32_t res_handle)75 void virgl_renderer_resource_unref(uint32_t res_handle)
76 {
77 vrend_renderer_resource_unref(res_handle);
78 }
79
virgl_renderer_fill_caps(uint32_t set,uint32_t version,void * caps)80 void virgl_renderer_fill_caps(uint32_t set, uint32_t version,
81 void *caps)
82 {
83 vrend_renderer_fill_caps(set, version, (union virgl_caps *)caps);
84 }
85
virgl_renderer_context_create(uint32_t handle,uint32_t nlen,const char * name)86 int virgl_renderer_context_create(uint32_t handle, uint32_t nlen, const char *name)
87 {
88 return vrend_renderer_context_create(handle, nlen, name);
89 }
90
virgl_renderer_context_destroy(uint32_t handle)91 void virgl_renderer_context_destroy(uint32_t handle)
92 {
93 vrend_renderer_context_destroy(handle);
94 }
95
virgl_renderer_submit_cmd(void * buffer,int ctx_id,int ndw)96 int virgl_renderer_submit_cmd(void *buffer,
97 int ctx_id,
98 int ndw)
99 {
100 return vrend_decode_block(ctx_id, buffer, ndw);
101 }
102
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)103 int virgl_renderer_transfer_write_iov(uint32_t handle,
104 uint32_t ctx_id,
105 int level,
106 uint32_t stride,
107 uint32_t layer_stride,
108 struct virgl_box *box,
109 uint64_t offset,
110 struct iovec *iovec,
111 unsigned int iovec_cnt)
112 {
113 struct vrend_transfer_info transfer_info;
114
115 transfer_info.handle = handle;
116 transfer_info.ctx_id = ctx_id;
117 transfer_info.level = level;
118 transfer_info.stride = stride;
119 transfer_info.layer_stride = layer_stride;
120 transfer_info.box = (struct pipe_box *)box;
121 transfer_info.offset = offset;
122 transfer_info.iovec = iovec;
123 transfer_info.iovec_cnt = iovec_cnt;
124
125 return vrend_renderer_transfer_iov(&transfer_info, VREND_TRANSFER_WRITE);
126 }
127
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)128 int virgl_renderer_transfer_read_iov(uint32_t handle, uint32_t ctx_id,
129 uint32_t level, uint32_t stride,
130 uint32_t layer_stride,
131 struct virgl_box *box,
132 uint64_t offset, struct iovec *iovec,
133 int iovec_cnt)
134 {
135 struct vrend_transfer_info transfer_info;
136
137 transfer_info.handle = handle;
138 transfer_info.ctx_id = ctx_id;
139 transfer_info.level = level;
140 transfer_info.stride = stride;
141 transfer_info.layer_stride = layer_stride;
142 transfer_info.box = (struct pipe_box *)box;
143 transfer_info.offset = offset;
144 transfer_info.iovec = iovec;
145 transfer_info.iovec_cnt = iovec_cnt;
146
147 return vrend_renderer_transfer_iov(&transfer_info, VREND_TRANSFER_READ);
148 }
149
virgl_renderer_resource_attach_iov(int res_handle,struct iovec * iov,int num_iovs)150 int virgl_renderer_resource_attach_iov(int res_handle, struct iovec *iov,
151 int num_iovs)
152 {
153 return vrend_renderer_resource_attach_iov(res_handle, iov, num_iovs);
154 }
155
virgl_renderer_resource_detach_iov(int res_handle,struct iovec ** iov_p,int * num_iovs_p)156 void virgl_renderer_resource_detach_iov(int res_handle, struct iovec **iov_p, int *num_iovs_p)
157 {
158 return vrend_renderer_resource_detach_iov(res_handle, iov_p, num_iovs_p);
159 }
160
virgl_renderer_create_fence(int client_fence_id,uint32_t ctx_id)161 int virgl_renderer_create_fence(int client_fence_id, uint32_t ctx_id)
162 {
163 return vrend_renderer_create_fence(client_fence_id, ctx_id);
164 }
165
virgl_renderer_force_ctx_0(void)166 void virgl_renderer_force_ctx_0(void)
167 {
168 vrend_renderer_force_ctx_0();
169 }
170
virgl_renderer_ctx_attach_resource(int ctx_id,int res_handle)171 void virgl_renderer_ctx_attach_resource(int ctx_id, int res_handle)
172 {
173 vrend_renderer_attach_res_ctx(ctx_id, res_handle);
174 }
175
virgl_renderer_ctx_detach_resource(int ctx_id,int res_handle)176 void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle)
177 {
178 vrend_renderer_detach_res_ctx(ctx_id, res_handle);
179 }
180
virgl_renderer_resource_get_info(int res_handle,struct virgl_renderer_resource_info * info)181 int virgl_renderer_resource_get_info(int res_handle,
182 struct virgl_renderer_resource_info *info)
183 {
184 int ret;
185 ret = vrend_renderer_resource_get_info(res_handle, (struct vrend_renderer_resource_info *)info);
186 #ifdef HAVE_EPOXY_EGL_H
187 if (ret == 0 && use_context == CONTEXT_EGL)
188 return virgl_egl_get_fourcc_for_texture(egl_info, info->tex_id, info->virgl_format, &info->drm_fourcc);
189 #endif
190
191 return ret;
192 }
193
virgl_renderer_get_cap_set(uint32_t cap_set,uint32_t * max_ver,uint32_t * max_size)194 void virgl_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver,
195 uint32_t *max_size)
196 {
197 vrend_renderer_get_cap_set(cap_set, max_ver, max_size);
198 }
199
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)200 void virgl_renderer_get_rect(int resource_id, struct iovec *iov, unsigned int num_iovs,
201 uint32_t offset, int x, int y, int width, int height)
202 {
203 vrend_renderer_get_rect(resource_id, iov, num_iovs, offset, x, y, width, height);
204 }
205
206
207 static struct virgl_renderer_callbacks *rcbs;
208
209 static void *dev_cookie;
210
211 static struct vrend_if_cbs virgl_cbs;
212
virgl_write_fence(uint32_t fence_id)213 static void virgl_write_fence(uint32_t fence_id)
214 {
215 rcbs->write_fence(dev_cookie, fence_id);
216 }
217
create_gl_context(int scanout_idx,struct virgl_gl_ctx_param * param)218 static virgl_renderer_gl_context create_gl_context(int scanout_idx, struct virgl_gl_ctx_param *param)
219 {
220 struct virgl_renderer_gl_ctx_param vparam;
221
222 #ifdef HAVE_EPOXY_EGL_H
223 if (use_context == CONTEXT_EGL)
224 return virgl_egl_create_context(egl_info, param);
225 #endif
226 #ifdef HAVE_EPOXY_GLX_H
227 if (use_context == CONTEXT_GLX)
228 return virgl_glx_create_context(glx_info, param);
229 #endif
230 vparam.version = 1;
231 vparam.shared = param->shared;
232 vparam.major_ver = param->major_ver;
233 vparam.minor_ver = param->minor_ver;
234 return rcbs->create_gl_context(dev_cookie, scanout_idx, &vparam);
235 }
236
destroy_gl_context(virgl_renderer_gl_context ctx)237 static void destroy_gl_context(virgl_renderer_gl_context ctx)
238 {
239 #ifdef HAVE_EPOXY_EGL_H
240 if (use_context == CONTEXT_EGL)
241 return virgl_egl_destroy_context(egl_info, ctx);
242 #endif
243 #ifdef HAVE_EPOXY_GLX_H
244 if (use_context == CONTEXT_GLX)
245 return virgl_glx_destroy_context(glx_info, ctx);
246 #endif
247 return rcbs->destroy_gl_context(dev_cookie, ctx);
248 }
249
make_current(int scanout_idx,virgl_renderer_gl_context ctx)250 static int make_current(int scanout_idx, virgl_renderer_gl_context ctx)
251 {
252 #ifdef HAVE_EPOXY_EGL_H
253 if (use_context == CONTEXT_EGL)
254 return virgl_egl_make_context_current(egl_info, ctx);
255 #endif
256 #ifdef HAVE_EPOXY_GLX_H
257 if (use_context == CONTEXT_GLX)
258 return virgl_glx_make_context_current(glx_info, ctx);
259 #endif
260 return rcbs->make_current(dev_cookie, scanout_idx, ctx);
261 }
262
263 static struct vrend_if_cbs virgl_cbs = {
264 virgl_write_fence,
265 create_gl_context,
266 destroy_gl_context,
267 make_current,
268 };
269
virgl_renderer_get_cursor_data(uint32_t resource_id,uint32_t * width,uint32_t * height)270 void *virgl_renderer_get_cursor_data(uint32_t resource_id, uint32_t *width, uint32_t *height)
271 {
272 return vrend_renderer_get_cursor_contents(resource_id, width, height);
273 }
274
virgl_renderer_poll(void)275 void virgl_renderer_poll(void)
276 {
277 vrend_renderer_check_queries();
278 vrend_renderer_check_fences();
279 }
280
virgl_renderer_cleanup(UNUSED void * cookie)281 void virgl_renderer_cleanup(UNUSED void *cookie)
282 {
283 vrend_renderer_fini();
284 #ifdef HAVE_EPOXY_EGL_H
285 if (use_context == CONTEXT_EGL) {
286 virgl_egl_destroy(egl_info);
287 egl_info = NULL;
288 use_context = CONTEXT_NONE;
289 }
290 #endif
291 #ifdef HAVE_EPOXY_GLX_H
292 if (use_context == CONTEXT_GLX) {
293 virgl_glx_destroy(glx_info);
294 glx_info = NULL;
295 use_context = CONTEXT_NONE;
296 }
297 #endif
298 }
299
virgl_renderer_init(void * cookie,int flags,struct virgl_renderer_callbacks * cbs)300 int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks *cbs)
301 {
302 uint32_t renderer_flags = 0;
303 if (!cookie || !cbs)
304 return -1;
305
306 if (cbs->version < 1 || cbs->version > VIRGL_RENDERER_CALLBACKS_VERSION)
307 return -1;
308
309 dev_cookie = cookie;
310 rcbs = cbs;
311
312 if (flags & VIRGL_RENDERER_USE_EGL) {
313 #ifdef HAVE_EPOXY_EGL_H
314 int fd = -1;
315 if (cbs->version >= 2 && cbs->get_drm_fd) {
316 fd = cbs->get_drm_fd(cookie);
317 }
318 egl_info = virgl_egl_init(fd, flags & VIRGL_RENDERER_USE_SURFACELESS,
319 flags & VIRGL_RENDERER_USE_GLES);
320 if (!egl_info)
321 return -1;
322 use_context = CONTEXT_EGL;
323 #else
324 fprintf(stderr, "EGL is not supported on this platform\n");
325 return -1;
326 #endif
327 } else if (flags & VIRGL_RENDERER_USE_GLX) {
328 #ifdef HAVE_EPOXY_GLX_H
329 glx_info = virgl_glx_init();
330 if (!glx_info)
331 return -1;
332 use_context = CONTEXT_GLX;
333 #else
334 fprintf(stderr, "GLX is not supported on this platform\n");
335 return -1;
336 #endif
337 }
338
339 if (flags & VIRGL_RENDERER_THREAD_SYNC)
340 renderer_flags |= VREND_USE_THREAD_SYNC;
341
342 return vrend_renderer_init(&virgl_cbs, renderer_flags);
343 }
344
virgl_renderer_get_fd_for_texture(uint32_t tex_id,int * fd)345 int virgl_renderer_get_fd_for_texture(uint32_t tex_id, int *fd)
346 {
347 #ifdef HAVE_EPOXY_EGL_H
348 return virgl_egl_get_fd_for_texture(egl_info, tex_id, fd);
349 #else
350 return -1;
351 #endif
352 }
353
virgl_renderer_get_fd_for_texture2(uint32_t tex_id,int * fd,int * stride,int * offset)354 int virgl_renderer_get_fd_for_texture2(uint32_t tex_id, int *fd, int *stride, int *offset)
355 {
356 #ifdef HAVE_EPOXY_EGL_H
357 return virgl_egl_get_fd_for_texture2(egl_info, tex_id, fd, stride, offset);
358 #else
359 return -1;
360 #endif
361 }
362
virgl_renderer_reset(void)363 void virgl_renderer_reset(void)
364 {
365 vrend_renderer_reset();
366 }
367
virgl_renderer_get_poll_fd(void)368 int virgl_renderer_get_poll_fd(void)
369 {
370 return vrend_renderer_get_poll_fd();
371 }
372