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 /* create our own EGL offscreen rendering context via gbm and rendernodes */
25
26
27 /* if we are using EGL and rendernodes then we talk via file descriptors to the remote
28 node */
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #define EGL_EGLEXT_PROTOTYPES
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <stdbool.h>
37 #include <xf86drm.h>
38
39 #include "util/u_memory.h"
40
41 #include "virglrenderer.h"
42 #include "vrend_winsys.h"
43 #include "vrend_winsys_egl.h"
44 #include "virgl_hw.h"
45 #include "vrend_winsys_gbm.h"
46 #include "virgl_util.h"
47
48 #define EGL_KHR_SURFACELESS_CONTEXT BIT(0)
49 #define EGL_KHR_CREATE_CONTEXT BIT(1)
50 #define EGL_MESA_DRM_IMAGE BIT(2)
51 #define EGL_MESA_IMAGE_DMA_BUF_EXPORT BIT(3)
52 #define EGL_MESA_DMA_BUF_IMAGE_IMPORT BIT(4)
53 #define EGL_KHR_GL_COLORSPACE BIT(5)
54 #define EGL_EXT_IMAGE_DMA_BUF_IMPORT BIT(6)
55 #define EGL_EXT_IMAGE_DMA_BUF_IMPORT_MODIFIERS BIT(7)
56 #define EGL_KHR_FENCE_SYNC_ANDROID BIT(8)
57
58 static const struct {
59 uint32_t bit;
60 const char *string;
61 } extensions_list[] = {
62 { EGL_KHR_SURFACELESS_CONTEXT, "EGL_KHR_surfaceless_context" },
63 { EGL_KHR_CREATE_CONTEXT, "EGL_KHR_create_context" },
64 { EGL_MESA_DRM_IMAGE, "EGL_MESA_drm_image" },
65 { EGL_MESA_IMAGE_DMA_BUF_EXPORT, "EGL_MESA_image_dma_buf_export" },
66 { EGL_KHR_GL_COLORSPACE, "EGL_KHR_gl_colorspace" },
67 { EGL_EXT_IMAGE_DMA_BUF_IMPORT, "EGL_EXT_image_dma_buf_import" },
68 { EGL_EXT_IMAGE_DMA_BUF_IMPORT_MODIFIERS, "EGL_EXT_image_dma_buf_import_modifiers" },
69 { EGL_KHR_FENCE_SYNC_ANDROID, "EGL_ANDROID_native_fence_sync"}
70 };
71
72 struct virgl_egl {
73 struct virgl_gbm *gbm;
74 EGLDisplay egl_display;
75 EGLConfig egl_conf;
76 EGLContext egl_ctx;
77 uint32_t extension_bits;
78 EGLSyncKHR signaled_fence;
79 };
80
virgl_egl_has_extension_in_string(const char * haystack,const char * needle)81 static bool virgl_egl_has_extension_in_string(const char *haystack, const char *needle)
82 {
83 const unsigned needle_len = strlen(needle);
84
85 if (needle_len == 0)
86 return false;
87
88 while (true) {
89 const char *const s = strstr(haystack, needle);
90
91 if (s == NULL)
92 return false;
93
94 if (s[needle_len] == ' ' || s[needle_len] == '\0') {
95 return true;
96 }
97
98 /* strstr found an extension whose name begins with
99 * needle, but whose name is not equal to needle.
100 * Restart the search at s + needle_len so that we
101 * don't just find the same extension again and go
102 * into an infinite loop.
103 */
104 haystack = s + needle_len;
105 }
106
107 return false;
108 }
109
virgl_egl_init_extensions(struct virgl_egl * egl,const char * extensions)110 static int virgl_egl_init_extensions(struct virgl_egl *egl, const char *extensions)
111 {
112 for (uint32_t i = 0; i < ARRAY_SIZE(extensions_list); i++) {
113 if (virgl_egl_has_extension_in_string(extensions, extensions_list[i].string))
114 egl->extension_bits |= extensions_list[i].bit;
115 }
116
117 if (!has_bits(egl->extension_bits, EGL_KHR_SURFACELESS_CONTEXT | EGL_KHR_CREATE_CONTEXT)) {
118 vrend_printf( "Missing EGL_KHR_surfaceless_context or EGL_KHR_create_context\n");
119 return -1;
120 }
121
122 return 0;
123 }
124
virgl_egl_init(struct virgl_gbm * gbm,bool surfaceless,bool gles)125 struct virgl_egl *virgl_egl_init(struct virgl_gbm *gbm, bool surfaceless, bool gles)
126 {
127 static EGLint conf_att[] = {
128 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
129 EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
130 EGL_RED_SIZE, 1,
131 EGL_GREEN_SIZE, 1,
132 EGL_BLUE_SIZE, 1,
133 EGL_ALPHA_SIZE, 0,
134 EGL_NONE,
135 };
136 static const EGLint ctx_att[] = {
137 EGL_CONTEXT_CLIENT_VERSION, 2,
138 EGL_NONE
139 };
140 EGLBoolean success;
141 EGLenum api;
142 EGLint major, minor, num_configs;
143 const char *extensions;
144 struct virgl_egl *egl;
145
146 egl = calloc(1, sizeof(struct virgl_egl));
147 if (!egl)
148 return NULL;
149
150 if (gles)
151 conf_att[3] = EGL_OPENGL_ES2_BIT;
152
153 if (surfaceless)
154 conf_att[1] = EGL_PBUFFER_BIT;
155 else if (!gbm)
156 goto fail;
157
158 egl->gbm = gbm;
159 const char *client_extensions = eglQueryString (NULL, EGL_EXTENSIONS);
160
161 if (client_extensions && strstr(client_extensions, "EGL_KHR_platform_base")) {
162 PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display =
163 (PFNEGLGETPLATFORMDISPLAYEXTPROC) eglGetProcAddress ("eglGetPlatformDisplay");
164
165 if (!get_platform_display)
166 goto fail;
167
168 if (surfaceless) {
169 egl->egl_display = get_platform_display (EGL_PLATFORM_SURFACELESS_MESA,
170 EGL_DEFAULT_DISPLAY, NULL);
171 } else
172 egl->egl_display = get_platform_display (EGL_PLATFORM_GBM_KHR,
173 (EGLNativeDisplayType)egl->gbm->device, NULL);
174 } else if (client_extensions && strstr(client_extensions, "EGL_EXT_platform_base")) {
175 PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display =
176 (PFNEGLGETPLATFORMDISPLAYEXTPROC) eglGetProcAddress ("eglGetPlatformDisplayEXT");
177
178 if (!get_platform_display)
179 goto fail;
180
181 if (surfaceless) {
182 egl->egl_display = get_platform_display (EGL_PLATFORM_SURFACELESS_MESA,
183 EGL_DEFAULT_DISPLAY, NULL);
184 } else
185 egl->egl_display = get_platform_display (EGL_PLATFORM_GBM_KHR,
186 (EGLNativeDisplayType)egl->gbm->device, NULL);
187 } else {
188 egl->egl_display = eglGetDisplay((EGLNativeDisplayType)egl->gbm->device);
189 }
190
191 if (!egl->egl_display) {
192 /*
193 * Don't fallback to the default display if the fd provided by (*get_drm_fd)
194 * can't be used.
195 */
196 if (egl->gbm && egl->gbm->fd < 0)
197 goto fail;
198
199 egl->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
200 if (!egl->egl_display)
201 goto fail;
202 }
203
204 success = eglInitialize(egl->egl_display, &major, &minor);
205 if (!success)
206 goto fail;
207
208 extensions = eglQueryString(egl->egl_display, EGL_EXTENSIONS);
209 #ifdef VIRGL_EGL_DEBUG
210 vrend_printf( "EGL major/minor: %d.%d\n", major, minor);
211 vrend_printf( "EGL version: %s\n",
212 eglQueryString(egl->egl_display, EGL_VERSION));
213 vrend_printf( "EGL vendor: %s\n",
214 eglQueryString(egl->egl_display, EGL_VENDOR));
215 vrend_printf( "EGL extensions: %s\n", extensions);
216 #endif
217
218 if (virgl_egl_init_extensions(egl, extensions))
219 goto fail;
220
221 if (gles)
222 api = EGL_OPENGL_ES_API;
223 else
224 api = EGL_OPENGL_API;
225 success = eglBindAPI(api);
226 if (!success)
227 goto fail;
228
229 success = eglChooseConfig(egl->egl_display, conf_att, &egl->egl_conf,
230 1, &num_configs);
231 if (!success || num_configs != 1)
232 goto fail;
233
234 egl->egl_ctx = eglCreateContext(egl->egl_display, egl->egl_conf, EGL_NO_CONTEXT,
235 ctx_att);
236 if (!egl->egl_ctx)
237 goto fail;
238
239 eglMakeCurrent(egl->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
240 egl->egl_ctx);
241
242 if (gles && virgl_egl_supports_fences(egl)) {
243 egl->signaled_fence = eglCreateSyncKHR(egl->egl_display,
244 EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
245 if (!egl->signaled_fence) {
246 vrend_printf("Failed to create signaled fence");
247 goto fail;
248 }
249 }
250
251 return egl;
252
253 fail:
254 free(egl);
255 return NULL;
256 }
257
virgl_egl_destroy(struct virgl_egl * egl)258 void virgl_egl_destroy(struct virgl_egl *egl)
259 {
260 if (egl->signaled_fence) {
261 eglDestroySyncKHR(egl->egl_display, egl->signaled_fence);
262 }
263 eglMakeCurrent(egl->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
264 EGL_NO_CONTEXT);
265 eglDestroyContext(egl->egl_display, egl->egl_ctx);
266 eglTerminate(egl->egl_display);
267 free(egl);
268 }
269
virgl_egl_create_context(struct virgl_egl * egl,struct virgl_gl_ctx_param * vparams)270 virgl_renderer_gl_context virgl_egl_create_context(struct virgl_egl *egl, struct virgl_gl_ctx_param *vparams)
271 {
272 EGLContext egl_ctx;
273 EGLint ctx_att[] = {
274 EGL_CONTEXT_CLIENT_VERSION, vparams->major_ver,
275 EGL_CONTEXT_MINOR_VERSION_KHR, vparams->minor_ver,
276 EGL_NONE
277 };
278 egl_ctx = eglCreateContext(egl->egl_display,
279 egl->egl_conf,
280 vparams->shared ? eglGetCurrentContext() : EGL_NO_CONTEXT,
281 ctx_att);
282 return (virgl_renderer_gl_context)egl_ctx;
283 }
284
virgl_egl_destroy_context(struct virgl_egl * egl,virgl_renderer_gl_context virglctx)285 void virgl_egl_destroy_context(struct virgl_egl *egl, virgl_renderer_gl_context virglctx)
286 {
287 EGLContext egl_ctx = (EGLContext)virglctx;
288 eglDestroyContext(egl->egl_display, egl_ctx);
289 }
290
virgl_egl_make_context_current(struct virgl_egl * egl,virgl_renderer_gl_context virglctx)291 int virgl_egl_make_context_current(struct virgl_egl *egl, virgl_renderer_gl_context virglctx)
292 {
293 EGLContext egl_ctx = (EGLContext)virglctx;
294
295 return eglMakeCurrent(egl->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
296 egl_ctx);
297 }
298
virgl_egl_get_current_context(UNUSED struct virgl_egl * egl)299 virgl_renderer_gl_context virgl_egl_get_current_context(UNUSED struct virgl_egl *egl)
300 {
301 EGLContext egl_ctx = eglGetCurrentContext();
302 return (virgl_renderer_gl_context)egl_ctx;
303 }
304
virgl_egl_get_fourcc_for_texture(struct virgl_egl * egl,uint32_t tex_id,uint32_t format,int * fourcc)305 int virgl_egl_get_fourcc_for_texture(struct virgl_egl *egl, uint32_t tex_id, uint32_t format, int *fourcc)
306 {
307 int ret = EINVAL;
308 uint32_t gbm_format = 0;
309
310 EGLImageKHR image;
311 EGLBoolean success;
312
313 if (!has_bit(egl->extension_bits, EGL_MESA_IMAGE_DMA_BUF_EXPORT)) {
314 ret = 0;
315 goto fallback;
316 }
317
318 image = eglCreateImageKHR(egl->egl_display, eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR,
319 (EGLClientBuffer)(unsigned long)tex_id, NULL);
320
321 if (!image)
322 return EINVAL;
323
324 success = eglExportDMABUFImageQueryMESA(egl->egl_display, image, fourcc, NULL, NULL);
325 if (!success)
326 goto out_destroy;
327 ret = 0;
328 out_destroy:
329 eglDestroyImageKHR(egl->egl_display, image);
330 return ret;
331
332 fallback:
333 ret = virgl_gbm_convert_format(&format, &gbm_format);
334 *fourcc = (int)gbm_format;
335 return ret;
336 }
337
virgl_egl_get_fd_for_texture2(struct virgl_egl * egl,uint32_t tex_id,int * fd,int * stride,int * offset)338 int virgl_egl_get_fd_for_texture2(struct virgl_egl *egl, uint32_t tex_id, int *fd,
339 int *stride, int *offset)
340 {
341 int ret = EINVAL;
342 EGLImageKHR image = eglCreateImageKHR(egl->egl_display, eglGetCurrentContext(),
343 EGL_GL_TEXTURE_2D_KHR,
344 (EGLClientBuffer)(unsigned long)tex_id, NULL);
345 if (!image)
346 return EINVAL;
347 if (!has_bit(egl->extension_bits, EGL_MESA_IMAGE_DMA_BUF_EXPORT))
348 goto out_destroy;
349
350 if (!eglExportDMABUFImageMESA(egl->egl_display, image, fd,
351 stride, offset))
352 goto out_destroy;
353
354 ret = 0;
355
356 out_destroy:
357 eglDestroyImageKHR(egl->egl_display, image);
358 return ret;
359 }
360
virgl_egl_get_fd_for_texture(struct virgl_egl * egl,uint32_t tex_id,int * fd)361 int virgl_egl_get_fd_for_texture(struct virgl_egl *egl, uint32_t tex_id, int *fd)
362 {
363 EGLImageKHR image;
364 EGLint stride;
365 EGLint offset;
366 EGLBoolean success;
367 int ret;
368 image = eglCreateImageKHR(egl->egl_display, eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR,
369 (EGLClientBuffer)(unsigned long)tex_id, NULL);
370
371 if (!image)
372 return EINVAL;
373
374 ret = EINVAL;
375 if (has_bit(egl->extension_bits, EGL_MESA_IMAGE_DMA_BUF_EXPORT)) {
376 success = eglExportDMABUFImageMESA(egl->egl_display, image, fd, &stride,
377 &offset);
378 if (!success)
379 goto out_destroy;
380 } else if (has_bit(egl->extension_bits, EGL_MESA_DRM_IMAGE)) {
381 EGLint handle;
382 success = eglExportDRMImageMESA(egl->egl_display, image, NULL, &handle,
383 &stride);
384
385 if (!success)
386 goto out_destroy;
387
388 if (!egl->gbm)
389 goto out_destroy;
390
391 ret = virgl_gbm_export_fd(egl->gbm->device, handle, fd);
392 if (ret < 0)
393 goto out_destroy;
394 } else {
395 goto out_destroy;
396 }
397
398 ret = 0;
399 out_destroy:
400 eglDestroyImageKHR(egl->egl_display, image);
401 return ret;
402 }
403
virgl_has_egl_khr_gl_colorspace(struct virgl_egl * egl)404 bool virgl_has_egl_khr_gl_colorspace(struct virgl_egl *egl)
405 {
406 return has_bit(egl->extension_bits, EGL_KHR_GL_COLORSPACE);
407 }
408
virgl_egl_image_from_dmabuf(struct virgl_egl * egl,uint32_t width,uint32_t height,uint32_t drm_format,uint64_t drm_modifier,uint32_t plane_count,const int * plane_fds,const uint32_t * plane_strides,const uint32_t * plane_offsets)409 void *virgl_egl_image_from_dmabuf(struct virgl_egl *egl,
410 uint32_t width,
411 uint32_t height,
412 uint32_t drm_format,
413 uint64_t drm_modifier,
414 uint32_t plane_count,
415 const int *plane_fds,
416 const uint32_t *plane_strides,
417 const uint32_t *plane_offsets)
418 {
419 EGLint attrs[6 + VIRGL_GBM_MAX_PLANES * 10 + 1];
420 uint32_t count;
421
422 assert(VIRGL_GBM_MAX_PLANES <= 4);
423 assert(plane_count && plane_count <= VIRGL_GBM_MAX_PLANES);
424
425 count = 0;
426 attrs[count++] = EGL_WIDTH;
427 attrs[count++] = width;
428 attrs[count++] = EGL_HEIGHT;
429 attrs[count++] = height;
430 attrs[count++] = EGL_LINUX_DRM_FOURCC_EXT;
431 attrs[count++] = drm_format;
432 for (uint32_t i = 0; i < plane_count; i++) {
433 if (i < 3) {
434 attrs[count++] = EGL_DMA_BUF_PLANE0_FD_EXT + i * 3;
435 attrs[count++] = plane_fds[i];
436 attrs[count++] = EGL_DMA_BUF_PLANE0_PITCH_EXT + i * 3;
437 attrs[count++] = plane_strides[i];
438 attrs[count++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT + i * 3;
439 attrs[count++] = plane_offsets[i];
440 }
441
442 if (has_bit(egl->extension_bits, EGL_EXT_IMAGE_DMA_BUF_IMPORT_MODIFIERS)) {
443 if (i == 3) {
444 attrs[count++] = EGL_DMA_BUF_PLANE3_FD_EXT;
445 attrs[count++] = plane_fds[i];
446 attrs[count++] = EGL_DMA_BUF_PLANE3_PITCH_EXT;
447 attrs[count++] = plane_strides[i];
448 attrs[count++] = EGL_DMA_BUF_PLANE3_OFFSET_EXT;
449 attrs[count++] = plane_offsets[i];
450 }
451
452 if (drm_modifier != DRM_FORMAT_MOD_INVALID) {
453 attrs[count++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT + i * 2;
454 attrs[count++] = (uint32_t)drm_modifier;
455 attrs[count++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT + i * 2;
456 attrs[count++] = (uint32_t)(drm_modifier >> 32);
457 }
458 }
459 }
460 attrs[count++] = EGL_NONE;
461 assert(count <= ARRAY_SIZE(attrs));
462
463 return (void *)eglCreateImageKHR(egl->egl_display,
464 EGL_NO_CONTEXT,
465 EGL_LINUX_DMA_BUF_EXT,
466 (EGLClientBuffer)NULL,
467 attrs);
468 }
469
virgl_egl_image_destroy(struct virgl_egl * egl,void * image)470 void virgl_egl_image_destroy(struct virgl_egl *egl, void *image)
471 {
472 eglDestroyImageKHR(egl->egl_display, image);
473 }
474
475 #ifdef ENABLE_MINIGBM_ALLOCATION
virgl_egl_image_from_gbm_bo(struct virgl_egl * egl,struct gbm_bo * bo)476 void *virgl_egl_image_from_gbm_bo(struct virgl_egl *egl, struct gbm_bo *bo)
477 {
478 int ret;
479 void *image = NULL;
480 int fds[VIRGL_GBM_MAX_PLANES] = {-1, -1, -1, -1};
481 uint32_t strides[VIRGL_GBM_MAX_PLANES];
482 uint32_t offsets[VIRGL_GBM_MAX_PLANES];
483 int num_planes = gbm_bo_get_plane_count(bo);
484
485 if (num_planes < 0 || num_planes > VIRGL_GBM_MAX_PLANES)
486 return NULL;
487
488 for (int plane = 0; plane < num_planes; plane++) {
489 uint32_t handle = gbm_bo_get_handle_for_plane(bo, plane).u32;
490 ret = virgl_gbm_export_fd(egl->gbm->device, handle, &fds[plane]);
491 if (ret < 0) {
492 vrend_printf( "failed to export plane handle\n");
493 goto out_close;
494 }
495
496 strides[plane] = gbm_bo_get_stride_for_plane(bo, plane);
497 offsets[plane] = gbm_bo_get_offset(bo, plane);
498 }
499
500 image = virgl_egl_image_from_dmabuf(egl,
501 gbm_bo_get_width(bo),
502 gbm_bo_get_height(bo),
503 gbm_bo_get_format(bo),
504 gbm_bo_get_modifier(bo),
505 num_planes,
506 fds,
507 strides,
508 offsets);
509
510 out_close:
511 for (int plane = 0; plane < num_planes; plane++)
512 close(fds[plane]);
513
514 return image;
515 }
516
virgl_egl_aux_plane_image_from_gbm_bo(struct virgl_egl * egl,struct gbm_bo * bo,int plane)517 void *virgl_egl_aux_plane_image_from_gbm_bo(struct virgl_egl *egl, struct gbm_bo *bo, int plane)
518 {
519 int ret;
520 void *image = NULL;
521 int fd = -1;
522
523 int bytes_per_pixel = virgl_gbm_get_plane_bytes_per_pixel(bo, plane);
524 if (bytes_per_pixel != 1 && bytes_per_pixel != 2)
525 return NULL;
526
527 uint32_t handle = gbm_bo_get_handle_for_plane(bo, plane).u32;
528 ret = drmPrimeHandleToFD(gbm_device_get_fd(egl->gbm->device), handle, DRM_CLOEXEC, &fd);
529 if (ret < 0) {
530 vrend_printf("failed to export plane handle %d\n", errno);
531 return NULL;
532 }
533
534 const uint32_t format = bytes_per_pixel == 1 ? GBM_FORMAT_R8 : GBM_FORMAT_GR88;
535 const uint32_t stride = gbm_bo_get_stride_for_plane(bo, plane);
536 const uint32_t offset = gbm_bo_get_offset(bo, plane);
537 image = virgl_egl_image_from_dmabuf(egl,
538 virgl_gbm_get_plane_width(bo, plane),
539 virgl_gbm_get_plane_height(bo, plane),
540 format,
541 gbm_bo_get_modifier(bo),
542 1,
543 &fd,
544 &stride,
545 &offset);
546 close(fd);
547
548 return image;
549 }
550 #endif /* ENABLE_MINIGBM_ALLOCATION */
551
virgl_egl_supports_fences(struct virgl_egl * egl)552 bool virgl_egl_supports_fences(struct virgl_egl *egl)
553 {
554 return (egl && has_bit(egl->extension_bits, EGL_KHR_FENCE_SYNC_ANDROID));
555 }
556
virgl_egl_fence_create(struct virgl_egl * egl)557 EGLSyncKHR virgl_egl_fence_create(struct virgl_egl *egl)
558 {
559 if (!egl || !has_bit(egl->extension_bits, EGL_KHR_FENCE_SYNC_ANDROID)) {
560 return EGL_NO_SYNC_KHR;
561 }
562
563 return eglCreateSyncKHR(egl->egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
564 }
565
virgl_egl_fence_destroy(struct virgl_egl * egl,EGLSyncKHR fence)566 void virgl_egl_fence_destroy(struct virgl_egl *egl, EGLSyncKHR fence) {
567 eglDestroySyncKHR(egl->egl_display, fence);
568 }
569
virgl_egl_client_wait_fence(struct virgl_egl * egl,EGLSyncKHR fence,uint64_t timeout)570 bool virgl_egl_client_wait_fence(struct virgl_egl *egl, EGLSyncKHR fence, uint64_t timeout)
571 {
572 EGLint ret = eglClientWaitSyncKHR(egl->egl_display, fence, 0, timeout);
573 if (ret == EGL_FALSE) {
574 vrend_printf("wait sync failed\n");
575 }
576 return ret != EGL_TIMEOUT_EXPIRED_KHR;
577 }
578
virgl_egl_export_signaled_fence(struct virgl_egl * egl,int * out_fd)579 bool virgl_egl_export_signaled_fence(struct virgl_egl *egl, int *out_fd) {
580 return virgl_egl_export_fence(egl, egl->signaled_fence, out_fd);
581 }
582
virgl_egl_export_fence(struct virgl_egl * egl,EGLSyncKHR fence,int * out_fd)583 bool virgl_egl_export_fence(struct virgl_egl *egl, EGLSyncKHR fence, int *out_fd) {
584 *out_fd = eglDupNativeFenceFDANDROID(egl->egl_display, fence);
585 return *out_fd != EGL_NO_NATIVE_FENCE_FD_ANDROID;
586 }
587