qemu-trivial
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] ui/gtk: Properly scale OpenGL content on GTK frontend


From: James
Subject: [PATCH] ui/gtk: Properly scale OpenGL content on GTK frontend
Date: Thu, 27 May 2021 22:05:32 +1000

This patch enables proper aspect ratio scaling on virgl enabled guests on
GTK OpenGL mode (previously guest framebuffer is stretched). This patch also
enables proper HiDPI scaling on the same scenario (previously guest would
appear smaller and resides on bottom-left on the screen if GTK scaling value
is more than 1).

At the moment the glClear function call is commented out. I'm afraid that it
will damage performance on certain GPUs. I think that I will submit another
patch for UI/GTK so that the ww, wh, fbw, fbh, and other values are only
computed when guest resolution changes or the GTK window is resized. What do
you think about this?

Note that this is not to be confused with my previous patch. That one fix
HiDPI scaling when OpenGL mode is enabled, but without virgl support from
guest (e.g. when in BIOS or host's OpenGL failed to initialise).

Signed-off-by: James <j1@ionbox.in>
---
 include/ui/egl-helpers.h |  3 +++
 ui/egl-helpers.c         | 18 ++++++++++++++++--
 ui/gtk-egl.c             | 32 ++++++++++++++++++++++++--------
 3 files changed, 43 insertions(+), 10 deletions(-)

diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h
index f1bf8f97fc..76c3932b41 100644
--- a/include/ui/egl-helpers.h
+++ b/include/ui/egl-helpers.h
@@ -16,6 +16,8 @@ extern DisplayGLMode qemu_egl_mode;
 typedef struct egl_fb {
     int width;
     int height;
+    int offset_x;
+    int offset_y;
     GLuint texture;
     GLuint framebuffer;
     bool delete_texture;
@@ -27,6 +29,7 @@ void egl_fb_setup_for_tex(egl_fb *fb, int width, int height,
                           GLuint texture, bool delete);
 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);
+void egl_fb_clear(egl_fb *dst);
 void egl_fb_read(DisplaySurface *dst, egl_fb *src);
 
 void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip);
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index 6d0cb2b5cb..e4cf100a74 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -47,6 +47,8 @@ void egl_fb_destroy(egl_fb *fb)
 
     fb->width = 0;
     fb->height = 0;
+    fb->offset_x = 0;
+    fb->offset_y = 0;
     fb->texture = 0;
     fb->framebuffer = 0;
 }
@@ -55,6 +57,8 @@ void egl_fb_setup_default(egl_fb *fb, int width, int height)
 {
     fb->width = width;
     fb->height = height;
+    fb->offset_x = 0;
+    fb->offset_y = 0;
     fb->framebuffer = 0; /* default framebuffer */
 }
 
@@ -65,6 +69,8 @@ void egl_fb_setup_for_tex(egl_fb *fb, int width, int height,
 
     fb->width = width;
     fb->height = height;
+    fb->offset_x = 0;
+    fb->offset_y = 0;
     fb->texture = texture;
     fb->delete_texture = delete;
     if (!fb->framebuffer) {
@@ -94,14 +100,22 @@ void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip)
 
     glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer);
     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->framebuffer);
-    glViewport(0, 0, dst->width, dst->height);
+    glViewport(dst->offset_x, dst->offset_y, 
+               dst->width + dst->offset_x, dst->height + dst->offset_y);
     y1 = flip ? src->height : 0;
     y2 = flip ? 0 : src->height;
     glBlitFramebuffer(0, y1, src->width, y2,
-                      0, 0, dst->width, dst->height,
+                      dst->offset_x, dst->offset_y,
+                      dst->width + dst->offset_x, dst->height + dst->offset_y,
                       GL_COLOR_BUFFER_BIT, GL_LINEAR);
 }
 
+void egl_fb_clear(egl_fb *dst)
+{
+    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->framebuffer);
+    glClear(GL_COLOR_BUFFER_BIT);
+}
+
 void egl_fb_read(DisplaySurface *dst, egl_fb *src)
 {
     glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer);
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index 2a2e6d3a17..c440434b4c 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -62,7 +62,8 @@ void gd_egl_init(VirtualConsole *vc)
 void gd_egl_draw(VirtualConsole *vc)
 {
     GdkWindow *window;
-    int ww, wh;
+    int ww, wh, wsf;
+    double scale;
 
     if (!vc->gfx.gls) {
         return;
@@ -71,12 +72,15 @@ void gd_egl_draw(VirtualConsole *vc)
     window = gtk_widget_get_window(vc->gfx.drawing_area);
     ww = gdk_window_get_width(window);
     wh = gdk_window_get_height(window);
+    wsf = gdk_window_get_scale_factor(window);
 
     if (vc->gfx.scanout_mode) {
         gd_egl_scanout_flush(&vc->gfx.dcl, 0, 0, vc->gfx.w, vc->gfx.h);
 
-        vc->gfx.scale_x = (double)ww / vc->gfx.w;
-        vc->gfx.scale_y = (double)wh / vc->gfx.h;
+        scale = MIN((double)ww / vc->gfx.w, (double)wh / vc->gfx.h);
+        vc->gfx.scale_x = scale;
+        vc->gfx.scale_y = scale;
+
     } else {
         if (!vc->gfx.ds) {
             return;
@@ -84,7 +88,7 @@ void gd_egl_draw(VirtualConsole *vc)
         eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
                        vc->gfx.esurface, vc->gfx.ectx);
 
-        surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
+        surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww * wsf, wh * wsf);
         surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
 
         eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
@@ -262,7 +266,8 @@ void gd_egl_scanout_flush(DisplayChangeListener *dcl,
 {
     VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
     GdkWindow *window;
-    int ww, wh;
+    int ww, wh, wsf;
+    int fbw, fbh;
 
     if (!vc->gfx.scanout_mode) {
         return;
@@ -275,9 +280,18 @@ void gd_egl_scanout_flush(DisplayChangeListener *dcl,
                    vc->gfx.esurface, vc->gfx.ectx);
 
     window = gtk_widget_get_window(vc->gfx.drawing_area);
-    ww = gdk_window_get_width(window);
-    wh = gdk_window_get_height(window);
-    egl_fb_setup_default(&vc->gfx.win_fb, ww, wh);
+    wsf = gdk_window_get_scale_factor(window);
+    ww = gdk_window_get_width(window) * wsf;
+    wh = gdk_window_get_height(window) * wsf;
+    fbw = wsf * vc->gfx.guest_fb.width * vc->gfx.scale_x;
+    fbh = wsf * vc->gfx.guest_fb.height * vc->gfx.scale_y;
+    egl_fb_setup_default(&vc->gfx.win_fb, fbw, fbh);
+    if (ww > fbw) {
+        vc->gfx.win_fb.offset_x = (ww - fbw) / 2;
+    } else {
+        vc->gfx.win_fb.offset_y = (wh - fbh) / 2;
+    }
+    
     if (vc->gfx.cursor_fb.texture) {
         egl_texture_blit(vc->gfx.gls, &vc->gfx.win_fb, &vc->gfx.guest_fb,
                          vc->gfx.y0_top);
@@ -286,6 +300,8 @@ void gd_egl_scanout_flush(DisplayChangeListener *dcl,
                           vc->gfx.cursor_x, vc->gfx.cursor_y,
                           vc->gfx.scale_x, vc->gfx.scale_y);
     } else {
+        /* will enable this on later patches */
+        /* egl_fb_clear(&vc->gfx.win_fb); */
         egl_fb_blit(&vc->gfx.win_fb, &vc->gfx.guest_fb, !vc->gfx.y0_top);
     }
 
-- 
2.25.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]