mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-10 10:50:10 +00:00
broadway: Use textures to configure window contents
Instead of using the old buffer code, just use textures to define the window contents.
This commit is contained in:
parent
a4636a06a7
commit
cc7423855b
@ -1,528 +0,0 @@
|
|||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include "broadway-buffer.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* This code is based on some code from weston with this license:
|
|
||||||
*
|
|
||||||
* Copyright © 2012 Intel Corporation
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, distribute, and sell this software and
|
|
||||||
* its documentation for any purpose is hereby granted without fee, provided
|
|
||||||
* that the above copyright notice appear in all copies and that both that
|
|
||||||
* copyright notice and this permission notice appear in supporting
|
|
||||||
* documentation, and that the name of the copyright holders not be used in
|
|
||||||
* advertising or publicity pertaining to distribution of the software
|
|
||||||
* without specific, written prior permission. The copyright holders make
|
|
||||||
* no representations about the suitability of this software for any
|
|
||||||
* purpose. It is provided "as is" without express or implied warranty.
|
|
||||||
*
|
|
||||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
|
||||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
||||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
|
||||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
|
||||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
||||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct entry {
|
|
||||||
int count;
|
|
||||||
int matches;
|
|
||||||
guint32 hash;
|
|
||||||
int x, y;
|
|
||||||
int index;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _BroadwayBuffer {
|
|
||||||
guint8 *data;
|
|
||||||
struct entry *table;
|
|
||||||
int width, height, stride;
|
|
||||||
int encoded;
|
|
||||||
int block_stride, length, block_count, shift;
|
|
||||||
int stats[5];
|
|
||||||
int clashes;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const guint32 prime = 0x1f821e2d;
|
|
||||||
static const guint32 end_prime = 0xf907ec81; /* prime^block_size */
|
|
||||||
#if 0
|
|
||||||
static const guint32 vprime = 0x0137b89d;
|
|
||||||
static const guint32 end_vprime = 0xaea9a281; /* vprime^block_size */
|
|
||||||
#else
|
|
||||||
static const guint32 vprime = 0xf907ec81;
|
|
||||||
static const guint32 end_vprime = 0xcdb99001; /* vprime^block_size */
|
|
||||||
#endif
|
|
||||||
static const guint32 step = 0x0ac93019;
|
|
||||||
static const int block_size = 32, block_mask = 31;
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
verify_block_match (BroadwayBuffer *buffer, int x, int y,
|
|
||||||
BroadwayBuffer *prev, struct entry *entry)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
void *old, *match;
|
|
||||||
int w1, w2, h1, h2;
|
|
||||||
|
|
||||||
w1 = block_size;
|
|
||||||
if (x + block_size > buffer->width)
|
|
||||||
w1 = buffer->width - x;
|
|
||||||
|
|
||||||
h1 = block_size;
|
|
||||||
if (y + block_size > buffer->height)
|
|
||||||
h1 = buffer->height - y;
|
|
||||||
|
|
||||||
w2 = block_size;
|
|
||||||
if (entry->x + block_size > prev->width)
|
|
||||||
w2 = prev->width - entry->x;
|
|
||||||
|
|
||||||
h2 = block_size;
|
|
||||||
if (entry->y + block_size > prev->height)
|
|
||||||
h2 = prev->height - entry->y;
|
|
||||||
|
|
||||||
if (w1 != w2 || h1 != h2)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
for (i = 0; i < h1; i++)
|
|
||||||
{
|
|
||||||
match = buffer->data + (y + i) * buffer->stride + x * 4;
|
|
||||||
old = prev->data + (entry->y + i) * prev->stride + entry->x * 4;
|
|
||||||
if (memcmp (match, old, w1 * 4) != 0)
|
|
||||||
{
|
|
||||||
buffer->clashes++;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
insert_block (BroadwayBuffer *buffer, guint32 h, int x, int y)
|
|
||||||
{
|
|
||||||
struct entry *entry;
|
|
||||||
int i;
|
|
||||||
guint32 collision = 0;
|
|
||||||
|
|
||||||
entry = &buffer->table[h >> buffer->shift];
|
|
||||||
for (i = step; entry->count > 0 && entry->hash != h; i += step)
|
|
||||||
{
|
|
||||||
entry = &buffer->table[(h + i) >> buffer->shift];
|
|
||||||
collision++;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry->hash = h;
|
|
||||||
entry->count++;
|
|
||||||
entry->x = x;
|
|
||||||
entry->y = y;
|
|
||||||
entry->index = (buffer->block_stride * y + x) / block_size;
|
|
||||||
|
|
||||||
if (collision > G_N_ELEMENTS (buffer->stats) - 1)
|
|
||||||
collision = G_N_ELEMENTS (buffer->stats) - 1;
|
|
||||||
buffer->stats[collision]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct entry *
|
|
||||||
lookup_block (BroadwayBuffer *prev, guint32 h)
|
|
||||||
{
|
|
||||||
guint32 i;
|
|
||||||
struct entry *entry;
|
|
||||||
int shift = prev->shift;
|
|
||||||
|
|
||||||
for (i = h;
|
|
||||||
entry = &prev->table[i >> shift], entry->count > 0;
|
|
||||||
i += step)
|
|
||||||
{
|
|
||||||
if (entry->hash == h)
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct encoder {
|
|
||||||
guint32 color;
|
|
||||||
guint32 color_run;
|
|
||||||
guint32 delta;
|
|
||||||
guint32 delta_run;
|
|
||||||
GString *dest;
|
|
||||||
int bytes;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Encoding:
|
|
||||||
*
|
|
||||||
* - all 1 pixel colors are encoded literally
|
|
||||||
*
|
|
||||||
* - We don’t need to support colors with alpha 0 and non-zero
|
|
||||||
* color components, as they mean the same on the canvas anyway.
|
|
||||||
* So we use these as special codes:
|
|
||||||
*
|
|
||||||
* - 0x00 00 00 00 : one alpha 0 pixel
|
|
||||||
* - 0xaa rr gg bb : one color pixel, alpha > 0
|
|
||||||
* - 0x00 1x xx xx : delta 0 run, x is length, (20 bits)
|
|
||||||
* - 0x00 2x xx xx 0x xxxx yyyy: block ref, block number x (20 bits) at x, y
|
|
||||||
* - 0x00 3x xx xx 0xaarrggbb : solid color run, length x
|
|
||||||
* - 0x00 4x xx xx 0xaarrggbb : delta run, length x
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
emit (struct encoder *encoder, guint32 symbol)
|
|
||||||
{
|
|
||||||
g_string_append_len (encoder->dest, (char *)&symbol, sizeof (guint32));
|
|
||||||
encoder->bytes += sizeof (guint32);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
encode_run (struct encoder *encoder)
|
|
||||||
{
|
|
||||||
if (encoder->color_run == 0 && encoder->delta_run == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (encoder->color_run >= encoder->delta_run)
|
|
||||||
{
|
|
||||||
if (encoder->color_run == 1)
|
|
||||||
emit (encoder, encoder->color);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
emit (encoder, 0x00300000 | encoder->color_run);
|
|
||||||
emit (encoder, encoder->color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (encoder->delta == 0)
|
|
||||||
emit(encoder, 0x00100000 | encoder->delta_run);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
emit(encoder, 0x00400000 | encoder->delta_run);
|
|
||||||
emit(encoder, encoder->delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
encode_pixel (struct encoder *encoder, guint32 color, guint32 prev_color)
|
|
||||||
{
|
|
||||||
guint32 delta = 0;
|
|
||||||
guint32 a, r, g, b;
|
|
||||||
|
|
||||||
if (color == prev_color)
|
|
||||||
delta = 0;
|
|
||||||
else if (prev_color == 0)
|
|
||||||
delta = color;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a = ((color & 0xff000000) - (prev_color & 0xff000000)) & 0xff000000;
|
|
||||||
r = ((color & 0x00ff0000) - (prev_color & 0x00ff0000)) & 0x00ff0000;
|
|
||||||
g = ((color & 0x0000ff00) - (prev_color & 0x0000ff00)) & 0x0000ff00;
|
|
||||||
b = ((color & 0x000000ff) - (prev_color & 0x000000ff)) & 0x000000ff;
|
|
||||||
|
|
||||||
delta = a | r | g | b;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((encoder->color != color &&
|
|
||||||
encoder->color_run > encoder->delta_run) ||
|
|
||||||
|
|
||||||
(encoder->delta != delta &&
|
|
||||||
encoder->delta_run > encoder->color_run) ||
|
|
||||||
|
|
||||||
(encoder->delta != delta && encoder->color != color) ||
|
|
||||||
|
|
||||||
(encoder->delta_run == 0xFFFFF || encoder->color_run == 0xFFFFF))
|
|
||||||
{
|
|
||||||
encode_run (encoder);
|
|
||||||
|
|
||||||
encoder->color_run = 1;
|
|
||||||
encoder->color = color;
|
|
||||||
encoder->delta_run = 1;
|
|
||||||
encoder->delta = delta;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (encoder->color == color)
|
|
||||||
encoder->color_run++;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
encoder->color_run = 1;
|
|
||||||
encoder->color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (encoder->delta == delta)
|
|
||||||
encoder->delta_run++;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
encoder->delta_run = 1;
|
|
||||||
encoder->delta = delta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
encoder_flush (struct encoder *encoder)
|
|
||||||
{
|
|
||||||
encode_run (encoder);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
encode_block (struct encoder *encoder, struct entry *entry, int x, int y)
|
|
||||||
{
|
|
||||||
/* 0x00 2x xx xx 0x xxxx yyyy:
|
|
||||||
* block ref, block number x (20 bits) at x, y */
|
|
||||||
|
|
||||||
/* FIXME: Maybe don't encode pixels under blocks and just emit
|
|
||||||
* blocks at their position within the stream. */
|
|
||||||
|
|
||||||
emit (encoder, 0x00200000 | entry->index);
|
|
||||||
emit (encoder, (x << 16) | y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
broadway_buffer_destroy (BroadwayBuffer *buffer)
|
|
||||||
{
|
|
||||||
g_free (buffer->data);
|
|
||||||
g_free (buffer->table);
|
|
||||||
g_free (buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
broadway_buffer_get_width (BroadwayBuffer *buffer)
|
|
||||||
{
|
|
||||||
return buffer->width;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
broadway_buffer_get_height (BroadwayBuffer *buffer)
|
|
||||||
{
|
|
||||||
return buffer->height;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
unpremultiply_line (void *destp, void *srcp, int width)
|
|
||||||
{
|
|
||||||
guint32 *src = srcp;
|
|
||||||
guint32 *dest = destp;
|
|
||||||
guint32 *end = src + width;
|
|
||||||
while (src < end)
|
|
||||||
{
|
|
||||||
guint32 pixel;
|
|
||||||
guint8 alpha, r, g, b;
|
|
||||||
|
|
||||||
pixel = *src++;
|
|
||||||
|
|
||||||
alpha = (pixel & 0xff000000) >> 24;
|
|
||||||
|
|
||||||
if (alpha == 0xff)
|
|
||||||
*dest++ = pixel;
|
|
||||||
else if (alpha == 0)
|
|
||||||
*dest++ = 0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
|
|
||||||
g = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
|
|
||||||
b = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
|
|
||||||
*dest++ = (guint32)alpha << 24 | (guint32)r << 16 | (guint32)g << 8 | (guint32)b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BroadwayBuffer *
|
|
||||||
broadway_buffer_create (int width, int height, guint8 *data, int stride)
|
|
||||||
{
|
|
||||||
BroadwayBuffer *buffer;
|
|
||||||
int y, bits_required;
|
|
||||||
|
|
||||||
buffer = g_new0 (BroadwayBuffer, 1);
|
|
||||||
buffer->width = width;
|
|
||||||
buffer->stride = width * 4;
|
|
||||||
buffer->height = height;
|
|
||||||
|
|
||||||
buffer->block_stride = (width + block_size - 1) / block_size;
|
|
||||||
buffer->block_count =
|
|
||||||
buffer->block_stride * ((height + block_size - 1) / block_size);
|
|
||||||
bits_required = g_bit_storage (buffer->block_count * 4);
|
|
||||||
buffer->shift = 32 - bits_required;
|
|
||||||
buffer->length = 1 << bits_required;
|
|
||||||
|
|
||||||
buffer->table = g_malloc0 (buffer->length * sizeof buffer->table[0]);
|
|
||||||
|
|
||||||
memset (buffer->stats, 0, sizeof buffer->stats);
|
|
||||||
buffer->clashes = 0;
|
|
||||||
|
|
||||||
buffer->data = g_malloc (buffer->stride * height);
|
|
||||||
|
|
||||||
for (y = 0; y < height; y++)
|
|
||||||
unpremultiply_line (buffer->data + y * buffer->stride, data + y * stride, width);
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
broadway_buffer_encode (BroadwayBuffer *buffer, BroadwayBuffer *prev, GString *dest)
|
|
||||||
{
|
|
||||||
struct entry *entry;
|
|
||||||
int i, j, k;
|
|
||||||
int x0, x1, y0, y1;
|
|
||||||
guint32 *block_hashes;
|
|
||||||
guint32 hash, bottom_hash, h, *line, *bottom, *prev_line;
|
|
||||||
int width, height;
|
|
||||||
struct encoder encoder = { 0 };
|
|
||||||
int *skyline, skyline_pixels;
|
|
||||||
int matches;
|
|
||||||
|
|
||||||
width = buffer->width;
|
|
||||||
height = buffer->height;
|
|
||||||
x0 = 0;
|
|
||||||
x1 = width;
|
|
||||||
y0 = 0;
|
|
||||||
y1 = height;
|
|
||||||
|
|
||||||
skyline = g_malloc0 ((width + block_size) * sizeof skyline[0]);
|
|
||||||
|
|
||||||
block_hashes = g_malloc0 (width * sizeof block_hashes[0]);
|
|
||||||
|
|
||||||
matches = 0;
|
|
||||||
encoder.dest = dest;
|
|
||||||
|
|
||||||
// Calculate the block hashes for the first row
|
|
||||||
for (i = y0; i < MIN(y1, y0 + block_size); i++)
|
|
||||||
{
|
|
||||||
line = (guint32 *)(buffer->data + i * buffer->stride);
|
|
||||||
hash = 0;
|
|
||||||
for (j = x0; j < MIN(x1, x0 + block_size); j++)
|
|
||||||
hash = hash * prime + line[j];
|
|
||||||
for (; j < x0 + block_size; j++)
|
|
||||||
hash = hash * prime;
|
|
||||||
|
|
||||||
for (j = x0; j < x1; j++)
|
|
||||||
{
|
|
||||||
block_hashes[j] = block_hashes[j] * vprime + hash;
|
|
||||||
|
|
||||||
hash = hash * prime - line[j] * end_prime;
|
|
||||||
if (j + block_size < width)
|
|
||||||
hash += line[j + block_size];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Do the last rows if height < block_size
|
|
||||||
for (; i < y0 + block_size; i++)
|
|
||||||
{
|
|
||||||
for (j = x0; j < x1; j++)
|
|
||||||
block_hashes[j] = block_hashes[j] * vprime;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = y0; i < y1; i++)
|
|
||||||
{
|
|
||||||
line = (guint32 *) (buffer->data + i * buffer->stride);
|
|
||||||
bottom = (guint32 *) (buffer->data + (i + block_size) * buffer->stride);
|
|
||||||
bottom_hash = 0;
|
|
||||||
hash = 0;
|
|
||||||
skyline_pixels = 0;
|
|
||||||
|
|
||||||
if (prev && i < prev->height)
|
|
||||||
prev_line = (guint32 *) (prev->data + i * prev->stride);
|
|
||||||
else
|
|
||||||
prev_line = NULL;
|
|
||||||
|
|
||||||
for (j = x0; j < x0 + block_size; j++)
|
|
||||||
{
|
|
||||||
hash = hash * prime;
|
|
||||||
if (j < width)
|
|
||||||
hash += line[j];
|
|
||||||
if (i + block_size < height)
|
|
||||||
{
|
|
||||||
bottom_hash = bottom_hash * prime;
|
|
||||||
if (j < width)
|
|
||||||
bottom_hash += bottom[j];
|
|
||||||
}
|
|
||||||
if (i < skyline[j])
|
|
||||||
skyline_pixels = 0;
|
|
||||||
else
|
|
||||||
skyline_pixels++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (j = x0; j < x1; j++)
|
|
||||||
{
|
|
||||||
if (i < skyline[j])
|
|
||||||
encode_pixel (&encoder, line[j], line[j]);
|
|
||||||
else if (prev)
|
|
||||||
{
|
|
||||||
/* FIXME: Add back overlap exception
|
|
||||||
* for consecutive blocks */
|
|
||||||
|
|
||||||
h = block_hashes[j];
|
|
||||||
entry = lookup_block (prev, h);
|
|
||||||
if (entry && entry->count < 2 &&
|
|
||||||
skyline_pixels >= block_size &&
|
|
||||||
verify_block_match (buffer, j, i, prev, entry) &&
|
|
||||||
(entry->x != j || entry->y != i))
|
|
||||||
{
|
|
||||||
matches++;
|
|
||||||
encode_block (&encoder, entry, j, i);
|
|
||||||
|
|
||||||
for (k = 0; k < block_size; k++)
|
|
||||||
skyline[j + k] = i + block_size;
|
|
||||||
|
|
||||||
encode_pixel (&encoder, line[j], line[j]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (prev_line && j < prev->width)
|
|
||||||
encode_pixel (&encoder, line[j],
|
|
||||||
prev_line[j]);
|
|
||||||
else
|
|
||||||
encode_pixel (&encoder, line[j], 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
encode_pixel (&encoder, line[j], 0);
|
|
||||||
|
|
||||||
if (i < skyline[j + block_size])
|
|
||||||
skyline_pixels = 0;
|
|
||||||
else
|
|
||||||
skyline_pixels++;
|
|
||||||
|
|
||||||
/* Insert block in hash table if we're on a
|
|
||||||
* grid point. */
|
|
||||||
if (((i | j) & block_mask) == 0 && !buffer->encoded)
|
|
||||||
insert_block (buffer, block_hashes[j], j, i);
|
|
||||||
|
|
||||||
/* Update sliding block hash */
|
|
||||||
block_hashes[j] =
|
|
||||||
block_hashes[j] * vprime + bottom_hash -
|
|
||||||
hash * end_vprime;
|
|
||||||
|
|
||||||
if (i + block_size < height)
|
|
||||||
{
|
|
||||||
bottom_hash = bottom_hash * prime - bottom[j] * end_prime;
|
|
||||||
if (j + block_size < width)
|
|
||||||
bottom_hash += bottom[j + block_size];
|
|
||||||
}
|
|
||||||
hash = hash * prime - line[j] * end_prime;
|
|
||||||
if (j + block_size < width)
|
|
||||||
hash += line[j + block_size] ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder_flush (&encoder);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
fprintf(stderr, "collision stats:");
|
|
||||||
for (i = 0; i < (int) G_N_ELEMENTS(buffer->stats); i++)
|
|
||||||
fprintf(stderr, "%c%d", i == 0 ? ' ' : '/', buffer->stats[i]);
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
|
|
||||||
fprintf(stderr, "%d / %d blocks (%d%%) matched, %d clashes\n",
|
|
||||||
matches, buffer->block_count,
|
|
||||||
100 * matches / buffer->block_count, buffer->clashes);
|
|
||||||
|
|
||||||
fprintf(stderr, "output stream %d bytes, raw buffer %d bytes (%d%%)\n",
|
|
||||||
encoder.bytes, height * buffer->stride,
|
|
||||||
100 * encoder.bytes / (height * buffer->stride));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
g_free (skyline);
|
|
||||||
g_free (block_hashes);
|
|
||||||
|
|
||||||
buffer->encoded = TRUE;
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
#ifndef __BROADWAY_BUFFER__
|
|
||||||
#define __BROADWAY_BUFFER__
|
|
||||||
|
|
||||||
#include "broadway-protocol.h"
|
|
||||||
#include <glib-object.h>
|
|
||||||
|
|
||||||
typedef struct _BroadwayBuffer BroadwayBuffer;
|
|
||||||
|
|
||||||
BroadwayBuffer *broadway_buffer_create (int width,
|
|
||||||
int height,
|
|
||||||
guint8 *data,
|
|
||||||
int stride);
|
|
||||||
void broadway_buffer_destroy (BroadwayBuffer *buffer);
|
|
||||||
void broadway_buffer_encode (BroadwayBuffer *buffer,
|
|
||||||
BroadwayBuffer *prev,
|
|
||||||
GString *dest);
|
|
||||||
int broadway_buffer_get_width (BroadwayBuffer *buffer);
|
|
||||||
int broadway_buffer_get_height (BroadwayBuffer *buffer);
|
|
||||||
|
|
||||||
#endif /* __BROADWAY_BUFFER__ */
|
|
@ -287,48 +287,14 @@ broadway_output_set_transient_for (BroadwayOutput *output,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
broadway_output_put_buffer (BroadwayOutput *output,
|
broadway_output_window_update (BroadwayOutput *output,
|
||||||
int id,
|
int id,
|
||||||
BroadwayBuffer *prev_buffer,
|
guint32 texture)
|
||||||
BroadwayBuffer *buffer)
|
|
||||||
{
|
{
|
||||||
gsize len;
|
write_header (output, BROADWAY_OP_WINDOW_UPDATE);
|
||||||
int w, h;
|
|
||||||
GZlibCompressor *compressor;
|
|
||||||
GOutputStream *out, *out_mem;
|
|
||||||
GString *encoded;
|
|
||||||
|
|
||||||
write_header (output, BROADWAY_OP_PUT_BUFFER);
|
|
||||||
|
|
||||||
w = broadway_buffer_get_width (buffer);
|
|
||||||
h = broadway_buffer_get_height (buffer);
|
|
||||||
|
|
||||||
append_uint16 (output, id);
|
append_uint16 (output, id);
|
||||||
append_uint16 (output, w);
|
append_uint32 (output, texture);
|
||||||
append_uint16 (output, h);
|
|
||||||
|
|
||||||
encoded = g_string_new ("");
|
|
||||||
broadway_buffer_encode (buffer, prev_buffer, encoded);
|
|
||||||
|
|
||||||
compressor = g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_RAW, -1);
|
|
||||||
out_mem = g_memory_output_stream_new_resizable ();
|
|
||||||
out = g_converter_output_stream_new (out_mem, G_CONVERTER (compressor));
|
|
||||||
g_object_unref (compressor);
|
|
||||||
|
|
||||||
if (!g_output_stream_write_all (out, encoded->str, encoded->len,
|
|
||||||
NULL, NULL, NULL) ||
|
|
||||||
!g_output_stream_close (out, NULL, NULL))
|
|
||||||
g_warning ("compression failed");
|
|
||||||
|
|
||||||
|
|
||||||
len = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (out_mem));
|
|
||||||
append_uint32 (output, len);
|
|
||||||
|
|
||||||
g_string_append_len (output->buf, g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (out_mem)), len);
|
|
||||||
|
|
||||||
g_string_free (encoded, TRUE);
|
|
||||||
g_object_unref (out);
|
|
||||||
g_object_unref (out_mem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
#include "broadway-protocol.h"
|
#include "broadway-protocol.h"
|
||||||
#include "broadway-buffer.h"
|
|
||||||
|
|
||||||
typedef struct BroadwayOutput BroadwayOutput;
|
typedef struct BroadwayOutput BroadwayOutput;
|
||||||
|
|
||||||
@ -54,10 +53,9 @@ void broadway_output_move_resize_surface (BroadwayOutput *output,
|
|||||||
void broadway_output_set_transient_for (BroadwayOutput *output,
|
void broadway_output_set_transient_for (BroadwayOutput *output,
|
||||||
int id,
|
int id,
|
||||||
int parent_id);
|
int parent_id);
|
||||||
void broadway_output_put_buffer (BroadwayOutput *output,
|
void broadway_output_window_update (BroadwayOutput *output,
|
||||||
int id,
|
int id,
|
||||||
BroadwayBuffer *prev_buffer,
|
guint32 texture);
|
||||||
BroadwayBuffer *buffer);
|
|
||||||
void broadway_output_upload_texture (BroadwayOutput *output,
|
void broadway_output_upload_texture (BroadwayOutput *output,
|
||||||
guint32 id,
|
guint32 id,
|
||||||
GBytes *texture);
|
GBytes *texture);
|
||||||
|
@ -41,7 +41,7 @@ typedef enum {
|
|||||||
BROADWAY_OP_REQUEST_AUTH = 'l',
|
BROADWAY_OP_REQUEST_AUTH = 'l',
|
||||||
BROADWAY_OP_AUTH_OK = 'L',
|
BROADWAY_OP_AUTH_OK = 'L',
|
||||||
BROADWAY_OP_DISCONNECTED = 'D',
|
BROADWAY_OP_DISCONNECTED = 'D',
|
||||||
BROADWAY_OP_PUT_BUFFER = 'b',
|
BROADWAY_OP_WINDOW_UPDATE = 'b',
|
||||||
BROADWAY_OP_SET_SHOW_KEYBOARD = 'k',
|
BROADWAY_OP_SET_SHOW_KEYBOARD = 'k',
|
||||||
BROADWAY_OP_UPLOAD_TEXTURE = 't',
|
BROADWAY_OP_UPLOAD_TEXTURE = 't',
|
||||||
BROADWAY_OP_RELEASE_TEXTURE = 'T',
|
BROADWAY_OP_RELEASE_TEXTURE = 'T',
|
||||||
@ -193,9 +193,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
BroadwayRequestBase base;
|
BroadwayRequestBase base;
|
||||||
guint32 id;
|
guint32 id;
|
||||||
char name[36];
|
guint32 texture;
|
||||||
guint32 width;
|
|
||||||
guint32 height;
|
|
||||||
} BroadwayRequestUpdate;
|
} BroadwayRequestUpdate;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -116,12 +116,7 @@ struct BroadwayWindow {
|
|||||||
gboolean is_temp;
|
gboolean is_temp;
|
||||||
gboolean visible;
|
gboolean visible;
|
||||||
gint32 transient_for;
|
gint32 transient_for;
|
||||||
|
guint32 texture;
|
||||||
BroadwayBuffer *buffer;
|
|
||||||
gboolean buffer_synced;
|
|
||||||
|
|
||||||
char *cached_surface_name;
|
|
||||||
cairo_surface_t *cached_surface;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void broadway_server_resync_windows (BroadwayServer *server);
|
static void broadway_server_resync_windows (BroadwayServer *server);
|
||||||
@ -826,87 +821,6 @@ broadway_server_block_for_input (BroadwayServer *server, char op,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void *
|
|
||||||
map_named_shm (char *name, gsize size)
|
|
||||||
{
|
|
||||||
#ifdef G_OS_UNIX
|
|
||||||
|
|
||||||
int fd;
|
|
||||||
void *ptr;
|
|
||||||
char *filename = NULL;
|
|
||||||
|
|
||||||
fd = shm_open (name, O_RDONLY, 0600);
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
filename = g_build_filename (g_get_tmp_dir (), name, NULL);
|
|
||||||
fd = open (filename, O_RDONLY);
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
perror ("Failed to map shm");
|
|
||||||
g_free (filename);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr = mmap (0, size, PROT_READ, MAP_SHARED, fd, 0);
|
|
||||||
|
|
||||||
(void) close (fd);
|
|
||||||
|
|
||||||
if (filename)
|
|
||||||
{
|
|
||||||
unlink (filename);
|
|
||||||
g_free (filename);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
shm_unlink (name);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
|
|
||||||
#elif defined(G_OS_WIN32)
|
|
||||||
|
|
||||||
int fd;
|
|
||||||
void *ptr;
|
|
||||||
char *shmpath;
|
|
||||||
void *map = ((void *)-1);
|
|
||||||
|
|
||||||
if (*name == '/')
|
|
||||||
++name;
|
|
||||||
shmpath = g_build_filename (g_get_tmp_dir (), name, NULL);
|
|
||||||
|
|
||||||
fd = open(shmpath, O_RDONLY, 0600);
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
g_free (shmpath);
|
|
||||||
perror ("Failed to shm_open");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size == 0)
|
|
||||||
ptr = map;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HANDLE h, fm;
|
|
||||||
h = (HANDLE)_get_osfhandle (fd);
|
|
||||||
fm = CreateFileMapping (h, NULL, PAGE_READONLY, 0, (DWORD)size, NULL);
|
|
||||||
ptr = MapViewOfFile (fm, FILE_MAP_READ, 0, 0, (size_t)size);
|
|
||||||
CloseHandle (fm);
|
|
||||||
}
|
|
||||||
|
|
||||||
(void) close(fd);
|
|
||||||
|
|
||||||
remove (shmpath);
|
|
||||||
g_free (shmpath);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error "No shm mapping supported"
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
parse_line (const char *line, const char *key)
|
parse_line (const char *line, const char *key)
|
||||||
{
|
{
|
||||||
@ -1463,10 +1377,6 @@ broadway_server_destroy_window (BroadwayServer *server,
|
|||||||
g_hash_table_remove (server->id_ht,
|
g_hash_table_remove (server->id_ht,
|
||||||
GINT_TO_POINTER (id));
|
GINT_TO_POINTER (id));
|
||||||
|
|
||||||
g_free (window->cached_surface_name);
|
|
||||||
if (window->cached_surface != NULL)
|
|
||||||
cairo_surface_destroy (window->cached_surface);
|
|
||||||
|
|
||||||
g_free (window);
|
g_free (window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1601,39 +1511,22 @@ broadway_server_has_client (BroadwayServer *server)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
broadway_server_window_update (BroadwayServer *server,
|
broadway_server_window_update (BroadwayServer *server,
|
||||||
gint id,
|
gint id,
|
||||||
cairo_surface_t *surface)
|
guint32 texture)
|
||||||
{
|
{
|
||||||
BroadwayWindow *window;
|
BroadwayWindow *window;
|
||||||
BroadwayBuffer *buffer;
|
|
||||||
|
|
||||||
if (surface == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
window = g_hash_table_lookup (server->id_ht,
|
window = g_hash_table_lookup (server->id_ht,
|
||||||
GINT_TO_POINTER (id));
|
GINT_TO_POINTER (id));
|
||||||
if (window == NULL)
|
if (window == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g_assert (window->width == cairo_image_surface_get_width (surface));
|
window->texture = texture;
|
||||||
g_assert (window->height == cairo_image_surface_get_height (surface));
|
|
||||||
|
|
||||||
buffer = broadway_buffer_create (window->width, window->height,
|
|
||||||
cairo_image_surface_get_data (surface),
|
|
||||||
cairo_image_surface_get_stride (surface));
|
|
||||||
|
|
||||||
if (server->output != NULL)
|
if (server->output != NULL)
|
||||||
{
|
broadway_output_window_update (server->output, window->id,
|
||||||
window->buffer_synced = TRUE;
|
window->texture);
|
||||||
broadway_output_put_buffer (server->output, window->id,
|
|
||||||
window->buffer, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window->buffer)
|
|
||||||
broadway_buffer_destroy (window->buffer);
|
|
||||||
|
|
||||||
window->buffer = buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
guint32
|
guint32
|
||||||
@ -1788,78 +1681,6 @@ broadway_server_ungrab_pointer (BroadwayServer *server,
|
|||||||
return serial;
|
return serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const cairo_user_data_key_t shm_cairo_key;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
void *data;
|
|
||||||
gsize data_size;
|
|
||||||
} ShmSurfaceData;
|
|
||||||
|
|
||||||
static void
|
|
||||||
shm_data_unmap (void *_data)
|
|
||||||
{
|
|
||||||
ShmSurfaceData *data = _data;
|
|
||||||
#ifdef G_OS_UNIX
|
|
||||||
munmap (data->data, data->data_size);
|
|
||||||
#elif defined(G_OS_WIN32)
|
|
||||||
UnmapViewOfFile (data->data);
|
|
||||||
#endif
|
|
||||||
g_free (data);
|
|
||||||
}
|
|
||||||
|
|
||||||
cairo_surface_t *
|
|
||||||
broadway_server_open_surface (BroadwayServer *server,
|
|
||||||
guint32 id,
|
|
||||||
char *name,
|
|
||||||
int width,
|
|
||||||
int height)
|
|
||||||
{
|
|
||||||
BroadwayWindow *window;
|
|
||||||
ShmSurfaceData *data;
|
|
||||||
cairo_surface_t *surface;
|
|
||||||
gsize size;
|
|
||||||
void *ptr;
|
|
||||||
|
|
||||||
window = g_hash_table_lookup (server->id_ht,
|
|
||||||
GINT_TO_POINTER (id));
|
|
||||||
if (window == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (window->cached_surface_name != NULL &&
|
|
||||||
strcmp (name, window->cached_surface_name) == 0)
|
|
||||||
return cairo_surface_reference (window->cached_surface);
|
|
||||||
|
|
||||||
size = width * height * sizeof (guint32);
|
|
||||||
|
|
||||||
ptr = map_named_shm (name, size);
|
|
||||||
|
|
||||||
if (ptr == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
data = g_new0 (ShmSurfaceData, 1);
|
|
||||||
|
|
||||||
data->data = ptr;
|
|
||||||
data->data_size = size;
|
|
||||||
|
|
||||||
surface = cairo_image_surface_create_for_data ((guchar *)data->data,
|
|
||||||
CAIRO_FORMAT_ARGB32,
|
|
||||||
width, height,
|
|
||||||
width * sizeof (guint32));
|
|
||||||
g_assert (surface != NULL);
|
|
||||||
|
|
||||||
cairo_surface_set_user_data (surface, &shm_cairo_key,
|
|
||||||
data, shm_data_unmap);
|
|
||||||
|
|
||||||
g_free (window->cached_surface_name);
|
|
||||||
window->cached_surface_name = g_strdup (name);
|
|
||||||
|
|
||||||
if (window->cached_surface != NULL)
|
|
||||||
cairo_surface_destroy (window->cached_surface);
|
|
||||||
window->cached_surface = cairo_surface_reference (surface);
|
|
||||||
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
guint32
|
guint32
|
||||||
broadway_server_new_window (BroadwayServer *server,
|
broadway_server_new_window (BroadwayServer *server,
|
||||||
int x,
|
int x,
|
||||||
@ -1929,7 +1750,6 @@ broadway_server_resync_windows (BroadwayServer *server)
|
|||||||
if (window->id == 0)
|
if (window->id == 0)
|
||||||
continue; /* Skip root */
|
continue; /* Skip root */
|
||||||
|
|
||||||
window->buffer_synced = FALSE;
|
|
||||||
broadway_output_new_surface (server->output,
|
broadway_output_new_surface (server->output,
|
||||||
window->id,
|
window->id,
|
||||||
window->x,
|
window->x,
|
||||||
@ -1948,18 +1768,14 @@ broadway_server_resync_windows (BroadwayServer *server)
|
|||||||
continue; /* Skip root */
|
continue; /* Skip root */
|
||||||
|
|
||||||
if (window->transient_for != -1)
|
if (window->transient_for != -1)
|
||||||
broadway_output_set_transient_for (server->output, window->id, window->transient_for);
|
broadway_output_set_transient_for (server->output, window->id,
|
||||||
if (window->visible)
|
window->transient_for);
|
||||||
{
|
|
||||||
broadway_output_show_surface (server->output, window->id);
|
|
||||||
|
|
||||||
if (window->buffer != NULL)
|
broadway_output_window_update (server->output, window->id,
|
||||||
{
|
window->texture);
|
||||||
window->buffer_synced = TRUE;
|
|
||||||
broadway_output_put_buffer (server->output, window->id,
|
if (window->visible)
|
||||||
NULL, window->buffer);
|
broadway_output_show_surface (server->output, window->id);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server->show_keyboard)
|
if (server->show_keyboard)
|
||||||
|
@ -84,7 +84,7 @@ cairo_surface_t * broadway_server_create_surface (int
|
|||||||
int height);
|
int height);
|
||||||
void broadway_server_window_update (BroadwayServer *server,
|
void broadway_server_window_update (BroadwayServer *server,
|
||||||
gint id,
|
gint id,
|
||||||
cairo_surface_t *surface);
|
guint32 texture);
|
||||||
gboolean broadway_server_window_move_resize (BroadwayServer *server,
|
gboolean broadway_server_window_move_resize (BroadwayServer *server,
|
||||||
gint id,
|
gint id,
|
||||||
gboolean with_move,
|
gboolean with_move,
|
||||||
@ -94,10 +94,5 @@ gboolean broadway_server_window_move_resize (BroadwayServer *
|
|||||||
int height);
|
int height);
|
||||||
void broadway_server_focus_window (BroadwayServer *server,
|
void broadway_server_focus_window (BroadwayServer *server,
|
||||||
gint new_focused_window);
|
gint new_focused_window);
|
||||||
cairo_surface_t * broadway_server_open_surface (BroadwayServer *server,
|
|
||||||
guint32 id,
|
|
||||||
char *name,
|
|
||||||
int width,
|
|
||||||
int height);
|
|
||||||
|
|
||||||
#endif /* __BROADWAY_SERVER__ */
|
#endif /* __BROADWAY_SERVER__ */
|
||||||
|
@ -67,25 +67,6 @@ function logStackTrace(len) {
|
|||||||
log(callstack[i]);
|
log(callstack[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resizeCanvas(canvas, w, h)
|
|
||||||
{
|
|
||||||
/* Canvas resize clears the data, so we need to save it first */
|
|
||||||
var tmpCanvas = canvas.ownerDocument.createElement("canvas");
|
|
||||||
tmpCanvas.width = canvas.width;
|
|
||||||
tmpCanvas.height = canvas.height;
|
|
||||||
var tmpContext = tmpCanvas.getContext("2d");
|
|
||||||
tmpContext.globalCompositeOperation = "copy";
|
|
||||||
tmpContext.drawImage(canvas, 0, 0, tmpCanvas.width, tmpCanvas.height);
|
|
||||||
|
|
||||||
canvas.width = w;
|
|
||||||
canvas.height = h;
|
|
||||||
|
|
||||||
var context = canvas.getContext("2d");
|
|
||||||
|
|
||||||
context.globalCompositeOperation = "copy";
|
|
||||||
context.drawImage(tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
var grab = new Object();
|
var grab = new Object();
|
||||||
grab.window = null;
|
grab.window = null;
|
||||||
grab.ownerEvents = false;
|
grab.ownerEvents = false;
|
||||||
@ -160,15 +141,15 @@ function cmdCreateSurface(id, x, y, width, height, isTemp)
|
|||||||
surface.visible = false;
|
surface.visible = false;
|
||||||
surface.imageData = null;
|
surface.imageData = null;
|
||||||
|
|
||||||
var canvas = document.createElement("canvas");
|
var image = new Image();
|
||||||
canvas.width = width;
|
image.width = width;
|
||||||
canvas.height = height;
|
image.height = height;
|
||||||
canvas.surface = surface;
|
image.surface = surface;
|
||||||
surface.canvas = canvas;
|
surface.image = image;
|
||||||
var toplevelElement;
|
var toplevelElement;
|
||||||
|
|
||||||
toplevelElement = canvas;
|
toplevelElement = image;
|
||||||
document.body.appendChild(canvas);
|
document.body.appendChild(image);
|
||||||
|
|
||||||
surface.toplevelElement = toplevelElement;
|
surface.toplevelElement = toplevelElement;
|
||||||
toplevelElement.style["position"] = "absolute";
|
toplevelElement.style["position"] = "absolute";
|
||||||
@ -268,8 +249,8 @@ function cmdDeleteSurface(id)
|
|||||||
var i = stackingOrder.indexOf(surface);
|
var i = stackingOrder.indexOf(surface);
|
||||||
if (i >= 0)
|
if (i >= 0)
|
||||||
stackingOrder.splice(i, 1);
|
stackingOrder.splice(i, 1);
|
||||||
var canvas = surface.canvas;
|
var image = surface.image;
|
||||||
canvas.parentNode.removeChild(canvas);
|
image.parentNode.removeChild(image);
|
||||||
delete surfaces[id];
|
delete surfaces[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,15 +267,17 @@ function cmdMoveResizeSurface(id, has_pos, x, y, has_size, w, h)
|
|||||||
surface.height = h;
|
surface.height = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_size)
|
if (has_size) {
|
||||||
resizeCanvas(surface.canvas, w, h);
|
surface.image.width = w;
|
||||||
|
surface.image.height = h;
|
||||||
|
}
|
||||||
|
|
||||||
if (surface.visible) {
|
if (surface.visible) {
|
||||||
if (has_pos) {
|
if (has_pos) {
|
||||||
var xOffset = surface.x;
|
var xOffset = surface.x;
|
||||||
var yOffset = surface.y;
|
var yOffset = surface.y;
|
||||||
|
|
||||||
var element = surface.canvas;
|
var element = surface.image;
|
||||||
|
|
||||||
element.style["left"] = xOffset + "px";
|
element.style["left"] = xOffset + "px";
|
||||||
element.style["top"] = yOffset + "px";
|
element.style["top"] = yOffset + "px";
|
||||||
@ -512,21 +495,12 @@ function decodeBuffer(context, oldData, w, h, data, debug)
|
|||||||
return imageData;
|
return imageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cmdPutBuffer(id, w, h, compressed)
|
function cmdWindowUpdate(id, texture_id)
|
||||||
{
|
{
|
||||||
var surface = surfaces[id];
|
var surface = surfaces[id];
|
||||||
var context = surface.canvas.getContext("2d");
|
var texture_url = textures[texture];
|
||||||
|
|
||||||
var inflate = new Zlib.RawInflate(compressed);
|
surface.image.src = texture_url;
|
||||||
var data = inflate.decompress();
|
|
||||||
|
|
||||||
var imageData = decodeBuffer (context, surface.imageData, w, h, data, debugDecoding);
|
|
||||||
context.putImageData(imageData, 0, 0);
|
|
||||||
|
|
||||||
if (debugDecoding)
|
|
||||||
imageData = decodeBuffer (context, surface.imageData, w, h, data, false);
|
|
||||||
|
|
||||||
surface.imageData = imageData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cmdUploadTexture(id, data)
|
function cmdUploadTexture(id, data)
|
||||||
@ -631,12 +605,10 @@ function handleCommands(cmd)
|
|||||||
cmdLowerSurface(id);
|
cmdLowerSurface(id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'b': // Put image buffer
|
case 'b': // Update window
|
||||||
id = cmd.get_16();
|
id = cmd.get_16();
|
||||||
w = cmd.get_16();
|
texture = cmd.get_32();
|
||||||
h = cmd.get_16();
|
cmdWindowUpdate(id, texture);
|
||||||
var data = cmd.get_data();
|
|
||||||
cmdPutBuffer(id, w, h, data);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 't': // Upload texture
|
case 't': // Upload texture
|
||||||
|
@ -225,7 +225,6 @@ client_handle_request (BroadwayClient *client,
|
|||||||
BroadwayReplyQueryMouse reply_query_mouse;
|
BroadwayReplyQueryMouse reply_query_mouse;
|
||||||
BroadwayReplyGrabPointer reply_grab_pointer;
|
BroadwayReplyGrabPointer reply_grab_pointer;
|
||||||
BroadwayReplyUngrabPointer reply_ungrab_pointer;
|
BroadwayReplyUngrabPointer reply_ungrab_pointer;
|
||||||
cairo_surface_t *surface;
|
|
||||||
guint32 before_serial, now_serial;
|
guint32 before_serial, now_serial;
|
||||||
guint32 global_id;
|
guint32 global_id;
|
||||||
int fd;
|
int fd;
|
||||||
@ -284,18 +283,11 @@ client_handle_request (BroadwayClient *client,
|
|||||||
request->set_transient_for.parent);
|
request->set_transient_for.parent);
|
||||||
break;
|
break;
|
||||||
case BROADWAY_REQUEST_UPDATE:
|
case BROADWAY_REQUEST_UPDATE:
|
||||||
surface = broadway_server_open_surface (server,
|
global_id = GPOINTER_TO_INT (g_hash_table_lookup (client->textures,
|
||||||
request->update.id,
|
GINT_TO_POINTER (request->update.texture)));
|
||||||
request->update.name,
|
broadway_server_window_update (server,
|
||||||
request->update.width,
|
request->update.id,
|
||||||
request->update.height);
|
global_id);
|
||||||
if (surface != NULL)
|
|
||||||
{
|
|
||||||
broadway_server_window_update (server,
|
|
||||||
request->update.id,
|
|
||||||
surface);
|
|
||||||
cairo_surface_destroy (surface);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case BROADWAY_REQUEST_UPLOAD_TEXTURE:
|
case BROADWAY_REQUEST_UPLOAD_TEXTURE:
|
||||||
if (client->fds == NULL)
|
if (client->fds == NULL)
|
||||||
|
@ -552,229 +552,15 @@ _gdk_broadway_server_window_set_transient_for (GdkBroadwayServer *server,
|
|||||||
BROADWAY_REQUEST_SET_TRANSIENT_FOR);
|
BROADWAY_REQUEST_SET_TRANSIENT_FOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
|
||||||
map_named_shm (char *name, gsize size, gboolean *is_shm)
|
|
||||||
{
|
|
||||||
#ifdef G_OS_UNIX
|
|
||||||
|
|
||||||
char *filename = NULL;
|
|
||||||
int fd;
|
|
||||||
void *ptr;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
fd = shm_open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
if (errno == EEXIST)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
filename = g_build_filename (g_get_tmp_dir (), name, NULL);
|
|
||||||
|
|
||||||
fd = open (filename, O_RDWR | O_CREAT | O_EXCL, 0600);
|
|
||||||
g_free (filename);
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
if (errno != EEXIST)
|
|
||||||
g_error ("Unable to allocate shared mem for window");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*is_shm = FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*is_shm = TRUE;
|
|
||||||
|
|
||||||
res = ftruncate (fd, size);
|
|
||||||
g_assert (res != -1);
|
|
||||||
|
|
||||||
#ifdef HAVE_POSIX_FALLOCATE
|
|
||||||
res = posix_fallocate (fd, 0, size);
|
|
||||||
if (res != 0 && errno == ENOSPC)
|
|
||||||
{
|
|
||||||
if (filename)
|
|
||||||
unlink (filename);
|
|
||||||
else
|
|
||||||
shm_unlink (name);
|
|
||||||
g_error ("Not enough shared memory for window surface");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ptr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
|
||||||
|
|
||||||
(void) close(fd);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
|
|
||||||
#elif defined(G_OS_WIN32)
|
|
||||||
|
|
||||||
int fd;
|
|
||||||
void *ptr;
|
|
||||||
char *shmpath;
|
|
||||||
void *map = ((void *)-1);
|
|
||||||
int res;
|
|
||||||
|
|
||||||
if (*name == '/')
|
|
||||||
++name;
|
|
||||||
shmpath = g_build_filename (g_get_tmp_dir (), name, NULL);
|
|
||||||
|
|
||||||
fd = open(shmpath, O_RDWR|O_CREAT|O_EXCL, 0600);
|
|
||||||
g_free (shmpath);
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
if (errno != EEXIST)
|
|
||||||
g_error ("Unable to allocate shared mem for window");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*is_shm = TRUE;
|
|
||||||
res = ftruncate (fd, size);
|
|
||||||
g_assert (res != -1);
|
|
||||||
|
|
||||||
if (size == 0)
|
|
||||||
ptr = map;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HANDLE h, fm;
|
|
||||||
h = (HANDLE)_get_osfhandle (fd);
|
|
||||||
fm = CreateFileMapping (h, NULL, PAGE_READWRITE, 0, (DWORD)size, NULL);
|
|
||||||
ptr = MapViewOfFile (fm, FILE_MAP_WRITE, 0, 0, (size_t)size);
|
|
||||||
CloseHandle (fm);
|
|
||||||
}
|
|
||||||
|
|
||||||
(void) close(fd);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error "No shm mapping supported"
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static char
|
|
||||||
make_valid_fs_char (char c)
|
|
||||||
{
|
|
||||||
char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890";
|
|
||||||
|
|
||||||
return chars[c % (sizeof (chars) - 1)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* name must have at least space for 34 bytes */
|
|
||||||
static gpointer
|
|
||||||
create_random_shm (char *name, gsize size, gboolean *is_shm)
|
|
||||||
{
|
|
||||||
guint32 r;
|
|
||||||
int i, o;
|
|
||||||
gpointer ptr;
|
|
||||||
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
o = 0;
|
|
||||||
name[o++] = '/';
|
|
||||||
name[o++] = 'b';
|
|
||||||
name[o++] = 'd';
|
|
||||||
name[o++] = 'w';
|
|
||||||
name[o++] = '-';
|
|
||||||
for (i = 0; i < 32/4 - 1; i++)
|
|
||||||
{
|
|
||||||
r = g_random_int ();
|
|
||||||
name[o++] = make_valid_fs_char ((r >> 0) & 0xff);
|
|
||||||
name[o++] = make_valid_fs_char ((r >> 8) & 0xff);
|
|
||||||
name[o++] = make_valid_fs_char ((r >> 16) & 0xff);
|
|
||||||
name[o++] = make_valid_fs_char ((r >> 24) & 0xff);
|
|
||||||
}
|
|
||||||
name[o++] = 0;
|
|
||||||
|
|
||||||
ptr = map_named_shm (name, size, is_shm);
|
|
||||||
if (ptr)
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const cairo_user_data_key_t gdk_broadway_shm_cairo_key;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char name[36];
|
|
||||||
void *data;
|
|
||||||
gsize data_size;
|
|
||||||
gboolean is_shm;
|
|
||||||
} BroadwayShmSurfaceData;
|
|
||||||
|
|
||||||
static void
|
|
||||||
shm_data_destroy (void *_data)
|
|
||||||
{
|
|
||||||
BroadwayShmSurfaceData *data = _data;
|
|
||||||
|
|
||||||
#ifdef G_OS_UNIX
|
|
||||||
|
|
||||||
munmap (data->data, data->data_size);
|
|
||||||
if (data->is_shm)
|
|
||||||
shm_unlink (data->name);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char *filename = g_build_filename (g_get_tmp_dir (), data->name, NULL);
|
|
||||||
unlink (filename);
|
|
||||||
g_free (filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(G_OS_WIN32)
|
|
||||||
|
|
||||||
char *name = data->name;
|
|
||||||
char *shmpath;
|
|
||||||
|
|
||||||
if (*name == '/')
|
|
||||||
++name;
|
|
||||||
|
|
||||||
shmpath = g_build_filename (g_get_tmp_dir (), name, NULL);
|
|
||||||
UnmapViewOfFile (data->data);
|
|
||||||
remove (shmpath);
|
|
||||||
g_free (shmpath);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
g_free (data);
|
|
||||||
}
|
|
||||||
|
|
||||||
cairo_surface_t *
|
|
||||||
_gdk_broadway_server_create_surface (int width,
|
|
||||||
int height)
|
|
||||||
{
|
|
||||||
BroadwayShmSurfaceData *data;
|
|
||||||
cairo_surface_t *surface;
|
|
||||||
|
|
||||||
data = g_new (BroadwayShmSurfaceData, 1);
|
|
||||||
data->data_size = width * height * sizeof (guint32);
|
|
||||||
data->data = create_random_shm (data->name, data->data_size, &data->is_shm);
|
|
||||||
|
|
||||||
surface = cairo_image_surface_create_for_data ((guchar *)data->data,
|
|
||||||
CAIRO_FORMAT_ARGB32, width, height, width * sizeof (guint32));
|
|
||||||
g_assert (surface != NULL);
|
|
||||||
|
|
||||||
cairo_surface_set_user_data (surface, &gdk_broadway_shm_cairo_key,
|
|
||||||
data, shm_data_destroy);
|
|
||||||
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_gdk_broadway_server_window_update (GdkBroadwayServer *server,
|
_gdk_broadway_server_window_update (GdkBroadwayServer *server,
|
||||||
gint id,
|
gint id,
|
||||||
cairo_surface_t *surface)
|
guint32 texture)
|
||||||
{
|
{
|
||||||
BroadwayRequestUpdate msg;
|
BroadwayRequestUpdate msg;
|
||||||
BroadwayShmSurfaceData *data;
|
|
||||||
|
|
||||||
if (surface == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
data = cairo_surface_get_user_data (surface, &gdk_broadway_shm_cairo_key);
|
|
||||||
g_assert (data != NULL);
|
|
||||||
|
|
||||||
msg.id = id;
|
msg.id = id;
|
||||||
memcpy (msg.name, data->name, 36);
|
msg.texture = texture;
|
||||||
msg.width = cairo_image_surface_get_width (surface);
|
|
||||||
msg.height = cairo_image_surface_get_height (surface);
|
|
||||||
|
|
||||||
gdk_broadway_server_send_message (server, msg,
|
gdk_broadway_server_send_message (server, msg,
|
||||||
BROADWAY_REQUEST_UPDATE);
|
BROADWAY_REQUEST_UPDATE);
|
||||||
|
@ -63,11 +63,9 @@ guint32 gdk_broadway_server_upload_texture (GdkBroadwaySer
|
|||||||
GdkTexture *texture);
|
GdkTexture *texture);
|
||||||
void gdk_broadway_server_release_texture (GdkBroadwayServer *server,
|
void gdk_broadway_server_release_texture (GdkBroadwayServer *server,
|
||||||
guint32 id);
|
guint32 id);
|
||||||
cairo_surface_t *_gdk_broadway_server_create_surface (int width,
|
|
||||||
int height);
|
|
||||||
void _gdk_broadway_server_window_update (GdkBroadwayServer *server,
|
void _gdk_broadway_server_window_update (GdkBroadwayServer *server,
|
||||||
gint id,
|
gint id,
|
||||||
cairo_surface_t *surface);
|
guint32 texture);
|
||||||
gboolean _gdk_broadway_server_window_move_resize (GdkBroadwayServer *server,
|
gboolean _gdk_broadway_server_window_move_resize (GdkBroadwayServer *server,
|
||||||
gint id,
|
gint id,
|
||||||
gboolean with_move,
|
gboolean with_move,
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "gdkinternals.h"
|
#include "gdkinternals.h"
|
||||||
#include "gdkdeviceprivate.h"
|
#include "gdkdeviceprivate.h"
|
||||||
#include "gdkdevicemanager-broadway.h"
|
#include "gdkdevicemanager-broadway.h"
|
||||||
|
#include <gdk/gdktextureprivate.h>
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib/gprintf.h>
|
#include <glib/gprintf.h>
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "gdkinternals.h"
|
#include "gdkinternals.h"
|
||||||
#include "gdkdeviceprivate.h"
|
#include "gdkdeviceprivate.h"
|
||||||
#include "gdkeventsource.h"
|
#include "gdkeventsource.h"
|
||||||
|
#include <gdk/gdktextureprivate.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -112,11 +113,26 @@ update_dirty_windows_and_sync (void)
|
|||||||
|
|
||||||
if (impl->dirty)
|
if (impl->dirty)
|
||||||
{
|
{
|
||||||
|
GdkTexture *texture;
|
||||||
|
guint32 texture_id;
|
||||||
|
|
||||||
impl->dirty = FALSE;
|
impl->dirty = FALSE;
|
||||||
updated_surface = TRUE;
|
updated_surface = TRUE;
|
||||||
|
|
||||||
|
if (impl->texture_id)
|
||||||
|
gdk_broadway_server_release_texture (display->server, impl->texture_id);
|
||||||
|
impl->texture_id = 0;
|
||||||
|
|
||||||
|
texture = gdk_texture_new_for_surface (impl->surface);
|
||||||
|
texture_id = gdk_broadway_server_upload_texture (display->server, texture);
|
||||||
|
g_object_unref (texture);
|
||||||
|
|
||||||
|
impl->texture_id = texture_id;
|
||||||
|
|
||||||
_gdk_broadway_server_window_update (display->server,
|
_gdk_broadway_server_window_update (display->server,
|
||||||
impl->id,
|
impl->id,
|
||||||
impl->surface);
|
texture_id);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,8 +262,9 @@ _gdk_broadway_window_resize_surface (GdkWindow *window)
|
|||||||
{
|
{
|
||||||
cairo_surface_destroy (impl->surface);
|
cairo_surface_destroy (impl->surface);
|
||||||
|
|
||||||
impl->surface = _gdk_broadway_server_create_surface (gdk_window_get_width (impl->wrapper),
|
impl->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||||
gdk_window_get_height (impl->wrapper));
|
gdk_window_get_width (impl->wrapper),
|
||||||
|
gdk_window_get_height (impl->wrapper));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (impl->ref_surface)
|
if (impl->ref_surface)
|
||||||
@ -283,7 +300,7 @@ gdk_window_broadway_ref_cairo_surface (GdkWindow *window)
|
|||||||
|
|
||||||
/* Create actual backing store if missing */
|
/* Create actual backing store if missing */
|
||||||
if (!impl->surface)
|
if (!impl->surface)
|
||||||
impl->surface = _gdk_broadway_server_create_surface (w, h);
|
impl->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
|
||||||
|
|
||||||
/* Create a destroyable surface referencing the real one */
|
/* Create a destroyable surface referencing the real one */
|
||||||
if (!impl->ref_surface)
|
if (!impl->ref_surface)
|
||||||
@ -334,6 +351,9 @@ _gdk_broadway_window_destroy (GdkWindow *window,
|
|||||||
g_hash_table_remove (broadway_display->id_ht, GINT_TO_POINTER (impl->id));
|
g_hash_table_remove (broadway_display->id_ht, GINT_TO_POINTER (impl->id));
|
||||||
|
|
||||||
_gdk_broadway_server_destroy_window (broadway_display->server, impl->id);
|
_gdk_broadway_server_destroy_window (broadway_display->server, impl->id);
|
||||||
|
if (impl->texture_id)
|
||||||
|
gdk_broadway_server_release_texture (broadway_display->server, impl->texture_id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is called when the XWindow is really gone.
|
/* This function is called when the XWindow is really gone.
|
||||||
|
@ -55,6 +55,7 @@ struct _GdkWindowImplBroadway
|
|||||||
GdkCursor *cursor;
|
GdkCursor *cursor;
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
|
int texture_id;
|
||||||
|
|
||||||
gboolean visible;
|
gboolean visible;
|
||||||
gboolean maximized;
|
gboolean maximized;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
gdk_broadway_sources = files([
|
gdk_broadway_sources = files([
|
||||||
'broadway-buffer.c',
|
|
||||||
'broadway-output.c',
|
'broadway-output.c',
|
||||||
'broadway-server.c',
|
'broadway-server.c',
|
||||||
'broadwayd.c',
|
'broadwayd.c',
|
||||||
@ -60,7 +59,7 @@ broadwayjs_h = custom_target('broadwayjs.h',
|
|||||||
|
|
||||||
executable('gtk4-broadwayd',
|
executable('gtk4-broadwayd',
|
||||||
clienthtml_h, broadwayjs_h,
|
clienthtml_h, broadwayjs_h,
|
||||||
'broadwayd.c', 'broadway-server.c', 'broadway-buffer.c', 'broadway-output.c',
|
'broadwayd.c', 'broadway-server.c', 'broadway-output.c',
|
||||||
include_directories: [confinc, gdkinc],
|
include_directories: [confinc, gdkinc],
|
||||||
c_args: ['-DGDK_COMPILATION', '-DG_LOG_DOMAIN="Gdk"', ],
|
c_args: ['-DGDK_COMPILATION', '-DG_LOG_DOMAIN="Gdk"', ],
|
||||||
dependencies : [broadwayd_syslib, gdk_deps],
|
dependencies : [broadwayd_syslib, gdk_deps],
|
||||||
|
Loading…
Reference in New Issue
Block a user