[broadway] Send diffs as bilevel rgba instead of true diff

The true diff only works if the destination keeps perfect 32bit
canvas data, which is not always true. So, instead we send only
changed pixels, masking the others to 0 via alpha 0.
This commit is contained in:
Alexander Larsson 2010-11-21 19:52:05 +01:00
parent 6fe849d4f1
commit e6c340519c
5 changed files with 65 additions and 138 deletions

View File

@ -5,14 +5,15 @@
#include "broadway.h"
#include <math.h>
#include <unistd.h>
#include <stdint.h>
#include <cairo.h>
static void
diff_surfaces (cairo_surface_t *surface,
cairo_surface_t *old_surface)
{
unsigned char *data, *old_data;
unsigned char *line, *old_line;
uint8_t *data, *old_data;
uint32_t *line, *old_line;
int w, h, stride, old_stride;
int x, y;
@ -27,16 +28,17 @@ diff_surfaces (cairo_surface_t *surface,
for (y = 0; y < h; y++)
{
line = data;
old_line = old_data;
line = (uint32_t *)data;
old_line = (uint32_t *)old_data;
for (x = 0; x < w; x++)
{
int j;
for (j = 0; j < 4; j++)
old_line[j] = line[j] - old_line[j];
line += 4;
old_line += 4;
if (*line & 0xffffff == *old_line & 0xffffff)
*old_line = 0;
else
*old_line = *line | 0xff000000;
line ++;
old_line ++;
}
data += stride;
@ -181,8 +183,8 @@ demo2 (BroadwayClient *client)
{
diff_surfaces (surface,
old_surface);
broadway_client_put_delta_rgb (client, 0, 0, 0, 800, 600, 800*4,
cairo_image_surface_get_data(old_surface));
broadway_client_put_rgba (client, 0, 0, 0, 800, 600, 800*4,
cairo_image_surface_get_data(old_surface));
}
broadway_client_move_surface (client, 0, 100 + i, 100 + i);

View File

@ -834,12 +834,12 @@ broadway_client_put_rgb (BroadwayClient *client, int id, int x, int y,
}
static void
rgb_autocrop (unsigned char *data,
int byte_stride,
int *x_arg, int *y_arg,
int *w_arg, int *h_arg)
rgba_autocrop (unsigned char *data,
int byte_stride,
int *x_arg, int *y_arg,
int *w_arg, int *h_arg)
{
unsigned char *line;
uint32_t *line;
int w, h;
int x, y, xx, yy;
boolean non_zero;
@ -851,16 +851,16 @@ rgb_autocrop (unsigned char *data,
while (h > 0)
{
line = data + y * byte_stride + x * 4;
line = (uint32_t *)(data + y * byte_stride + x * 4);
non_zero = FALSE;
for (xx = 0; xx < w; xx++)
{
if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
if (*line != 0) {
non_zero = TRUE;
break;
}
line += 4;
line++;
}
if (non_zero)
@ -872,16 +872,16 @@ rgb_autocrop (unsigned char *data,
while (h > 0)
{
line = data + (y + h - 1) * byte_stride + x * 4;
line = (uint32_t *)(data + (y + h - 1) * byte_stride + x * 4);
non_zero = FALSE;
for (xx = 0; xx < w; xx++)
{
if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
if (*line != 0) {
non_zero = TRUE;
break;
}
line += 4;
line++;
}
if (non_zero)
@ -891,16 +891,16 @@ rgb_autocrop (unsigned char *data,
while (w > 0)
{
line = data + y * byte_stride + x * 4;
line = (uint32_t *)(data + y * byte_stride + x * 4);
non_zero = FALSE;
for (yy = 0; yy < h; yy++)
{
if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
if (*line != 0) {
non_zero = TRUE;
break;
}
line += byte_stride;
line += byte_stride / 4;
}
if (non_zero)
@ -912,16 +912,16 @@ rgb_autocrop (unsigned char *data,
while (w > 0)
{
line = data + y * byte_stride + (x + w - 1) * 4;
line = (uint32_t *)(data + y * byte_stride + (x + w - 1) * 4);
non_zero = FALSE;
for (yy = 0; yy < h; yy++)
{
if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
if (*line != 0) {
non_zero = TRUE;
break;
}
line += byte_stride;
line += byte_stride / 4;
}
if (non_zero)
@ -935,43 +935,6 @@ rgb_autocrop (unsigned char *data,
*h_arg = h;
}
void
broadway_client_put_delta_rgb (BroadwayClient *client, int id, int dest_x, int dest_y,
int w, int h, int byte_stride, void *data)
{
char buf[16];
size_t len;
char *url;
int src_x, src_y;
src_x = 0;
src_y = 0;
rgb_autocrop (data,
byte_stride,
&src_x, &src_y, &w, &h);
if (w == 0 || h == 0)
return;
data = (uint8_t *)data + src_x * 4 + src_y * byte_stride;
buf[0] = 'D';
base64_uint16(id, &buf[1]);
base64_uint16(dest_x + src_x, &buf[4]);
base64_uint16(dest_y + src_y, &buf[7]);
url = to_png_rgb (w, h, byte_stride, (uint32_t*)data);
len = strlen (url);
base64_uint32(len, &buf[10]);
broadway_client_write (client, buf, 16);
broadway_client_write (client, url, len);
free (url);
}
void
broadway_client_put_rgba (BroadwayClient *client, int id, int x, int y,
int w, int h, int byte_stride, void *data)
@ -979,11 +942,26 @@ broadway_client_put_rgba (BroadwayClient *client, int id, int x, int y,
char buf[16];
size_t len;
char *url;
int crop_x, crop_y;
crop_x = 0;
crop_y = 0;
printf ("pre crop: %dx%d\n", w, h);
rgba_autocrop (data,
byte_stride,
&crop_x, &crop_y, &w, &h);
printf ("post crop: %dx%d %d,%d\n", w, h, crop_x, crop_y);
if (w == 0 || h == 0)
return;
data = (uint8_t *)data + crop_x * 4 + crop_y * byte_stride;
buf[0] = 'i';
base64_uint16(id, &buf[1]);
base64_uint16(x, &buf[4]);
base64_uint16(y, &buf[7]);
base64_uint16(x + crop_x, &buf[4]);
base64_uint16(y + crop_y, &buf[7]);
url = to_png_rgba (w, h, byte_stride, (uint32_t*)data);
len = strlen (url);

View File

@ -39,14 +39,6 @@ void broadway_client_put_rgba (BroadwayClient *client,
int h,
int byte_stride,
void *data);
void broadway_client_put_delta_rgb (BroadwayClient *client,
int id,
int dest_x,
int dest_y,
int w,
int h,
int byte_stride,
void *data);
void broadway_client_copy_rectangles (BroadwayClient *client,
int id,
BroadwayRect *rects,

View File

@ -68,31 +68,6 @@ var surfaces = {};
var outstanding_commands = new Array();
var input_socket = null;
function apply_delta(id, img, x, y)
{
var tmp_surface = document.createElement("canvas");
var w = img.width;
var h = img.height;
tmp_surface.width = w;
tmp_surface.height = h;
tmp_context = tmp_surface.getContext("2d");
tmp_context.drawImage(img, 0, 0);
var data = surfaces[id].getImageData(x, y, w, h);
var d = data.data
var delta = tmp_context.getImageData(0, 0, w, h).data;
var imax = w * h * 4;
for (var i = 0; i < imax; i += 4) {
d[i ] = (d[i ] + delta[i ]) & 0xff;
d[i+1] = (d[i+1] + delta[i+1]) & 0xff;
d[i+2] = (d[i+2] + delta[i+2]) & 0xff;
d[i+3] = 255;
}
surfaces[id].putImageData(data, x, y);
delete tmp_surface
}
function initContext(canvas, x, y, id)
{
canvas.surface_id = id;
@ -101,7 +76,7 @@ function initContext(canvas, x, y, id)
canvas.style["left"] = y + "px"
canvas.style["display"] = "none"
context = canvas.getContext("2d")
context.globalCompositeOperation = "copy"
context.globalCompositeOperation = "src-over"
context.fillRect(0, 0, canvas.width, canvas.height);
document.body.appendChild(canvas)
@ -194,30 +169,6 @@ function handleCommands(cmd_obj)
break;
/* put delta image data surface */
case 'D':
var id = base64_16(cmd, i);
i = i + 3;
var x = base64_16(cmd, i);
i = i + 3;
var y = base64_16(cmd, i);
i = i + 3;
var size = base64_32(cmd, i);
i = i + 6;
var url = cmd.slice(i, i + size);
i = i + size;
var img = new Image();
img.src = url
if (img.complete) {
apply_delta(id, img, x, y);
} else {
cmd_obj.pos = i;
img.onload = function() { apply_delta(id, img, x, y); handleOutstanding(); }
return false
}
break;
/* copy rects */
case 'b':
var id = base64_16(cmd, i);

View File

@ -87,7 +87,7 @@ diff_surfaces (cairo_surface_t *surface,
cairo_surface_t *old_surface)
{
guint8 *data, *old_data;
guint8 *line, *old_line;
guint32 *line, *old_line;
int w, h, stride, old_stride;
int x, y;
@ -102,16 +102,17 @@ diff_surfaces (cairo_surface_t *surface,
for (y = 0; y < h; y++)
{
line = data;
old_line = old_data;
line = (guint32 *)data;
old_line = (guint32 *)old_data;
for (x = 0; x < w; x++)
{
int j;
for (j = 0; j < 4; j++)
old_line[j] = line[j] - old_line[j];
line += 4;
old_line += 4;
if ((*line & 0xffffff) == (*old_line & 0xffffff))
*old_line = 0;
else
*old_line = *line | 0xff000000;
line ++;
old_line ++;
}
data += stride;
@ -127,15 +128,18 @@ window_data_send (BroadwayClient *client, GdkWindowImplBroadway *impl)
GdkDrawableImplBroadway *drawable_impl = GDK_DRAWABLE_IMPL_BROADWAY (impl);
cairo_t *cr;
if (drawable_impl->surface == NULL)
return;
if (impl->last_synced)
{
diff_surfaces (drawable_impl->surface,
drawable_impl->last_surface);
broadway_client_put_delta_rgb (client, impl->id, 0, 0,
cairo_image_surface_get_width (drawable_impl->last_surface),
cairo_image_surface_get_height (drawable_impl->last_surface),
cairo_image_surface_get_stride (drawable_impl->last_surface),
cairo_image_surface_get_data (drawable_impl->last_surface));
broadway_client_put_rgba (client, impl->id, 0, 0,
cairo_image_surface_get_width (drawable_impl->last_surface),
cairo_image_surface_get_height (drawable_impl->last_surface),
cairo_image_surface_get_stride (drawable_impl->last_surface),
cairo_image_surface_get_data (drawable_impl->last_surface));
}
else
{