[gtk-vnc] Re-introduce a server side pixmap via cairo to cache framebuffer

Daniel P. Berrange berrange at fedoraproject.org
Mon Nov 29 16:37:27 UTC 2010


commit 938e008c19e051922076001083d5da9a13907128
Author: Daniel P. Berrange <berrange at redhat.com>
Date:   Mon Nov 29 16:37:05 2010 +0000

    Re-introduce a server side pixmap via cairo to cache framebuffer

 gtk-vnc-0.4.2-pixmap-cache.patch |  127 ++++++++++++++++++++++++++++++++++++++
 gtk-vnc.spec                     |    9 ++-
 2 files changed, 134 insertions(+), 2 deletions(-)
---
diff --git a/gtk-vnc-0.4.2-pixmap-cache.patch b/gtk-vnc-0.4.2-pixmap-cache.patch
new file mode 100644
index 0000000..319c334
--- /dev/null
+++ b/gtk-vnc-0.4.2-pixmap-cache.patch
@@ -0,0 +1,127 @@
+commit 20a8875df00d7e6d918fa7b94aca2baebe034cb5
+Author: Daniel P. Berrange <berrange at redhat.com>
+Date:   Mon Nov 29 16:12:53 2010 +0000
+
+    Re-introduce a server side Pixmap to cache framebuffer
+    
+    Despite use of clipping during drawing, rendering directly
+    from the client side cairo image, to the window incurred
+    a serious performance penalty for some users' X servers.
+    Re-introduce a server side copy of the VNC desktop using
+    a cairo surface, backed by an X Pixmap. This uses cairo
+    APIs directly, avoiding any need for GdkPixmap.
+
+diff --git a/src/vncdisplay.c b/src/vncdisplay.c
+index 0b7e800..33d2623 100644
+--- a/src/vncdisplay.c
++++ b/src/vncdisplay.c
+@@ -50,6 +50,7 @@ struct _VncDisplayPrivate
+ 
+ 	VncConnection *conn;
+ 	VncCairoFramebuffer *fb;
++	cairo_surface_t *fbCache; /* Cache on server display */
+ 
+ 	VncDisplayDepthColor depth;
+ 
+@@ -282,6 +283,32 @@ static GdkCursor *create_null_cursor(void)
+ 	return cursor;
+ }
+ 
++
++static void setup_surface_cache(VncDisplay *dpy, cairo_t *crWin, int w, int h)
++{
++	VncDisplayPrivate *priv = dpy->priv;
++	cairo_surface_t *win = cairo_get_target(crWin);
++	cairo_t *crCache;
++
++	if (priv->fbCache)
++		return;
++
++	/* Creates a Pixmap on the X11 server matching the Window */
++	priv->fbCache = cairo_surface_create_similar(win,
++						     CAIRO_CONTENT_COLOR,
++						     w, h);
++	crCache = cairo_create(priv->fbCache);
++
++	/* Copy our local framebuffer contents to the Pixmap */
++	cairo_set_source_surface(crCache,
++				 vnc_cairo_framebuffer_get_surface(priv->fb),
++				 0,
++				 0);
++	cairo_paint(crCache);
++
++	cairo_destroy(crCache);
++}
++
+ static gboolean draw_event(GtkWidget *widget, cairo_t *cr)
+ {
+ 	VncDisplay *obj = VNC_DISPLAY(widget);
+@@ -293,6 +320,8 @@ static gboolean draw_event(GtkWidget *widget, cairo_t *cr)
+ 	if (priv->fb) {
+ 		fbw = vnc_framebuffer_get_width(VNC_FRAMEBUFFER(priv->fb));
+ 		fbh = vnc_framebuffer_get_height(VNC_FRAMEBUFFER(priv->fb));
++
++		setup_surface_cache(obj, cr, fbw, fbh);
+ 	}
+ 
+ 	gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
+@@ -327,12 +356,12 @@ static gboolean draw_event(GtkWidget *widget, cairo_t *cr)
+ 			sy = (double)wh / (double)fbh;
+ 			cairo_scale(cr, sx, sy);
+ 			cairo_set_source_surface(cr,
+-						 vnc_cairo_framebuffer_get_surface(priv->fb),
++						 priv->fbCache,
+ 						 0,
+ 						 0);
+ 		} else {
+ 			cairo_set_source_surface(cr,
+-						 vnc_cairo_framebuffer_get_surface(priv->fb),
++						 priv->fbCache,
+ 						 mx,
+ 						 my);
+ 		}
+@@ -848,6 +877,22 @@ static void on_framebuffer_update(VncConnection *conn G_GNUC_UNUSED,
+ 
+ 	gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
+ 
++	/* If we have a pixmap, update the region which changed.
++	 * If we don't have a pixmap, the entire thing will be
++	 * created & rendered during the drawing handler
++	 */
++	if (priv->fbCache) {
++		cairo_t *cr = cairo_create(priv->fbCache);
++		cairo_surface_t *surface = vnc_cairo_framebuffer_get_surface(priv->fb);
++
++		cairo_rectangle(cr, x, y, w, h);
++		cairo_clip(cr);
++		cairo_set_source_surface(cr, surface, 0, 0);
++		cairo_paint(cr);
++
++		cairo_destroy(cr);
++	}
++
+ 	if (priv->allow_scaling) {
+ 		double sx, sy;
+ 
+@@ -905,6 +950,10 @@ static void do_framebuffer_init(VncDisplay *obj,
+ 		g_object_unref(priv->fb);
+ 		priv->fb = NULL;
+ 	}
++	if (priv->fbCache) {
++		cairo_surface_destroy(priv->fbCache);
++		priv->fbCache = NULL;
++	}
+ 
+ 	if (priv->null_cursor == NULL) {
+ 		priv->null_cursor = create_null_cursor();
+@@ -1496,6 +1545,10 @@ static void vnc_display_finalize (GObject *obj)
+ 		g_object_unref(priv->fb);
+ 		priv->fb = NULL;
+ 	}
++	if (priv->fbCache) {
++		cairo_surface_destroy(priv->fbCache);
++		priv->fbCache = NULL;
++	}
+ 
+ 	if (priv->null_cursor) {
+ 		gdk_cursor_unref (priv->null_cursor);
diff --git a/gtk-vnc.spec b/gtk-vnc.spec
index 2f8cd06..0684812 100644
--- a/gtk-vnc.spec
+++ b/gtk-vnc.spec
@@ -11,20 +11,21 @@
 %endif
 
 %define with_gtk3 0
-%if 0%{fedora} >= 15
+%if 0%{?fedora} >= 15
 %define with_gtk3 1
 %endif
 
 Summary: A GTK2 widget for VNC clients
 Name: gtk-vnc
 Version: 0.4.2
-Release: 2%{?dist}%{?extra_release}
+Release: 3%{?dist}%{?extra_release}
 License: LGPLv2+
 Group: Development/Libraries
 Source: http://ftp.gnome.org/pub/GNOME/sources/%{name}/0.4/%{name}-%{version}.tar.bz2
 Patch1: %{name}-%{version}-motion-event-crash.patch
 Patch2: %{name}-%{version}-tls-shutdown-crash.patch
 Patch3: %{name}-%{version}-framebuffer-update-bounds-check.patch
+Patch4: %{name}-%{version}-pixmap-cache.patch
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 URL: http://live.gnome.org/gtk-vnc
 BuildRequires: gtk2-devel >= 2.14
@@ -152,6 +153,7 @@ cd %{name}-%{version}
 %patch1 -p1
 %patch2 -p1
 %patch3 -p1
+%patch4 -p1
 cd ..
 %if %{with_gtk3}
 cp -a gtk-vnc-%{version} gtk-vnc2-%{version}
@@ -297,6 +299,9 @@ rm -fr %{buildroot}
 
 
 %changelog
+* Mon Nov 29 2010 Daniel P. Berrange <berrange at redhat.com> - 0.4.2-3
+- Re-introduce a server side pixmap via cairo to cache framebuffer (rhbz #657542)
+
 * Mon Nov 29 2010 Daniel P. Berrange <berrange at redhat.com> - 0.4.2-2
 - Fix crash in TLS shutdown code (rhbz #650601)
 - Fix crash in motion event handler (rhbz #650104)


More information about the scm-commits mailing list