[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:
@ -5,14 +5,15 @@
|
|||||||
#include "broadway.h"
|
#include "broadway.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
|
|
||||||
static void
|
static void
|
||||||
diff_surfaces (cairo_surface_t *surface,
|
diff_surfaces (cairo_surface_t *surface,
|
||||||
cairo_surface_t *old_surface)
|
cairo_surface_t *old_surface)
|
||||||
{
|
{
|
||||||
unsigned char *data, *old_data;
|
uint8_t *data, *old_data;
|
||||||
unsigned char *line, *old_line;
|
uint32_t *line, *old_line;
|
||||||
int w, h, stride, old_stride;
|
int w, h, stride, old_stride;
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
@ -27,16 +28,17 @@ diff_surfaces (cairo_surface_t *surface,
|
|||||||
|
|
||||||
for (y = 0; y < h; y++)
|
for (y = 0; y < h; y++)
|
||||||
{
|
{
|
||||||
line = data;
|
line = (uint32_t *)data;
|
||||||
old_line = old_data;
|
old_line = (uint32_t *)old_data;
|
||||||
|
|
||||||
for (x = 0; x < w; x++)
|
for (x = 0; x < w; x++)
|
||||||
{
|
{
|
||||||
int j;
|
if (*line & 0xffffff == *old_line & 0xffffff)
|
||||||
for (j = 0; j < 4; j++)
|
*old_line = 0;
|
||||||
old_line[j] = line[j] - old_line[j];
|
else
|
||||||
line += 4;
|
*old_line = *line | 0xff000000;
|
||||||
old_line += 4;
|
line ++;
|
||||||
|
old_line ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
data += stride;
|
data += stride;
|
||||||
@ -181,7 +183,7 @@ demo2 (BroadwayClient *client)
|
|||||||
{
|
{
|
||||||
diff_surfaces (surface,
|
diff_surfaces (surface,
|
||||||
old_surface);
|
old_surface);
|
||||||
broadway_client_put_delta_rgb (client, 0, 0, 0, 800, 600, 800*4,
|
broadway_client_put_rgba (client, 0, 0, 0, 800, 600, 800*4,
|
||||||
cairo_image_surface_get_data(old_surface));
|
cairo_image_surface_get_data(old_surface));
|
||||||
}
|
}
|
||||||
broadway_client_move_surface (client, 0, 100 + i, 100 + i);
|
broadway_client_move_surface (client, 0, 100 + i, 100 + i);
|
||||||
|
|||||||
@ -834,12 +834,12 @@ broadway_client_put_rgb (BroadwayClient *client, int id, int x, int y,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rgb_autocrop (unsigned char *data,
|
rgba_autocrop (unsigned char *data,
|
||||||
int byte_stride,
|
int byte_stride,
|
||||||
int *x_arg, int *y_arg,
|
int *x_arg, int *y_arg,
|
||||||
int *w_arg, int *h_arg)
|
int *w_arg, int *h_arg)
|
||||||
{
|
{
|
||||||
unsigned char *line;
|
uint32_t *line;
|
||||||
int w, h;
|
int w, h;
|
||||||
int x, y, xx, yy;
|
int x, y, xx, yy;
|
||||||
boolean non_zero;
|
boolean non_zero;
|
||||||
@ -851,16 +851,16 @@ rgb_autocrop (unsigned char *data,
|
|||||||
|
|
||||||
while (h > 0)
|
while (h > 0)
|
||||||
{
|
{
|
||||||
line = data + y * byte_stride + x * 4;
|
line = (uint32_t *)(data + y * byte_stride + x * 4);
|
||||||
|
|
||||||
non_zero = FALSE;
|
non_zero = FALSE;
|
||||||
for (xx = 0; xx < w; xx++)
|
for (xx = 0; xx < w; xx++)
|
||||||
{
|
{
|
||||||
if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
|
if (*line != 0) {
|
||||||
non_zero = TRUE;
|
non_zero = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
line += 4;
|
line++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (non_zero)
|
if (non_zero)
|
||||||
@ -872,16 +872,16 @@ rgb_autocrop (unsigned char *data,
|
|||||||
|
|
||||||
while (h > 0)
|
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;
|
non_zero = FALSE;
|
||||||
for (xx = 0; xx < w; xx++)
|
for (xx = 0; xx < w; xx++)
|
||||||
{
|
{
|
||||||
if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
|
if (*line != 0) {
|
||||||
non_zero = TRUE;
|
non_zero = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
line += 4;
|
line++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (non_zero)
|
if (non_zero)
|
||||||
@ -891,16 +891,16 @@ rgb_autocrop (unsigned char *data,
|
|||||||
|
|
||||||
while (w > 0)
|
while (w > 0)
|
||||||
{
|
{
|
||||||
line = data + y * byte_stride + x * 4;
|
line = (uint32_t *)(data + y * byte_stride + x * 4);
|
||||||
|
|
||||||
non_zero = FALSE;
|
non_zero = FALSE;
|
||||||
for (yy = 0; yy < h; yy++)
|
for (yy = 0; yy < h; yy++)
|
||||||
{
|
{
|
||||||
if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
|
if (*line != 0) {
|
||||||
non_zero = TRUE;
|
non_zero = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
line += byte_stride;
|
line += byte_stride / 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (non_zero)
|
if (non_zero)
|
||||||
@ -912,16 +912,16 @@ rgb_autocrop (unsigned char *data,
|
|||||||
|
|
||||||
while (w > 0)
|
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;
|
non_zero = FALSE;
|
||||||
for (yy = 0; yy < h; yy++)
|
for (yy = 0; yy < h; yy++)
|
||||||
{
|
{
|
||||||
if (line[1] != 0 || line[2] != 0 || line[3] != 0) {
|
if (*line != 0) {
|
||||||
non_zero = TRUE;
|
non_zero = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
line += byte_stride;
|
line += byte_stride / 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (non_zero)
|
if (non_zero)
|
||||||
@ -935,43 +935,6 @@ rgb_autocrop (unsigned char *data,
|
|||||||
*h_arg = h;
|
*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
|
void
|
||||||
broadway_client_put_rgba (BroadwayClient *client, int id, int x, int y,
|
broadway_client_put_rgba (BroadwayClient *client, int id, int x, int y,
|
||||||
int w, int h, int byte_stride, void *data)
|
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];
|
char buf[16];
|
||||||
size_t len;
|
size_t len;
|
||||||
char *url;
|
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';
|
buf[0] = 'i';
|
||||||
base64_uint16(id, &buf[1]);
|
base64_uint16(id, &buf[1]);
|
||||||
base64_uint16(x, &buf[4]);
|
base64_uint16(x + crop_x, &buf[4]);
|
||||||
base64_uint16(y, &buf[7]);
|
base64_uint16(y + crop_y, &buf[7]);
|
||||||
|
|
||||||
url = to_png_rgba (w, h, byte_stride, (uint32_t*)data);
|
url = to_png_rgba (w, h, byte_stride, (uint32_t*)data);
|
||||||
len = strlen (url);
|
len = strlen (url);
|
||||||
|
|||||||
@ -39,14 +39,6 @@ void broadway_client_put_rgba (BroadwayClient *client,
|
|||||||
int h,
|
int h,
|
||||||
int byte_stride,
|
int byte_stride,
|
||||||
void *data);
|
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,
|
void broadway_client_copy_rectangles (BroadwayClient *client,
|
||||||
int id,
|
int id,
|
||||||
BroadwayRect *rects,
|
BroadwayRect *rects,
|
||||||
|
|||||||
@ -68,31 +68,6 @@ var surfaces = {};
|
|||||||
var outstanding_commands = new Array();
|
var outstanding_commands = new Array();
|
||||||
var input_socket = null;
|
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)
|
function initContext(canvas, x, y, id)
|
||||||
{
|
{
|
||||||
canvas.surface_id = id;
|
canvas.surface_id = id;
|
||||||
@ -101,7 +76,7 @@ function initContext(canvas, x, y, id)
|
|||||||
canvas.style["left"] = y + "px"
|
canvas.style["left"] = y + "px"
|
||||||
canvas.style["display"] = "none"
|
canvas.style["display"] = "none"
|
||||||
context = canvas.getContext("2d")
|
context = canvas.getContext("2d")
|
||||||
context.globalCompositeOperation = "copy"
|
context.globalCompositeOperation = "src-over"
|
||||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
document.body.appendChild(canvas)
|
document.body.appendChild(canvas)
|
||||||
|
|
||||||
@ -194,30 +169,6 @@ function handleCommands(cmd_obj)
|
|||||||
|
|
||||||
break;
|
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 */
|
/* copy rects */
|
||||||
case 'b':
|
case 'b':
|
||||||
var id = base64_16(cmd, i);
|
var id = base64_16(cmd, i);
|
||||||
|
|||||||
@ -87,7 +87,7 @@ diff_surfaces (cairo_surface_t *surface,
|
|||||||
cairo_surface_t *old_surface)
|
cairo_surface_t *old_surface)
|
||||||
{
|
{
|
||||||
guint8 *data, *old_data;
|
guint8 *data, *old_data;
|
||||||
guint8 *line, *old_line;
|
guint32 *line, *old_line;
|
||||||
int w, h, stride, old_stride;
|
int w, h, stride, old_stride;
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
@ -102,16 +102,17 @@ diff_surfaces (cairo_surface_t *surface,
|
|||||||
|
|
||||||
for (y = 0; y < h; y++)
|
for (y = 0; y < h; y++)
|
||||||
{
|
{
|
||||||
line = data;
|
line = (guint32 *)data;
|
||||||
old_line = old_data;
|
old_line = (guint32 *)old_data;
|
||||||
|
|
||||||
for (x = 0; x < w; x++)
|
for (x = 0; x < w; x++)
|
||||||
{
|
{
|
||||||
int j;
|
if ((*line & 0xffffff) == (*old_line & 0xffffff))
|
||||||
for (j = 0; j < 4; j++)
|
*old_line = 0;
|
||||||
old_line[j] = line[j] - old_line[j];
|
else
|
||||||
line += 4;
|
*old_line = *line | 0xff000000;
|
||||||
old_line += 4;
|
line ++;
|
||||||
|
old_line ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
data += stride;
|
data += stride;
|
||||||
@ -127,11 +128,14 @@ window_data_send (BroadwayClient *client, GdkWindowImplBroadway *impl)
|
|||||||
GdkDrawableImplBroadway *drawable_impl = GDK_DRAWABLE_IMPL_BROADWAY (impl);
|
GdkDrawableImplBroadway *drawable_impl = GDK_DRAWABLE_IMPL_BROADWAY (impl);
|
||||||
cairo_t *cr;
|
cairo_t *cr;
|
||||||
|
|
||||||
|
if (drawable_impl->surface == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
if (impl->last_synced)
|
if (impl->last_synced)
|
||||||
{
|
{
|
||||||
diff_surfaces (drawable_impl->surface,
|
diff_surfaces (drawable_impl->surface,
|
||||||
drawable_impl->last_surface);
|
drawable_impl->last_surface);
|
||||||
broadway_client_put_delta_rgb (client, impl->id, 0, 0,
|
broadway_client_put_rgba (client, impl->id, 0, 0,
|
||||||
cairo_image_surface_get_width (drawable_impl->last_surface),
|
cairo_image_surface_get_width (drawable_impl->last_surface),
|
||||||
cairo_image_surface_get_height (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_stride (drawable_impl->last_surface),
|
||||||
|
|||||||
Reference in New Issue
Block a user