Index: uspace/drv/fb/amdm37x_dispc/amdm37x_dispc.c
===================================================================
--- uspace/drv/fb/amdm37x_dispc/amdm37x_dispc.c	(revision e1f2079eea6e0ce553d66ced5b7ca0b64e0b4929)
+++ uspace/drv/fb/amdm37x_dispc/amdm37x_dispc.c	(revision 7bb45e33b98aa347a21453b63e27f209dc3ab3d9)
@@ -1,3 +1,4 @@
 /*
+ * Copyright (c) 2020 Jiri Svoboda
  * Copyright (c) 2013 Jan Vesely
  * All rights reserved.
@@ -35,9 +36,14 @@
 
 #include <align.h>
+#include <as.h>
 #include <assert.h>
 #include <errno.h>
+#include <ddev_srv.h>
+#include <ddev/info.h>
+#include <ddf/driver.h>
 #include <ddf/log.h>
 #include <ddi.h>
-#include <as.h>
+#include <gfx/color.h>
+#include <io/pixelmap.h>
 
 #include "amdm37x_dispc.h"
@@ -55,20 +61,30 @@
 #endif
 
-static errno_t change_mode(visualizer_t *vis, vslmode_t mode);
-static errno_t handle_damage(visualizer_t *vs,
-    sysarg_t x0, sysarg_t y0, sysarg_t width, sysarg_t height,
-    sysarg_t x_offset, sysarg_t y_offset);
-static errno_t dummy(visualizer_t *vs)
-{
-	return EOK;
-}
-
-static const visualizer_ops_t amdm37x_dispc_vis_ops = {
-	.change_mode = change_mode,
-	.handle_damage = handle_damage,
-	.claim = dummy,
-	.yield = dummy,
-	.suspend = dummy,
-	.wakeup = dummy,
+static errno_t amdm37x_change_mode(amdm37x_dispc_t *, unsigned, unsigned,
+    visual_t);
+
+static errno_t amdm37x_ddev_get_gc(void *, sysarg_t *, sysarg_t *);
+static errno_t amdm37x_ddev_get_info(void *, ddev_info_t *);
+
+static errno_t amdm37x_gc_set_color(void *, gfx_color_t *);
+static errno_t amdm37x_gc_fill_rect(void *, gfx_rect_t *);
+static errno_t amdm37x_gc_bitmap_create(void *, gfx_bitmap_params_t *,
+    gfx_bitmap_alloc_t *, void **);
+static errno_t amdm37x_gc_bitmap_destroy(void *);
+static errno_t amdm37x_gc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
+static errno_t amdm37x_gc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
+
+ddev_ops_t amdm37x_ddev_ops = {
+	.get_gc = amdm37x_ddev_get_gc,
+	.get_info = amdm37x_ddev_get_info
+};
+
+gfx_context_ops_t amdm37x_gc_ops = {
+	.set_color = amdm37x_gc_set_color,
+	.fill_rect = amdm37x_gc_fill_rect,
+	.bitmap_create = amdm37x_gc_bitmap_create,
+	.bitmap_destroy = amdm37x_gc_bitmap_destroy,
+	.bitmap_render = amdm37x_gc_bitmap_render,
+	.bitmap_get_alloc = amdm37x_gc_bitmap_get_alloc
 };
 
@@ -94,27 +110,7 @@
 };
 
-static void mode_init(vslmode_list_element_t *mode,
-    unsigned width, unsigned height, visual_t visual)
-{
-	mode->mode.index = 0;
-	mode->mode.version = 0;
-	mode->mode.refresh_rate = 0;
-	mode->mode.screen_aspect.width = width;
-	mode->mode.screen_aspect.height = height;
-	mode->mode.screen_width = width;
-	mode->mode.screen_height = height;
-	mode->mode.cell_aspect.width = 1;
-	mode->mode.cell_aspect.height = 1;
-	mode->mode.cell_visual.pixel_visual = visual;
-
-	link_initialize(&mode->link);
-
-}
-
-errno_t amdm37x_dispc_init(amdm37x_dispc_t *instance, visualizer_t *vis)
-{
-	assert(instance);
-	assert(vis);
-
+errno_t amdm37x_dispc_init(amdm37x_dispc_t *instance, ddf_fun_t *fun)
+{
+	instance->fun = fun;
 	instance->fb_data = NULL;
 	instance->size = 0;
@@ -145,12 +141,8 @@
 	}
 
-	mode_init(&instance->modes[0],
-	    CONFIG_BFB_WIDTH, CONFIG_BFB_HEIGHT, visual);
-
-	/* Handle vis stuff */
-	vis->dev_ctx = instance;
-	vis->def_mode_idx = 0;
-	vis->ops = amdm37x_dispc_vis_ops;
-	list_append(&instance->modes[0].link, &vis->modes);
+	ret = amdm37x_change_mode(instance, CONFIG_BFB_WIDTH,
+	    CONFIG_BFB_HEIGHT, visual);
+	if (ret != EOK)
+		return EIO;
 
 	return EOK;
@@ -269,16 +261,10 @@
 }
 
-static errno_t change_mode(visualizer_t *vis, vslmode_t mode)
-{
-	assert(vis);
-	assert(vis->dev_ctx);
-
-	amdm37x_dispc_t *dispc = vis->dev_ctx;
-	const visual_t visual = mode.cell_visual.pixel_visual;
+static errno_t amdm37x_change_mode(amdm37x_dispc_t *dispc, unsigned x,
+    unsigned y, visual_t visual)
+{
 	assert((size_t)visual < sizeof(pixel2visual_table) / sizeof(pixel2visual_table[0]));
 	const unsigned bpp = pixel2visual_table[visual].bpp;
 	pixel2visual_t p2v = pixel2visual_table[visual].func;
-	const unsigned x = mode.screen_width;
-	const unsigned y = mode.screen_height;
 	ddf_log_note("Setting mode: %ux%ux%u\n", x, y, bpp * 8);
 	const size_t size = ALIGN_UP(x * y * bpp, PAGE_SIZE);
@@ -296,5 +282,4 @@
 	dispc->fb_data = buffer;
 	amdm37x_dispc_setup_fb(dispc->regs, x, y, bpp * 8, (uint32_t)pa);
-	dispc->active_fb.idx = mode.index;
 	dispc->active_fb.width = x;
 	dispc->active_fb.height = y;
@@ -302,43 +287,224 @@
 	dispc->active_fb.bpp = bpp;
 	dispc->active_fb.pixel2visual = p2v;
+	dispc->rect.p0.x = 0;
+	dispc->rect.p0.y = 0;
+	dispc->rect.p1.x = x;
+	dispc->rect.p1.y = y;
 	dispc->size = size;
-	assert(mode.index < 1);
-
-	return EOK;
-}
-
-static errno_t handle_damage(visualizer_t *vs,
-    sysarg_t x0, sysarg_t y0, sysarg_t width, sysarg_t height,
-    sysarg_t x_offset, sysarg_t y_offset)
-{
-	assert(vs);
-	assert(vs->dev_ctx);
-	amdm37x_dispc_t *dispc = vs->dev_ctx;
-	pixelmap_t *map = &vs->cells;
-
-#define FB_POS(x, y) \
-	(((y) * (dispc->active_fb.width + dispc->active_fb.pitch) + (x)) \
-	    * dispc->active_fb.bpp)
-	if (x_offset == 0 && y_offset == 0) {
-		/* Faster damage routine ignoring offsets. */
-		for (sysarg_t y = y0; y < height + y0; ++y) {
-			pixel_t *pixel = pixelmap_pixel_at(map, x0, y);
-			for (sysarg_t x = x0; x < width + x0; ++x) {
-				dispc->active_fb.pixel2visual(
-				    dispc->fb_data + FB_POS(x, y), *pixel++);
-			}
+
+	return EOK;
+}
+
+#define FB_POS(d, x, y) \
+    (((y) * ((d)->active_fb.width + (d)->active_fb.pitch) + (x)) \
+    * (d)->active_fb.bpp)
+
+static errno_t amdm37x_ddev_get_gc(void *arg, sysarg_t *arg2, sysarg_t *arg3)
+{
+	amdm37x_dispc_t *dispc = (amdm37x_dispc_t *) arg;
+
+	*arg2 = ddf_fun_get_handle(dispc->fun);
+	*arg3 = 42;
+	return EOK;
+}
+
+static errno_t amdm37x_ddev_get_info(void *arg, ddev_info_t *info)
+{
+	amdm37x_dispc_t *dispc = (amdm37x_dispc_t *) arg;
+
+	ddev_info_init(info);
+	info->rect.p0.x = 0;
+	info->rect.p0.y = 0;
+	info->rect.p1.x = dispc->active_fb.width;
+	info->rect.p1.y = dispc->active_fb.height;
+	return EOK;
+}
+
+/** Set color on AMDM37x display controller.
+ *
+ * Set drawing color on AMDM37x GC.
+ *
+ * @param arg AMDM37x display controller
+ * @param color Color
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t amdm37x_gc_set_color(void *arg, gfx_color_t *color)
+{
+	amdm37x_dispc_t *dispc = (amdm37x_dispc_t *) arg;
+	uint16_t r, g, b;
+
+	gfx_color_get_rgb_i16(color, &r, &g, &b);
+	dispc->color = PIXEL(0, r >> 8, g >> 8, b >> 8);
+	return EOK;
+}
+
+/** Fill rectangle on AMDM37x display controller.
+ *
+ * @param arg AMDM37x display controller
+ * @param rect Rectangle
+ *
+ * @return EOK on success or an error code
+ */
+static errno_t amdm37x_gc_fill_rect(void *arg, gfx_rect_t *rect)
+{
+	amdm37x_dispc_t *dispc = (amdm37x_dispc_t *) arg;
+	gfx_rect_t crect;
+	gfx_coord_t x, y;
+
+	/* Make sure we have a sorted, clipped rectangle */
+	gfx_rect_clip(rect, &dispc->rect, &crect);
+
+	for (y = crect.p0.y; y < crect.p1.y; y++) {
+		for (x = crect.p0.x; x < crect.p1.x; x++) {
+			dispc->active_fb.pixel2visual(dispc->fb_data +
+			    FB_POS(dispc, x, y), dispc->color);
+		}
+	}
+
+	return EOK;
+}
+
+/** Create bitmap in AMDM37x GC.
+ *
+ * @param arg AMDM37x display controller
+ * @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 amdm37x_gc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
+    gfx_bitmap_alloc_t *alloc, void **rbm)
+{
+	amdm37x_dispc_t *dispc = (amdm37x_dispc_t *) arg;
+	amdm37x_bitmap_t *dcbm = NULL;
+	gfx_coord2_t dim;
+	errno_t rc;
+
+	dcbm = calloc(1, sizeof(amdm37x_bitmap_t));
+	if (dcbm == NULL)
+		return ENOMEM;
+
+	gfx_coord2_subtract(&params->rect.p1, &params->rect.p0, &dim);
+	dcbm->rect = params->rect;
+
+	if (alloc == NULL) {
+		dcbm->alloc.pitch = dim.x * sizeof(uint32_t);
+		dcbm->alloc.off0 = 0;
+		dcbm->alloc.pixels = malloc(dcbm->alloc.pitch * dim.y);
+		dcbm->myalloc = true;
+
+		if (dcbm->alloc.pixels == NULL) {
+			rc = ENOMEM;
+			goto error;
 		}
 	} else {
-		for (sysarg_t y = y0; y < height + y0; ++y) {
-			for (sysarg_t x = x0; x < width + x0; ++x) {
-				dispc->active_fb.pixel2visual(
-				    dispc->fb_data + FB_POS(x, y),
-				    *pixelmap_pixel_at(map,
-				    (x + x_offset) % map->width,
-				    (y + y_offset) % map->height));
-			}
+		dcbm->alloc = *alloc;
+	}
+
+	dcbm->dispc = dispc;
+	*rbm = (void *)dcbm;
+	return EOK;
+error:
+	if (rbm != NULL)
+		free(dcbm);
+	return rc;
+}
+
+/** Destroy bitmap in AMDM37x GC.
+ *
+ * @param bm Bitmap
+ * @return EOK on success or an error code
+ */
+static errno_t amdm37x_gc_bitmap_destroy(void *bm)
+{
+	amdm37x_bitmap_t *dcbm = (amdm37x_bitmap_t *)bm;
+	if (dcbm->myalloc)
+		free(dcbm->alloc.pixels);
+	free(dcbm);
+	return EOK;
+}
+
+/** Render bitmap in AMDM37x 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 amdm37x_gc_bitmap_render(void *bm, gfx_rect_t *srect0,
+    gfx_coord2_t *offs0)
+{
+	amdm37x_bitmap_t *dcbm = (amdm37x_bitmap_t *)bm;
+	amdm37x_dispc_t *dispc = dcbm->dispc;
+	gfx_rect_t srect;
+	gfx_rect_t drect;
+	gfx_rect_t skfbrect;
+	gfx_rect_t crect;
+	gfx_coord2_t offs;
+	gfx_coord2_t bmdim;
+	gfx_coord2_t dim;
+	gfx_coord2_t sp;
+	gfx_coord2_t dp;
+	gfx_coord2_t pos;
+	pixelmap_t pbm;
+	pixel_t color;
+
+	/* Clip source rectangle to bitmap bounds */
+
+	if (srect0 != NULL)
+		gfx_rect_clip(srect0, &dcbm->rect, &srect);
+	else
+		srect = dcbm->rect;
+
+	if (offs0 != NULL) {
+		offs = *offs0;
+	} else {
+		offs.x = 0;
+		offs.y = 0;
+	}
+
+	/* Destination rectangle */
+	gfx_rect_translate(&offs, &srect, &drect);
+	gfx_coord2_subtract(&drect.p1, &drect.p0, &dim);
+	gfx_coord2_subtract(&dcbm->rect.p1, &dcbm->rect.p0, &bmdim);
+
+	pbm.width = bmdim.x;
+	pbm.height = bmdim.y;
+	pbm.data = dcbm->alloc.pixels;
+
+	/* Transform AMDM37x bounding rectangle back to bitmap coordinate system */
+	gfx_rect_rtranslate(&offs, &dispc->rect, &skfbrect);
+
+	/*
+	 * Make sure we have a sorted source rectangle, clipped so that
+	 * destination lies within AMDM37x bounding rectangle
+	 */
+	gfx_rect_clip(&srect, &skfbrect, &crect);
+
+	for (pos.y = crect.p0.y; pos.y < crect.p1.y; pos.y++) {
+		for (pos.x = crect.p0.x; pos.x < crect.p1.x; pos.x++) {
+			gfx_coord2_subtract(&pos, &dcbm->rect.p0, &sp);
+			gfx_coord2_add(&pos, &offs, &dp);
+
+			color = pixelmap_get_pixel(&pbm, sp.x, sp.y);
+			dispc->active_fb.pixel2visual(dispc->fb_data +
+			    FB_POS(dispc, dp.x, dp.y), color);
 		}
 	}
 
+	return EOK;
+}
+
+/** Get allocation info for bitmap in AMDM37x GC.
+ *
+ * @param bm Bitmap
+ * @param alloc Place to store allocation info
+ * @return EOK on success or an error code
+ */
+static errno_t amdm37x_gc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
+{
+	amdm37x_bitmap_t *dcbm = (amdm37x_bitmap_t *)bm;
+	*alloc = dcbm->alloc;
 	return EOK;
 }
Index: uspace/drv/fb/amdm37x_dispc/amdm37x_dispc.h
===================================================================
--- uspace/drv/fb/amdm37x_dispc/amdm37x_dispc.h	(revision e1f2079eea6e0ce553d66ced5b7ca0b64e0b4929)
+++ uspace/drv/fb/amdm37x_dispc/amdm37x_dispc.h	(revision 7bb45e33b98aa347a21453b63e27f209dc3ab3d9)
@@ -1,3 +1,4 @@
 /*
+ * Copyright (c) 2020 Jiri Svoboda
  * Copyright (c) 2013 Jan Vesely
  * All rights reserved.
@@ -37,6 +38,10 @@
 #define AMDM37X_DISPC_H_
 
-#include <graph.h>
 #include <abi/fb/visuals.h>
+#include <ddev_srv.h>
+#include <ddf/driver.h>
+#include <gfx/context.h>
+#include <gfx/coord.h>
+#include <io/pixel.h>
 #include <pixconv.h>
 #include <ddi.h>
@@ -45,4 +50,5 @@
 
 typedef struct {
+	ddf_fun_t *fun;
 	amdm37x_dispc_regs_t *regs;
 
@@ -53,15 +59,24 @@
 		unsigned pitch;
 		unsigned bpp;
-		unsigned idx;
 	} active_fb;
 
+	pixel_t color;
+	gfx_rect_t rect;
 	size_t size;
 	void *fb_data;
-
-	vslmode_list_element_t modes[1];
 } amdm37x_dispc_t;
 
-errno_t amdm37x_dispc_init(amdm37x_dispc_t *instance, visualizer_t *vis);
-errno_t amdm37x_dispc_fini(amdm37x_dispc_t *instance);
+typedef struct {
+	amdm37x_dispc_t *dispc;
+	gfx_bitmap_alloc_t alloc;
+	gfx_rect_t rect;
+	bool myalloc;
+} amdm37x_bitmap_t;
+
+extern ddev_ops_t amdm37x_ddev_ops;
+extern gfx_context_ops_t amdm37x_gc_ops;
+
+extern errno_t amdm37x_dispc_init(amdm37x_dispc_t *, ddf_fun_t *);
+extern errno_t amdm37x_dispc_fini(amdm37x_dispc_t *);
 
 #endif
Index: uspace/drv/fb/amdm37x_dispc/main.c
===================================================================
--- uspace/drv/fb/amdm37x_dispc/main.c	(revision e1f2079eea6e0ce553d66ced5b7ca0b64e0b4929)
+++ uspace/drv/fb/amdm37x_dispc/main.c	(revision 7bb45e33b98aa347a21453b63e27f209dc3ab3d9)
@@ -1,3 +1,4 @@
 /*
+ * Copyright (c) 2020 Jiri Svoboda
  * Copyright (c) 2013 Jan Vesely
  * Copyright (c) 2011 Petr Koupy
@@ -35,10 +36,11 @@
  */
 
+#include <ddev_srv.h>
 #include <ddf/driver.h>
 #include <ddf/log.h>
 #include <errno.h>
+#include <ipcgfx/server.h>
 #include <str_error.h>
 #include <stdio.h>
-#include <graph.h>
 
 #include "amdm37x_dispc.h"
@@ -46,10 +48,39 @@
 #define NAME  "amdm37x_dispc"
 
-static void graph_vsl_connection(ipc_call_t *icall, void *arg)
+static void amdm37x_client_conn(ipc_call_t *icall, void *arg)
 {
-	visualizer_t *vsl;
+	amdm37x_dispc_t *dispc;
+	ddev_srv_t srv;
+	sysarg_t gc_id;
+	gfx_context_t *gc;
+	errno_t rc;
 
-	vsl = (visualizer_t *) ddf_fun_data_get((ddf_fun_t *)arg);
-	graph_visualizer_connection(vsl, icall, NULL);
+	dispc = (amdm37x_dispc_t *) ddf_dev_data_get(
+	    ddf_fun_get_dev((ddf_fun_t *) arg));
+
+	gc_id = ipc_get_arg3(icall);
+
+	if (gc_id == 0) {
+		/* Set up protocol structure */
+		ddev_srv_initialize(&srv);
+		srv.ops = &amdm37x_ddev_ops;
+		srv.arg = dispc;
+
+		/* Handle connection */
+		ddev_conn(icall, &srv);
+	} else {
+		assert(gc_id == 42);
+
+		rc = gfx_context_new(&amdm37x_gc_ops, dispc, &gc);
+		if (rc != EOK)
+			goto error;
+
+		/* GC connection */
+		gc_conn(icall, gc);
+	}
+
+	return;
+error:
+	async_answer_0(icall, rc);
 }
 
@@ -57,6 +88,6 @@
 {
 	assert(dev);
-	/* Visualizer part */
-	ddf_fun_t *fun = ddf_fun_create(dev, fun_exposed, "viz");
+
+	ddf_fun_t *fun = ddf_fun_create(dev, fun_exposed, "a");
 	if (!fun) {
 		ddf_log_error("Failed to create visualizer function.");
@@ -64,15 +95,6 @@
 	}
 
-	visualizer_t *vis = ddf_fun_data_alloc(fun, sizeof(visualizer_t));
-	if (!vis) {
-		ddf_log_error("Failed to allocate visualizer structure.");
-		ddf_fun_destroy(fun);
-		return ENOMEM;
-	}
+	ddf_fun_set_conn_handler(fun, &amdm37x_client_conn);
 
-	graph_init_visualizer(vis);
-	vis->reg_svc_handle = ddf_fun_get_handle(fun);
-
-	ddf_fun_set_conn_handler(fun, graph_vsl_connection);
 	/* Hw part */
 	amdm37x_dispc_t *dispc =
@@ -84,5 +106,5 @@
 	}
 
-	errno_t rc = amdm37x_dispc_init(dispc, vis);
+	errno_t rc = amdm37x_dispc_init(dispc, fun);
 	if (rc != EOK) {
 		ddf_log_error("Failed to init dispc: %s.", str_error(rc));
@@ -100,5 +122,5 @@
 	}
 
-	rc = ddf_fun_add_to_category(fun, "visualizer");
+	rc = ddf_fun_add_to_category(fun, "display-device");
 	if (rc != EOK) {
 		ddf_log_error("Failed to add function: %s to visualizer "
Index: uspace/drv/fb/amdm37x_dispc/meson.build
===================================================================
--- uspace/drv/fb/amdm37x_dispc/meson.build	(revision e1f2079eea6e0ce553d66ced5b7ca0b64e0b4929)
+++ uspace/drv/fb/amdm37x_dispc/meson.build	(revision 7bb45e33b98aa347a21453b63e27f209dc3ab3d9)
@@ -29,4 +29,4 @@
 #
 
-deps = [ 'graph', 'softrend' ]
+deps = [ 'gfx', 'ipcgfx', 'ddev', 'softrend' ]
 src = files('amdm37x_dispc.c', 'main.c')
