--- hostx.c.orig 2006-07-24 11:31:07.000000000 +0200 +++ hostx.c 2006-08-08 20:06:10.000000000 +0200 @@ -67,6 +67,7 @@ long damage_debug_msec; unsigned char *fb_data; /* only used when host bpp != server bpp */ + unsigned char *original_fb; /* Only used in color swizzling & AA mode */ unsigned long cmap[256]; XShmSegmentInfo shminfo; @@ -87,6 +88,8 @@ extern int kdKeymapWidth; extern int monitorResolution; +int swizzle = 1; + static void hostx_set_fullscreen_hint(void); @@ -553,6 +556,16 @@ } } +#define MAKE_24BITS_PIXEL_FROM_16BITS(server_pixel) ((((server_pixel & 0xf800) >> 8) << 16) | (((server_pixel & 0x07e0) >> 3) << 8) | ((server_pixel & 0x001f) << 3)) + +static void +copy_16bits_pixel_into_host_fb (unsigned char *host, unsigned short server_pixel) { + + host[2] = ((server_pixel & 0xf800) >> 8); + host[1] = ((server_pixel & 0x07e0) >> 3); + host[0] = ((server_pixel & 0x001f) << 3); +} + void hostx_paint_rect(int sx, int sy, int dx, int dy, @@ -563,6 +576,23 @@ * on to the window */ + int x_min = 0, x_max = 0, y_min = 0, y_max = 0; + + static Bool swizzle_initialized = 0; + + /* + * The color swizzling mode was designed to simulate the "One Laptop + * Per Child" display, for which 16bit colors are best. + */ + if (swizzle && HostX.server_depth != 16) { + fprintf (stderr, "Warning: you asked for color swizzling but the server's depth is different from 16 bit, swizzling is disabled.\n"); + } + + if (swizzle && !swizzle_initialized) { + HostX.original_fb = (unsigned char *) malloc (HostX.ximg->bytes_per_line * HostX.ximg->height); + swizzle_initialized = 1; + } + if (HostXWantDamageDebug) { hostx_paint_debug_rect(dx, dy, width, height); @@ -582,51 +612,132 @@ if (!host_depth_matches_server()) { - int x,y,idx, bytes_per_pixel = (HostX.server_depth>>3); - unsigned char r,g,b; - unsigned long host_pixel; - - for (y=sy; y>3), host_bpp = HostX.ximg->bits_per_pixel / 8; + unsigned char r, g, b, aa_color; + unsigned char *host_pixel; + unsigned long final_host_pixel; + + if (swizzle) { + int border, sum, swizzle_position; + unsigned short server_pixel; + + border = 1; + x_min = (sx - border < 0)? 0 : sx - border; + y_min = (sy - border < 0)? 0 : sy - border; + x_max = (sx + width + border > HostX.ximg->width)? HostX.ximg->width : sx + width + border; + y_max = (sy + height + border > HostX.ximg->height)? HostX.ximg->height : sy + height + border; + + /* First, update the zone we're redrawing in the local, + * unaltered framebuffer. + */ + + for (y = sy; y < sy + height; y++) { + for (x = sx; x < sx + width; x++) { + idx = (HostX.win_width * y + x) * server_bpp; + server_pixel = *(unsigned short*)(HostX.fb_data+idx); + host_pixel = HostX.original_fb + (x + y * HostX.ximg->width) * host_bpp; + copy_16bits_pixel_into_host_fb (host_pixel, server_pixel); + } + } + + /* + * Then, perform the antialiasing the way OLPC's DCON chip does it. This is a + * very simple filter: for every pixel figure out which color it will be + * emitting (see the swizzling part below), sum up the corresponding color + * component of his four neighbors (up, down, left, right), add this sum to + * 4 times the value of the color component of the pixel itself, and divide all + * this by 8 to get the antialiased pixel's color component. + */ + + for (y = y_min; y < y_max; y++) { + for (x = x_min; x < x_max; x++) { + + swizzle_position = (x + y) % 3; + sum = 0; - switch (HostX.server_depth) + if (x > 0) { /* Left */ + host_pixel = HostX.original_fb + ((x - 1) + y * HostX.ximg->width) * host_bpp; + sum += host_pixel[2 - swizzle_position]; + } + if (x < HostX.ximg->width - 1) { /* Right */ + host_pixel = HostX.original_fb + ((x - 1) + y * HostX.ximg->width) * host_bpp; + sum += host_pixel[2 - swizzle_position]; + } + if (y > 0) { /* Top */ + host_pixel = HostX.original_fb + (x + (y - 1) * HostX.ximg->width) * host_bpp; + sum += host_pixel[2 - swizzle_position]; + } + if (y < HostX.ximg->height - 1) { /* Bottom */ + host_pixel = HostX.original_fb + (x + (y + 1) * HostX.ximg->width) * host_bpp; + sum += host_pixel[2 - swizzle_position]; + } + + host_pixel = HostX.original_fb + (x + y * HostX.ximg->width) * host_bpp; + + aa_color = (unsigned char) ((sum + 4 * host_pixel[2 - swizzle_position]) >> 3); + + /* + * Now comes color swizzling. In the OLPC color mode, each pixel can only + * emit light of one of the three R, G, B colors. The first one is red, the + * second one (to the right) is green, etc. The second line is shifted by one + * pixel, so that the first pixel is green, the second is blue, etc. To + * reproduce this effect, figure out which color the current pixel will be + * emitting, keep the corresponding component, and discard the two others. + */ + + r = (swizzle_position == 0)? aa_color : 0; + g = (swizzle_position == 1)? aa_color : 0; + b = (swizzle_position == 2)? aa_color : 0; + + final_host_pixel = (r << 16) | (g << 8) | (b); + + XPutPixel (HostX.ximg, x, y, final_host_pixel); + } + } + } else { + + for (y = sy; y < sy + height; y++) { + for (x = sx; x < sx + width; x++) { + idx = (HostX.win_width * y + x) * server_bpp; + + switch (HostX.server_depth) { + case 16: { - case 16: - { - unsigned short pixel = *(unsigned short*)(HostX.fb_data+idx); - - r = ((pixel & 0xf800) >> 8); - g = ((pixel & 0x07e0) >> 3); - b = ((pixel & 0x001f) << 3); - - host_pixel = (r << 16) | (g << 8) | (b); - - XPutPixel(HostX.ximg, x, y, host_pixel); - break; - } - case 8: - { - unsigned char pixel = *(unsigned char*)(HostX.fb_data+idx); - XPutPixel(HostX.ximg, x, y, HostX.cmap[pixel]); - break; - } - default: - break; + unsigned short server_pixel = *(unsigned short*) (HostX.fb_data + idx); + XPutPixel (HostX.ximg, x, y, MAKE_24BITS_PIXEL_FROM_16BITS(server_pixel)); + break; } + case 8: + { + unsigned char server_pixel = *(unsigned char*)(HostX.fb_data + idx); + XPutPixel (HostX.ximg, x, y, HostX.cmap[server_pixel]); + break; + } + default: + break; + } } + } + } } - + if (HostX.have_shm) { - XShmPutImage(HostX.dpy, HostX.win, HostX.gc, HostX.ximg, - sx, sy, dx, dy, width, height, False); + if (swizzle) + XShmPutImage (HostX.dpy, HostX.win, HostX.gc, HostX.ximg, + x_min, y_min, x_min, y_min, x_max - x_min, y_max - y_min, False); + else + XShmPutImage (HostX.dpy, HostX.win, HostX.gc, HostX.ximg, + sx, sy, dx, dy, width, height, False); } else { - XPutImage(HostX.dpy, HostX.win, HostX.gc, HostX.ximg, - sx, sy, dx, dy, width, height); + if (swizzle) + XPutImage (HostX.dpy, HostX.win, HostX.gc, HostX.ximg, + x_min, y_min, x_min, y_min, x_max - x_min, y_max - y_min); + else + XPutImage (HostX.dpy, HostX.win, HostX.gc, HostX.ximg, + sx, sy, dx, dy, width, height); } XSync(HostX.dpy, False);