Index: uspace/srv/hid/display/ddev.c
===================================================================
--- uspace/srv/hid/display/ddev.c	(revision 6301a24fb081993e0e1d27b0a61a9bab72fca055)
+++ uspace/srv/hid/display/ddev.c	(revision 8aef01c4d489de18fa8cbe206afb2db10c2d6a9f)
@@ -59,4 +59,5 @@
 {
 	ds_ddev_t *ddev;
+	errno_t rc;
 
 	ddev = calloc(1, sizeof(ds_ddev_t));
@@ -70,5 +71,9 @@
 	ddev->info = *info;
 
-	ds_display_add_ddev(display, ddev);
+	rc = ds_display_add_ddev(display, ddev);
+	if (rc != EOK) {
+		free(ddev);
+		return rc;
+	}
 
 	*rddev = ddev;
Index: uspace/srv/hid/display/display.c
===================================================================
--- uspace/srv/hid/display/display.c	(revision 6301a24fb081993e0e1d27b0a61a9bab72fca055)
+++ uspace/srv/hid/display/display.c	(revision 8aef01c4d489de18fa8cbe206afb2db10c2d6a9f)
@@ -35,7 +35,9 @@
 
 #include <errno.h>
+#include <gfx/bitmap.h>
 #include <gfx/context.h>
 #include <gfx/render.h>
 #include <io/log.h>
+#include <memgfx/memgc.h>
 #include <stdlib.h>
 #include "client.h"
@@ -46,11 +48,16 @@
 #include "display.h"
 
+static gfx_context_t *ds_display_get_unbuf_gc(ds_display_t *);
+static void ds_display_update_cb(void *, gfx_rect_t *);
+
 /** Create display.
  *
  * @param gc Graphics context for displaying output
+ * @param flags Display flags
  * @param rdisp Place to store pointer to new display.
  * @return EOK on success, ENOMEM if out of memory
  */
-errno_t ds_display_create(gfx_context_t *gc, ds_display_t **rdisp)
+errno_t ds_display_create(gfx_context_t *gc, ds_display_flags_t flags,
+    ds_display_t **rdisp)
 {
 	ds_display_t *disp;
@@ -86,4 +93,5 @@
 	list_initialize(&disp->seats);
 	list_initialize(&disp->windows);
+	disp->flags = flags;
 	*rdisp = disp;
 	return EOK;
@@ -423,20 +431,92 @@
 }
 
+/** Allocate back buffer for display.
+ *
+ * @param disp Display
+ * @return EOK on success or if no back buffer is required, otherwise
+ *         an error code.
+ */
+static errno_t ds_display_alloc_backbuf(ds_display_t *disp)
+{
+	gfx_context_t *ugc;
+	gfx_bitmap_params_t params;
+	gfx_bitmap_alloc_t alloc;
+	errno_t rc;
+
+	/* Allocate backbuffer */
+	if ((disp->flags & df_disp_double_buf) == 0) {
+		/* Not double buffering. Nothing to do. */
+		return EOK;
+	}
+
+	ugc = ds_display_get_unbuf_gc(disp);
+
+	gfx_bitmap_params_init(&params);
+	params.rect = disp->rect;
+
+	rc = gfx_bitmap_create(ugc, &params, NULL,
+	    &disp->backbuf);
+	if (rc != EOK)
+		goto error;
+
+	rc = gfx_bitmap_get_alloc(disp->backbuf, &alloc);
+	if (rc != EOK)
+		goto error;
+
+	rc = mem_gc_create(&disp->rect, &alloc,
+	    ds_display_update_cb, (void *) disp, &disp->bbgc);
+	if (rc != EOK)
+		goto error;
+
+	disp->dirty_rect.p0.x = 0;
+	disp->dirty_rect.p0.y = 0;
+	disp->dirty_rect.p1.x = 0;
+	disp->dirty_rect.p1.y = 0;
+
+	return EOK;
+error:
+	if (disp->backbuf != NULL) {
+		gfx_bitmap_destroy(disp->backbuf);
+		disp->backbuf = NULL;
+	}
+
+	return rc;
+}
+
 /** Add display device to display.
  *
  * @param disp Display
  * @param ddev Display device
- */
-void ds_display_add_ddev(ds_display_t *disp, ds_ddev_t *ddev)
-{
+ * @return EOK on success, or an error code
+ */
+errno_t ds_display_add_ddev(ds_display_t *disp, ds_ddev_t *ddev)
+{
+	errno_t rc;
+
 	assert(ddev->display == NULL);
 	assert(!link_used(&ddev->lddevs));
 
-	/* Set display dimensions to dimensions of first display device */
-	if (gfx_rect_is_empty(&disp->rect))
-		disp->rect = ddev->info.rect;
-
 	ddev->display = disp;
 	list_append(&ddev->lddevs, &disp->ddevs);
+
+	/* First display device */
+	if (gfx_rect_is_empty(&disp->rect)) {
+		/* Set screen dimensions */
+		disp->rect = ddev->info.rect;
+
+		/* Allocate backbuffer */
+		rc = ds_display_alloc_backbuf(disp);
+		if (rc != EOK)
+			goto error;
+	}
+
+	return EOK;
+error:
+	disp->rect.p0.x = 0;
+	disp->rect.p0.y = 0;
+	disp->rect.p1.x = 0;
+	disp->rect.p1.y = 0;
+	list_remove(&ddev->lddevs);
+	return rc;
 }
 
@@ -506,5 +586,5 @@
 
 // XXX
-gfx_context_t *ds_display_get_gc(ds_display_t *display)
+static gfx_context_t *ds_display_get_unbuf_gc(ds_display_t *display)
 {
 	ds_ddev_t *ddev;
@@ -515,4 +595,13 @@
 
 	return ddev->gc;
+}
+
+// XXX
+gfx_context_t *ds_display_get_gc(ds_display_t *display)
+{
+	if ((display->flags & df_disp_double_buf) != 0)
+		return mem_gc_get_ctx(display->bbgc);
+	else
+		return ds_display_get_unbuf_gc(display);
 }
 
@@ -542,4 +631,32 @@
 
 	return gfx_fill_rect(gc, &crect);
+}
+
+/** Update front buffer from back buffer.
+ *
+ * If the display is not double-buffered, no action is taken.
+ *
+ * @param disp Display
+ * @return EOK on success, or an error code
+ */
+static errno_t ds_display_update(ds_display_t *disp)
+{
+	errno_t rc;
+
+	if (disp->backbuf == NULL) {
+		/* Not double-buffered, nothing to do. */
+		return EOK;
+	}
+
+	rc = gfx_bitmap_render(disp->backbuf, &disp->dirty_rect, NULL);
+	if (rc != EOK)
+		return rc;
+
+	disp->dirty_rect.p0.x = 0;
+	disp->dirty_rect.p0.y = 0;
+	disp->dirty_rect.p1.x = 0;
+	disp->dirty_rect.p1.y = 0;
+
+	return EOK;
 }
 
@@ -590,5 +707,22 @@
 	}
 
-	return EOK;
+	return ds_display_update(disp);
+}
+
+/** Display update callback.
+ *
+ * Called by backbuffer memory GC when something is rendered into it.
+ * Updates the display's dirty rectangle.
+ *
+ * @param arg Argument (display cast as void *)
+ * @param rect Rectangle to update
+ */
+static void ds_display_update_cb(void *arg, gfx_rect_t *rect)
+{
+	ds_display_t *disp = (ds_display_t *) arg;
+	gfx_rect_t env;
+
+	gfx_rect_envelope(&disp->dirty_rect, rect, &env);
+	disp->dirty_rect = env;
 }
 
Index: uspace/srv/hid/display/display.h
===================================================================
--- uspace/srv/hid/display/display.h	(revision 6301a24fb081993e0e1d27b0a61a9bab72fca055)
+++ uspace/srv/hid/display/display.h	(revision 8aef01c4d489de18fa8cbe206afb2db10c2d6a9f)
@@ -49,5 +49,6 @@
 #include "types/display/seat.h"
 
-extern errno_t ds_display_create(gfx_context_t *, ds_display_t **);
+extern errno_t ds_display_create(gfx_context_t *, ds_display_flags_t,
+    ds_display_t **);
 extern void ds_display_destroy(ds_display_t *);
 extern void ds_display_lock(ds_display_t *);
@@ -72,5 +73,5 @@
 extern ds_seat_t *ds_display_first_seat(ds_display_t *);
 extern ds_seat_t *ds_display_next_seat(ds_seat_t *);
-extern void ds_display_add_ddev(ds_display_t *, ds_ddev_t *);
+extern errno_t ds_display_add_ddev(ds_display_t *, ds_ddev_t *);
 extern void ds_display_remove_ddev(ds_ddev_t *);
 extern ds_ddev_t *ds_display_first_ddev(ds_display_t *);
Index: uspace/srv/hid/display/main.c
===================================================================
--- uspace/srv/hid/display/main.c	(revision 6301a24fb081993e0e1d27b0a61a9bab72fca055)
+++ uspace/srv/hid/display/main.c	(revision 8aef01c4d489de18fa8cbe206afb2db10c2d6a9f)
@@ -59,4 +59,17 @@
 static void display_client_ev_pending(void *);
 
+#ifdef CONFIG_DISP_DOUBLE_BUF
+/*
+ * Double buffering is one way to provide flicker-free display.
+ */
+static ds_display_flags_t disp_flags = df_disp_double_buf;
+#else
+/*
+ * With double buffering disabled, wet screen flicker since front-to-back
+ * rendering is not implemented.
+ */
+static ds_display_flags_t disp_flags = df_none;
+#endif
+
 static ds_client_cb_t display_client_cb = {
 	.ev_pending = display_client_ev_pending
@@ -81,5 +94,5 @@
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "display_srv_init()");
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, disp_flags, &disp);
 	if (rc != EOK)
 		goto error;
Index: uspace/srv/hid/display/test/client.c
===================================================================
--- uspace/srv/hid/display/test/client.c	(revision 6301a24fb081993e0e1d27b0a61a9bab72fca055)
+++ uspace/srv/hid/display/test/client.c	(revision 8aef01c4d489de18fa8cbe206afb2db10c2d6a9f)
@@ -62,5 +62,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -87,5 +87,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -132,5 +132,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -175,5 +175,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -222,5 +222,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -270,5 +270,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -327,5 +327,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -382,5 +382,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -438,5 +438,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -486,5 +486,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
Index: uspace/srv/hid/display/test/cursor.c
===================================================================
--- uspace/srv/hid/display/test/cursor.c	(revision 6301a24fb081993e0e1d27b0a61a9bab72fca055)
+++ uspace/srv/hid/display/test/cursor.c	(revision 8aef01c4d489de18fa8cbe206afb2db10c2d6a9f)
@@ -71,5 +71,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -97,5 +97,5 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
-	rc = ds_display_create(gc, &disp);
+	rc = ds_display_create(gc, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -130,5 +130,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
Index: uspace/srv/hid/display/test/display.c
===================================================================
--- uspace/srv/hid/display/test/display.c	(revision 6301a24fb081993e0e1d27b0a61a9bab72fca055)
+++ uspace/srv/hid/display/test/display.c	(revision 8aef01c4d489de18fa8cbe206afb2db10c2d6a9f)
@@ -61,5 +61,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -75,5 +75,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -102,5 +102,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -166,5 +166,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -212,5 +212,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -241,5 +241,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -289,5 +289,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -357,5 +357,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
Index: uspace/srv/hid/display/test/seat.c
===================================================================
--- uspace/srv/hid/display/test/seat.c	(revision 6301a24fb081993e0e1d27b0a61a9bab72fca055)
+++ uspace/srv/hid/display/test/seat.c	(revision 8aef01c4d489de18fa8cbe206afb2db10c2d6a9f)
@@ -66,5 +66,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -104,5 +104,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -152,5 +152,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -205,5 +205,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -272,5 +272,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -362,5 +362,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
Index: uspace/srv/hid/display/test/window.c
===================================================================
--- uspace/srv/hid/display/test/window.c	(revision 6301a24fb081993e0e1d27b0a61a9bab72fca055)
+++ uspace/srv/hid/display/test/window.c	(revision 8aef01c4d489de18fa8cbe206afb2db10c2d6a9f)
@@ -63,5 +63,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -109,5 +109,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -146,5 +146,5 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
-	rc = ds_display_create(gc, &disp);
+	rc = ds_display_create(gc, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -192,5 +192,5 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
-	rc = ds_display_create(gc, &disp);
+	rc = ds_display_create(gc, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -260,5 +260,5 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
-	rc = ds_display_create(gc, &disp);
+	rc = ds_display_create(gc, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -303,5 +303,5 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
-	rc = ds_display_create(gc, &disp);
+	rc = ds_display_create(gc, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -349,5 +349,5 @@
 	errno_t rc;
 
-	rc = ds_display_create(NULL, &disp);
+	rc = ds_display_create(NULL, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -614,5 +614,5 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
-	rc = ds_display_create(gc, &disp);
+	rc = ds_display_create(gc, df_none, &disp);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
Index: uspace/srv/hid/display/types/display/display.h
===================================================================
--- uspace/srv/hid/display/types/display/display.h	(revision 6301a24fb081993e0e1d27b0a61a9bab72fca055)
+++ uspace/srv/hid/display/types/display/display.h	(revision 8aef01c4d489de18fa8cbe206afb2db10c2d6a9f)
@@ -42,7 +42,16 @@
 #include <gfx/coord.h>
 #include <io/input.h>
+#include <memgfx/memgc.h>
 #include <types/display/cursor.h>
 #include "cursor.h"
 #include "window.h"
+
+/** Display flags */
+typedef enum {
+	/** No flags enabled */
+	df_none = 0,
+	/** Use double buffer for display */
+	df_disp_double_buf = 0x1
+} ds_display_flags_t;
 
 /** Display server display */
@@ -84,4 +93,16 @@
 	/** Bounding rectangle */
 	gfx_rect_t rect;
+
+	/** Backbuffer bitmap or @c NULL if not double-buffering */
+	gfx_bitmap_t *backbuf;
+
+	/** Backbuffer GC or @c NULL if not double-buffering */
+	mem_gc_t *bbgc;
+
+	/** Backbuffer dirty rectangle */
+	gfx_rect_t dirty_rect;
+
+	/** Display flags */
+	ds_display_flags_t flags;
 } ds_display_t;
 
