From cc7423855b5ce92081828c863b5ba3ecbb970e4f Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Sat, 18 Nov 2017 20:36:57 +0100 Subject: [PATCH] broadway: Use textures to configure window contents Instead of using the old buffer code, just use textures to define the window contents. --- gdk/broadway/broadway-buffer.c | 528 ----------------------------- gdk/broadway/broadway-buffer.h | 20 -- gdk/broadway/broadway-output.c | 44 +-- gdk/broadway/broadway-output.h | 6 +- gdk/broadway/broadway-protocol.h | 6 +- gdk/broadway/broadway-server.c | 212 +----------- gdk/broadway/broadway-server.h | 7 +- gdk/broadway/broadway.js | 68 ++-- gdk/broadway/broadwayd.c | 18 +- gdk/broadway/gdkbroadway-server.c | 218 +----------- gdk/broadway/gdkbroadway-server.h | 4 +- gdk/broadway/gdkdisplay-broadway.c | 1 + gdk/broadway/gdkwindow-broadway.c | 28 +- gdk/broadway/gdkwindow-broadway.h | 1 + gdk/broadway/meson.build | 3 +- 15 files changed, 79 insertions(+), 1085 deletions(-) delete mode 100644 gdk/broadway/broadway-buffer.c delete mode 100644 gdk/broadway/broadway-buffer.h diff --git a/gdk/broadway/broadway-buffer.c b/gdk/broadway/broadway-buffer.c deleted file mode 100644 index d77d1de86e..0000000000 --- a/gdk/broadway/broadway-buffer.c +++ /dev/null @@ -1,528 +0,0 @@ -#include "config.h" - -#include "broadway-buffer.h" - -#include - -/* 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; -} diff --git a/gdk/broadway/broadway-buffer.h b/gdk/broadway/broadway-buffer.h deleted file mode 100644 index 9bc5f467ae..0000000000 --- a/gdk/broadway/broadway-buffer.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __BROADWAY_BUFFER__ -#define __BROADWAY_BUFFER__ - -#include "broadway-protocol.h" -#include - -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__ */ diff --git a/gdk/broadway/broadway-output.c b/gdk/broadway/broadway-output.c index b9a86daf61..770fa438b5 100644 --- a/gdk/broadway/broadway-output.c +++ b/gdk/broadway/broadway-output.c @@ -287,48 +287,14 @@ broadway_output_set_transient_for (BroadwayOutput *output, } void -broadway_output_put_buffer (BroadwayOutput *output, - int id, - BroadwayBuffer *prev_buffer, - BroadwayBuffer *buffer) +broadway_output_window_update (BroadwayOutput *output, + int id, + guint32 texture) { - gsize len; - 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); + write_header (output, BROADWAY_OP_WINDOW_UPDATE); append_uint16 (output, id); - append_uint16 (output, w); - 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); + append_uint32 (output, texture); } void diff --git a/gdk/broadway/broadway-output.h b/gdk/broadway/broadway-output.h index 784ae179db..7c69e3bd8f 100644 --- a/gdk/broadway/broadway-output.h +++ b/gdk/broadway/broadway-output.h @@ -4,7 +4,6 @@ #include #include #include "broadway-protocol.h" -#include "broadway-buffer.h" typedef struct BroadwayOutput BroadwayOutput; @@ -54,10 +53,9 @@ void broadway_output_move_resize_surface (BroadwayOutput *output, void broadway_output_set_transient_for (BroadwayOutput *output, int id, int parent_id); -void broadway_output_put_buffer (BroadwayOutput *output, +void broadway_output_window_update (BroadwayOutput *output, int id, - BroadwayBuffer *prev_buffer, - BroadwayBuffer *buffer); + guint32 texture); void broadway_output_upload_texture (BroadwayOutput *output, guint32 id, GBytes *texture); diff --git a/gdk/broadway/broadway-protocol.h b/gdk/broadway/broadway-protocol.h index 2fa93d4182..3bf963f74e 100644 --- a/gdk/broadway/broadway-protocol.h +++ b/gdk/broadway/broadway-protocol.h @@ -41,7 +41,7 @@ typedef enum { BROADWAY_OP_REQUEST_AUTH = 'l', BROADWAY_OP_AUTH_OK = 'L', BROADWAY_OP_DISCONNECTED = 'D', - BROADWAY_OP_PUT_BUFFER = 'b', + BROADWAY_OP_WINDOW_UPDATE = 'b', BROADWAY_OP_SET_SHOW_KEYBOARD = 'k', BROADWAY_OP_UPLOAD_TEXTURE = 't', BROADWAY_OP_RELEASE_TEXTURE = 'T', @@ -193,9 +193,7 @@ typedef struct { typedef struct { BroadwayRequestBase base; guint32 id; - char name[36]; - guint32 width; - guint32 height; + guint32 texture; } BroadwayRequestUpdate; typedef struct { diff --git a/gdk/broadway/broadway-server.c b/gdk/broadway/broadway-server.c index 6d5dde86fe..8d86a9e069 100644 --- a/gdk/broadway/broadway-server.c +++ b/gdk/broadway/broadway-server.c @@ -116,12 +116,7 @@ struct BroadwayWindow { gboolean is_temp; gboolean visible; gint32 transient_for; - - BroadwayBuffer *buffer; - gboolean buffer_synced; - - char *cached_surface_name; - cairo_surface_t *cached_surface; + guint32 texture; }; static void broadway_server_resync_windows (BroadwayServer *server); @@ -826,87 +821,6 @@ broadway_server_block_for_input (BroadwayServer *server, char op, } #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 * 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, GINT_TO_POINTER (id)); - g_free (window->cached_surface_name); - if (window->cached_surface != NULL) - cairo_surface_destroy (window->cached_surface); - g_free (window); } } @@ -1601,39 +1511,22 @@ broadway_server_has_client (BroadwayServer *server) } void -broadway_server_window_update (BroadwayServer *server, - gint id, - cairo_surface_t *surface) +broadway_server_window_update (BroadwayServer *server, + gint id, + guint32 texture) { BroadwayWindow *window; - BroadwayBuffer *buffer; - - if (surface == NULL) - return; window = g_hash_table_lookup (server->id_ht, GINT_TO_POINTER (id)); if (window == NULL) return; - g_assert (window->width == cairo_image_surface_get_width (surface)); - 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)); + window->texture = texture; if (server->output != NULL) - { - window->buffer_synced = TRUE; - broadway_output_put_buffer (server->output, window->id, - window->buffer, buffer); - } - - if (window->buffer) - broadway_buffer_destroy (window->buffer); - - window->buffer = buffer; + broadway_output_window_update (server->output, window->id, + window->texture); } guint32 @@ -1788,78 +1681,6 @@ broadway_server_ungrab_pointer (BroadwayServer *server, 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 broadway_server_new_window (BroadwayServer *server, int x, @@ -1929,7 +1750,6 @@ broadway_server_resync_windows (BroadwayServer *server) if (window->id == 0) continue; /* Skip root */ - window->buffer_synced = FALSE; broadway_output_new_surface (server->output, window->id, window->x, @@ -1948,18 +1768,14 @@ broadway_server_resync_windows (BroadwayServer *server) continue; /* Skip root */ if (window->transient_for != -1) - broadway_output_set_transient_for (server->output, window->id, window->transient_for); - if (window->visible) - { - broadway_output_show_surface (server->output, window->id); + broadway_output_set_transient_for (server->output, window->id, + window->transient_for); - if (window->buffer != NULL) - { - window->buffer_synced = TRUE; - broadway_output_put_buffer (server->output, window->id, - NULL, window->buffer); - } - } + broadway_output_window_update (server->output, window->id, + window->texture); + + if (window->visible) + broadway_output_show_surface (server->output, window->id); } if (server->show_keyboard) diff --git a/gdk/broadway/broadway-server.h b/gdk/broadway/broadway-server.h index 7cb7694a5b..422488c038 100644 --- a/gdk/broadway/broadway-server.h +++ b/gdk/broadway/broadway-server.h @@ -84,7 +84,7 @@ cairo_surface_t * broadway_server_create_surface (int int height); void broadway_server_window_update (BroadwayServer *server, gint id, - cairo_surface_t *surface); + guint32 texture); gboolean broadway_server_window_move_resize (BroadwayServer *server, gint id, gboolean with_move, @@ -94,10 +94,5 @@ gboolean broadway_server_window_move_resize (BroadwayServer * int height); void broadway_server_focus_window (BroadwayServer *server, gint new_focused_window); -cairo_surface_t * broadway_server_open_surface (BroadwayServer *server, - guint32 id, - char *name, - int width, - int height); #endif /* __BROADWAY_SERVER__ */ diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js index 12578d78ae..b268e0da6b 100644 --- a/gdk/broadway/broadway.js +++ b/gdk/broadway/broadway.js @@ -67,25 +67,6 @@ function logStackTrace(len) { 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(); grab.window = null; grab.ownerEvents = false; @@ -160,15 +141,15 @@ function cmdCreateSurface(id, x, y, width, height, isTemp) surface.visible = false; surface.imageData = null; - var canvas = document.createElement("canvas"); - canvas.width = width; - canvas.height = height; - canvas.surface = surface; - surface.canvas = canvas; + var image = new Image(); + image.width = width; + image.height = height; + image.surface = surface; + surface.image = image; var toplevelElement; - toplevelElement = canvas; - document.body.appendChild(canvas); + toplevelElement = image; + document.body.appendChild(image); surface.toplevelElement = toplevelElement; toplevelElement.style["position"] = "absolute"; @@ -268,8 +249,8 @@ function cmdDeleteSurface(id) var i = stackingOrder.indexOf(surface); if (i >= 0) stackingOrder.splice(i, 1); - var canvas = surface.canvas; - canvas.parentNode.removeChild(canvas); + var image = surface.image; + image.parentNode.removeChild(image); delete surfaces[id]; } @@ -286,15 +267,17 @@ function cmdMoveResizeSurface(id, has_pos, x, y, has_size, w, h) surface.height = h; } - if (has_size) - resizeCanvas(surface.canvas, w, h); + if (has_size) { + surface.image.width = w; + surface.image.height = h; + } if (surface.visible) { if (has_pos) { var xOffset = surface.x; var yOffset = surface.y; - var element = surface.canvas; + var element = surface.image; element.style["left"] = xOffset + "px"; element.style["top"] = yOffset + "px"; @@ -512,21 +495,12 @@ function decodeBuffer(context, oldData, w, h, data, debug) return imageData; } -function cmdPutBuffer(id, w, h, compressed) +function cmdWindowUpdate(id, texture_id) { var surface = surfaces[id]; - var context = surface.canvas.getContext("2d"); + var texture_url = textures[texture]; - var inflate = new Zlib.RawInflate(compressed); - 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; + surface.image.src = texture_url; } function cmdUploadTexture(id, data) @@ -631,12 +605,10 @@ function handleCommands(cmd) cmdLowerSurface(id); break; - case 'b': // Put image buffer + case 'b': // Update window id = cmd.get_16(); - w = cmd.get_16(); - h = cmd.get_16(); - var data = cmd.get_data(); - cmdPutBuffer(id, w, h, data); + texture = cmd.get_32(); + cmdWindowUpdate(id, texture); break; case 't': // Upload texture diff --git a/gdk/broadway/broadwayd.c b/gdk/broadway/broadwayd.c index ee0cd5fa00..2706cc9580 100644 --- a/gdk/broadway/broadwayd.c +++ b/gdk/broadway/broadwayd.c @@ -225,7 +225,6 @@ client_handle_request (BroadwayClient *client, BroadwayReplyQueryMouse reply_query_mouse; BroadwayReplyGrabPointer reply_grab_pointer; BroadwayReplyUngrabPointer reply_ungrab_pointer; - cairo_surface_t *surface; guint32 before_serial, now_serial; guint32 global_id; int fd; @@ -284,18 +283,11 @@ client_handle_request (BroadwayClient *client, request->set_transient_for.parent); break; case BROADWAY_REQUEST_UPDATE: - surface = broadway_server_open_surface (server, - request->update.id, - request->update.name, - request->update.width, - request->update.height); - if (surface != NULL) - { - broadway_server_window_update (server, - request->update.id, - surface); - cairo_surface_destroy (surface); - } + global_id = GPOINTER_TO_INT (g_hash_table_lookup (client->textures, + GINT_TO_POINTER (request->update.texture))); + broadway_server_window_update (server, + request->update.id, + global_id); break; case BROADWAY_REQUEST_UPLOAD_TEXTURE: if (client->fds == NULL) diff --git a/gdk/broadway/gdkbroadway-server.c b/gdk/broadway/gdkbroadway-server.c index 2ee75ab128..40238337ff 100644 --- a/gdk/broadway/gdkbroadway-server.c +++ b/gdk/broadway/gdkbroadway-server.c @@ -552,229 +552,15 @@ _gdk_broadway_server_window_set_transient_for (GdkBroadwayServer *server, 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 _gdk_broadway_server_window_update (GdkBroadwayServer *server, gint id, - cairo_surface_t *surface) + guint32 texture) { 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; - memcpy (msg.name, data->name, 36); - msg.width = cairo_image_surface_get_width (surface); - msg.height = cairo_image_surface_get_height (surface); + msg.texture = texture; gdk_broadway_server_send_message (server, msg, BROADWAY_REQUEST_UPDATE); diff --git a/gdk/broadway/gdkbroadway-server.h b/gdk/broadway/gdkbroadway-server.h index ea16e5598f..91554e5eae 100644 --- a/gdk/broadway/gdkbroadway-server.h +++ b/gdk/broadway/gdkbroadway-server.h @@ -63,11 +63,9 @@ guint32 gdk_broadway_server_upload_texture (GdkBroadwaySer GdkTexture *texture); void gdk_broadway_server_release_texture (GdkBroadwayServer *server, guint32 id); -cairo_surface_t *_gdk_broadway_server_create_surface (int width, - int height); void _gdk_broadway_server_window_update (GdkBroadwayServer *server, gint id, - cairo_surface_t *surface); + guint32 texture); gboolean _gdk_broadway_server_window_move_resize (GdkBroadwayServer *server, gint id, gboolean with_move, diff --git a/gdk/broadway/gdkdisplay-broadway.c b/gdk/broadway/gdkdisplay-broadway.c index c5eede1a94..aa2c0f6257 100644 --- a/gdk/broadway/gdkdisplay-broadway.c +++ b/gdk/broadway/gdkdisplay-broadway.c @@ -30,6 +30,7 @@ #include "gdkinternals.h" #include "gdkdeviceprivate.h" #include "gdkdevicemanager-broadway.h" +#include #include #include diff --git a/gdk/broadway/gdkwindow-broadway.c b/gdk/broadway/gdkwindow-broadway.c index ce02f97510..2f05c31ab9 100644 --- a/gdk/broadway/gdkwindow-broadway.c +++ b/gdk/broadway/gdkwindow-broadway.c @@ -36,6 +36,7 @@ #include "gdkinternals.h" #include "gdkdeviceprivate.h" #include "gdkeventsource.h" +#include #include #include @@ -112,11 +113,26 @@ update_dirty_windows_and_sync (void) if (impl->dirty) { + GdkTexture *texture; + guint32 texture_id; + impl->dirty = FALSE; 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, impl->id, - impl->surface); + texture_id); + } } @@ -246,8 +262,9 @@ _gdk_broadway_window_resize_surface (GdkWindow *window) { cairo_surface_destroy (impl->surface); - impl->surface = _gdk_broadway_server_create_surface (gdk_window_get_width (impl->wrapper), - gdk_window_get_height (impl->wrapper)); + impl->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + gdk_window_get_width (impl->wrapper), + gdk_window_get_height (impl->wrapper)); } if (impl->ref_surface) @@ -283,7 +300,7 @@ gdk_window_broadway_ref_cairo_surface (GdkWindow *window) /* Create actual backing store if missing */ 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 */ 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)); _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. diff --git a/gdk/broadway/gdkwindow-broadway.h b/gdk/broadway/gdkwindow-broadway.h index 5fe7c78026..4a2a727976 100644 --- a/gdk/broadway/gdkwindow-broadway.h +++ b/gdk/broadway/gdkwindow-broadway.h @@ -55,6 +55,7 @@ struct _GdkWindowImplBroadway GdkCursor *cursor; int id; + int texture_id; gboolean visible; gboolean maximized; diff --git a/gdk/broadway/meson.build b/gdk/broadway/meson.build index 4534a9d747..70b11a2ade 100644 --- a/gdk/broadway/meson.build +++ b/gdk/broadway/meson.build @@ -1,5 +1,4 @@ gdk_broadway_sources = files([ - 'broadway-buffer.c', 'broadway-output.c', 'broadway-server.c', 'broadwayd.c', @@ -60,7 +59,7 @@ broadwayjs_h = custom_target('broadwayjs.h', executable('gtk4-broadwayd', 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], c_args: ['-DGDK_COMPILATION', '-DG_LOG_DOMAIN="Gdk"', ], dependencies : [broadwayd_syslib, gdk_deps],