diff --git a/hw/display/virtio-gpu-udmabuf-stubs.c b/hw/display/virtio-gpu-udmabuf-stubs.c index 81f661441a..f692e13510 100644 --- a/hw/display/virtio-gpu-udmabuf-stubs.c +++ b/hw/display/virtio-gpu-udmabuf-stubs.c @@ -20,7 +20,8 @@ void virtio_gpu_fini_udmabuf(struct virtio_gpu_simple_resource *res) int virtio_gpu_update_dmabuf(VirtIOGPU *g, uint32_t scanout_id, struct virtio_gpu_simple_resource *res, - struct virtio_gpu_framebuffer *fb) + struct virtio_gpu_framebuffer *fb, + struct virtio_gpu_rect *r) { /* nothing (stub) */ return 0; diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c index 60ea7f8f49..1597921c51 100644 --- a/hw/display/virtio-gpu-udmabuf.c +++ b/hw/display/virtio-gpu-udmabuf.c @@ -171,7 +171,8 @@ static VGPUDMABuf *virtio_gpu_create_dmabuf(VirtIOGPU *g, uint32_t scanout_id, struct virtio_gpu_simple_resource *res, - struct virtio_gpu_framebuffer *fb) + struct virtio_gpu_framebuffer *fb, + struct virtio_gpu_rect *r) { VGPUDMABuf *dmabuf; @@ -183,6 +184,10 @@ static VGPUDMABuf dmabuf->buf.width = fb->width; dmabuf->buf.height = fb->height; dmabuf->buf.stride = fb->stride; + dmabuf->buf.x = r->x; + dmabuf->buf.y = r->y; + dmabuf->buf.scanout_width = r->width; + dmabuf->buf.scanout_height = r->height; dmabuf->buf.fourcc = qemu_pixman_to_drm_format(fb->format); dmabuf->buf.fd = res->dmabuf_fd; dmabuf->buf.allow_fences = true; @@ -196,24 +201,25 @@ static VGPUDMABuf int virtio_gpu_update_dmabuf(VirtIOGPU *g, uint32_t scanout_id, struct virtio_gpu_simple_resource *res, - struct virtio_gpu_framebuffer *fb) + struct virtio_gpu_framebuffer *fb, + struct virtio_gpu_rect *r) { struct virtio_gpu_scanout *scanout = &g->parent_obj.scanout[scanout_id]; VGPUDMABuf *new_primary, *old_primary = NULL; - new_primary = virtio_gpu_create_dmabuf(g, scanout_id, res, fb); + new_primary = virtio_gpu_create_dmabuf(g, scanout_id, res, fb, r); if (!new_primary) { return -EINVAL; } - if (g->dmabuf.primary) { - old_primary = g->dmabuf.primary; + if (g->dmabuf.primary[scanout_id]) { + old_primary = g->dmabuf.primary[scanout_id]; } - g->dmabuf.primary = new_primary; + g->dmabuf.primary[scanout_id] = new_primary; qemu_console_resize(scanout->con, - new_primary->buf.width, - new_primary->buf.height); + new_primary->buf.scanout_width, + new_primary->buf.scanout_height); dpy_gl_scanout_dmabuf(scanout->con, &new_primary->buf); if (old_primary) { diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 182e0868b0..d78b9700c7 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -517,9 +517,9 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g, console_has_gl(scanout->con)) { dpy_gl_update(scanout->con, 0, 0, scanout->width, scanout->height); - return; } } + return; } if (!res->blob && @@ -627,7 +627,7 @@ static void virtio_gpu_do_set_scanout(VirtIOGPU *g, if (res->blob) { if (console_has_gl(scanout->con)) { - if (!virtio_gpu_update_dmabuf(g, scanout_id, res, fb)) { + if (!virtio_gpu_update_dmabuf(g, scanout_id, res, fb, r)) { virtio_gpu_update_scanout(g, scanout_id, res, r); return; } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 24c6628944..acfba7c76c 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -187,7 +187,7 @@ struct VirtIOGPU { struct { QTAILQ_HEAD(, VGPUDMABuf) bufs; - VGPUDMABuf *primary; + VGPUDMABuf *primary[VIRTIO_GPU_MAX_SCANOUTS]; } dmabuf; }; @@ -273,7 +273,8 @@ void virtio_gpu_fini_udmabuf(struct virtio_gpu_simple_resource *res); int virtio_gpu_update_dmabuf(VirtIOGPU *g, uint32_t scanout_id, struct virtio_gpu_simple_resource *res, - struct virtio_gpu_framebuffer *fb); + struct virtio_gpu_framebuffer *fb, + struct virtio_gpu_rect *r); /* virtio-gpu-3d.c */ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, diff --git a/include/ui/console.h b/include/ui/console.h index b6bedc5f41..6d678924f6 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -167,6 +167,10 @@ typedef struct QemuDmaBuf { uint32_t fourcc; uint64_t modifier; uint32_t texture; + uint32_t x; + uint32_t y; + uint32_t scanout_width; + uint32_t scanout_height; bool y0_top; void *sync; int fence_fd; diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index 385a3fa752..3a88245b67 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -90,14 +90,31 @@ void egl_fb_setup_new_tex(egl_fb *fb, int width, int height) void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip) { - GLuint y1, y2; + GLuint x1 = 0; + GLuint y1 = 0; + GLuint x2, y2; + GLuint w = src->width; + GLuint h = src->height; glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->framebuffer); glViewport(0, 0, dst->width, dst->height); - y1 = flip ? src->height : 0; - y2 = flip ? 0 : src->height; - glBlitFramebuffer(0, y1, src->width, y2, + + if (src->dmabuf) { + x1 = src->dmabuf->x; + y1 = src->dmabuf->y; + w = src->dmabuf->scanout_width; + h = src->dmabuf->scanout_height; + } + + w = (x1 + w) > src->width ? src->width - x1 : w; + h = (y1 + h) > src->height ? src->height - y1 : h; + + y2 = flip ? y1 : h + y1; + y1 = flip ? h + y1 : y1; + x2 = x1 + w; + + glBlitFramebuffer(x1, y1, x2, y2, 0, 0, dst->width, dst->height, GL_COLOR_BUFFER_BIT, GL_LINEAR); } diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index e912b20075..f2026e4b5c 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -152,8 +152,13 @@ void gd_egl_refresh(DisplayChangeListener *dcl) } vc->gfx.gls = qemu_gl_init_shader(); if (vc->gfx.ds) { + surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds); surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds); } + if (vc->gfx.guest_fb.dmabuf) { + egl_dmabuf_release_texture(vc->gfx.guest_fb.dmabuf); + gd_egl_scanout_dmabuf(dcl, vc->gfx.guest_fb.dmabuf); + } } graphic_hw_update(dcl->con); @@ -178,6 +183,8 @@ void gd_egl_switch(DisplayChangeListener *dcl, surface_height(vc->gfx.ds) == surface_height(surface)) { resized = false; } + eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, + vc->gfx.esurface, vc->gfx.ectx); surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds); vc->gfx.ds = surface; @@ -237,6 +244,9 @@ void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl, #ifdef CONFIG_GBM VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, + vc->gfx.esurface, vc->gfx.ectx); + egl_dmabuf_import_texture(dmabuf); if (!dmabuf->texture) { return; diff --git a/ui/gtk.c b/ui/gtk.c index b0564d80c1..d2892ea6b4 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -778,6 +778,9 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) if (!vc->gfx.ds) { return FALSE; } + if (!vc->gfx.surface) { + return FALSE; + } vc->gfx.dcl.update_interval = gd_monitor_update_interval(vc->window ? vc->window : s->window); @@ -1242,6 +1245,16 @@ static gboolean gd_tab_window_close(GtkWidget *widget, GdkEvent *event, vc->tab_item, vc->label); gtk_widget_destroy(vc->window); vc->window = NULL; +#if defined(CONFIG_OPENGL) + if (vc->gfx.esurface) { + eglDestroySurface(qemu_egl_display, vc->gfx.esurface); + vc->gfx.esurface = NULL; + } + if (vc->gfx.ectx) { + eglDestroyContext(qemu_egl_display, vc->gfx.ectx); + vc->gfx.ectx = NULL; + } +#endif return TRUE; } @@ -1271,6 +1284,16 @@ static void gd_menu_untabify(GtkMenuItem *item, void *opaque) if (!vc->window) { gtk_widget_set_sensitive(vc->menu_item, false); vc->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); +#if defined(CONFIG_OPENGL) + if (vc->gfx.esurface) { + eglDestroySurface(qemu_egl_display, vc->gfx.esurface); + vc->gfx.esurface = NULL; + } + if (vc->gfx.esurface) { + eglDestroyContext(qemu_egl_display, vc->gfx.ectx); + vc->gfx.ectx = NULL; + } +#endif gd_widget_reparent(s->notebook, vc->window, vc->tab_item); g_signal_connect(vc->window, "delete-event",