[gtk-vnc] Remove the server side framebuffer cached in GdkPixmap



commit 693d51118fc3775ef71f6f07e5b55839beacecdb
Author: Daniel P. Berrange <berrange redhat com>
Date:   Wed Oct 27 21:34:28 2010 +0100

    Remove the server side framebuffer cached in GdkPixmap
    
    For rendering efficiency a GdkPixmap was kept on the server
    duplicating what was in the old GdkImage object on the client
    side. The client was changed to use a cairo image surface.
    This can easily be rendered straight to the window and does
    not appear to have any performance degradation. Thus the
    GdkPixmap can be eliminated, avoiding the extra memory usage
    that entails
    
    * src/vncdisplay.c: Remove the GdkPixmap copy of the framebuffer

 src/vncdisplay.c |   94 ++++++++++++++++++++++++++++-------------------------
 1 files changed, 50 insertions(+), 44 deletions(-)
---
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index d754fb6..d0a04dc 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -45,7 +45,6 @@
 
 struct _VncDisplayPrivate
 {
-	GdkPixmap *pixmap;
 	GdkCursor *null_cursor;
 	GdkCursor *remote_cursor;
 
@@ -300,7 +299,7 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *expose)
 
 	/* If we don't have a pixmap, or we're not scaling, then
 	   we need to fill with background color */
-	if (!priv->pixmap ||
+	if (!priv->fb ||
 	    !priv->allow_scaling) {
 		cairo_rectangle(cr, 0, 0, ww, wh);
 		/* Optionally cut out the inner area where the pixmap
@@ -308,27 +307,29 @@ static gboolean expose_event(GtkWidget *widget, GdkEventExpose *expose)
 		   not double-buffering. Note we're using the undocumented
 		   behaviour of drawing the rectangle from right to left
 		   to cut out the whole */
-		if (priv->pixmap)
+		if (priv->fb)
 			cairo_rectangle(cr, mx + fbw, my,
 					-1 * fbw, fbh);
 		cairo_fill(cr);
 	}
 
 	/* Draw the VNC display */
-	if (priv->pixmap) {
+	if (priv->fb) {
 		if (priv->allow_scaling) {
 			double sx, sy;
 			/* Scale to fill window */
 			sx = (double)ww / (double)fbw;
 			sy = (double)wh / (double)fbh;
 			cairo_scale(cr, sx, sy);
-			gdk_cairo_set_source_pixmap(cr,
-						    priv->pixmap,
-						    0, 0);
+			cairo_set_source_surface(cr,
+						 vnc_cairo_framebuffer_get_surface(priv->fb),
+						 0,
+						 0);
 		} else {
-			gdk_cairo_set_source_pixmap(cr,
-						    priv->pixmap,
-						    mx, my);
+			cairo_set_source_surface(cr,
+						 vnc_cairo_framebuffer_get_surface(priv->fb),
+						 mx,
+						 my);
 		}
 		cairo_paint(cr);
 	}
@@ -811,22 +812,10 @@ static void on_framebuffer_update(VncConnection *conn G_GNUC_UNUSED,
 	VncDisplayPrivate *priv = obj->priv;
 	int ww, wh;
 	int fbw, fbh;
-	cairo_surface_t *surface;
-	cairo_t *cr;
 
 	fbw = vnc_framebuffer_get_width(VNC_FRAMEBUFFER(priv->fb));
 	fbh = vnc_framebuffer_get_height(VNC_FRAMEBUFFER(priv->fb));
 
-	cr = gdk_cairo_create(priv->pixmap);
-	cairo_rectangle(cr, x, y, w, h);
-	cairo_clip(cr);
-
-	surface = vnc_cairo_framebuffer_get_surface(priv->fb);
-	cairo_set_source_surface(cr, surface, 0, 0);
-	cairo_paint(cr);
-
-	cairo_destroy(cr);
-
 	gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
 
 	if (priv->allow_scaling) {
@@ -876,10 +865,6 @@ static void do_framebuffer_init(VncDisplay *obj,
 		g_object_unref(priv->fb);
 		priv->fb = NULL;
 	}
-	if (priv->pixmap) {
-		g_object_unref(priv->pixmap);
-		priv->pixmap = NULL;
-	}
 
 	if (priv->null_cursor == NULL) {
 		priv->null_cursor = create_null_cursor();
@@ -890,8 +875,6 @@ static void do_framebuffer_init(VncDisplay *obj,
 	}
 
 	priv->fb = vnc_cairo_framebuffer_new(width, height, remoteFormat);
-	priv->pixmap = gdk_pixmap_new(gtk_widget_get_window(GTK_WIDGET(obj)), width, height, -1);
-
 	vnc_connection_set_framebuffer(priv->conn, VNC_FRAMEBUFFER(priv->fb));
 
 	if (priv->force_size)
@@ -1990,31 +1973,54 @@ void vnc_display_set_read_only(VncDisplay *obj, gboolean enable)
 	obj->priv->read_only = enable;
 }
 
+static void vnc_display_convert_data(GdkPixbuf *pixbuf,
+				     cairo_surface_t *surface,
+				     int      width,
+				     int      height)
+{
+	int x, y;
+	guchar  *dest_data = gdk_pixbuf_get_pixels(pixbuf);
+	int      dest_stride = gdk_pixbuf_get_rowstride(pixbuf);
+	guchar  *src_data = cairo_image_surface_get_data(surface);
+	int      src_stride = cairo_image_surface_get_stride(surface);
+
+	for (y = 0; y < height; y++) {
+		guint32 *src = (guint32 *) src_data;
+		for (x = 0; x < width; x++) {
+			dest_data[x * 3 + 0] = src[x] >> 16;
+			dest_data[x * 3 + 1] = src[x] >>  8;
+			dest_data[x * 3 + 2] = src[x];
+		}
+
+		src_data += src_stride;
+		dest_data += dest_stride;
+	}
+}
+
 GdkPixbuf *vnc_display_get_pixbuf(VncDisplay *obj)
 {
 	VncDisplayPrivate *priv = obj->priv;
-	GdkPixbuf *pixbuf;
+	VncFramebuffer *fb;
+	cairo_content_t content;
 	cairo_surface_t *surface;
-	gint w, h;
+	GdkPixbuf *pixbuf;
 
 	if (!priv->conn ||
 	    !vnc_connection_is_initialized(priv->conn))
 		return NULL;
 
+	fb = VNC_FRAMEBUFFER(priv->fb);
 	surface = vnc_cairo_framebuffer_get_surface(priv->fb);
-	w = vnc_framebuffer_get_width(VNC_FRAMEBUFFER(priv->fb));
-	h = vnc_framebuffer_get_height(VNC_FRAMEBUFFER(priv->fb));
-
-	pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
-				w,
-				h);
-
-	if (!gdk_pixbuf_get_from_drawable(pixbuf,
-					  priv->pixmap,
-					  NULL,
-					  0, 0, 0, 0,
-					  w, h))
-		return NULL;
+	content = cairo_surface_get_content(surface) | CAIRO_CONTENT_COLOR;
+	pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
+				!!(content & CAIRO_CONTENT_ALPHA),
+				8,
+				vnc_framebuffer_get_width(fb),
+				vnc_framebuffer_get_height(fb));
+
+	vnc_display_convert_data(pixbuf, surface,
+				 vnc_framebuffer_get_width(fb),
+				 vnc_framebuffer_get_height(fb));
 
 	return pixbuf;
 }
@@ -2068,7 +2074,7 @@ gboolean vnc_display_set_scaling(VncDisplay *obj,
 
 	obj->priv->allow_scaling = enable;
 
-	if (obj->priv->pixmap != NULL) {
+	if (obj->priv->fb != NULL) {
 		gdk_drawable_get_size(gtk_widget_get_window(GTK_WIDGET(obj)), &ww, &wh);
 		gtk_widget_queue_draw_area(GTK_WIDGET(obj), 0, 0, ww, wh);
 	}



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