Index: uspace/lib/softrend/filter.c
===================================================================
--- uspace/lib/softrend/filter.c	(revision c6c39d4fc4006cdc10bdb3c7c6bc139f722b78af)
+++ uspace/lib/softrend/filter.c	(revision 8d3512f119e2a44f134b45bad386692c49984b5b)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2012 Petr Koupy
+ * Copyright (c) 2014 Martin Sucha
  * All rights reserved.
  *
@@ -35,22 +36,85 @@
 
 #include "filter.h"
+#include <io/pixel.h>
+
+static long round(double val)
+{
+	return val > 0 ? (long) (val + 0.5) : (long) (val - 0.5);
+}
+
+static long floor(double val)
+{
+	long lval = (long) val;
+	if (val < 0 && lval != val)
+		return lval - 1;
+	return lval;
+}
+
+static long ceil(double val)
+{
+	long lval = (long) val;
+	if (val > 0 && lval != val)
+		return lval + 1;
+	return lval;
+}
+
+static pixel_t get_pixel(pixelmap_t *pixmap, sysarg_t x, sysarg_t y, bool tile)
+{
+	if (tile) {
+		x %= pixmap->width;
+		y %= pixmap->height;
+	}
+
+	return pixelmap_get_pixel(pixmap, (sysarg_t) x, (sysarg_t) y);
+}
+
+static inline pixel_t blend_pixels(size_t count, float *weights,
+    pixel_t *pixels)
+{
+	float alpha = 0, red = 0, green = 0, blue = 0;
+	for (size_t index = 0; index < count; index++) {
+		alpha += weights[index] * ALPHA(pixels[index]);
+		red   += weights[index] *   RED(pixels[index]);
+		green += weights[index] * GREEN(pixels[index]);
+		blue  += weights[index] *  BLUE(pixels[index]);
+	}
+	
+	return PIXEL((uint8_t) alpha, (uint8_t) red, (uint8_t) green,
+	    (uint8_t) blue);
+}
 
 pixel_t filter_nearest(pixelmap_t *pixmap, double x, double y, bool tile)
 {
-	long _x = x > 0 ? (long) (x + 0.5) : (long) (x - 0.5);
-	long _y = y > 0 ? (long) (y + 0.5) : (long) (y - 0.5);
-
-	if (tile) {
-		_x %= pixmap->width;
-		_y %= pixmap->height;
-	}
-
-	return pixelmap_get_pixel(pixmap, (sysarg_t) _x, (sysarg_t) _y);
+	return get_pixel(pixmap, round(x), round(y), tile);
 }
 
 pixel_t filter_bilinear(pixelmap_t *pixmap, double x, double y, bool tile)
 {
-	// TODO
-	return 0;
+	long x1 = floor(x);
+	long x2 = ceil(x);
+	long y1 = floor(y);
+	long y2 = ceil(y);
+	
+	if (y1 == y2 && x1 == x2) {
+		return get_pixel(pixmap, (sysarg_t) x1, (sysarg_t) y1,
+		    tile);
+	}
+	
+	double x_delta = x - x1;
+	double y_delta = y - y1;
+	
+	pixel_t pixels[4];
+	pixels[0] = get_pixel(pixmap, x1, y1, tile);
+	pixels[1] = get_pixel(pixmap, x2, y1, tile);
+	pixels[2] = get_pixel(pixmap, x1, y2, tile);
+	pixels[3] = get_pixel(pixmap, x2, y2, tile);
+	
+	float weights[4];
+	weights[0] = (1 - x_delta) * (1 - y_delta);
+	weights[1] = (    x_delta) * (1 - y_delta);
+	weights[2] = (1 - x_delta) * (    y_delta);
+	weights[3] = (    x_delta) * (    y_delta);
+	
+	return blend_pixels(4, weights, pixels);
 }
 
Index: uspace/srv/hid/compositor/compositor.c
===================================================================
--- uspace/srv/hid/compositor/compositor.c	(revision c6c39d4fc4006cdc10bdb3c7c6bc139f722b78af)
+++ uspace/srv/hid/compositor/compositor.c	(revision 8d3512f119e2a44f134b45bad386692c49984b5b)
@@ -84,4 +84,6 @@
 static sysarg_t coord_origin;
 static pixel_t bg_color;
+static filter_t filter = filter_bilinear;
+static unsigned int filter_index = 1;
 
 typedef struct {
@@ -408,5 +410,5 @@
 
 			source_init(&source);
-			source_set_filter(&source, filter_nearest);
+			source_set_filter(&source, filter);
 			drawctx_init(&context, vp->surface);
 			drawctx_set_compose(&context, compose_over);
@@ -1818,10 +1820,11 @@
 	    key == KC_O || key == KC_P);
 	bool kconsole_switch = (mods & KM_ALT) && (key == KC_M);
-
-	bool filter = (type == KEY_RELEASE) && (win_transform || win_resize ||
+	bool filter_switch = (mods & KM_ALT) && (key == KC_Y);
+
+	bool key_filter = (type == KEY_RELEASE) && (win_transform || win_resize ||
 	    win_opacity || win_close || win_switch || viewport_move ||
-	    viewport_change || kconsole_switch);
-
-	if (filter) {
+	    viewport_change || kconsole_switch || filter_switch);
+
+	if (key_filter) {
 		/* no-op */
 	} else if (win_transform) {
@@ -2091,4 +2094,15 @@
 		if (console_kcon())
 			active = false;
+	} else if (filter_switch) {
+		filter_index++;
+		if (filter_index > 1)
+			filter_index = 0;
+		if (filter_index == 0) {
+			filter = filter_nearest;
+		}
+		else {
+			filter = filter_bilinear;
+		}
+		comp_damage(0, 0, UINT32_MAX, UINT32_MAX);
 	} else {
 		window_event_t *event = (window_event_t *) malloc(sizeof(window_event_t));
