Index: uspace/lib/ipcgfx/src/client.c
===================================================================
--- uspace/lib/ipcgfx/src/client.c	(revision c8cf261a450bf22fa6cc6e9872a1f07f9e7dccda)
+++ uspace/lib/ipcgfx/src/client.c	(revision da41254778976dfa4ab1b54a56ef57de822fb353)
@@ -36,7 +36,9 @@
  */
 
+#include <as.h>
 #include <ipcgfx/client.h>
 #include <ipcgfx/ipc/gc.h>
 #include <gfx/color.h>
+#include <gfx/coord.h>
 #include <gfx/context.h>
 #include <stdlib.h>
@@ -45,8 +47,17 @@
 static errno_t ipc_gc_set_color(void *, gfx_color_t *);
 static errno_t ipc_gc_fill_rect(void *, gfx_rect_t *);
+static errno_t ipc_gc_bitmap_create(void *, gfx_bitmap_params_t *,
+    gfx_bitmap_alloc_t *, void **);
+static errno_t ipc_gc_bitmap_destroy(void *);
+static errno_t ipc_gc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
+static errno_t ipc_gc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
 
 gfx_context_ops_t ipc_gc_ops = {
 	.set_color = ipc_gc_set_color,
-	.fill_rect = ipc_gc_fill_rect
+	.fill_rect = ipc_gc_fill_rect,
+	.bitmap_create = ipc_gc_bitmap_create,
+	.bitmap_destroy = ipc_gc_bitmap_destroy,
+	.bitmap_render = ipc_gc_bitmap_render,
+	.bitmap_get_alloc = ipc_gc_bitmap_get_alloc
 };
 
@@ -101,4 +112,184 @@
 }
 
+/** Create bitmap in IPC GC.
+ *
+ * @param arg IPC GC
+ * @param params Bitmap params
+ * @param alloc Bitmap allocation info or @c NULL
+ * @param rbm Place to store pointer to new bitmap
+ * @return EOK on success or an error code
+ */
+errno_t ipc_gc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
+    gfx_bitmap_alloc_t *alloc, void **rbm)
+{
+	ipc_gc_t *ipcgc = (ipc_gc_t *) arg;
+	ipc_gc_bitmap_t *ipcbm = NULL;
+	gfx_coord2_t dim;
+	async_exch_t *exch = NULL;
+	ipc_call_t answer;
+	aid_t req;
+	errno_t rc;
+
+	ipcbm = calloc(1, sizeof(ipc_gc_bitmap_t));
+	if (ipcbm == NULL)
+		return ENOMEM;
+
+	gfx_coord2_subtract(&params->rect.p1, &params->rect.p0, &dim);
+	ipcbm->rect = params->rect;
+
+	if (alloc == NULL) {
+		ipcbm->alloc.pitch = dim.x * sizeof(uint32_t);
+		ipcbm->alloc.off0 = 0;
+		ipcbm->alloc.pixels = as_area_create(AS_AREA_ANY,
+		    dim.x * dim.y * sizeof(uint32_t), AS_AREA_READ |
+		    AS_AREA_WRITE | AS_AREA_CACHEABLE, AS_AREA_UNPAGED);
+		if (ipcbm->alloc.pixels == NULL) {
+			rc = ENOMEM;
+			goto error;
+		}
+
+		ipcbm->myalloc = true;
+	} else {
+		/*
+		 * XXX We could allow this if the pixels point to a shareable
+		 * area or we could do a copy of the data when rendering
+		 */
+		rc = ENOTSUP;
+		goto error;
+	}
+
+	exch = async_exchange_begin(ipcgc->sess);
+	req = async_send_0(exch, GC_BITMAP_CREATE, &answer);
+	rc = async_data_write_start(exch, params, sizeof (gfx_bitmap_params_t));
+	if (rc != EOK) {
+		async_forget(req);
+		goto error;
+	}
+
+	rc = async_share_out_start(exch, ipcbm->alloc.pixels,
+	    AS_AREA_READ | AS_AREA_CACHEABLE);
+	if (rc != EOK) {
+		async_forget(req);
+		goto error;
+	}
+	async_exchange_end(exch);
+	exch = NULL;
+
+	async_wait_for(req, &rc);
+	if (rc != EOK)
+		goto error;
+
+	ipcbm->ipcgc = ipcgc;
+	ipcbm->bmp_id = ipc_get_arg1(&answer);
+	*rbm = (void *)ipcbm;
+	return EOK;
+error:
+	if (exch != NULL)
+		async_exchange_end(exch);
+	if (ipcbm != NULL) {
+		if (ipcbm->alloc.pixels != NULL)
+			as_area_destroy(ipcbm->alloc.pixels);
+		free(ipcbm);
+	}
+	return rc;
+}
+
+/** Destroy bitmap in IPC GC.
+ *
+ * @param bm Bitmap
+ * @return EOK on success or an error code
+ */
+static errno_t ipc_gc_bitmap_destroy(void *bm)
+{
+	ipc_gc_bitmap_t *ipcbm = (ipc_gc_bitmap_t *)bm;
+	async_exch_t *exch;
+	errno_t rc;
+
+	printf("ipc_gc_bitmap_destroy\n");
+
+	exch = async_exchange_begin(ipcbm->ipcgc->sess);
+	rc = async_req_1_0(exch, GC_BITMAP_DESTROY, ipcbm->bmp_id);
+	async_exchange_end(exch);
+
+	if (rc != EOK)
+		return rc;
+
+	if (ipcbm->myalloc)
+		as_area_destroy(ipcbm->alloc.pixels);
+	free(ipcbm);
+	return EOK;
+}
+
+/** Render bitmap in IPC GC.
+ *
+ * @param bm Bitmap
+ * @param srect0 Source rectangle or @c NULL
+ * @param offs0 Offset or @c NULL
+ * @return EOK on success or an error code
+ */
+static errno_t ipc_gc_bitmap_render(void *bm, gfx_rect_t *srect0,
+    gfx_coord2_t *offs0)
+{
+	ipc_gc_bitmap_t *ipcbm = (ipc_gc_bitmap_t *)bm;
+	gfx_rect_t srect;
+	gfx_rect_t drect;
+	gfx_coord2_t offs;
+	async_exch_t *exch = NULL;
+	ipc_call_t answer;
+	aid_t req;
+	errno_t rc;
+
+	if (srect0 != NULL)
+		srect = *srect0;
+	else
+		srect = ipcbm->rect;
+
+	if (offs0 != NULL) {
+		offs = *offs0;
+	} else {
+		offs.x = 0;
+		offs.y = 0;
+	}
+
+	/* Destination rectangle */
+	gfx_rect_translate(&offs, &srect, &drect);
+
+	exch = async_exchange_begin(ipcbm->ipcgc->sess);
+	req = async_send_3(exch, GC_BITMAP_RENDER, ipcbm->bmp_id, offs.x,
+	    offs.y, &answer);
+
+	rc = async_data_write_start(exch, &srect, sizeof (gfx_rect_t));
+	if (rc != EOK) {
+		async_forget(req);
+		goto error;
+	}
+
+	async_exchange_end(exch);
+	exch = NULL;
+
+	async_wait_for(req, &rc);
+	if (rc != EOK)
+		goto error;
+
+	return EOK;
+error:
+	if (exch != NULL)
+		async_exchange_end(exch);
+	return rc;
+}
+
+/** Get allocation info for bitmap in IPC GC.
+ *
+ * @param bm Bitmap
+ * @param alloc Place to store allocation info
+ * @return EOK on success or an error code
+ */
+static errno_t ipc_gc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
+{
+	ipc_gc_bitmap_t *ipcbm = (ipc_gc_bitmap_t *)bm;
+	*alloc = ipcbm->alloc;
+	return EOK;
+}
+
 /** Create IPC GC.
  *
Index: uspace/lib/ipcgfx/src/server.c
===================================================================
--- uspace/lib/ipcgfx/src/server.c	(revision c8cf261a450bf22fa6cc6e9872a1f07f9e7dccda)
+++ uspace/lib/ipcgfx/src/server.c	(revision da41254778976dfa4ab1b54a56ef57de822fb353)
@@ -36,5 +36,7 @@
  */
 
+#include <as.h>
 #include <errno.h>
+#include <gfx/bitmap.h>
 #include <gfx/color.h>
 #include <gfx/render.h>
@@ -43,10 +45,12 @@
 #include <ipcgfx/server.h>
 #include <stdint.h>
-
+#include <stdlib.h>
 #include <stdio.h>
 
-#include <bd_srv.h>
-
-static void gc_set_rgb_color_srv(gfx_context_t *gc, ipc_call_t *call)
+#include "../private/server.h"
+
+static ipc_gc_srv_bitmap_t *gc_bitmap_lookup(ipc_gc_srv_t *, sysarg_t);
+
+static void gc_set_rgb_color_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
 {
 	uint16_t r, g, b;
@@ -64,10 +68,10 @@
 	}
 
-	rc = gfx_set_color(gc, color);
+	rc = gfx_set_color(srvgc->gc, color);
 	async_answer_0(call, rc);
 	printf("done with rgb_color_srv\n");
 }
 
-static void gc_fill_rect_srv(gfx_context_t *gc, ipc_call_t *call)
+static void gc_fill_rect_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
 {
 	gfx_rect_t rect;
@@ -79,14 +83,169 @@
 	rect.p1.y = ipc_get_arg4(call);
 
-	rc = gfx_fill_rect(gc, &rect);
+	rc = gfx_fill_rect(srvgc->gc, &rect);
 	async_answer_0(call, rc);
 }
 
+static void gc_bitmap_create_srv(ipc_gc_srv_t *srvgc, ipc_call_t *icall)
+{
+	gfx_bitmap_params_t params;
+	gfx_bitmap_alloc_t alloc;
+	gfx_bitmap_t *bitmap;
+	gfx_coord2_t dim;
+	ipc_gc_srv_bitmap_t *srvbmp = NULL;
+	ipc_call_t call;
+	size_t size;
+	unsigned int flags;
+	void *pixels;
+	errno_t rc;
+
+	if (!async_data_write_receive(&call, &size)) {
+		async_answer_0(&call, EREFUSED);
+		async_answer_0(icall, EREFUSED);
+		return;
+	}
+
+	if (size != sizeof(gfx_bitmap_params_t)) {
+		async_answer_0(&call, EINVAL);
+		async_answer_0(icall, EINVAL);
+		return;
+	}
+
+	rc = async_data_write_finalize(&call, &params, size);
+	if (rc != EOK) {
+		async_answer_0(&call, rc);
+		async_answer_0(icall, rc);
+		return;
+	}
+
+	/* Bitmap dimensions */
+	gfx_coord2_subtract(&params.rect.p1, &params.rect.p0, &dim);
+
+	if (!async_share_out_receive(&call, &size, &flags)) {
+		async_answer_0(icall, EINVAL);
+		return;
+	}
+
+	/* Check size */
+	if (size != PAGES2SIZE(SIZE2PAGES(dim.x * dim.y * sizeof(uint32_t)))) {
+		printf("size=%zu, expected=%zu\n", size, dim.x * dim.y * sizeof(uint32_t));
+		async_answer_0(icall, EINVAL);
+		return;
+	}
+
+	rc = async_share_out_finalize(&call, &pixels);
+	if (rc != EOK || pixels == AS_MAP_FAILED) {
+		async_answer_0(icall, ENOMEM);
+		return;
+	}
+
+	alloc.pitch = dim.x * sizeof(uint32_t);
+	alloc.off0 = 0;
+	alloc.pixels = pixels;
+
+	srvbmp = calloc(1, sizeof(ipc_gc_srv_bitmap_t));
+	if (srvbmp == NULL) {
+		as_area_destroy(pixels);
+		async_answer_0(icall, ENOMEM);
+		return;
+	}
+
+	rc = gfx_bitmap_create(srvgc->gc, &params, &alloc, &bitmap);
+	if (rc != EOK) {
+		free(srvbmp);
+		as_area_destroy(pixels);
+		async_answer_0(icall, rc);
+		return;
+	}
+
+	srvbmp->srvgc = srvgc;
+	list_append(&srvbmp->lbitmaps, &srvgc->bitmaps);
+	srvbmp->bmp = bitmap;
+	srvbmp->bmp_id = srvgc->next_bmp_id++;
+	printf("gc_bitmap_create_srv: storing bmp_id=%lu\n", srvbmp->bmp_id);
+
+	async_answer_1(icall, EOK, srvbmp->bmp_id);
+}
+
+static void gc_bitmap_destroy_srv(ipc_gc_srv_t *srvgc, ipc_call_t *call)
+{
+	sysarg_t bmp_id;
+	ipc_gc_srv_bitmap_t *bitmap;
+	errno_t rc;
+
+	bmp_id = ipc_get_arg1(call);
+
+	bitmap = gc_bitmap_lookup(srvgc, bmp_id);
+	if (bitmap == NULL) {
+		async_answer_0(call, ENOENT);
+		return;
+	}
+
+	rc = gfx_bitmap_destroy(bitmap->bmp);
+	if (rc != EOK) {
+		async_answer_0(call, rc);
+		return;
+	}
+
+	list_remove(&bitmap->lbitmaps);
+	free(bitmap);
+
+	async_answer_0(call, rc);
+}
+
+static void gc_bitmap_render_srv(ipc_gc_srv_t *srvgc, ipc_call_t *icall)
+{
+	ipc_gc_srv_bitmap_t *bitmap;
+	sysarg_t bmp_id;
+	gfx_rect_t srect;
+	gfx_coord2_t offs;
+	ipc_call_t call;
+	size_t size;
+	errno_t rc;
+
+	if (!async_data_write_receive(&call, &size)) {
+		async_answer_0(&call, EREFUSED);
+		async_answer_0(icall, EREFUSED);
+		return;
+	}
+
+	if (size != sizeof(gfx_rect_t)) {
+		async_answer_0(&call, EINVAL);
+		async_answer_0(icall, EINVAL);
+		return;
+	}
+
+	rc = async_data_write_finalize(&call, &srect, size);
+	if (rc != EOK) {
+		async_answer_0(&call, rc);
+		async_answer_0(icall, rc);
+		return;
+	}
+
+	bmp_id = ipc_get_arg1(icall);
+	offs.x = ipc_get_arg2(icall);
+	offs.y = ipc_get_arg3(icall);
+
+	bitmap = gc_bitmap_lookup(srvgc, bmp_id);
+	if (bitmap == NULL) {
+		async_answer_0(icall, ENOENT);
+		return;
+	}
+
+	rc = gfx_bitmap_render(bitmap->bmp, &srect, &offs);
+	async_answer_0(icall, rc);
+}
+
 errno_t gc_conn(ipc_call_t *icall, gfx_context_t *gc)
 {
+	ipc_gc_srv_t srvgc;
+
 	/* Accept the connection */
 	async_accept_0(icall);
 
 	printf("gc_conn: accepted connection\n");
+	srvgc.gc = gc;
+	list_initialize(&srvgc.bitmaps);
+	srvgc.next_bmp_id = 1;
 
 	while (true) {
@@ -104,11 +263,26 @@
 		case GC_SET_RGB_COLOR:
 			printf("gc_conn: set_rgb_color\n");
-			gc_set_rgb_color_srv(gc, &call);
+			gc_set_rgb_color_srv(&srvgc, &call);
 			printf("gc_conn: done set_rgb_color\n");
 			break;
 		case GC_FILL_RECT:
 			printf("gc_conn: fill_rect_srv\n");
-			gc_fill_rect_srv(gc, &call);
+			gc_fill_rect_srv(&srvgc, &call);
 			printf("gc_conn: done fill_rect_srv\n");
+			break;
+		case GC_BITMAP_CREATE:
+			printf("gc_conn: bitmap_create_srv\n");
+			gc_bitmap_create_srv(&srvgc, &call);
+			printf("gc_conn: done bitmap_create_srv\n");
+			break;
+		case GC_BITMAP_DESTROY:
+			printf("gc_conn: bitmap_destroy_srv\n");
+			gc_bitmap_destroy_srv(&srvgc, &call);
+			printf("gc_conn: done bitmap_destroy_srv\n");
+			break;
+		case GC_BITMAP_RENDER:
+			printf("gc_conn: bitmap_render_srv\n");
+			gc_bitmap_render_srv(&srvgc, &call);
+			printf("gc_conn: done bitmap_render_srv\n");
 			break;
 		default:
@@ -122,4 +296,22 @@
 }
 
+static ipc_gc_srv_bitmap_t *gc_bitmap_lookup(ipc_gc_srv_t *srvgc,
+    sysarg_t bmp_id)
+{
+	link_t *link;
+	ipc_gc_srv_bitmap_t *bmp;
+
+	link = list_first(&srvgc->bitmaps);
+	while (link != NULL) {
+		bmp = list_get_instance(link, ipc_gc_srv_bitmap_t, lbitmaps);
+		printf("gc_bitmap_lookup: %lu==%lu?\n", bmp->bmp_id, bmp_id);
+		if (bmp->bmp_id == bmp_id)
+			return bmp;
+		link = list_next(link, &srvgc->bitmaps);
+	}
+
+	return NULL;
+}
+
 /** @}
  */
