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