[Spice-commits] 9 commits - src/channel-display.c src/channel-main.c src/spice-widget.c src/spice-widget-egl.c src/spice-widget-priv.h

Marc-André Lureau elmarco at kemper.freedesktop.org
Thu Mar 24 15:56:19 UTC 2016


 src/channel-display.c   |    4 +-
 src/channel-main.c      |   29 +++++++++++------
 src/spice-widget-egl.c  |   22 +++++++++----
 src/spice-widget-priv.h |    4 ++
 src/spice-widget.c      |   78 ++++++++++++++++++++++++++++++++----------------
 5 files changed, 93 insertions(+), 44 deletions(-)

New commits:
commit c075c54729bf168efd916fdcbca55a77458209e1
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Mon Mar 21 18:50:36 2016 +0100

    widget: modify update-area to not require primary surface
    
    If egl display is enabled, use GL scanout geometry to check intersection
    with the monitor area. This solves displaying GL display without
    software canvas (currently d->area is empty and gl drawing fails)
    
    Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
    Acked-by: Pavel Grunt <pgrunt at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index fdac085..21b1c14 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -2188,32 +2188,47 @@ static void update_area(SpiceDisplay *display,
                         gint x, gint y, gint width, gint height)
 {
     SpiceDisplayPrivate *d = display->priv;
-    GdkRectangle primary = {
-        .x = 0,
-        .y = 0,
-        .width = d->width,
-        .height = d->height
-    };
-    GdkRectangle area = {
+    GdkRectangle primary;
+
+    SPICE_DEBUG("update area +%d+%d %dx%d", x, y, width, height);
+    d->area = (GdkRectangle) {
         .x = x,
         .y = y,
         .width = width,
         .height = height
     };
 
-    SPICE_DEBUG("update area, primary: %dx%d, area: +%d+%d %dx%d", d->width, d->height, area.x, area.y, area.width, area.height);
+#ifndef G_OS_WIN32
+    if (d->egl.enabled) {
+        primary = (GdkRectangle) {
+            .width = d->egl.scanout.width,
+            .height = d->egl.scanout.height
+        };
+    } else
+#endif
+    {
+        primary = (GdkRectangle) {
+            .width = d->width,
+            .height = d->height
+        };
+    }
 
-    if (!gdk_rectangle_intersect(&primary, &area, &area)) {
+    SPICE_DEBUG("primary: %dx%d", primary.width, primary.height);
+    if (!gdk_rectangle_intersect(&primary, &d->area, &d->area)) {
         SPICE_DEBUG("The monitor area is not intersecting primary surface");
         memset(&d->area, '\0', sizeof(d->area));
         set_monitor_ready(display, false);
         return;
     }
 
-    spicex_image_destroy(display);
-    d->area = area;
-    if (gtk_widget_get_realized(GTK_WIDGET(display)))
-        update_image(display);
+#ifndef G_OS_WIN32
+    if (!d->egl.enabled)
+#endif
+    {
+        spicex_image_destroy(display);
+        if (gtk_widget_get_realized(GTK_WIDGET(display)))
+            update_image(display);
+    }
 
     update_size_request(display);
 
commit ec6bfc00f81afddbdcc0fac86d7039385d89c6b6
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Wed Mar 23 17:11:08 2016 +0100

    main: don't update display timer for unchanged config
    
    With virgl, set_monitor_ready() may be called each time the scanout is
    updated to set the monitor area. This will call
    spice_main_update_display(), and keep the timer postponed even if the
    monitor configuration didn't change. Treat unchanged configuration as a
    no-op and keep configuration timer unchanged. This fixes monitor
    autoconfig with virgl (when the display is regularly updated).
    
    It also solves/avoids problems with a guest running on wayland when the
    "resize-guest" property is TRUE.
    
    Fixes:
    https://bugzilla.redhat.com/show_bug.cgi?id=1266484
    
    Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
    Acked-by: Jonathon Jongsma <jjongsma at redhat.com>

diff --git a/src/channel-main.c b/src/channel-main.c
index 8dd580a..4a1f58a 100644
--- a/src/channel-main.c
+++ b/src/channel-main.c
@@ -121,6 +121,14 @@ typedef enum {
     DISPLAY_ENABLED,
 } SpiceDisplayState;
 
+typedef struct {
+    int                     x;
+    int                     y;
+    int                     width;
+    int                     height;
+    SpiceDisplayState       display_state;
+} SpiceDisplayConfig;
+
 struct _SpiceMainChannelPrivate  {
     enum SpiceMouseMode         mouse_mode;
     bool                        agent_connected;
@@ -140,13 +148,7 @@ struct _SpiceMainChannelPrivate  {
     guint                       agent_msg_pos;
     uint8_t                     agent_msg_size;
     uint32_t                    agent_caps[VD_AGENT_CAPS_SIZE];
-    struct {
-        int                     x;
-        int                     y;
-        int                     width;
-        int                     height;
-        SpiceDisplayState       display_state;
-    } display[MAX_DISPLAY];
+    SpiceDisplayConfig          display[MAX_DISPLAY];
     gint                        timer_id;
     GQueue                      *agent_msg_queue;
     GHashTable                  *file_xfer_tasks;
@@ -2688,10 +2690,15 @@ void spice_main_update_display(SpiceMainChannel *channel, int id,
 
     g_return_if_fail(id < SPICE_N_ELEMENTS(c->display));
 
-    c->display[id].x      = x;
-    c->display[id].y      = y;
-    c->display[id].width  = width;
-    c->display[id].height = height;
+    SpiceDisplayConfig display = {
+        .x = x, .y = y, .width = width, .height = height,
+        .display_state = c->display[id].display_state
+    };
+
+    if (memcmp(&display, &c->display[id], sizeof(SpiceDisplayConfig)) == 0)
+        return;
+
+    c->display[id] = display;
 
     if (update)
         update_display_timer(channel, 1);
commit 962ebf97e706df657793c45cfe58b1f17f3abb38
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Mon Mar 21 18:50:17 2016 +0100

    widget: update d->ready based on scanout image available
    
    d->ready is updated based on monitor area & canvas. In case of GL
    rendering, update it based on monitor area & scanout and add check
    before drawing update.
    
    Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
    Acked-by: Pavel Grunt <pgrunt at redhat.com>

diff --git a/src/spice-widget-egl.c b/src/spice-widget-egl.c
index b9bec68..126269f 100644
--- a/src/spice-widget-egl.c
+++ b/src/spice-widget-egl.c
@@ -396,7 +396,7 @@ void spice_egl_resize_display(SpiceDisplay *display, int w, int h)
     apply_ortho(d->egl.mproj, 0, w, 0, h, -1, 1);
     glViewport(0, 0, w, h);
 
-    if (d->egl.image)
+    if (d->ready)
         spice_egl_update_display(display);
 
     glUseProgram(prog);
@@ -506,9 +506,7 @@ void spice_egl_update_display(SpiceDisplay *display)
     gdouble tx, ty, tw, th;
     int prog;
 
-    g_return_if_fail(d->egl.image != NULL);
-    if (d->egl.surface == EGL_NO_SURFACE)
-        return;
+    g_return_if_fail(d->ready);
 
     spice_display_get_scaling(display, &s, &x, &y, &w, &h);
 
diff --git a/src/spice-widget.c b/src/spice-widget.c
index b75bcd7..fdac085 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -232,7 +232,11 @@ static void update_ready(SpiceDisplay *display)
     SpiceDisplayPrivate *d = display->priv;
     gboolean ready;
 
-    ready = d->mark != 0 && d->monitor_ready;
+    ready = d->monitor_ready &&
+#ifndef G_OS_WIN32
+        d->egl.enabled ? d->egl.image != NULL :
+#endif
+        d->mark;
 
     /* If the 'resize-guest' property is set, the application expects spice-gtk
      * to manage the size and state of the displays, so update the 'enabled'
commit 629eb3db57d2a2083669ba0d0bcdc38e61d870a8
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Mon Mar 21 18:50:28 2016 +0100

    egl: check and update scanout after egl init
    
    Once the egl/GL context are initialized, check if there is a scanout to
    associate to display widget. This solves races when scanout update is
    happening before the egl/GL context is ready.
    
    Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
    Acked-by: Pavel Grunt <pgrunt at redhat.com>

diff --git a/src/spice-widget-egl.c b/src/spice-widget-egl.c
index 151970c..b9bec68 100644
--- a/src/spice-widget-egl.c
+++ b/src/spice-widget-egl.c
@@ -272,6 +272,12 @@ end:
 
     d->egl.context_ready = TRUE;
 
+    if (spice_display_get_gl_scanout(SPICE_DISPLAY_CHANNEL(d->display)) != NULL) {
+        SPICE_DEBUG("scanout present during egl init, updating widget");
+        spice_display_widget_gl_scanout(display);
+        spice_display_widget_update_monitor_area(display);
+    }
+
     return TRUE;
 }
 
commit 75efdeaeba9a025d205f842c26b0df46121111b0
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Mon Mar 21 18:48:49 2016 +0100

    widget: make gl-scanout and update-monitor-area privately exported
    
    The following changes will call these functions from spice-widget-egl.c
    
    Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
    Acked-by: Pavel Grunt <pgrunt at redhat.com>

diff --git a/src/spice-widget-priv.h b/src/spice-widget-priv.h
index bafeb7d..95bca8a 100644
--- a/src/spice-widget-priv.h
+++ b/src/spice-widget-priv.h
@@ -163,6 +163,9 @@ gboolean spice_egl_update_scanout            (SpiceDisplay *display,
                                               GError **err);
 void     spice_egl_cursor_set                (SpiceDisplay *display);
 
+void     spice_display_widget_gl_scanout     (SpiceDisplay *display);
+void     spice_display_widget_update_monitor_area(SpiceDisplay *display);
+
 G_END_DECLS
 
 #endif
diff --git a/src/spice-widget.c b/src/spice-widget.c
index a820ed2..b75bcd7 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -262,7 +262,8 @@ static void set_monitor_ready(SpiceDisplay *self, gboolean ready)
     update_ready(self);
 }
 
-static void update_monitor_area(SpiceDisplay *display)
+G_GNUC_INTERNAL
+void spice_display_widget_update_monitor_area(SpiceDisplay *display)
 {
     SpiceDisplayPrivate *d = display->priv;
     SpiceDisplayMonitorConfig *cfg, *c = NULL;
@@ -337,7 +338,7 @@ static void spice_display_set_property(GObject      *object,
     case PROP_MONITOR_ID:
         d->monitor_id = g_value_get_int(value);
         if (d->display) /* if constructed */
-            update_monitor_area(display);
+            spice_display_widget_update_monitor_area(display);
         break;
     case PROP_KEYBOARD_GRAB:
         d->keyboard_grab_enable = g_value_get_boolean(value);
@@ -2228,7 +2229,7 @@ static void primary_create(SpiceChannel *channel, gint format,
     d->height = height;
     d->data_origin = d->data = imgdata;
 
-    update_monitor_area(display);
+    spice_display_widget_update_monitor_area(display);
 }
 
 static void primary_destroy(SpiceChannel *channel, gpointer data)
@@ -2494,7 +2495,8 @@ static void cursor_reset(SpiceCursorChannel *channel, gpointer data)
 }
 
 #ifndef G_OS_WIN32
-static void gl_scanout(SpiceDisplay *display)
+G_GNUC_INTERNAL
+void spice_display_widget_gl_scanout(SpiceDisplay *display)
 {
     SpiceDisplayPrivate *d = display->priv;
     const SpiceGlScanout *scanout;
@@ -2570,15 +2572,18 @@ static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data)
         spice_g_signal_connect_object(channel, "display-mark",
                                       G_CALLBACK(mark), display, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
         spice_g_signal_connect_object(channel, "notify::monitors",
-                                      G_CALLBACK(update_monitor_area), display, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
+                                      G_CALLBACK(spice_display_widget_update_monitor_area),
+                                      display, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
         if (spice_display_get_primary(channel, 0, &primary)) {
             primary_create(channel, primary.format, primary.width, primary.height,
                            primary.stride, primary.shmid, primary.data, display);
             mark(display, primary.marked);
         }
+
 #ifndef G_OS_WIN32
         spice_g_signal_connect_object(channel, "notify::gl-scanout",
-                                      G_CALLBACK(gl_scanout), display, G_CONNECT_SWAPPED);
+                                      G_CALLBACK(spice_display_widget_gl_scanout),
+                                      display, G_CONNECT_SWAPPED);
         spice_g_signal_connect_object(channel, "gl-draw",
                                       G_CALLBACK(gl_draw), display, G_CONNECT_SWAPPED);
 #endif
commit 81767eb4767675ee0f03888ed4d34660bb4089ba
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Mon Mar 21 19:03:43 2016 +0100

    display: return NULL in spice_display_get_gl_scanout()
    
    If there is no valid scanout, return NULL.
    
    Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
    Acked-by: Pavel Grunt <pgrunt at redhat.com>

diff --git a/src/channel-display.c b/src/channel-display.c
index 2c54df7..90d155e 100644
--- a/src/channel-display.c
+++ b/src/channel-display.c
@@ -532,7 +532,7 @@ void spice_display_change_preferred_compression(SpiceChannel *channel, gint comp
  * spice_display_get_gl_scanout:
  * @channel: a #SpiceDisplayChannel
  *
- * Returns: the current GL scanout
+ * Returns: the current GL scanout, or %NULL if none or not valid
  *
  * Since: 0.31
  **/
@@ -541,7 +541,7 @@ spice_display_get_gl_scanout(SpiceDisplayChannel *channel)
 {
     g_return_val_if_fail(SPICE_IS_DISPLAY_CHANNEL(channel), NULL);
 
-    return &channel->priv->scanout;
+    return channel->priv->scanout.fd != -1 ? &channel->priv->scanout : NULL;
 }
 
 /* ------------------------------------------------------------------ */
diff --git a/src/spice-widget.c b/src/spice-widget.c
index 03c7cd8..a820ed2 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -2506,6 +2506,7 @@ static void gl_scanout(SpiceDisplay *display)
     g_return_if_fail(d->egl.context_ready);
 
     scanout = spice_display_get_gl_scanout(SPICE_DISPLAY_CHANNEL(d->display));
+    /* should only be called when the display has a scanout */
     g_return_if_fail(scanout != NULL);
 
     if (!spice_egl_update_scanout(display, scanout, &err)) {
commit 804b50fa44023dba544094ec285b21176e69c32a
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Mar 22 13:15:38 2016 +0100

    widget: enable egl before updating scanout
    
    The GLArea is realized lazily, when it is made visible in
    set_egl_enabled(). The egl context is initialized once the GLArea is
    realized. Enable egl before updating the scanout.
    
    Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
    Acked-by: Pavel Grunt <pgrunt at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index f8bc160..03c7cd8 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -2500,14 +2500,14 @@ static void gl_scanout(SpiceDisplay *display)
     const SpiceGlScanout *scanout;
     GError *err = NULL;
 
+    SPICE_DEBUG("%s: got scanout",  __FUNCTION__);
+    set_egl_enabled(display, true);
+
     g_return_if_fail(d->egl.context_ready);
 
     scanout = spice_display_get_gl_scanout(SPICE_DISPLAY_CHANNEL(d->display));
     g_return_if_fail(scanout != NULL);
 
-    SPICE_DEBUG("%s: got scanout",  __FUNCTION__);
-    set_egl_enabled(display, true);
-
     if (!spice_egl_update_scanout(display, scanout, &err)) {
         g_critical("update scanout failed: %s", err->message);
         g_clear_error(&err);
commit ec20a61d68d3b9c5821d272bab37e41e19e20cd1
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Mon Mar 21 18:30:09 2016 +0100

    egl: check context is ready
    
    Add a new GL status field to check if the GL context is ready. This
    helps debugging races where GL is called before the context is ready.
    
    Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
    Acked-by: Pavel Grunt <pgrunt at redhat.com>

diff --git a/src/spice-widget-egl.c b/src/spice-widget-egl.c
index 3bdc806..151970c 100644
--- a/src/spice-widget-egl.c
+++ b/src/spice-widget-egl.c
@@ -207,7 +207,7 @@ gboolean spice_egl_init(SpiceDisplay *display, GError **err)
         d->egl.ctx = eglGetCurrentContext();
         dpy = (EGLNativeDisplayType)gdk_wayland_display_get_wl_display(gdk_dpy);
         d->egl.display = eglGetDisplay(dpy);
-        return spice_egl_init_shaders(display, err);
+        goto end;
     }
 #endif
 #ifdef GDK_WINDOWING_X11
@@ -266,7 +266,13 @@ gboolean spice_egl_init(SpiceDisplay *display, GError **err)
     eglMakeCurrent(d->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE,
                    d->egl.ctx);
 
-    return spice_egl_init_shaders(display, err);
+end:
+    if (!spice_egl_init_shaders(display, err))
+        return FALSE;
+
+    d->egl.context_ready = TRUE;
+
+    return TRUE;
 }
 
 static gboolean spice_widget_init_egl_win(SpiceDisplay *display, GdkWindow *win,
diff --git a/src/spice-widget-priv.h b/src/spice-widget-priv.h
index 2f7e39e..bafeb7d 100644
--- a/src/spice-widget-priv.h
+++ b/src/spice-widget-priv.h
@@ -129,6 +129,7 @@ struct _SpiceDisplayPrivate {
 #endif
 #ifndef G_OS_WIN32
     struct {
+        gboolean            context_ready;
         gboolean            enabled;
         EGLSurface          surface;
         EGLDisplay          display;
diff --git a/src/spice-widget.c b/src/spice-widget.c
index 2a64443..f8bc160 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -2500,6 +2500,8 @@ static void gl_scanout(SpiceDisplay *display)
     const SpiceGlScanout *scanout;
     GError *err = NULL;
 
+    g_return_if_fail(d->egl.context_ready);
+
     scanout = spice_display_get_gl_scanout(SPICE_DISPLAY_CHANNEL(d->display));
     g_return_if_fail(scanout != NULL);
 
@@ -2518,8 +2520,11 @@ static void gl_draw(SpiceDisplay *display,
     SpiceDisplayPrivate *d = display->priv;
 
     SPICE_DEBUG("%s",  __FUNCTION__);
+
     set_egl_enabled(display, true);
 
+    g_return_if_fail(d->egl.context_ready);
+
 #if GTK_CHECK_VERSION(3,16,0)
     GtkWidget *gl = gtk_stack_get_child_by_name(GTK_STACK(display), "gl-area");
 
commit f6d351662d8db8eaf16d13245d6781409561c684
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Mon Mar 21 18:49:51 2016 +0100

    widget: remove superflous WIN32 check
    
    The egl call is already inside a X11 conditional block.
    
    Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
    Acked-by: Pavel Grunt <pgrunt at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index 08040d3..2a64443 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -578,13 +578,11 @@ drawing_area_realize(GtkWidget *area, gpointer user_data)
         g_clear_error(&err);
     }
 
-#ifndef G_OS_WIN32
     if (!spice_egl_realize_display(display, gtk_widget_get_window(area), &err)) {
         g_critical("egl realize failed: %s", err->message);
         g_clear_error(&err);
     }
 #endif
-#endif
 }
 
 static void spice_display_init(SpiceDisplay *display)


More information about the Spice-commits mailing list