@@ -169,6 +169,8 @@ typedef struct QemuDmaBuf {
uint32_t texture;
bool y0_top;
void *sync;
+ bool blob;
+ int fence_fd;
} QemuDmaBuf;
typedef struct DisplayState DisplayState;
@@ -19,6 +19,7 @@ typedef struct egl_fb {
GLuint texture;
GLuint framebuffer;
bool delete_texture;
+ QemuDmaBuf *dmabuf;
} egl_fb;
void egl_fb_destroy(egl_fb *fb);
@@ -45,6 +46,9 @@ int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc,
void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf);
void egl_dmabuf_release_texture(QemuDmaBuf *dmabuf);
+void egl_dmabuf_create_sync(QemuDmaBuf *dmabuf);
+void egl_dmabuf_create_fence(QemuDmaBuf *dmabuf);
+void egl_dmabuf_wait_sync(QemuDmaBuf *dmabuf);
#endif
@@ -76,6 +76,50 @@ void egl_fb_setup_for_tex(egl_fb *fb, int width, int height,
GL_TEXTURE_2D, fb->texture, 0);
}
+void egl_dmabuf_create_sync(QemuDmaBuf *dmabuf)
+{
+ EGLSyncKHR sync;
+
+ if (epoxy_has_egl_extension(qemu_egl_display,
+ "EGL_KHR_fence_sync") &&
+ epoxy_has_egl_extension(qemu_egl_display,
+ "EGL_ANDROID_native_fence_sync")) {
+ sync = eglCreateSyncKHR(qemu_egl_display,
+ EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+ if (sync != EGL_NO_SYNC_KHR) {
+ dmabuf->sync = sync;
+ }
+ }
+}
+
+void egl_dmabuf_create_fence(QemuDmaBuf *dmabuf)
+{
+ if (dmabuf->sync) {
+ dmabuf->fence_fd = eglDupNativeFenceFDANDROID(qemu_egl_display,
+ dmabuf->sync);
+ eglDestroySyncKHR(qemu_egl_display, dmabuf->sync);
+ dmabuf->sync = NULL;
+ }
+}
+
+void egl_dmabuf_wait_sync(QemuDmaBuf *dmabuf)
+{
+ EGLSyncKHR sync;
+ EGLint attrib_list[] = {
+ EGL_SYNC_NATIVE_FENCE_FD_ANDROID, dmabuf->fence_fd,
+ EGL_NONE,
+ };
+
+ sync = eglCreateSyncKHR(qemu_egl_display,
+ EGL_SYNC_NATIVE_FENCE_ANDROID, attrib_list);
+ if (sync != EGL_NO_SYNC_KHR) {
+ eglClientWaitSyncKHR(qemu_egl_display, sync,
+ 0, EGL_FOREVER_KHR);
+ eglDestroySyncKHR(qemu_egl_display, sync);
+ dmabuf->fence_fd = -1;
+ }
+}
+
void egl_fb_setup_new_tex(egl_fb *fb, int width, int height)
{
GLuint texture;
@@ -209,6 +209,8 @@ void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
QemuDmaBuf *dmabuf)
{
#ifdef CONFIG_GBM
+ VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
egl_dmabuf_import_texture(dmabuf);
if (!dmabuf->texture) {
return;
@@ -217,6 +219,10 @@ void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
gd_egl_scanout_texture(dcl, dmabuf->texture,
false, dmabuf->width, dmabuf->height,
0, 0, dmabuf->width, dmabuf->height);
+
+ if (dmabuf->blob) {
+ vc->gfx.guest_fb.dmabuf = dmabuf;
+ }
#endif
}
@@ -289,6 +295,10 @@ void gd_egl_scanout_flush(DisplayChangeListener *dcl,
egl_fb_blit(&vc->gfx.win_fb, &vc->gfx.guest_fb, !vc->gfx.y0_top);
}
+ if (vc->gfx.guest_fb.dmabuf) {
+ egl_dmabuf_create_sync(vc->gfx.guest_fb.dmabuf);
+ }
+
eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
}
@@ -71,6 +71,10 @@ void gd_gl_area_draw(VirtualConsole *vc)
surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
}
+ if (vc->gfx.guest_fb.dmabuf) {
+ egl_dmabuf_create_sync(vc->gfx.guest_fb.dmabuf);
+ }
+
glFlush();
graphic_hw_gl_flushed(vc->gfx.dcl.con);
}
@@ -231,6 +235,10 @@ void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl,
gd_gl_area_scanout_texture(dcl, dmabuf->texture,
false, dmabuf->width, dmabuf->height,
0, 0, dmabuf->width, dmabuf->height);
+
+ if (dmabuf->blob) {
+ vc->gfx.guest_fb.dmabuf = dmabuf;
+ }
#endif
}
@@ -630,6 +630,19 @@ static bool gd_has_dmabuf(DisplayChangeListener *dcl)
return vc->gfx.has_dmabuf;
}
+static void gd_gl_wait_dmabuf(DisplayChangeListener *dcl,
+ QemuDmaBuf *dmabuf)
+{
+#ifdef CONFIG_GBM
+ egl_dmabuf_create_fence(dmabuf);
+ if (dmabuf->fence_fd <= 0) {
+ return;
+ }
+
+ egl_dmabuf_wait_sync(dmabuf);
+#endif
+}
+
/** DisplayState Callbacks (opengl version) **/
static const DisplayChangeListenerOps dcl_gl_area_ops = {
@@ -648,6 +661,7 @@ static const DisplayChangeListenerOps dcl_gl_area_ops = {
.dpy_gl_scanout_disable = gd_gl_area_scanout_disable,
.dpy_gl_update = gd_gl_area_scanout_flush,
.dpy_gl_scanout_dmabuf = gd_gl_area_scanout_dmabuf,
+ .dpy_gl_wait_dmabuf = gd_gl_wait_dmabuf,
.dpy_has_dmabuf = gd_has_dmabuf,
};
@@ -672,6 +686,7 @@ static const DisplayChangeListenerOps dcl_egl_ops = {
.dpy_gl_cursor_position = gd_egl_cursor_position,
.dpy_gl_release_dmabuf = gd_egl_release_dmabuf,
.dpy_gl_update = gd_egl_scanout_flush,
+ .dpy_gl_wait_dmabuf = gd_gl_wait_dmabuf,
.dpy_has_dmabuf = gd_has_dmabuf,
};
These egl helpers will be useful for creating a sync object and waiting on it when called from the virtio-gpu wait_flush API. Cc: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com> --- include/ui/console.h | 2 ++ include/ui/egl-helpers.h | 4 ++++ ui/egl-helpers.c | 44 ++++++++++++++++++++++++++++++++++++++++ ui/gtk-egl.c | 10 +++++++++ ui/gtk-gl-area.c | 8 ++++++++ ui/gtk.c | 15 ++++++++++++++ 6 files changed, 83 insertions(+)