From: Dongwon Kim <dongwon....@intel.com> It is required to ensure the current scanout frame is completed before transitioning guest's run-state to save to prevent potential guest waiting for the response on the resource flush of the old scanout frame upon resume.
v2: Giving some time for the fence to be signaled before flushing the pipeline v3: Prevent redudant call of gd_hw_gl_flushed by checking dmabuf and fence_fd >= 0 in it (e.g. during and after eglClientWaitSync in gd_change_runstate) v4: Rewrote the commit msg Creating fence_fd in the same function where sync is created to handle the case where the valid sync is created but fence_fd is failed to be created. 0 is a valid fd so any fence_fd > -1 for the fence in draw function in gtk-egl.c and gtk-gl-area.c will be considered valid egl_sync and fence_fd for it are created in the same function Cc: Marc-André Lureau <marcandre.lur...@redhat.com> Cc: Vivek Kasireddy <vivek.kasire...@intel.com> Signed-off-by: Dongwon Kim <dongwon....@intel.com> --- ui/egl-helpers.c | 16 ++++++---------- ui/gtk-egl.c | 10 ++-------- ui/gtk-gl-area.c | 9 ++------- ui/gtk.c | 31 +++++++++++++++++++++++++++---- 4 files changed, 37 insertions(+), 29 deletions(-) diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index 3d19dbe382..b6a8169ffc 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -376,20 +376,16 @@ void egl_dmabuf_create_sync(QemuDmaBuf *dmabuf) EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); if (sync != EGL_NO_SYNC_KHR) { dmabuf->sync = sync; + dmabuf->fence_fd = eglDupNativeFenceFDANDROID(qemu_egl_display, + dmabuf->sync); + if (dmabuf->fence_fd < 0) { + eglDestroySyncKHR(qemu_egl_display, dmabuf->sync); + dmabuf->sync = NULL; + } } } } -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; - } -} - #endif /* CONFIG_GBM */ /* ---------------------------------------------------------------------- */ diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index 3af5ac5bcf..683a87c6b3 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -98,8 +98,8 @@ void gd_egl_draw(VirtualConsole *vc) glFlush(); #ifdef CONFIG_GBM if (dmabuf) { - egl_dmabuf_create_fence(dmabuf); - if (dmabuf->fence_fd > 0) { + egl_dmabuf_create_sync(dmabuf); + if (dmabuf->fence_fd > -1) { qemu_set_fd_handler(dmabuf->fence_fd, gd_hw_gl_flushed, NULL, vc); return; } @@ -348,12 +348,6 @@ void gd_egl_scanout_flush(DisplayChangeListener *dcl, egl_fb_blit(&vc->gfx.win_fb, &vc->gfx.guest_fb, !vc->gfx.y0_top); } -#ifdef CONFIG_GBM - if (vc->gfx.guest_fb.dmabuf) { - egl_dmabuf_create_sync(vc->gfx.guest_fb.dmabuf); - } -#endif - eglSwapBuffers(qemu_egl_display, vc->gfx.esurface); } diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index 52dcac161e..7791498646 100644 --- a/ui/gtk-gl-area.c +++ b/ui/gtk-gl-area.c @@ -77,16 +77,11 @@ void gd_gl_area_draw(VirtualConsole *vc) glBlitFramebuffer(0, y1, vc->gfx.w, y2, 0, 0, ww, wh, GL_COLOR_BUFFER_BIT, GL_NEAREST); -#ifdef CONFIG_GBM - if (dmabuf) { - egl_dmabuf_create_sync(dmabuf); - } -#endif glFlush(); #ifdef CONFIG_GBM if (dmabuf) { - egl_dmabuf_create_fence(dmabuf); - if (dmabuf->fence_fd > 0) { + egl_dmabuf_create_sync(dmabuf); + if (dmabuf->fence_fd > -1) { qemu_set_fd_handler(dmabuf->fence_fd, gd_hw_gl_flushed, NULL, vc); return; } diff --git a/ui/gtk.c b/ui/gtk.c index 810d7fc796..bbe05a0baf 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -597,10 +597,14 @@ void gd_hw_gl_flushed(void *vcon) VirtualConsole *vc = vcon; QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf; - qemu_set_fd_handler(dmabuf->fence_fd, NULL, NULL, NULL); - close(dmabuf->fence_fd); - dmabuf->fence_fd = -1; - graphic_hw_gl_block(vc->gfx.dcl.con, false); + if (dmabuf && dmabuf->fence_fd > -1) { + qemu_set_fd_handler(dmabuf->fence_fd, NULL, NULL, NULL); + close(dmabuf->fence_fd); + dmabuf->fence_fd = -1; + eglDestroySyncKHR(qemu_egl_display, dmabuf->sync); + dmabuf->sync = NULL; + graphic_hw_gl_block(vc->gfx.dcl.con, false); + } } /** DisplayState Callbacks (opengl version) **/ @@ -678,6 +682,25 @@ static const DisplayGLCtxOps egl_ctx_ops = { static void gd_change_runstate(void *opaque, bool running, RunState state) { GtkDisplayState *s = opaque; + int i; + + if (state == RUN_STATE_SAVE_VM) { + for (i = 0; i < s->nb_vcs; i++) { + VirtualConsole *vc = &s->vc[i]; + + if (vc->gfx.guest_fb.dmabuf && + vc->gfx.guest_fb.dmabuf->fence_fd >= 0) { + eglClientWaitSync(qemu_egl_display, + vc->gfx.guest_fb.dmabuf->sync, + EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, + 100000000); + + /* force flushing current scanout blob rendering process + * just in case the fence is still not signaled */ + gd_hw_gl_flushed(vc); + } + } + } gd_update_caption(s); } -- 2.34.1