From 1b5b1bfd0e3b1725a5bdf8a8b1d9fadcca31b6c6 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 22 Mar 2019 10:02:18 +0100 Subject: [PATCH 01/14] broadway: Don't fall back for translation transform nodes These are trivial anyway --- gdk/broadway/broadway-protocol.h | 2 ++ gdk/broadway/broadway.js | 16 ++++++++++++++ gdk/broadway/broadwayd.c | 4 ++++ gsk/gskbroadwayrenderer.c | 36 +++++++++++++++++++++++++++++--- 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/gdk/broadway/broadway-protocol.h b/gdk/broadway/broadway-protocol.h index 68911add81..b397195521 100644 --- a/gdk/broadway/broadway-protocol.h +++ b/gdk/broadway/broadway-protocol.h @@ -22,6 +22,7 @@ typedef enum { /* Sync changes with broadway.js */ BROADWAY_NODE_CLIP = 10, BROADWAY_NODE_KEEP_ALL = 11, BROADWAY_NODE_KEEP_THIS = 12, + BROADWAY_NODE_TRANSLATE = 13, } BroadwayNodeType; static const char *broadway_node_type_names[] G_GNUC_UNUSED = { @@ -38,6 +39,7 @@ static const char *broadway_node_type_names[] G_GNUC_UNUSED = { "CLIP", "KEEP_ALL", "KEEP_THIS", + "TRANSLATE", }; typedef enum { diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js index 24859f1b15..d7a6a0d446 100644 --- a/gdk/broadway/broadway.js +++ b/gdk/broadway/broadway.js @@ -400,6 +400,11 @@ function px(x) { return x + "px"; } +function set_point_style (div, point) { + div.style["left"] = px(point.x); + div.style["top"] = px(point.y); +} + function set_rect_style (div, rect) { div.style["left"] = px(rect.x); div.style["top"] = px(rect.y); @@ -569,6 +574,17 @@ SwapNodes.prototype.insertNode = function(parent, posInParent, oldNode) /* Bin nodes */ + case 13: // TRANSLATE + { + var point = this.decode_point(); + var div = document.createElement('div'); + div.style["position"] = "absolute"; + set_point_style(div, point); + this.insertNode(div, -1, oldChildren[0]); + newNode = div; + } + break; + case 10: // CLIP { var rect = this.decode_rect(); diff --git a/gdk/broadway/broadwayd.c b/gdk/broadway/broadwayd.c index e453af463c..13d5675633 100644 --- a/gdk/broadway/broadwayd.c +++ b/gdk/broadway/broadwayd.c @@ -277,6 +277,10 @@ decode_nodes (BroadwayClient *client, size = NODE_SIZE_RECT; n_children = 1; break; + case BROADWAY_NODE_TRANSLATE: + size = NODE_SIZE_POINT; + n_children = 1; + break; case BROADWAY_NODE_LINEAR_GRADIENT: size = NODE_SIZE_RECT + 2 * NODE_SIZE_POINT; n_stops = data[*pos + size++]; diff --git a/gsk/gskbroadwayrenderer.c b/gsk/gskbroadwayrenderer.c index 84b948d676..c90ccbeab5 100644 --- a/gsk/gskbroadwayrenderer.c +++ b/gsk/gskbroadwayrenderer.c @@ -4,6 +4,7 @@ #include "broadway/gdkprivate-broadway.h" #include "gskdebugprivate.h" +#include "gsktransformprivate.h" #include "gskrendererprivate.h" #include "gskrendernodeprivate.h" #include "gdk/gdktextureprivate.h" @@ -103,11 +104,17 @@ add_float (GArray *nodes, float f) g_array_append_val (nodes, u); } +static void +add_xy (GArray *nodes, float x, float y, float offset_x, float offset_y) +{ + add_float (nodes, x - offset_x); + add_float (nodes, y - offset_y); +} + static void add_point (GArray *nodes, const graphene_point_t *point, float offset_x, float offset_y) { - add_float (nodes, point->x - offset_x); - add_float (nodes, point->y - offset_y); + add_xy (nodes, point->x, point->y, offset_x, offset_y); } static void @@ -633,6 +640,30 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, } return; + case GSK_TRANSFORM_NODE: + { + GskTransform *transform = gsk_transform_node_get_transform (node); + GskTransformCategory category = gsk_transform_get_category (transform); + float dx, dy; + + if (category >= GSK_TRANSFORM_CATEGORY_2D_TRANSLATE) + { + gsk_transform_to_translate (transform, &dx, &dy); + add_uint32 (nodes, BROADWAY_NODE_TRANSLATE); + add_xy (nodes, dx, dy, offset_x, offset_y); + gsk_broadway_renderer_add_node (renderer, nodes, node_textures, + gsk_transform_node_get_child (node), + 0, 0); + } + else + { + /* Fallback to texture for now */ + break; + } + + } + return; + /* Generic nodes */ case GSK_CONTAINER_NODE: @@ -656,7 +687,6 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, case GSK_COLOR_MATRIX_NODE: case GSK_TEXT_NODE: case GSK_REPEATING_LINEAR_GRADIENT_NODE: - case GSK_TRANSFORM_NODE: case GSK_REPEAT_NODE: case GSK_BLEND_NODE: case GSK_CROSS_FADE_NODE: From b097f0a7d81511764f79ed227237332b97f1bbde Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 22 Mar 2019 12:42:12 +0100 Subject: [PATCH 02/14] Broadway: Add node for debug nodes This can be helpful when debugging broadway. --- gdk/broadway/broadway-protocol.h | 2 ++ gdk/broadway/broadway.js | 59 ++++++++++++++++++++++++++++++++ gdk/broadway/broadwayd.c | 7 +++- gsk/gskbroadwayrenderer.c | 40 +++++++++++++++++++--- 4 files changed, 102 insertions(+), 6 deletions(-) diff --git a/gdk/broadway/broadway-protocol.h b/gdk/broadway/broadway-protocol.h index b397195521..5c2d923a10 100644 --- a/gdk/broadway/broadway-protocol.h +++ b/gdk/broadway/broadway-protocol.h @@ -23,6 +23,7 @@ typedef enum { /* Sync changes with broadway.js */ BROADWAY_NODE_KEEP_ALL = 11, BROADWAY_NODE_KEEP_THIS = 12, BROADWAY_NODE_TRANSLATE = 13, + BROADWAY_NODE_DEBUG = 14, } BroadwayNodeType; static const char *broadway_node_type_names[] G_GNUC_UNUSED = { @@ -40,6 +41,7 @@ static const char *broadway_node_type_names[] G_GNUC_UNUSED = { "KEEP_ALL", "KEEP_THIS", "TRANSLATE", + "DEBUG", }; typedef enum { diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js index d7a6a0d446..b2441076a7 100644 --- a/gdk/broadway/broadway.js +++ b/gdk/broadway/broadway.js @@ -387,6 +387,55 @@ SwapNodes.prototype.decode_color_stops = function() { return stops; } +function utf8_to_string(array) { + var out, i, len, c; + var char2, char3; + + out = ""; + len = array.length; + i = 0; + while(i < len) { + c = array[i++]; + switch(c >> 4) + { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + // 0xxxxxxx + out += String.fromCharCode(c); + break; + case 12: case 13: + // 110x xxxx 10xx xxxx + char2 = array[i++]; + out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); + break; + case 14: + // 1110 xxxx 10xx xxxx 10xx xxxx + char2 = array[i++]; + char3 = array[i++]; + out += String.fromCharCode(((c & 0x0F) << 12) | + ((char2 & 0x3F) << 6) | + ((char3 & 0x3F) << 0)); + break; + } + } + + return out; +} + +SwapNodes.prototype.decode_string = function() { + var len = this.decode_uint32(); + var utf8 = new Array(); + var b; + for (var i = 0; i < len; i++) { + if (i % 4 == 0) { + b = this.decode_uint32(); + } + utf8[i] = b & 0xff; + b = b >> 8; + } + + return utf8_to_string (utf8); +} + function args() { var argsLength = arguments.length; var strings = []; @@ -645,6 +694,16 @@ SwapNodes.prototype.insertNode = function(parent, posInParent, oldNode) } break; + case 14: // DEBUG + { + var str = this.decode_string(); + var div = document.createElement('div'); + div.setAttribute('debug', str); + this.insertNode(div, -1, oldChildren[0]); + newNode = div; + } + break; + /* Generic nodes */ case 1: // CONTAINER diff --git a/gdk/broadway/broadwayd.c b/gdk/broadway/broadwayd.c index 13d5675633..e691f3ce90 100644 --- a/gdk/broadway/broadwayd.c +++ b/gdk/broadway/broadwayd.c @@ -238,7 +238,7 @@ decode_nodes (BroadwayClient *client, { BroadwayNode *node; guint32 type; - guint32 i, n_stops, n_shadows; + guint32 i, n_stops, n_shadows, n_chars; guint32 size, n_children; gint32 texture_offset; guint32 hash; @@ -296,6 +296,11 @@ decode_nodes (BroadwayClient *client, size = NODE_SIZE_FLOAT; n_children = 1; break; + case BROADWAY_NODE_DEBUG: + n_chars = data[*pos]; + size = 1 + (n_chars + 3) / 4; + n_children = 1; + break; default: g_assert_not_reached (); } diff --git a/gsk/gskbroadwayrenderer.c b/gsk/gskbroadwayrenderer.c index c90ccbeab5..552c9beafb 100644 --- a/gsk/gskbroadwayrenderer.c +++ b/gsk/gskbroadwayrenderer.c @@ -147,6 +147,31 @@ add_color_stop (GArray *nodes, const GskColorStop *stop) add_rgba (nodes, &stop->color); } +static void +add_string (GArray *nodes, const char *str) +{ + guint32 len = strlen(str); + guint32 v, c; + + add_uint32 (nodes, len); + + v = 0; + c = 0; + while (*str != 0) + { + v |= (*str++) << 8*c++; + if (c == 4) + { + add_uint32 (nodes, v); + v = 0; + c = 0; + } + } + + if (c != 0) + add_uint32 (nodes, v); +} + static gboolean float_is_int32 (float f) { @@ -664,6 +689,16 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, } return; + case GSK_DEBUG_NODE: + { + const char *message = gsk_debug_node_get_message (node); + add_uint32 (nodes, BROADWAY_NODE_DEBUG); + add_string (nodes, message); + gsk_broadway_renderer_add_node (renderer, nodes, node_textures, + gsk_debug_node_get_child (node), offset_x, offset_y); + } + return; + /* Generic nodes */ case GSK_CONTAINER_NODE: @@ -679,11 +714,6 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, } return; - case GSK_DEBUG_NODE: - gsk_broadway_renderer_add_node (renderer, nodes, node_textures, - gsk_debug_node_get_child (node), offset_x, offset_y); - return; - case GSK_COLOR_MATRIX_NODE: case GSK_TEXT_NODE: case GSK_REPEATING_LINEAR_GRADIENT_NODE: From d997903d29bbbf6f3a25f04f1f539b35861e9c6b Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 22 Mar 2019 13:38:19 +0100 Subject: [PATCH 03/14] broadway: Use DataView instead of hand-rolled int parsers This is nicer in general, but also will let us do floats more sanely. --- gdk/broadway/broadway.js | 53 +++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js index b2441076a7..fc55f4b59b 100644 --- a/gdk/broadway/broadway.js +++ b/gdk/broadway/broadway.js @@ -299,18 +299,21 @@ function cmdLowerSurface(id) function SwapNodes(node_data, div) { this.node_data = node_data; - this.node_data_signed = new Int32Array(node_data); this.data_pos = 0; this.div = div; this.outstanding = 1; } SwapNodes.prototype.decode_uint32 = function() { - return this.node_data[this.data_pos++]; + var v = this.node_data.getUint32(this.data_pos, true); + this.data_pos += 4; + return v; } SwapNodes.prototype.decode_int32 = function() { - return this.node_data_signed[this.data_pos++]; + var v = this.node_data.getInt32(this.data_pos, true); + this.data_pos += 4; + return v; } SwapNodes.prototype.decode_color = function() { @@ -778,8 +781,8 @@ function cmdSurfaceSetNodes(id, node_data) var swap = new SwapNodes (node_data, div); swap.insertNode(div, 0, div.firstChild); - if (swap.data_pos != node_data.length) - alert ("Did not consume entire array (len " + node_data.length + " end " + end + ")"); + if (swap.data_pos != node_data.byteLength) + alert ("Did not consume entire array (len " + node_data.byteLength + ")"); } function cmdUploadTexture(id, data) @@ -903,11 +906,7 @@ function handleCommands(cmd) case 'n': // Set nodes id = cmd.get_16(); - var len = cmd.get_32(); - var node_data = new Uint32Array(len); - for (var i = 0; i < len; i++) - node_data[i] = cmd.get_32(); - + var node_data = cmd.get_nodes (); cmdSurfaceSetNodes(id, node_data); break; @@ -947,43 +946,41 @@ function handleOutstanding() function BinCommands(message) { this.arraybuffer = message; - this.u8 = new Uint8Array(message); - this.length = this.u8.length; + this.dataview = new DataView(message); + this.length = this.arraybuffer.byteLength; this.pos = 0; } BinCommands.prototype.get_char = function() { - return String.fromCharCode(this.u8[this.pos++]); + return String.fromCharCode(this.dataview.getUint8(this.pos++)); }; BinCommands.prototype.get_bool = function() { - return this.u8[this.pos++] != 0; + return this.dataview.getUint8(this.pos++) != 0; }; BinCommands.prototype.get_flags = function() { - return this.u8[this.pos++]; + return this.dataview.getUint8(this.pos++); } BinCommands.prototype.get_16 = function() { - var v = - this.u8[this.pos] + - (this.u8[this.pos+1] << 8); + var v = this.dataview.getUint16(this.pos, true); this.pos = this.pos + 2; return v; }; BinCommands.prototype.get_16s = function() { - var v = this.get_16 (); - if (v > 32767) - return v - 65536; - else - return v; + var v = this.dataview.getInt16(this.pos, true); + this.pos = this.pos + 2; + return v; }; BinCommands.prototype.get_32 = function() { - var v = - this.u8[this.pos] + - (this.u8[this.pos+1] << 8) + - (this.u8[this.pos+2] << 16) + - (this.u8[this.pos+3] << 24); + var v = this.dataview.getUint32(this.pos, true); this.pos = this.pos + 4; return v; }; +BinCommands.prototype.get_nodes = function() { + var len = this.get_32(); + var node_data = new DataView(this.arraybuffer, this.pos, len * 4); + this.pos = this.pos + len * 4; + return node_data; +}; BinCommands.prototype.get_data = function() { var size = this.get_32(); var data = new Uint8Array (this.arraybuffer, this.pos, size); From 890b7590914581ed7da12c4e9c8f64ef65434ce0 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 22 Mar 2019 13:42:26 +0100 Subject: [PATCH 04/14] broadway: Send actual float32, not some hack --- gdk/broadway/broadway.js | 10 ++++++---- gsk/gskbroadwayrenderer.c | 21 +++++++++++++-------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js index fc55f4b59b..86259aa0a5 100644 --- a/gdk/broadway/broadway.js +++ b/gdk/broadway/broadway.js @@ -316,6 +316,12 @@ SwapNodes.prototype.decode_int32 = function() { return v; } +SwapNodes.prototype.decode_float = function() { + var v = this.node_data.getFloat32(this.data_pos, true); + this.data_pos += 4; + return v; +} + SwapNodes.prototype.decode_color = function() { var rgba = this.decode_uint32(); var a = (rgba >> 24) & 0xff; @@ -330,10 +336,6 @@ SwapNodes.prototype.decode_color = function() { return c; } -SwapNodes.prototype.decode_float = function() { - return this.decode_int32() / 256.0; -} - SwapNodes.prototype.decode_size = function() { var s = new Object(); s.width = this.decode_float (); diff --git a/gsk/gskbroadwayrenderer.c b/gsk/gskbroadwayrenderer.c index 552c9beafb..9350a2ab1f 100644 --- a/gsk/gskbroadwayrenderer.c +++ b/gsk/gskbroadwayrenderer.c @@ -72,12 +72,25 @@ gsk_broadway_renderer_render_texture (GskRenderer *renderer, return texture; } +/* uint32 is sent in native endianness, and then converted to little endian in broadwayd when sending to browser */ static void add_uint32 (GArray *nodes, guint32 v) { g_array_append_val (nodes, v); } +static void +add_float (GArray *nodes, float f) +{ + union { + float f; + guint32 i; + } u; + + u.f = f; + g_array_append_val (nodes, u.i); +} + static guint32 rgba_to_uint32 (const GdkRGBA *rgba) { @@ -96,14 +109,6 @@ add_rgba (GArray *nodes, const GdkRGBA *rgba) g_array_append_val (nodes, c); } -static void -add_float (GArray *nodes, float f) -{ - gint32 i = (gint32) (f * 256.0f); - guint u = (guint32) i; - g_array_append_val (nodes, u); -} - static void add_xy (GArray *nodes, float x, float y, float offset_x, float offset_y) { From 3bbbe9f71be62fe34ebca656558dc90bc7a04681 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 22 Mar 2019 13:52:08 +0100 Subject: [PATCH 05/14] broadway: Don't crash of drag-resizing when already active This is what the X11 code does. --- gdk/broadway/gdksurface-broadway.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gdk/broadway/gdksurface-broadway.c b/gdk/broadway/gdksurface-broadway.c index 56e9684112..b9fbec68c6 100644 --- a/gdk/broadway/gdksurface-broadway.c +++ b/gdk/broadway/gdksurface-broadway.c @@ -1232,6 +1232,9 @@ gdk_broadway_surface_begin_resize_drag (GdkSurface *surface, mv_resize = get_move_resize_data (gdk_surface_get_display (surface), TRUE); + if (mv_resize->moveresize_surface != NULL) + return; /* already a drag operation in progress */ + mv_resize->is_resize = TRUE; mv_resize->moveresize_button = button; mv_resize->resize_edge = edge; @@ -1270,8 +1273,13 @@ gdk_broadway_surface_begin_move_drag (GdkSurface *surface, if (impl->maximized) return; + g_print ("gdk_broadway_surface_begin_move_drag\n"); + mv_resize = get_move_resize_data (gdk_surface_get_display (surface), TRUE); + if (mv_resize->moveresize_surface != NULL) + return; /* already a drag operation in progress */ + mv_resize->is_resize = FALSE; mv_resize->moveresize_button = button; mv_resize->moveresize_x = root_x; From 311aa01e013e735d403700ed1e602bb0aa831f79 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 22 Mar 2019 15:29:24 +0100 Subject: [PATCH 06/14] broadway: Simplify fallback node cache Since nodes are now cached we just store the fallback as a texture in a hashtable indexed by the node. If its unused for 5 frames we drop it. --- gsk/gskbroadwayrenderer.c | 326 ++++++-------------------------------- 1 file changed, 48 insertions(+), 278 deletions(-) diff --git a/gsk/gskbroadwayrenderer.c b/gsk/gskbroadwayrenderer.c index 9350a2ab1f..dc09829724 100644 --- a/gsk/gskbroadwayrenderer.c +++ b/gsk/gskbroadwayrenderer.c @@ -13,6 +13,8 @@ struct _GskBroadwayRenderer { GskRenderer parent_instance; GdkBroadwayDrawContext *draw_context; + GHashTable *fallback_cache; + guint32 frame_nr; }; struct _GskBroadwayRendererClass @@ -177,289 +179,22 @@ add_string (GArray *nodes, const char *str) add_uint32 (nodes, v); } -static gboolean -float_is_int32 (float f) -{ - gint32 i = (gint32)f; - float f2 = (float)i; - return f2 == f; -} - -static GHashTable *gsk_broadway_node_cache; - typedef struct { - GdkTexture *texture; GskRenderNode *node; + GdkTexture *texture; float off_x; float off_y; -} NodeCacheElement; + int used_in_frame; +} FallbackCacheElement; static void -node_cache_element_free (NodeCacheElement *element) +fallback_cache_element_free (FallbackCacheElement *element) { gsk_render_node_unref (element->node); + g_object_unref (element->texture); g_free (element); } -static guint -glyph_info_hash (const PangoGlyphInfo *info) -{ - return info->glyph ^ - info->geometry.width << 6 ^ - info->geometry.x_offset << 12 ^ - info->geometry.y_offset << 18 ^ - info->attr.is_cluster_start << 30; -} - -static gboolean -glyph_info_equal (const PangoGlyphInfo *a, - const PangoGlyphInfo *b) -{ - return - a->glyph == b->glyph && - a->geometry.width == b->geometry.width && - a->geometry.x_offset == b->geometry.x_offset && - a->geometry.y_offset == b->geometry.y_offset && - a->attr.is_cluster_start == b->attr.is_cluster_start; - } - -static guint -hash_matrix (const graphene_matrix_t *matrix) -{ - float m[16]; - guint h = 0; - int i; - - graphene_matrix_to_float (matrix, m); - for (i = 0; i < 16; i++) - h ^= (guint) m[i]; - - return h; -} - -static gboolean -matrix_equal (const graphene_matrix_t *a, - const graphene_matrix_t *b) -{ - float ma[16]; - float mb[16]; - int i; - - graphene_matrix_to_float (a, ma); - graphene_matrix_to_float (b, mb); - for (i = 0; i < 16; i++) - { - if (ma[i] != mb[i]) - return FALSE; - } - - return TRUE; -} - -static guint -hash_vec4 (const graphene_vec4_t *vec4) -{ - float v[4]; - guint h = 0; - int i; - - graphene_vec4_to_float (vec4, v); - for (i = 0; i < 4; i++) - h ^= (guint) v[i]; - - return h; -} - -static gboolean -vec4_equal (const graphene_vec4_t *a, - const graphene_vec4_t *b) -{ - float va[4]; - float vb[4]; - int i; - - graphene_vec4_to_float (a, va); - graphene_vec4_to_float (b, vb); - for (i = 0; i < 4; i++) - { - if (va[i] != vb[i]) - return FALSE; - } - - return TRUE; -} - -static guint -node_cache_hash (GskRenderNode *node) -{ - GskRenderNodeType type; - guint h; - - type = gsk_render_node_get_node_type (node); - h = type << 28; - if (type == GSK_TEXT_NODE && - float_is_int32 (gsk_text_node_get_x (node)) && - float_is_int32 (gsk_text_node_get_y (node))) - { - guint i; - const PangoFont *font = gsk_text_node_peek_font (node); - guint n_glyphs = gsk_text_node_get_num_glyphs (node); - const PangoGlyphInfo *infos = gsk_text_node_peek_glyphs (node); - const GdkRGBA *color = gsk_text_node_peek_color (node); - - h ^= g_direct_hash (font) ^ n_glyphs << 16 ^ gdk_rgba_hash (color); - for (i = 0; i < n_glyphs; i++) - h ^= glyph_info_hash (&infos[i]); - - return h; - } - - if (type == GSK_COLOR_MATRIX_NODE && - gsk_render_node_get_node_type (gsk_color_matrix_node_get_child (node)) == GSK_TEXTURE_NODE) - { - const graphene_matrix_t *matrix = gsk_color_matrix_node_peek_color_matrix (node); - const graphene_vec4_t *offset = gsk_color_matrix_node_peek_color_offset (node); - GskRenderNode *child = gsk_color_matrix_node_get_child (node); - GdkTexture *texture = gsk_texture_node_get_texture (child); - - h ^= g_direct_hash (texture) ^ hash_matrix (matrix) ^ hash_vec4 (offset); - - return h; - } - - return 0; -} - -static gboolean -node_cache_equal (GskRenderNode *a, - GskRenderNode *b) -{ - GskRenderNodeType type; - - type = gsk_render_node_get_node_type (a); - if (type != gsk_render_node_get_node_type (b)) - return FALSE; - - if (type == GSK_TEXT_NODE && - float_is_int32 (gsk_text_node_get_x (a)) && - float_is_int32 (gsk_text_node_get_y (a)) && - float_is_int32 (gsk_text_node_get_x (b)) && - float_is_int32 (gsk_text_node_get_y (b))) - { - const PangoFont *a_font = gsk_text_node_peek_font (a); - guint a_n_glyphs = gsk_text_node_get_num_glyphs (a); - const PangoGlyphInfo *a_infos = gsk_text_node_peek_glyphs (a); - const GdkRGBA *a_color = gsk_text_node_peek_color (a); - const PangoFont *b_font = gsk_text_node_peek_font (b); - guint b_n_glyphs = gsk_text_node_get_num_glyphs (b); - const PangoGlyphInfo *b_infos = gsk_text_node_peek_glyphs (b); - const GdkRGBA *b_color = gsk_text_node_peek_color (a); - guint i; - - if (a_font != b_font) - return FALSE; - - if (a_n_glyphs != b_n_glyphs) - return FALSE; - - for (i = 0; i < a_n_glyphs; i++) - { - if (!glyph_info_equal (&a_infos[i], &b_infos[i])) - return FALSE; - } - - if (!gdk_rgba_equal (a_color, b_color)) - return FALSE; - - return TRUE; - } - - if (type == GSK_COLOR_MATRIX_NODE && - gsk_render_node_get_node_type (gsk_color_matrix_node_get_child (a)) == GSK_TEXTURE_NODE && - gsk_render_node_get_node_type (gsk_color_matrix_node_get_child (b)) == GSK_TEXTURE_NODE) - { - const graphene_matrix_t *a_matrix = gsk_color_matrix_node_peek_color_matrix (a); - const graphene_vec4_t *a_offset = gsk_color_matrix_node_peek_color_offset (a); - GskRenderNode *a_child = gsk_color_matrix_node_get_child (a); - GdkTexture *a_texture = gsk_texture_node_get_texture (a_child); - const graphene_matrix_t *b_matrix = gsk_color_matrix_node_peek_color_matrix (b); - const graphene_vec4_t *b_offset = gsk_color_matrix_node_peek_color_offset (b); - GskRenderNode *b_child = gsk_color_matrix_node_get_child (b); - GdkTexture *b_texture = gsk_texture_node_get_texture (b_child); - - if (a_texture != b_texture) - return FALSE; - - if (!matrix_equal (a_matrix, b_matrix)) - return FALSE; - - if (!vec4_equal (a_offset, b_offset)) - return FALSE; - - return TRUE; - } - - return FALSE; -} - -static GdkTexture * -node_cache_lookup (GskRenderNode *node, - float *off_x, float *off_y) -{ - NodeCacheElement *hit; - - if (gsk_broadway_node_cache == NULL) - gsk_broadway_node_cache = g_hash_table_new_full ((GHashFunc)node_cache_hash, - (GEqualFunc)node_cache_equal, - NULL, - (GDestroyNotify)node_cache_element_free); - - hit = g_hash_table_lookup (gsk_broadway_node_cache, node); - if (hit) - { - *off_x = hit->off_x; - *off_y = hit->off_y; - return g_object_ref (hit->texture); - } - - return NULL; -} - -static void -cached_texture_gone (gpointer data, - GObject *where_the_object_was) -{ - NodeCacheElement *element = data; - g_hash_table_remove (gsk_broadway_node_cache, element->node); -} - -static void -node_cache_store (GskRenderNode *node, - GdkTexture *texture, - float off_x, - float off_y) -{ - GskRenderNodeType type; - - type = gsk_render_node_get_node_type (node); - if ((type == GSK_TEXT_NODE && - float_is_int32 (gsk_text_node_get_x (node)) && - float_is_int32 (gsk_text_node_get_y (node))) || - (type == GSK_COLOR_MATRIX_NODE && - gsk_render_node_get_node_type (gsk_color_matrix_node_get_child (node)) == GSK_TEXTURE_NODE)) - { - NodeCacheElement *element = g_new0 (NodeCacheElement, 1); - element->texture = texture; - element->node = gsk_render_node_ref (node); - element->off_x = off_x; - element->off_y = off_y; - g_object_weak_ref (G_OBJECT (texture), cached_texture_gone, element); - g_hash_table_insert (gsk_broadway_node_cache, element->node, element); - - return; - } -} - static GdkTexture * node_texture_fallback (GskRenderNode *node, float *off_x, @@ -499,6 +234,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, float offset_y) { GdkDisplay *display = gdk_surface_get_display (gsk_renderer_get_surface (renderer)); + GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer); switch (gsk_render_node_get_node_type (node)) { @@ -733,18 +469,32 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, { GdkTexture *texture; guint32 texture_id; + FallbackCacheElement *hit; float t_off_x = 0, t_off_y = 0; - texture = node_cache_lookup (node, &t_off_x, &t_off_y); - - if (!texture) + hit = g_hash_table_lookup (self->fallback_cache, node); + if (hit) { + texture = g_object_ref (hit->texture); + t_off_x = hit->off_x; + t_off_y = hit->off_y; + hit->used_in_frame = self->frame_nr; + } + else + { + FallbackCacheElement *element; + texture = node_texture_fallback (node, &t_off_x, &t_off_y); -#if 0 +#if 1 g_print ("Fallback %p for %s\n", texture, node->node_class->type_name); #endif - - node_cache_store (node, texture, t_off_x, t_off_y); + element = g_new0 (FallbackCacheElement, 1); + element->texture = g_object_ref (texture); + element->node = gsk_render_node_ref (node); + element->off_x = t_off_x; + element->off_y = t_off_y; + element->used_in_frame = self->frame_nr; + g_hash_table_insert (self->fallback_cache, element->node, element); } g_ptr_array_add (node_textures, texture); /* Transfers ownership to node_textures */ @@ -758,6 +508,18 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, } } +static gboolean +clean_old_fallbacks (gpointer key, + gpointer value, + gpointer user_data) +{ + GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (user_data); + FallbackCacheElement *element = value; + + /* Remove cached fallbacks not used for 5 frames */ + return self->frame_nr - element->used_in_frame > 5; +} + static void gsk_broadway_renderer_render (GskRenderer *renderer, GskRenderNode *root, @@ -765,9 +527,13 @@ gsk_broadway_renderer_render (GskRenderer *renderer, { GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer); + self->frame_nr++; + gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->draw_context), update_area); gsk_broadway_renderer_add_node (renderer, self->draw_context->nodes, self->draw_context->node_textures, root, 0, 0); gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->draw_context)); + + g_hash_table_foreach_remove (self->fallback_cache, clean_old_fallbacks, renderer); } static void @@ -784,4 +550,8 @@ gsk_broadway_renderer_class_init (GskBroadwayRendererClass *klass) static void gsk_broadway_renderer_init (GskBroadwayRenderer *self) { + self->fallback_cache = g_hash_table_new_full ((GHashFunc)g_direct_hash, + (GEqualFunc)g_direct_equal, + NULL, + (GDestroyNotify)fallback_cache_element_free); } From 2f85443e376fd03b6dee3f69fceed877114b43cd Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 22 Mar 2019 16:41:19 +0100 Subject: [PATCH 07/14] broadway: Refcount textures We want to delay some rendering, and to make that safe we need to correctly refcount the use of blob uris for the textures so that we don't unref it while something is scheduled to use it. --- gdk/broadway/broadway.js | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js index 86259aa0a5..e246948e11 100644 --- a/gdk/broadway/broadway.js +++ b/gdk/broadway/broadway.js @@ -128,6 +128,27 @@ function getButtonMask (button) { return 0; } +function Texture(id, data) { + var blob = new Blob([data],{type: "image/png"}); + this.url = window.URL.createObjectURL(blob); + this.refcount = 1; + this.id = id; + textures[id] = this; +} + +Texture.prototype.ref = function() { + this.refcount += 1; + return this; +} + +Texture.prototype.unref = function() { + this.refcount -= 1; + if (this.refcount == 0) { + window.URL.revokeObjectURL(this.url); + delete textures[this.id]; + } +} + function sendConfigureNotify(surface) { sendInput("w", [surface.id, surface.x, surface.y, surface.width, surface.height]); @@ -499,8 +520,11 @@ SwapNodes.prototype.insertNode = function(parent, posInParent, oldNode) image.height = rect.height; image.style["position"] = "absolute"; set_rect_style(image, rect); - var texture_url = textures[texture_id]; - image.src = texture_url; + var texture = textures[texture_id]; + image.src = texture.url; + texture.ref(); + // Unref blob url when loaded + image.onload = function() { texture.unref(); }; newNode = image; } break; @@ -789,16 +813,12 @@ function cmdSurfaceSetNodes(id, node_data) function cmdUploadTexture(id, data) { - var blob = new Blob([data],{type: "image/png"}); - var url = window.URL.createObjectURL(blob); - textures[id] = url; + new Texture (id, data); // Stores a ref in textures } function cmdReleaseTexture(id) { - var url = textures[id]; - window.URL.revokeObjectURL(url); - delete textures[id]; + textures[id].unref(); } function cmdGrabPointer(id, ownerEvents) From 87a13fe3d2ef03d1c4b57a74b38ac636810ddad9 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 22 Mar 2019 19:55:22 +0100 Subject: [PATCH 08/14] broadway: Prepare for splitting display ops out of command handling --- gdk/broadway/broadway.js | 299 +++++++++++++++++++-------------------- 1 file changed, 147 insertions(+), 152 deletions(-) diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js index e246948e11..9a104249e7 100644 --- a/gdk/broadway/broadway.js +++ b/gdk/broadway/broadway.js @@ -154,7 +154,6 @@ function sendConfigureNotify(surface) sendInput("w", [surface.id, surface.x, surface.y, surface.width, surface.height]); } -var positionIndex = 0; function cmdCreateSurface(id, x, y, width, height, isTemp) { var surface = { id: id, x: x, y:y, width: width, height: height, isTemp: isTemp }; @@ -167,8 +166,6 @@ function cmdCreateSurface(id, x, y, width, height, isTemp) div.surface = surface; surface.div = div; - document.body.appendChild(div); - div.style["position"] = "absolute"; div.style["left"] = surface.x + "px"; div.style["top"] = surface.y + "px"; @@ -181,54 +178,8 @@ function cmdCreateSurface(id, x, y, width, height, isTemp) stackingOrder.push(surface); sendConfigureNotify(surface); -} -function cmdShowSurface(id) -{ - var surface = surfaces[id]; - - if (surface.visible) - return; - surface.visible = true; - - var xOffset = surface.x; - var yOffset = surface.y; - - surface.div.style["left"] = xOffset + "px"; - surface.div.style["top"] = yOffset + "px"; - surface.div.style["visibility"] = "visible"; - - restackSurfaces(); -} - -function cmdHideSurface(id) -{ - if (grab.surface == id) - doUngrab(); - - var surface = surfaces[id]; - if (!surface.visible) - return; - surface.visible = false; - - surface.div.style["visibility"] = "hidden"; -} - -function cmdSetTransientFor(id, parentId) -{ - var surface = surfaces[id]; - - if (surface.transientParent == parentId) - return; - - surface.transientParent = parentId; - if (parentId != 0 && surfaces[parentId]) { - moveToHelper(surface, stackingOrder.indexOf(surfaces[parentId])+1); - } - - if (surface.visible) { - restackSurfaces(); - } + return div; } function restackSurfaces() { @@ -253,97 +204,51 @@ function moveToHelper(surface, position) { } } -function cmdDeleteSurface(id) -{ - if (grab.surface == id) - doUngrab(); - - var surface = surfaces[id]; - var i = stackingOrder.indexOf(surface); - if (i >= 0) - stackingOrder.splice(i, 1); - var div = surface.div; - div.parentNode.removeChild(div); - delete surfaces[id]; -} - function cmdRoundtrip(id, tag) { sendInput("F", [id, tag]); } -function cmdMoveResizeSurface(id, has_pos, x, y, has_size, w, h) -{ - var surface = surfaces[id]; - if (has_pos) { - surface.positioned = true; - surface.x = x; - surface.y = y; - } - - if (has_size) { - surface.width = w; - surface.height = h; - - surface.div.style["width"] = surface.width + "px"; - surface.div.style["height"] = surface.height + "px"; - } - - if (surface.visible) { - if (has_pos) { - var xOffset = surface.x; - var yOffset = surface.y; - - surface.div.style["left"] = xOffset + "px"; - surface.div.style["top"] = yOffset + "px"; - } - } - - sendConfigureNotify(surface); -} - function cmdRaiseSurface(id) { var surface = surfaces[id]; moveToHelper(surface); - restackSurfaces(); } function cmdLowerSurface(id) { var surface = surfaces[id]; - moveToHelper(surface, 0); - restackSurfaces(); } -function SwapNodes(node_data, div) { +function TransformNodes(node_data, div, display_commands) { this.node_data = node_data; + this.display_commands = display_commands; this.data_pos = 0; this.div = div; this.outstanding = 1; } -SwapNodes.prototype.decode_uint32 = function() { +TransformNodes.prototype.decode_uint32 = function() { var v = this.node_data.getUint32(this.data_pos, true); this.data_pos += 4; return v; } -SwapNodes.prototype.decode_int32 = function() { +TransformNodes.prototype.decode_int32 = function() { var v = this.node_data.getInt32(this.data_pos, true); this.data_pos += 4; return v; } -SwapNodes.prototype.decode_float = function() { +TransformNodes.prototype.decode_float = function() { var v = this.node_data.getFloat32(this.data_pos, true); this.data_pos += 4; return v; } -SwapNodes.prototype.decode_color = function() { +TransformNodes.prototype.decode_color = function() { var rgba = this.decode_uint32(); var a = (rgba >> 24) & 0xff; var r = (rgba >> 16) & 0xff; @@ -357,21 +262,21 @@ SwapNodes.prototype.decode_color = function() { return c; } -SwapNodes.prototype.decode_size = function() { +TransformNodes.prototype.decode_size = function() { var s = new Object(); s.width = this.decode_float (); s.height = this.decode_float (); return s; } -SwapNodes.prototype.decode_point = function() { +TransformNodes.prototype.decode_point = function() { var p = new Object(); p.x = this.decode_float (); p.y = this.decode_float (); return p; } -SwapNodes.prototype.decode_rect = function() { +TransformNodes.prototype.decode_rect = function() { var r = new Object(); r.x = this.decode_float (); r.y = this.decode_float (); @@ -380,7 +285,7 @@ SwapNodes.prototype.decode_rect = function() { return r; } -SwapNodes.prototype.decode_irect = function() { +TransformNodes.prototype.decode_irect = function() { var r = new Object(); r.x = this.decode_int32 (); r.y = this.decode_int32 (); @@ -389,7 +294,7 @@ SwapNodes.prototype.decode_irect = function() { return r; } -SwapNodes.prototype.decode_rounded_rect = function() { +TransformNodes.prototype.decode_rounded_rect = function() { var r = new Object(); r.bounds = this.decode_rect(); r.sizes = []; @@ -398,14 +303,14 @@ SwapNodes.prototype.decode_rounded_rect = function() { return r; } -SwapNodes.prototype.decode_color_stop = function() { +TransformNodes.prototype.decode_color_stop = function() { var s = new Object(); s.offset = this.decode_float (); s.color = this.decode_color (); return s; } -SwapNodes.prototype.decode_color_stops = function() { +TransformNodes.prototype.decode_color_stops = function() { var stops = []; var len = this.decode_uint32(); for (var i = 0; i < len; i++) @@ -447,7 +352,7 @@ function utf8_to_string(array) { return out; } -SwapNodes.prototype.decode_string = function() { +TransformNodes.prototype.decode_string = function() { var len = this.decode_uint32(); var utf8 = new Array(); var b; @@ -495,7 +400,7 @@ function set_rrect_style (div, rrect) { div.style["border-bottom-left-radius"] = args(px(rrect.sizes[3].width), px(rrect.sizes[3].height)); } -SwapNodes.prototype.insertNode = function(parent, posInParent, oldNode) +TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) { var type = this.decode_uint32(); var newNode = null; @@ -790,36 +695,20 @@ SwapNodes.prototype.insertNode = function(parent, posInParent, oldNode) if (newNode) { if (posInParent >= 0 && parent.children[posInParent]) - parent.replaceChild(newNode, parent.children[posInParent]); + this.display_commands.push([DISPLAY_OP_REPLACE_CHILD, parent, newNode, parent.children[posInParent]]); else - parent.appendChild(newNode); + this.display_commands.push([DISPLAY_OP_APPEND_CHILD, parent, newNode]); } } -function cmdSurfaceSetNodes(id, node_data) +TransformNodes.prototype.execute = function(display_commands) { - var surface = surfaces[id]; - surface.node_data = node_data; - - var div = surface.div; - - /* We use a secondary div so that we can remove all previous children in one go */ - - var swap = new SwapNodes (node_data, div); - swap.insertNode(div, 0, div.firstChild); - if (swap.data_pos != node_data.byteLength) - alert ("Did not consume entire array (len " + node_data.byteLength + ")"); + var div = this.div; + this.insertNode(div, 0, div.firstChild, display_commands); + if (this.data_pos != this.node_data.byteLength) + alert ("Did not consume entire array (len " + this.node_data.byteLength + ")"); } -function cmdUploadTexture(id, data) -{ - new Texture (id, data); // Stores a ref in textures -} - -function cmdReleaseTexture(id) -{ - textures[id].unref(); -} function cmdGrabPointer(id, ownerEvents) { @@ -834,6 +723,65 @@ function cmdUngrabPointer() doUngrab(); } +const DISPLAY_OP_REPLACE_CHILD = 0; +const DISPLAY_OP_APPEND_CHILD = 1; +const DISPLAY_OP_APPEND_ROOT = 2; +const DISPLAY_OP_SHOW_SURFACE = 3; +const DISPLAY_OP_HIDE_SURFACE = 4; +const DISPLAY_OP_DELETE_NODE = 5; +const DISPLAY_OP_MOVE_NODE = 6; +const DISPLAY_OP_RESIZE_NODE = 7; + +function handleDisplayCommands(display_commands) +{ + var div; + var len = display_commands.length; + for (var i = 0; i < len; i++) { + var cmd = display_commands[i]; + + switch (cmd[0]) { + case DISPLAY_OP_REPLACE_CHILD: + cmd[1].replaceChild(cmd[2], cmd[3]); + break; + case DISPLAY_OP_APPEND_CHILD: + cmd[1].appendChild(cmd[2]); + break; + case DISPLAY_OP_APPEND_ROOT: + document.body.appendChild(cmd[1]); + break; + case DISPLAY_OP_SHOW_SURFACE: + div = cmd[1]; + var xOffset = cmd[2]; + var yOffset = cmd[3]; + div.style["left"] = xOffset + "px"; + div.style["top"] = yOffset + "px"; + div.style["visibility"] = "visible"; + break; + case DISPLAY_OP_HIDE_SURFACE: + div = cmd[1]; + div.style["visibility"] = "hidden"; + break; + case DISPLAY_OP_DELETE_NODE: + div = cmd[1]; + div.parentNode.removeChild(div); + break; + case DISPLAY_OP_MOVE_NODE: + div = cmd[1]; + div.style["left"] = cmd[2] + "px"; + div.style["top"] = cmd[3] + "px"; + break; + case DISPLAY_OP_RESIZE_NODE: + div = cmd[1]; + div.style["width"] = cmd[2] + "px"; + div.style["height"] = cmd[3] + "px"; + break; + + default: + alert("Unknown display op " + command); + } + } +} + var active = false; function handleCommands(cmd) { @@ -842,8 +790,11 @@ function handleCommands(cmd) active = true; } + var display_commands = new Array(); + var need_restack = false; + while (cmd.pos < cmd.length) { - var id, x, y, w, h, q; + var id, x, y, w, h, q, surface; var command = cmd.get_char(); lastSerial = cmd.get_32(); switch (command) { @@ -859,28 +810,58 @@ function handleCommands(cmd) w = cmd.get_16(); h = cmd.get_16(); var isTemp = cmd.get_bool(); - cmdCreateSurface(id, x, y, w, h, isTemp); + var div = cmdCreateSurface(id, x, y, w, h, isTemp); + display_commands.push([DISPLAY_OP_APPEND_ROOT, div]); + need_restack = true; break; case 'S': // Show a surface id = cmd.get_16(); - cmdShowSurface(id); - break; + surface = surfaces[id]; + if (!surface.visible) { + surface.visible = true; + display_commands.push([DISPLAY_OP_SHOW_SURFACE, surface.div, surface.x, surface.y]); + need_restack = true; + } + break; case 'H': // Hide a surface id = cmd.get_16(); - cmdHideSurface(id); + if (grab.surface == id) + doUngrab(); + surface = surfaces[id]; + if (surface.visible) { + display_commands.push([DISPLAY_OP_HIDE_SURFACE, surface.div]); + } break; case 'p': // Set transient parent id = cmd.get_16(); var parentId = cmd.get_16(); - cmdSetTransientFor(id, parentId); + surface = surfaces[id]; + if (surface.transientParent !== parentId) { + surface.transientParent = parentId; + if (parentId != 0 && surfaces[parentId]) { + moveToHelper(surface, stackingOrder.indexOf(surfaces[parentId])+1); + } + need_restack = true; + } break; case 'd': // Delete surface id = cmd.get_16(); - cmdDeleteSurface(id); + + if (grab.surface == id) + doUngrab(); + + surface = surfaces[id]; + var i = stackingOrder.indexOf(surface); + if (i >= 0) + stackingOrder.splice(i, 1); + var div = surface.div; + + display_commands.push([DISPLAY_OP_DELETE_NODE, div]); + delete surfaces[id]; break; case 'F': // RoundTrip @@ -893,43 +874,51 @@ function handleCommands(cmd) id = cmd.get_16(); var ops = cmd.get_flags(); var has_pos = ops & 1; - if (has_pos) { - x = cmd.get_16s(); - y = cmd.get_16s(); - } var has_size = ops & 2; - if (has_size) { - w = cmd.get_16(); - h = cmd.get_16(); + surface = surfaces[id]; + if (has_pos) { + surface.positioned = true; + surface.x = cmd.get_16s();; + surface.y = cmd.get_16s();; + display_commands.push([DISPLAY_OP_MOVE_NODE, surface.div, surface.x, surface.y]); + } + if (has_size) { + surface.width = cmd.get_16(); + surface.height = cmd.get_16();; + display_commands.push([DISPLAY_OP_RESIZE_NODE, surface.div, surface.width, surface.height]); + } - cmdMoveResizeSurface(id, has_pos, x, y, has_size, w, h); break; case 'r': // Raise a surface id = cmd.get_16(); cmdRaiseSurface(id); + need_restack = true; break; case 'R': // Lower a surface id = cmd.get_16(); cmdLowerSurface(id); + need_restack = true; break; case 't': // Upload texture id = cmd.get_32(); var data = cmd.get_data(); - cmdUploadTexture(id, data); + var texure = new Texture (id, data); // Stores a ref in textures break; case 'T': // Release texture id = cmd.get_32(); - cmdReleaseTexture(id); + textures[id].unref(); break; case 'n': // Set nodes id = cmd.get_16(); var node_data = cmd.get_nodes (); - cmdSurfaceSetNodes(id, node_data); + surface = surfaces[id]; + var transform_nodes = new TransformNodes (node_data, surface.div, display_commands); + transform_nodes.execute(); break; case 'g': // Grab @@ -952,6 +941,12 @@ function handleCommands(cmd) alert("Unknown op " + command); } } + + if (need_restack) + restackSurfaces(); + + handleDisplayCommands(display_commands); + return true; } From d59d8b5dd4a3719475c39ef3144e599b546ff9b3 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 25 Mar 2019 10:49:58 +0100 Subject: [PATCH 09/14] Disable accidental debug spew --- gsk/gskbroadwayrenderer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gsk/gskbroadwayrenderer.c b/gsk/gskbroadwayrenderer.c index dc09829724..0ebee3702d 100644 --- a/gsk/gskbroadwayrenderer.c +++ b/gsk/gskbroadwayrenderer.c @@ -485,7 +485,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, FallbackCacheElement *element; texture = node_texture_fallback (node, &t_off_x, &t_off_y); -#if 1 +#if 0 g_print ("Fallback %p for %s\n", texture, node->node_class->type_name); #endif element = g_new0 (FallbackCacheElement, 1); From fbefec52a56b45da4e77cefca16aea9e9db38f47 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 25 Mar 2019 14:15:49 +0100 Subject: [PATCH 10/14] Broadway: Add id for nodes and reuse old ones When sending render nodes from the client to the daemon we add an id, and whenever we're about to re-send the entire tree node we instead send the old id. We track all the nodes for the previous frame of the surface this way. Having the id on the daemon side will allow us do to much better deltas. --- gdk/broadway/broadway-protocol.h | 1 + gdk/broadway/broadway-server.c | 269 ++++++++++-- gdk/broadway/broadway-server.h | 10 +- gdk/broadway/broadwayd.c | 128 +----- gdk/broadway/gdkdisplay-broadway.c | 2 +- gdk/broadway/gdkdrawcontext-broadway.c | 2 + gsk/gskbroadwayrenderer.c | 565 +++++++++++++++---------- 7 files changed, 588 insertions(+), 389 deletions(-) diff --git a/gdk/broadway/broadway-protocol.h b/gdk/broadway/broadway-protocol.h index 5c2d923a10..70c5c18522 100644 --- a/gdk/broadway/broadway-protocol.h +++ b/gdk/broadway/broadway-protocol.h @@ -24,6 +24,7 @@ typedef enum { /* Sync changes with broadway.js */ BROADWAY_NODE_KEEP_THIS = 12, BROADWAY_NODE_TRANSLATE = 13, BROADWAY_NODE_DEBUG = 14, + BROADWAY_NODE_REUSE = 15, } BroadwayNodeType; static const char *broadway_node_type_names[] G_GNUC_UNUSED = { diff --git a/gdk/broadway/broadway-server.c b/gdk/broadway/broadway-server.c index 951c7035c1..ac9c424cf9 100644 --- a/gdk/broadway/broadway-server.c +++ b/gdk/broadway/broadway-server.c @@ -35,7 +35,6 @@ #include #endif - typedef struct { int id; guint32 tag; @@ -126,23 +125,56 @@ struct BroadwaySurface { gint32 transient_for; guint32 texture; BroadwayNode *nodes; + GHashTable *node_lookup; +}; + +struct _BroadwayTexture { + grefcount refcount; + guint32 id; + GBytes *bytes; }; static void broadway_server_resync_surfaces (BroadwayServer *server); static void send_outstanding_roundtrips (BroadwayServer *server); +static void broadway_server_ref_texture (BroadwayServer *server, + guint32 id); + static GType broadway_server_get_type (void); G_DEFINE_TYPE (BroadwayServer, broadway_server, G_TYPE_OBJECT) static void -broadway_node_free (BroadwayNode *node) +broadway_texture_free (BroadwayTexture *texture) +{ + g_bytes_unref (texture->bytes); + g_free (texture); +} + +static void +broadway_node_unref (BroadwayServer *server, + BroadwayNode *node) { int i; - for (i = 0; i < node->n_children; i++) - broadway_node_free (node->children[i]); - g_free (node); + if (g_ref_count_dec (&node->refcount)) + { + for (i = 0; i < node->n_children; i++) + broadway_node_unref (server, node->children[i]); + + if (node->texture_id) + broadway_server_release_texture (server, node->texture_id); + + g_free (node); + } +} + +static BroadwayNode * +broadway_node_ref (BroadwayNode *node) +{ + g_ref_count_inc (&node->refcount); + + return node; } gboolean @@ -204,7 +236,7 @@ broadway_server_init (BroadwayServer *server) server->surface_id_hash = g_hash_table_new (NULL, NULL); server->id_counter = 0; server->textures = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, - (GDestroyNotify)g_bytes_unref); + (GDestroyNotify)broadway_texture_free); root = g_new0 (BroadwaySurface, 1); root->id = server->id_counter++; @@ -241,10 +273,12 @@ broadway_server_class_init (BroadwayServerClass * class) } static void -broadway_surface_free (BroadwaySurface *surface) +broadway_surface_free (BroadwayServer *server, + BroadwaySurface *surface) { if (surface->nodes) - broadway_node_free (surface->nodes); + broadway_node_unref (server, surface->nodes); + g_hash_table_unref (surface->node_lookup); g_free (surface); } @@ -1477,7 +1511,7 @@ broadway_server_destroy_surface (BroadwayServer *server, server->surfaces = g_list_remove (server->surfaces, surface); g_hash_table_remove (server->surface_id_hash, GINT_TO_POINTER (id)); - broadway_surface_free (surface); + broadway_surface_free (server, surface); } } @@ -1605,53 +1639,232 @@ broadway_server_has_client (BroadwayServer *server) return server->output != NULL; } +#define NODE_SIZE_COLOR 1 +#define NODE_SIZE_FLOAT 1 +#define NODE_SIZE_POINT 2 +#define NODE_SIZE_SIZE 2 +#define NODE_SIZE_RECT (NODE_SIZE_POINT + NODE_SIZE_SIZE) +#define NODE_SIZE_RRECT (NODE_SIZE_RECT + 4 * NODE_SIZE_SIZE) +#define NODE_SIZE_COLOR_STOP (NODE_SIZE_FLOAT + NODE_SIZE_COLOR) +#define NODE_SIZE_SHADOW (NODE_SIZE_COLOR + 3 * NODE_SIZE_FLOAT) + +static guint32 +rotl (guint32 value, int shift) +{ + if ((shift &= 32 - 1) == 0) + return value; + return (value << shift) | (value >> (32 - shift)); +} + +static BroadwayNode * +decode_nodes (BroadwayServer *server, + BroadwaySurface *surface, + int len, + guint32 data[], + GHashTable *client_texture_map, + int *pos) +{ + BroadwayNode *node; + guint32 type, id; + guint32 i, n_stops, n_shadows, n_chars; + guint32 size, n_children; + gint32 texture_offset; + guint32 hash; + + g_assert (*pos < len); + + size = 0; + n_children = 0; + texture_offset = -1; + + type = data[(*pos)++]; + id = data[(*pos)++]; + switch (type) { + case BROADWAY_NODE_REUSE: + node = g_hash_table_lookup (surface->node_lookup, GINT_TO_POINTER(id)); + g_assert (node != NULL); + return broadway_node_ref (node); + break; + case BROADWAY_NODE_COLOR: + size = NODE_SIZE_RECT + NODE_SIZE_COLOR; + break; + case BROADWAY_NODE_BORDER: + size = NODE_SIZE_RRECT + 4 * NODE_SIZE_FLOAT + 4 * NODE_SIZE_COLOR; + break; + case BROADWAY_NODE_INSET_SHADOW: + case BROADWAY_NODE_OUTSET_SHADOW: + size = NODE_SIZE_RRECT + NODE_SIZE_COLOR + 4 * NODE_SIZE_FLOAT; + break; + case BROADWAY_NODE_TEXTURE: + texture_offset = 4; + size = 5; + break; + case BROADWAY_NODE_CONTAINER: + size = 1; + n_children = data[*pos]; + break; + case BROADWAY_NODE_ROUNDED_CLIP: + size = NODE_SIZE_RRECT; + n_children = 1; + break; + case BROADWAY_NODE_CLIP: + size = NODE_SIZE_RECT; + n_children = 1; + break; + case BROADWAY_NODE_TRANSLATE: + size = NODE_SIZE_POINT; + n_children = 1; + break; + case BROADWAY_NODE_LINEAR_GRADIENT: + size = NODE_SIZE_RECT + 2 * NODE_SIZE_POINT; + n_stops = data[*pos + size++]; + size += n_stops * NODE_SIZE_COLOR_STOP; + break; + case BROADWAY_NODE_SHADOW: + size = 1; + n_shadows = data[*pos]; + size += n_shadows * NODE_SIZE_SHADOW; + n_children = 1; + break; + case BROADWAY_NODE_OPACITY: + size = NODE_SIZE_FLOAT; + n_children = 1; + break; + case BROADWAY_NODE_DEBUG: + n_chars = data[*pos]; + size = 1 + (n_chars + 3) / 4; + n_children = 1; + break; + default: + g_assert_not_reached (); + } + + node = g_malloc (sizeof(BroadwayNode) + (size - 1) * sizeof(guint32) + n_children * sizeof (BroadwayNode *)); + g_ref_count_init (&node->refcount); + node->type = type; + node->id = id; + node->texture_id = 0; + node->n_children = n_children; + node->children = (BroadwayNode **)((char *)node + sizeof(BroadwayNode) + (size - 1) * sizeof(guint32)); + node->n_data = size; + for (i = 0; i < size; i++) + { + node->data[i] = data[(*pos)++]; + if (i == texture_offset) + { + node->texture_id = GPOINTER_TO_INT (g_hash_table_lookup (client_texture_map, GINT_TO_POINTER (node->data[i]))); + broadway_server_ref_texture (server, node->texture_id); + node->data[i] = node->texture_id; + } + } + + for (i = 0; i < n_children; i++) + node->children[i] = decode_nodes (server, surface, len, data, client_texture_map, pos); + + hash = node->type << 16; + + for (i = 0; i < size; i++) + hash ^= rotl (node->data[i], i); + + for (i = 0; i < n_children; i++) + hash ^= rotl (node->children[i]->hash, i); + + node->hash = hash; + + return node; +} + +static void +init_node_lookup (BroadwaySurface *surface, + BroadwayNode *node) +{ + int i; + + g_hash_table_insert (surface->node_lookup, GINT_TO_POINTER(node->id), node); + for (i = 0; i < node->n_children; i++) + init_node_lookup (surface, node->children[i]); +} + /* passes ownership of nodes */ void -broadway_server_surface_set_nodes (BroadwayServer *server, - gint id, - BroadwayNode *root) +broadway_server_surface_update_nodes (BroadwayServer *server, + gint id, + guint32 data[], + int len, + GHashTable *client_texture_map) { BroadwaySurface *surface; + int pos = 0; + BroadwayNode *root; surface = broadway_server_lookup_surface (server, id); if (surface == NULL) return; + root = decode_nodes (server, surface, len, data, client_texture_map, &pos); + if (server->output != NULL) broadway_output_surface_set_nodes (server->output, surface->id, root, surface->nodes); if (surface->nodes) - broadway_node_free (surface->nodes); + broadway_node_unref (server, surface->nodes); + surface->nodes = root; + + g_hash_table_remove_all (surface->node_lookup); + + init_node_lookup (surface, surface->nodes); } guint32 broadway_server_upload_texture (BroadwayServer *server, - GBytes *texture) + GBytes *bytes) { - guint32 id; + BroadwayTexture *texture; + + texture = g_new0 (BroadwayTexture, 1); + g_ref_count_init (&texture->refcount); + texture->id = ++server->next_texture_id; + texture->bytes = g_bytes_ref (bytes); - id = ++server->next_texture_id; g_hash_table_replace (server->textures, - GINT_TO_POINTER (id), - g_bytes_ref (texture)); + GINT_TO_POINTER (texture->id), + texture); if (server->output) - broadway_output_upload_texture (server->output, id, texture); + broadway_output_upload_texture (server->output, texture->id, texture->bytes); - return id; + return texture->id; +} + +static void +broadway_server_ref_texture (BroadwayServer *server, + guint32 id) +{ + BroadwayTexture *texture; + + texture = g_hash_table_lookup (server->textures, GINT_TO_POINTER (id)); + if (texture) + g_ref_count_inc (&texture->refcount); } void broadway_server_release_texture (BroadwayServer *server, guint32 id) { - g_hash_table_remove (server->textures, GINT_TO_POINTER (id)); + BroadwayTexture *texture; - if (server->output) - broadway_output_release_texture (server->output, id); + texture = g_hash_table_lookup (server->textures, GINT_TO_POINTER (id)); + + if (texture && g_ref_count_dec (&texture->refcount)) + { + g_hash_table_remove (server->textures, GINT_TO_POINTER (id)); + + if (server->output) + broadway_output_release_texture (server->output, id); + } } gboolean @@ -1801,6 +2014,7 @@ broadway_server_new_surface (BroadwayServer *server, surface->width = width; surface->height = height; surface->is_temp = is_temp; + surface->node_lookup = g_hash_table_new (g_direct_hash, g_direct_equal); g_hash_table_insert (server->surface_id_hash, GINT_TO_POINTER (surface->id), @@ -1835,9 +2049,12 @@ broadway_server_resync_surfaces (BroadwayServer *server) /* First upload all textures */ g_hash_table_iter_init (&iter, server->textures); while (g_hash_table_iter_next (&iter, &key, &value)) - broadway_output_upload_texture (server->output, - GPOINTER_TO_INT (key), - (GBytes *)value); + { + BroadwayTexture *texture = value; + broadway_output_upload_texture (server->output, + GPOINTER_TO_INT (key), + texture->bytes); + } /* Then create all surfaces */ for (l = server->surfaces; l != NULL; l = l->next) diff --git a/gdk/broadway/broadway-server.h b/gdk/broadway/broadway-server.h index 73ec89e051..1e125bd065 100644 --- a/gdk/broadway/broadway-server.h +++ b/gdk/broadway/broadway-server.h @@ -19,12 +19,16 @@ typedef struct _BroadwayServerClass BroadwayServerClass; #define BROADWAY_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BROADWAY_TYPE_SERVER, BroadwayServerClass)) typedef struct _BroadwayNode BroadwayNode; +typedef struct _BroadwayTexture BroadwayTexture; struct _BroadwayNode { + grefcount refcount; guint32 type; + guint32 id; guint32 hash; /* deep hash */ guint32 n_children; BroadwayNode **children; + guint32 texture_id; guint32 n_data; guint32 data[1]; }; @@ -99,9 +103,11 @@ void broadway_server_release_texture (BroadwayServer * guint32 id); cairo_surface_t * broadway_server_create_surface (int width, int height); -void broadway_server_surface_set_nodes (BroadwayServer *server, +void broadway_server_surface_update_nodes (BroadwayServer *server, gint id, - BroadwayNode *root); + guint32 data[], + int len, + GHashTable *client_texture_map); gboolean broadway_server_surface_move_resize (BroadwayServer *server, gint id, gboolean with_move, diff --git a/gdk/broadway/broadwayd.c b/gdk/broadway/broadwayd.c index e691f3ce90..a3b402f1f6 100644 --- a/gdk/broadway/broadwayd.c +++ b/gdk/broadway/broadwayd.c @@ -215,125 +215,6 @@ get_client_serial (BroadwayClient *client, guint32 daemon_serial) return client_serial; } -#define NODE_SIZE_COLOR 1 -#define NODE_SIZE_FLOAT 1 -#define NODE_SIZE_POINT 2 -#define NODE_SIZE_SIZE 2 -#define NODE_SIZE_RECT (NODE_SIZE_POINT + NODE_SIZE_SIZE) -#define NODE_SIZE_RRECT (NODE_SIZE_RECT + 4 * NODE_SIZE_SIZE) -#define NODE_SIZE_COLOR_STOP (NODE_SIZE_FLOAT + NODE_SIZE_COLOR) -#define NODE_SIZE_SHADOW (NODE_SIZE_COLOR + 3 * NODE_SIZE_FLOAT) - -static guint32 -rotl (guint32 value, int shift) -{ - if ((shift &= 32 - 1) == 0) - return value; - return (value << shift) | (value >> (32 - shift)); -} - -static BroadwayNode * -decode_nodes (BroadwayClient *client, - int len, guint32 data[], int *pos) -{ - BroadwayNode *node; - guint32 type; - guint32 i, n_stops, n_shadows, n_chars; - guint32 size, n_children; - gint32 texture_offset; - guint32 hash; - - g_assert (*pos < len); - - size = 0; - n_children = 0; - texture_offset = -1; - - type = data[(*pos)++]; - switch (type) { - case BROADWAY_NODE_COLOR: - size = NODE_SIZE_RECT + NODE_SIZE_COLOR; - break; - case BROADWAY_NODE_BORDER: - size = NODE_SIZE_RRECT + 4 * NODE_SIZE_FLOAT + 4 * NODE_SIZE_COLOR; - break; - case BROADWAY_NODE_INSET_SHADOW: - case BROADWAY_NODE_OUTSET_SHADOW: - size = NODE_SIZE_RRECT + NODE_SIZE_COLOR + 4 * NODE_SIZE_FLOAT; - break; - case BROADWAY_NODE_TEXTURE: - texture_offset = 4; - size = 5; - break; - case BROADWAY_NODE_CONTAINER: - size = 1; - n_children = data[*pos]; - break; - case BROADWAY_NODE_ROUNDED_CLIP: - size = NODE_SIZE_RRECT; - n_children = 1; - break; - case BROADWAY_NODE_CLIP: - size = NODE_SIZE_RECT; - n_children = 1; - break; - case BROADWAY_NODE_TRANSLATE: - size = NODE_SIZE_POINT; - n_children = 1; - break; - case BROADWAY_NODE_LINEAR_GRADIENT: - size = NODE_SIZE_RECT + 2 * NODE_SIZE_POINT; - n_stops = data[*pos + size++]; - size += n_stops * NODE_SIZE_COLOR_STOP; - break; - case BROADWAY_NODE_SHADOW: - size = 1; - n_shadows = data[*pos]; - size += n_shadows * NODE_SIZE_SHADOW; - n_children = 1; - break; - case BROADWAY_NODE_OPACITY: - size = NODE_SIZE_FLOAT; - n_children = 1; - break; - case BROADWAY_NODE_DEBUG: - n_chars = data[*pos]; - size = 1 + (n_chars + 3) / 4; - n_children = 1; - break; - default: - g_assert_not_reached (); - } - - node = g_malloc (sizeof(BroadwayNode) + (size - 1) * sizeof(guint32) + n_children * sizeof (BroadwayNode *)); - node->type = type; - node->n_children = n_children; - node->children = (BroadwayNode **)((char *)node + sizeof(BroadwayNode) + (size - 1) * sizeof(guint32)); - node->n_data = size; - for (i = 0; i < size; i++) - { - node->data[i] = data[(*pos)++]; - if (i == texture_offset) - node->data[i] = GPOINTER_TO_INT (g_hash_table_lookup (client->textures, - GINT_TO_POINTER (node->data[i]))); - } - - for (i = 0; i < n_children; i++) - node->children[i] = decode_nodes (client, len, data, pos); - - hash = node->type << 16; - - for (i = 0; i < size; i++) - hash ^= rotl (node->data[i], i); - - for (i = 0; i < n_children; i++) - hash ^= rotl (node->children[i]->hash, i); - - node->hash = hash; - - return node; -} - static void client_handle_request (BroadwayClient *client, BroadwayRequest *request) @@ -409,13 +290,10 @@ client_handle_request (BroadwayClient *client, { gsize array_size = request->base.size - sizeof (BroadwayRequestSetNodes) + sizeof(guint32); int n_data = array_size / sizeof(guint32); - int pos = 0; - BroadwayNode *node; - node = decode_nodes (client, n_data, request->set_nodes.data, &pos); - - broadway_server_surface_set_nodes (server, request->set_nodes.id, - node); + broadway_server_surface_update_nodes (server, request->set_nodes.id, + request->set_nodes.data, n_data, + client->textures); } break; case BROADWAY_REQUEST_UPLOAD_TEXTURE: diff --git a/gdk/broadway/gdkdisplay-broadway.c b/gdk/broadway/gdkdisplay-broadway.c index f27af0b3ef..9a80ec8d55 100644 --- a/gdk/broadway/gdkdisplay-broadway.c +++ b/gdk/broadway/gdkdisplay-broadway.c @@ -380,7 +380,7 @@ gdk_broadway_display_ensure_texture (GdkDisplay *display, data = g_new0 (BroadwayTextureData, 1); data->id = id; data->display = g_object_ref (display); - g_object_set_data_full (G_OBJECT (texture), "broadway-data", data, (GDestroyNotify)broadway_texture_data_free); + g_object_set_data_full (G_OBJECT (texture), "broadway-data", data, (GDestroyNotify)broadway_texture_data_free); } return data->id; diff --git a/gdk/broadway/gdkdrawcontext-broadway.c b/gdk/broadway/gdkdrawcontext-broadway.c index 889b52fb30..473488396a 100644 --- a/gdk/broadway/gdkdrawcontext-broadway.c +++ b/gdk/broadway/gdkdrawcontext-broadway.c @@ -64,6 +64,8 @@ gdk_broadway_draw_context_end_frame (GdkDrawContext *draw_context, g_array_unref (self->nodes); self->nodes = NULL; + + /* We now sent all new texture refs to the daemon via the nodes, so we can drop them here */ g_ptr_array_unref (self->node_textures); self->node_textures = NULL; } diff --git a/gsk/gskbroadwayrenderer.c b/gsk/gskbroadwayrenderer.c index 0ebee3702d..0730ca8a73 100644 --- a/gsk/gskbroadwayrenderer.c +++ b/gsk/gskbroadwayrenderer.c @@ -13,8 +13,16 @@ struct _GskBroadwayRenderer { GskRenderer parent_instance; GdkBroadwayDrawContext *draw_context; - GHashTable *fallback_cache; - guint32 frame_nr; + guint32 next_node_id; + + /* Set during rendering */ + GArray *nodes; /* Owned by draw_contex */ + GPtrArray *node_textures; /* Owned by draw_contex */ + GHashTable *node_lookup; + + /* Kept from last frame */ + GHashTable *last_node_lookup; + GskRenderNode *last_root; /* Owning refs to the things in last_node_lookup */ }; struct _GskBroadwayRendererClass @@ -179,46 +187,132 @@ add_string (GArray *nodes, const char *str) add_uint32 (nodes, v); } -typedef struct { - GskRenderNode *node; - GdkTexture *texture; - float off_x; - float off_y; - int used_in_frame; -} FallbackCacheElement; +static void +collect_reused_child_nodes (GskRenderer *renderer, + GskRenderNode *node); static void -fallback_cache_element_free (FallbackCacheElement *element) +collect_reused_node (GskRenderer *renderer, + GskRenderNode *node) { - gsk_render_node_unref (element->node); - g_object_unref (element->texture); - g_free (element); + GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer); + guint32 old_id; + + if (self->last_node_lookup && + (old_id = GPOINTER_TO_INT(g_hash_table_lookup (self->last_node_lookup, node))) != 0) + { + g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER (old_id)); + collect_reused_child_nodes (renderer, node); + } } -static GdkTexture * -node_texture_fallback (GskRenderNode *node, - float *off_x, - float *off_y) + +static void +collect_reused_child_nodes (GskRenderer *renderer, + GskRenderNode *node) { - cairo_surface_t *surface; - cairo_t *cr; - int x = floorf (node->bounds.origin.x); - int y = floorf (node->bounds.origin.y); - int width = ceil (node->bounds.origin.x + node->bounds.size.width) - x; - int height = ceil (node->bounds.origin.y + node->bounds.size.height) - y; - GdkTexture *texture; + guint i; - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); - cr = cairo_create (surface); - cairo_translate (cr, -x, -y); - gsk_render_node_draw (node, cr); - cairo_destroy (cr); + switch (gsk_render_node_get_node_type (node)) + { + case GSK_NOT_A_RENDER_NODE: + g_assert_not_reached (); + return; - texture = gdk_texture_new_for_surface (surface); - *off_x = x - node->bounds.origin.x; - *off_y = y - node->bounds.origin.y; + /* Leaf nodes */ - return texture; + case GSK_TEXTURE_NODE: + case GSK_CAIRO_NODE: + case GSK_COLOR_NODE: + case GSK_BORDER_NODE: + case GSK_OUTSET_SHADOW_NODE: + case GSK_INSET_SHADOW_NODE: + case GSK_LINEAR_GRADIENT_NODE: + + /* Fallbacks (=> leaf for now */ + case GSK_COLOR_MATRIX_NODE: + case GSK_TEXT_NODE: + case GSK_REPEATING_LINEAR_GRADIENT_NODE: + case GSK_REPEAT_NODE: + case GSK_BLEND_NODE: + case GSK_CROSS_FADE_NODE: + case GSK_BLUR_NODE: + + default: + + break; + + /* Bin nodes */ + + case GSK_SHADOW_NODE: + collect_reused_node (renderer, + gsk_shadow_node_get_child (node)); + break; + + case GSK_OPACITY_NODE: + collect_reused_node (renderer, + gsk_opacity_node_get_child (node)); + break; + + case GSK_ROUNDED_CLIP_NODE: + collect_reused_node (renderer, + gsk_rounded_clip_node_get_child (node)); + break; + + case GSK_CLIP_NODE: + collect_reused_node (renderer, + gsk_clip_node_get_child (node)); + break; + + case GSK_TRANSFORM_NODE: + collect_reused_node (renderer, + gsk_transform_node_get_child (node)); + break; + + case GSK_DEBUG_NODE: + collect_reused_node (renderer, + gsk_debug_node_get_child (node)); + break; + + /* Generic nodes */ + + case GSK_CONTAINER_NODE: + for (i = 0; i < gsk_container_node_get_n_children (node); i++) + collect_reused_node (renderer, + gsk_container_node_get_child (node, i)); + break; + + break; /* Fallback */ + } +} + +static gboolean +add_new_node (GskRenderer *renderer, + GskRenderNode *node, + BroadwayNodeType type) +{ + GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer); + guint32 id, old_id; + + if (self->last_node_lookup && + (old_id = GPOINTER_TO_INT (g_hash_table_lookup (self->last_node_lookup, node))) != 0) + { + add_uint32 (self->nodes, BROADWAY_NODE_REUSE); + add_uint32 (self->nodes, old_id); + + g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER(old_id)); + collect_reused_child_nodes (renderer, node); + + return FALSE; + } + + id = ++self->next_node_id; + g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER(id)); + + add_uint32 (self->nodes, type); + add_uint32 (self->nodes, id); + + return TRUE; } /* Note: This tracks the offset so that we can convert @@ -227,14 +321,13 @@ node_texture_fallback (GskRenderNode *node, which is good for re-using subtrees. */ static void gsk_broadway_renderer_add_node (GskRenderer *renderer, - GArray *nodes, - GPtrArray *node_textures, GskRenderNode *node, float offset_x, float offset_y) { GdkDisplay *display = gdk_surface_get_display (gsk_renderer_get_surface (renderer)); GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer); + GArray *nodes = self->nodes; switch (gsk_render_node_get_node_type (node)) { @@ -245,214 +338,218 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, /* Leaf nodes */ case GSK_TEXTURE_NODE: - { - GdkTexture *texture = gsk_texture_node_get_texture (node); - guint32 texture_id; + if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE)) + { + GdkTexture *texture = gsk_texture_node_get_texture (node); + guint32 texture_id; - g_ptr_array_add (node_textures, g_object_ref (texture)); /* Transfers ownership to node_textures */ - texture_id = gdk_broadway_display_ensure_texture (display, texture); + /* No need to add to self->node_textures here, the node will keep it alive until end of frame. */ - add_uint32 (nodes, BROADWAY_NODE_TEXTURE); - add_rect (nodes, &node->bounds, offset_x, offset_y); - add_uint32 (nodes, texture_id); - } + texture_id = gdk_broadway_display_ensure_texture (display, texture); + + add_rect (nodes, &node->bounds, offset_x, offset_y); + add_uint32 (nodes, texture_id); + } return; case GSK_CAIRO_NODE: - { - cairo_surface_t *surface = (cairo_surface_t *)gsk_cairo_node_peek_surface (node); - cairo_surface_t *image_surface = NULL; - GdkTexture *texture; - guint32 texture_id; + if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE)) + { + cairo_surface_t *surface = (cairo_surface_t *)gsk_cairo_node_peek_surface (node); + cairo_surface_t *image_surface = NULL; + GdkTexture *texture; + guint32 texture_id; - if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE) - image_surface = cairo_surface_reference (surface); - else - { - cairo_t *cr; - image_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - ceilf (node->bounds.size.width), - ceilf (node->bounds.size.height)); - cr = cairo_create (image_surface); - cairo_set_source_surface (cr, surface, 0, 0); - cairo_rectangle (cr, 0, 0, node->bounds.size.width, node->bounds.size.height); - cairo_fill (cr); - cairo_destroy (cr); - } + if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE) + image_surface = cairo_surface_reference (surface); + else + { + cairo_t *cr; + image_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + ceilf (node->bounds.size.width), + ceilf (node->bounds.size.height)); + cr = cairo_create (image_surface); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_rectangle (cr, 0, 0, node->bounds.size.width, node->bounds.size.height); + cairo_fill (cr); + cairo_destroy (cr); + } - texture = gdk_texture_new_for_surface (image_surface); - g_ptr_array_add (node_textures, g_object_ref (texture)); /* Transfers ownership to node_textures */ - texture_id = gdk_broadway_display_ensure_texture (display, texture); + texture = gdk_texture_new_for_surface (image_surface); + g_ptr_array_add (self->node_textures, g_object_ref (texture)); /* Transfers ownership to node_textures */ + texture_id = gdk_broadway_display_ensure_texture (display, texture); - add_uint32 (nodes, BROADWAY_NODE_TEXTURE); - add_rect (nodes, &node->bounds, offset_x, offset_y); - add_uint32 (nodes, texture_id); + add_rect (nodes, &node->bounds, offset_x, offset_y); + add_uint32 (nodes, texture_id); - cairo_surface_destroy (image_surface); - } + cairo_surface_destroy (image_surface); + } return; case GSK_COLOR_NODE: - { - add_uint32 (nodes, BROADWAY_NODE_COLOR); - add_rect (nodes, &node->bounds, offset_x, offset_y); - add_rgba (nodes, gsk_color_node_peek_color (node)); - } + if (add_new_node (renderer, node, BROADWAY_NODE_COLOR)) + { + add_rect (nodes, &node->bounds, offset_x, offset_y); + add_rgba (nodes, gsk_color_node_peek_color (node)); + } return; case GSK_BORDER_NODE: - { - int i; - add_uint32 (nodes, BROADWAY_NODE_BORDER); - add_rounded_rect (nodes, gsk_border_node_peek_outline (node), offset_x, offset_y); - for (i = 0; i < 4; i++) - add_float (nodes, gsk_border_node_peek_widths (node)[i]); - for (i = 0; i < 4; i++) - add_rgba (nodes, &gsk_border_node_peek_colors (node)[i]); - } + if (add_new_node (renderer, node, BROADWAY_NODE_BORDER)) + { + int i; + add_rounded_rect (nodes, gsk_border_node_peek_outline (node), offset_x, offset_y); + for (i = 0; i < 4; i++) + add_float (nodes, gsk_border_node_peek_widths (node)[i]); + for (i = 0; i < 4; i++) + add_rgba (nodes, &gsk_border_node_peek_colors (node)[i]); + } return; case GSK_OUTSET_SHADOW_NODE: - { - add_uint32 (nodes, BROADWAY_NODE_OUTSET_SHADOW); - add_rounded_rect (nodes, gsk_outset_shadow_node_peek_outline (node), offset_x, offset_y); - add_rgba (nodes, gsk_outset_shadow_node_peek_color (node)); - add_float (nodes, gsk_outset_shadow_node_get_dx (node)); - add_float (nodes, gsk_outset_shadow_node_get_dy (node)); - add_float (nodes, gsk_outset_shadow_node_get_spread (node)); - add_float (nodes, gsk_outset_shadow_node_get_blur_radius (node)); - } + if (add_new_node (renderer, node, BROADWAY_NODE_OUTSET_SHADOW)) + { + add_rounded_rect (nodes, gsk_outset_shadow_node_peek_outline (node), offset_x, offset_y); + add_rgba (nodes, gsk_outset_shadow_node_peek_color (node)); + add_float (nodes, gsk_outset_shadow_node_get_dx (node)); + add_float (nodes, gsk_outset_shadow_node_get_dy (node)); + add_float (nodes, gsk_outset_shadow_node_get_spread (node)); + add_float (nodes, gsk_outset_shadow_node_get_blur_radius (node)); + } return; case GSK_INSET_SHADOW_NODE: - { - add_uint32 (nodes, BROADWAY_NODE_INSET_SHADOW); - add_rounded_rect (nodes, gsk_inset_shadow_node_peek_outline (node), offset_x, offset_y); - add_rgba (nodes, gsk_inset_shadow_node_peek_color (node)); - add_float (nodes, gsk_inset_shadow_node_get_dx (node)); - add_float (nodes, gsk_inset_shadow_node_get_dy (node)); - add_float (nodes, gsk_inset_shadow_node_get_spread (node)); - add_float (nodes, gsk_inset_shadow_node_get_blur_radius (node)); - } + if (add_new_node (renderer, node, BROADWAY_NODE_INSET_SHADOW)) + { + add_rounded_rect (nodes, gsk_inset_shadow_node_peek_outline (node), offset_x, offset_y); + add_rgba (nodes, gsk_inset_shadow_node_peek_color (node)); + add_float (nodes, gsk_inset_shadow_node_get_dx (node)); + add_float (nodes, gsk_inset_shadow_node_get_dy (node)); + add_float (nodes, gsk_inset_shadow_node_get_spread (node)); + add_float (nodes, gsk_inset_shadow_node_get_blur_radius (node)); + } return; case GSK_LINEAR_GRADIENT_NODE: - { - guint i, n; + if (add_new_node (renderer, node, BROADWAY_NODE_LINEAR_GRADIENT)) + { + guint i, n; - add_uint32 (nodes, BROADWAY_NODE_LINEAR_GRADIENT); - add_rect (nodes, &node->bounds, offset_x, offset_y); - add_point (nodes, gsk_linear_gradient_node_peek_start (node), offset_x, offset_y); - add_point (nodes, gsk_linear_gradient_node_peek_end (node), offset_x, offset_y); - n = gsk_linear_gradient_node_get_n_color_stops (node); - add_uint32 (nodes, n); - for (i = 0; i < n; i++) - add_color_stop (nodes, &gsk_linear_gradient_node_peek_color_stops (node)[i]); - } + add_rect (nodes, &node->bounds, offset_x, offset_y); + add_point (nodes, gsk_linear_gradient_node_peek_start (node), offset_x, offset_y); + add_point (nodes, gsk_linear_gradient_node_peek_end (node), offset_x, offset_y); + n = gsk_linear_gradient_node_get_n_color_stops (node); + add_uint32 (nodes, n); + for (i = 0; i < n; i++) + add_color_stop (nodes, &gsk_linear_gradient_node_peek_color_stops (node)[i]); + } return; /* Bin nodes */ case GSK_SHADOW_NODE: - { - gsize i, n_shadows = gsk_shadow_node_get_n_shadows (node); - add_uint32 (nodes, BROADWAY_NODE_SHADOW); - add_uint32 (nodes, n_shadows); - for (i = 0; i < n_shadows; i++) - { - const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i); - add_rgba (nodes, &shadow->color); - add_float (nodes, shadow->dx); - add_float (nodes, shadow->dy); - add_float (nodes, shadow->radius); - } - gsk_broadway_renderer_add_node (renderer, nodes, node_textures, - gsk_shadow_node_get_child (node), - offset_x, offset_y); - } + if (add_new_node (renderer, node, BROADWAY_NODE_SHADOW)) + { + gsize i, n_shadows = gsk_shadow_node_get_n_shadows (node); + + add_uint32 (nodes, n_shadows); + for (i = 0; i < n_shadows; i++) + { + const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i); + add_rgba (nodes, &shadow->color); + add_float (nodes, shadow->dx); + add_float (nodes, shadow->dy); + add_float (nodes, shadow->radius); + } + gsk_broadway_renderer_add_node (renderer, + gsk_shadow_node_get_child (node), + offset_x, offset_y); + } return; case GSK_OPACITY_NODE: - { - add_uint32 (nodes, BROADWAY_NODE_OPACITY); - add_float (nodes, gsk_opacity_node_get_opacity (node)); - gsk_broadway_renderer_add_node (renderer, nodes, node_textures, - gsk_opacity_node_get_child (node), - offset_x, offset_y); - } + if (add_new_node (renderer, node, BROADWAY_NODE_OPACITY)) + { + add_float (nodes, gsk_opacity_node_get_opacity (node)); + gsk_broadway_renderer_add_node (renderer, + gsk_opacity_node_get_child (node), + offset_x, offset_y); + } return; case GSK_ROUNDED_CLIP_NODE: - { - const GskRoundedRect *rclip = gsk_rounded_clip_node_peek_clip (node); - add_uint32 (nodes, BROADWAY_NODE_ROUNDED_CLIP); - add_rounded_rect (nodes, rclip, offset_x, offset_y); - gsk_broadway_renderer_add_node (renderer, nodes, node_textures, - gsk_rounded_clip_node_get_child (node), - rclip->bounds.origin.x, - rclip->bounds.origin.y); - } + if (add_new_node (renderer, node, BROADWAY_NODE_ROUNDED_CLIP)) + { + const GskRoundedRect *rclip = gsk_rounded_clip_node_peek_clip (node); + + add_rounded_rect (nodes, rclip, offset_x, offset_y); + gsk_broadway_renderer_add_node (renderer, + gsk_rounded_clip_node_get_child (node), + rclip->bounds.origin.x, + rclip->bounds.origin.y); + } return; case GSK_CLIP_NODE: - { - const graphene_rect_t *clip = gsk_clip_node_peek_clip (node); - add_uint32 (nodes, BROADWAY_NODE_CLIP); - add_rect (nodes, clip, offset_x, offset_y); - gsk_broadway_renderer_add_node (renderer, nodes, node_textures, - gsk_clip_node_get_child (node), - clip->origin.x, - clip->origin.y); - } + if (add_new_node (renderer, node, BROADWAY_NODE_CLIP)) + { + const graphene_rect_t *clip = gsk_clip_node_peek_clip (node); + + add_rect (nodes, clip, offset_x, offset_y); + gsk_broadway_renderer_add_node (renderer, + gsk_clip_node_get_child (node), + clip->origin.x, + clip->origin.y); + } return; case GSK_TRANSFORM_NODE: { GskTransform *transform = gsk_transform_node_get_transform (node); GskTransformCategory category = gsk_transform_get_category (transform); - float dx, dy; if (category >= GSK_TRANSFORM_CATEGORY_2D_TRANSLATE) { - gsk_transform_to_translate (transform, &dx, &dy); - add_uint32 (nodes, BROADWAY_NODE_TRANSLATE); - add_xy (nodes, dx, dy, offset_x, offset_y); - gsk_broadway_renderer_add_node (renderer, nodes, node_textures, - gsk_transform_node_get_child (node), - 0, 0); + if (add_new_node (renderer, node, BROADWAY_NODE_TRANSLATE)) { + float dx, dy; + gsk_transform_to_translate (transform, &dx, &dy); + + add_xy (nodes, dx, dy, offset_x, offset_y); + gsk_broadway_renderer_add_node (renderer, + gsk_transform_node_get_child (node), + 0, 0); + } } else { /* Fallback to texture for now */ break; } - } return; case GSK_DEBUG_NODE: - { - const char *message = gsk_debug_node_get_message (node); - add_uint32 (nodes, BROADWAY_NODE_DEBUG); - add_string (nodes, message); - gsk_broadway_renderer_add_node (renderer, nodes, node_textures, - gsk_debug_node_get_child (node), offset_x, offset_y); - } + if (add_new_node (renderer, node, BROADWAY_NODE_DEBUG)) + { + const char *message = gsk_debug_node_get_message (node); + add_string (nodes, message); + gsk_broadway_renderer_add_node (renderer, + gsk_debug_node_get_child (node), offset_x, offset_y); + } return; /* Generic nodes */ case GSK_CONTAINER_NODE: - { - guint i; + if (add_new_node (renderer, node, BROADWAY_NODE_CONTAINER)) + { + guint i; - add_uint32 (nodes, BROADWAY_NODE_CONTAINER); - add_uint32 (nodes, gsk_container_node_get_n_children (node)); - - for (i = 0; i < gsk_container_node_get_n_children (node); i++) - gsk_broadway_renderer_add_node (renderer, nodes, node_textures, - gsk_container_node_get_child (node, i), offset_x, offset_y); - } + add_uint32 (nodes, gsk_container_node_get_n_children (node)); + for (i = 0; i < gsk_container_node_get_n_children (node); i++) + gsk_broadway_renderer_add_node (renderer, + gsk_container_node_get_child (node, i), offset_x, offset_y); + } return; case GSK_COLOR_MATRIX_NODE: @@ -466,58 +563,33 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, break; /* Fallback */ } - { - GdkTexture *texture; - guint32 texture_id; - FallbackCacheElement *hit; - float t_off_x = 0, t_off_y = 0; + if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE)) + { + GdkTexture *texture; + cairo_surface_t *surface; + cairo_t *cr; + guint32 texture_id; + int x = floorf (node->bounds.origin.x); + int y = floorf (node->bounds.origin.y); + int width = ceil (node->bounds.origin.x + node->bounds.size.width) - x; + int height = ceil (node->bounds.origin.y + node->bounds.size.height) - y; - hit = g_hash_table_lookup (self->fallback_cache, node); - if (hit) - { - texture = g_object_ref (hit->texture); - t_off_x = hit->off_x; - t_off_y = hit->off_y; - hit->used_in_frame = self->frame_nr; - } - else - { - FallbackCacheElement *element; + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + cr = cairo_create (surface); + cairo_translate (cr, -x, -y); + gsk_render_node_draw (node, cr); + cairo_destroy (cr); - texture = node_texture_fallback (node, &t_off_x, &t_off_y); -#if 0 - g_print ("Fallback %p for %s\n", texture, node->node_class->type_name); -#endif - element = g_new0 (FallbackCacheElement, 1); - element->texture = g_object_ref (texture); - element->node = gsk_render_node_ref (node); - element->off_x = t_off_x; - element->off_y = t_off_y; - element->used_in_frame = self->frame_nr; - g_hash_table_insert (self->fallback_cache, element->node, element); - } + texture = gdk_texture_new_for_surface (surface); + g_ptr_array_add (self->node_textures, texture); /* Transfers ownership to node_textures */ - g_ptr_array_add (node_textures, texture); /* Transfers ownership to node_textures */ - texture_id = gdk_broadway_display_ensure_texture (display, texture); - add_uint32 (nodes, BROADWAY_NODE_TEXTURE); - add_float (nodes, node->bounds.origin.x + t_off_x - offset_x); - add_float (nodes, node->bounds.origin.y + t_off_y - offset_y); - add_float (nodes, gdk_texture_get_width (texture)); - add_float (nodes, gdk_texture_get_height (texture)); - add_uint32 (nodes, texture_id); - } -} - -static gboolean -clean_old_fallbacks (gpointer key, - gpointer value, - gpointer user_data) -{ - GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (user_data); - FallbackCacheElement *element = value; - - /* Remove cached fallbacks not used for 5 frames */ - return self->frame_nr - element->used_in_frame > 5; + texture_id = gdk_broadway_display_ensure_texture (display, texture); + add_float (nodes, x - offset_x); + add_float (nodes, y - offset_y); + add_float (nodes, gdk_texture_get_width (texture)); + add_float (nodes, gdk_texture_get_height (texture)); + add_uint32 (nodes, texture_id); + } } static void @@ -527,13 +599,40 @@ gsk_broadway_renderer_render (GskRenderer *renderer, { GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer); - self->frame_nr++; + self->node_lookup = g_hash_table_new (g_direct_hash, g_direct_equal); gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->draw_context), update_area); - gsk_broadway_renderer_add_node (renderer, self->draw_context->nodes, self->draw_context->node_textures, root, 0, 0); + + /* These are owned by the draw context between begin and end, but + cache them here for easier access during the render */ + self->nodes = self->draw_context->nodes; + self->node_textures = self->draw_context->node_textures; + + gsk_broadway_renderer_add_node (renderer, root, 0, 0); + + self->nodes = NULL; + self->node_textures = NULL; + gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->draw_context)); - g_hash_table_foreach_remove (self->fallback_cache, clean_old_fallbacks, renderer); + if (self->last_node_lookup) + g_hash_table_unref (self->last_node_lookup); + self->last_node_lookup = self->node_lookup; + self->node_lookup = NULL; + + if (self->last_root) + gsk_render_node_unref (self->last_root); + self->last_root = gsk_render_node_ref (root); + + if (self->next_node_id > G_MAXUINT32 / 2) + { + /* We're "near" a wrap of the ids, lets avoid reusing any of + * these nodes next frame, then we can reset the id counter + * without risk of any old nodes sticking around and conflicting. */ + + g_hash_table_remove_all (self->last_node_lookup); + self->next_node_id = 0; + } } static void @@ -550,8 +649,4 @@ gsk_broadway_renderer_class_init (GskBroadwayRendererClass *klass) static void gsk_broadway_renderer_init (GskBroadwayRenderer *self) { - self->fallback_cache = g_hash_table_new_full ((GHashFunc)g_direct_hash, - (GEqualFunc)g_direct_equal, - NULL, - (GDestroyNotify)fallback_cache_element_free); } From edbaa0964fa49e0e540036b5d4d381f8868ac9ec Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 25 Mar 2019 16:21:34 +0100 Subject: [PATCH 11/14] broadway: Clean up stuff using const defines --- gdk/broadway/broadway.js | 47 ++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js index 9a104249e7..f12e71a7d4 100644 --- a/gdk/broadway/broadway.js +++ b/gdk/broadway/broadway.js @@ -1,3 +1,22 @@ +// Protocol stuff + +const BROADWAY_NODE_TEXTURE = 0; +const BROADWAY_NODE_CONTAINER = 1; +const BROADWAY_NODE_COLOR = 2; +const BROADWAY_NODE_BORDER = 3; +const BROADWAY_NODE_OUTSET_SHADOW = 4; +const BROADWAY_NODE_INSET_SHADOW = 5; +const BROADWAY_NODE_ROUNDED_CLIP = 6; +const BROADWAY_NODE_LINEAR_GRADIENT = 7; +const BROADWAY_NODE_SHADOW = 8; +const BROADWAY_NODE_OPACITY = 9; +const BROADWAY_NODE_CLIP = 10; +const BROADWAY_NODE_KEEP_ALL = 11; +const BROADWAY_NODE_KEEP_THIS = 12; +const BROADWAY_NODE_TRANSLATE = 13; +const BROADWAY_NODE_DEBUG = 14; +const BROADWAY_NODE_REUSE = 15; + /* Helper functions for debugging */ var logDiv = null; function log(str) { @@ -416,7 +435,7 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) { /* Leaf nodes */ - case 0: // TEXTURE + case BROADWAY_NODE_TEXTURE: { var rect = this.decode_rect(); var texture_id = this.decode_uint32(); @@ -434,7 +453,7 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) } break; - case 2: // COLOR + case BROADWAY_NODE_COLOR: { var rect = this.decode_rect(); var c = this.decode_color (); @@ -446,7 +465,7 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) } break; - case 3: // BORDER + case BROADWAY_NODE_BORDER: { var rrect = this.decode_rounded_rect(); var border_widths = []; @@ -474,7 +493,7 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) } break; - case 4: // OUTSET_SHADOW + case BROADWAY_NODE_OUTSET_SHADOW: { var rrect = this.decode_rounded_rect(); var color = this.decode_color(); @@ -491,7 +510,7 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) } break; - case 5: // INSET_SHADOW + case BROADWAY_NODE_INSET_SHADOW: { var rrect = this.decode_rounded_rect(); var color = this.decode_color(); @@ -509,7 +528,7 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) break; - case 7: // LINEAR_GRADIENT + case BROADWAY_NODE_LINEAR_GRADIENT: { var rect = this.decode_rect(); var start = this.decode_point (); @@ -557,7 +576,7 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) /* Bin nodes */ - case 13: // TRANSLATE + case BROADWAY_NODE_TRANSLATE: { var point = this.decode_point(); var div = document.createElement('div'); @@ -568,7 +587,7 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) } break; - case 10: // CLIP + case BROADWAY_NODE_CLIP: { var rect = this.decode_rect(); var div = document.createElement('div'); @@ -580,7 +599,7 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) } break; - case 6: // ROUNDED_CLIP + case BROADWAY_NODE_ROUNDED_CLIP: { var rrect = this.decode_rounded_rect(); var div = document.createElement('div'); @@ -592,7 +611,7 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) } break; - case 9: // OPACITY + case BROADWAY_NODE_OPACITY: { var opacity = this.decode_float(); var div = document.createElement('div'); @@ -606,7 +625,7 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) } break; - case 8: // SHADOW + case BROADWAY_NODE_SHADOW: { var len = this.decode_uint32(); var filters = ""; @@ -640,7 +659,7 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) /* Generic nodes */ - case 1: // CONTAINER + case BROADWAY_NODE_CONTAINER: { var div = document.createElement('div'); var len = this.decode_uint32(); @@ -651,7 +670,7 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) } break; - case 11: // KEEP_ALL + case BROADWAY_NODE_KEEP_ALL: { if (!oldNode) alert("KEEP_ALL with no oldNode"); @@ -663,7 +682,7 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) } break; - case 12: // KEEP_THIS + case BROADWAY_NODE_KEEP_THIS: { if (!oldNode) alert("KEEP_THIS with no oldNode "); From 0481aa10e7a5045badc7793e807bccb737e942da Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Tue, 26 Mar 2019 11:19:08 +0100 Subject: [PATCH 12/14] broadway: Use const use for constants in the js code --- gdk/broadway/broadway.js | 182 +++++++++++++++++++++++---------------- 1 file changed, 110 insertions(+), 72 deletions(-) diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js index f12e71a7d4..a0636aadf2 100644 --- a/gdk/broadway/broadway.js +++ b/gdk/broadway/broadway.js @@ -17,6 +17,76 @@ const BROADWAY_NODE_TRANSLATE = 13; const BROADWAY_NODE_DEBUG = 14; const BROADWAY_NODE_REUSE = 15; +const BROADWAY_OP_GRAB_POINTER = 'g'; +const BROADWAY_OP_UNGRAB_POINTER = 'u'; +const BROADWAY_OP_NEW_SURFACE = 's'; +const BROADWAY_OP_SHOW_SURFACE = 'S'; +const BROADWAY_OP_HIDE_SURFACE = 'H'; +const BROADWAY_OP_RAISE_SURFACE = 'r'; +const BROADWAY_OP_LOWER_SURFACE = 'R'; +const BROADWAY_OP_DESTROY_SURFACE = 'd'; +const BROADWAY_OP_MOVE_RESIZE = 'm'; +const BROADWAY_OP_SET_TRANSIENT_FOR = 'p'; +const BROADWAY_OP_PUT_RGB = 'i'; +const BROADWAY_OP_REQUEST_AUTH = 'l'; +const BROADWAY_OP_AUTH_OK = 'L'; +const BROADWAY_OP_DISCONNECTED = 'D'; +const BROADWAY_OP_SURFACE_UPDATE = 'b'; +const BROADWAY_OP_SET_SHOW_KEYBOARD = 'k'; +const BROADWAY_OP_UPLOAD_TEXTURE = 't'; +const BROADWAY_OP_RELEASE_TEXTURE = 'T'; +const BROADWAY_OP_SET_NODES = 'n'; +const BROADWAY_OP_ROUNDTRIP = 'F'; + +const BROADWAY_EVENT_ENTER = 'e'; +const BROADWAY_EVENT_LEAVE = 'l'; +const BROADWAY_EVENT_POINTER_MOVE = 'm'; +const BROADWAY_EVENT_BUTTON_PRESS = 'b'; +const BROADWAY_EVENT_BUTTON_RELEASE = 'B'; +const BROADWAY_EVENT_TOUCH = 't'; +const BROADWAY_EVENT_SCROLL = 's'; +const BROADWAY_EVENT_KEY_PRESS = 'k'; +const BROADWAY_EVENT_KEY_RELEASE = 'K'; +const BROADWAY_EVENT_GRAB_NOTIFY = 'g'; +const BROADWAY_EVENT_UNGRAB_NOTIFY = 'u'; +const BROADWAY_EVENT_CONFIGURE_NOTIFY = 'w'; +const BROADWAY_EVENT_SCREEN_SIZE_CHANGED = 'd'; +const BROADWAY_EVENT_FOCUS = 'f'; +const BROADWAY_EVENT_ROUNDTRIP_NOTIFY = 'F'; + +const DISPLAY_OP_REPLACE_CHILD = 0; +const DISPLAY_OP_APPEND_CHILD = 1; +const DISPLAY_OP_APPEND_ROOT = 2; +const DISPLAY_OP_SHOW_SURFACE = 3; +const DISPLAY_OP_HIDE_SURFACE = 4; +const DISPLAY_OP_DELETE_NODE = 5; +const DISPLAY_OP_MOVE_NODE = 6; +const DISPLAY_OP_RESIZE_NODE = 7; + +// GdkCrossingMode +const GDK_CROSSING_NORMAL = 0; +const GDK_CROSSING_GRAB = 1; +const GDK_CROSSING_UNGRAB = 2; + +// GdkModifierType +const GDK_SHIFT_MASK = 1 << 0; +const GDK_LOCK_MASK = 1 << 1; +const GDK_CONTROL_MASK = 1 << 2; +const GDK_MOD1_MASK = 1 << 3; +const GDK_MOD2_MASK = 1 << 4; +const GDK_MOD3_MASK = 1 << 5; +const GDK_MOD4_MASK = 1 << 6; +const GDK_MOD5_MASK = 1 << 7; +const GDK_BUTTON1_MASK = 1 << 8; +const GDK_BUTTON2_MASK = 1 << 9; +const GDK_BUTTON3_MASK = 1 << 10; +const GDK_BUTTON4_MASK = 1 << 11; +const GDK_BUTTON5_MASK = 1 << 12; +const GDK_SUPER_MASK = 1 << 26; +const GDK_HYPER_MASK = 1 << 27; +const GDK_META_MASK = 1 << 28; +const GDK_RELEASE_MASK = 1 << 30; + /* Helper functions for debugging */ var logDiv = null; function log(str) { @@ -110,29 +180,6 @@ var showKeyboard = false; var showKeyboardChanged = false; var firstTouchDownId = null; -var GDK_CROSSING_NORMAL = 0; -var GDK_CROSSING_GRAB = 1; -var GDK_CROSSING_UNGRAB = 2; - -// GdkModifierType -var GDK_SHIFT_MASK = 1 << 0; -var GDK_LOCK_MASK = 1 << 1; -var GDK_CONTROL_MASK = 1 << 2; -var GDK_MOD1_MASK = 1 << 3; -var GDK_MOD2_MASK = 1 << 4; -var GDK_MOD3_MASK = 1 << 5; -var GDK_MOD4_MASK = 1 << 6; -var GDK_MOD5_MASK = 1 << 7; -var GDK_BUTTON1_MASK = 1 << 8; -var GDK_BUTTON2_MASK = 1 << 9; -var GDK_BUTTON3_MASK = 1 << 10; -var GDK_BUTTON4_MASK = 1 << 11; -var GDK_BUTTON5_MASK = 1 << 12; -var GDK_SUPER_MASK = 1 << 26; -var GDK_HYPER_MASK = 1 << 27; -var GDK_META_MASK = 1 << 28; -var GDK_RELEASE_MASK = 1 << 30; - function getButtonMask (button) { if (button == 1) return GDK_BUTTON1_MASK; @@ -170,7 +217,7 @@ Texture.prototype.unref = function() { function sendConfigureNotify(surface) { - sendInput("w", [surface.id, surface.x, surface.y, surface.width, surface.height]); + sendInput(BROADWAY_EVENT_CONFIGURE_NOTIFY, [surface.id, surface.x, surface.y, surface.width, surface.height]); } function cmdCreateSurface(id, x, y, width, height, isTemp) @@ -225,7 +272,7 @@ function moveToHelper(surface, position) { function cmdRoundtrip(id, tag) { - sendInput("F", [id, tag]); + sendInput(BROADWAY_EVENT_ROUNDTRIP_NOTIFY, [id, tag]); } function cmdRaiseSurface(id) @@ -732,25 +779,16 @@ TransformNodes.prototype.execute = function(display_commands) function cmdGrabPointer(id, ownerEvents) { doGrab(id, ownerEvents, false); - sendInput ("g", []); + sendInput (BROADWAY_EVENT_GRAB_NOTIFY, []); } function cmdUngrabPointer() { - sendInput ("u", []); + sendInput (BROADWAY_EVENT_UNGRAB_NOTIFY, []); if (grab.surface) doUngrab(); } -const DISPLAY_OP_REPLACE_CHILD = 0; -const DISPLAY_OP_APPEND_CHILD = 1; -const DISPLAY_OP_APPEND_ROOT = 2; -const DISPLAY_OP_SHOW_SURFACE = 3; -const DISPLAY_OP_HIDE_SURFACE = 4; -const DISPLAY_OP_DELETE_NODE = 5; -const DISPLAY_OP_MOVE_NODE = 6; -const DISPLAY_OP_RESIZE_NODE = 7; - function handleDisplayCommands(display_commands) { var div; @@ -817,12 +855,12 @@ function handleCommands(cmd) var command = cmd.get_char(); lastSerial = cmd.get_32(); switch (command) { - case 'D': + case BROADWAY_OP_DISCONNECTED: alert ("disconnected"); inputSocket = null; break; - case 's': // create new surface + case BROADWAY_OP_NEW_SURFACE: id = cmd.get_16(); x = cmd.get_16s(); y = cmd.get_16s(); @@ -834,7 +872,7 @@ function handleCommands(cmd) need_restack = true; break; - case 'S': // Show a surface + case BROADWAY_OP_SHOW_SURFACE: id = cmd.get_16(); surface = surfaces[id]; if (!surface.visible) { @@ -844,7 +882,7 @@ function handleCommands(cmd) } break; - case 'H': // Hide a surface + case BROADWAY_OP_HIDE_SURFACE: id = cmd.get_16(); if (grab.surface == id) doUngrab(); @@ -854,7 +892,7 @@ function handleCommands(cmd) } break; - case 'p': // Set transient parent + case BROADWAY_OP_SET_TRANSIENT_FOR: id = cmd.get_16(); var parentId = cmd.get_16(); surface = surfaces[id]; @@ -867,7 +905,7 @@ function handleCommands(cmd) } break; - case 'd': // Delete surface + case BROADWAY_OP_DESTROY_SURFACE: id = cmd.get_16(); if (grab.surface == id) @@ -883,13 +921,13 @@ function handleCommands(cmd) delete surfaces[id]; break; - case 'F': // RoundTrip + case BROADWAY_OP_ROUNDTRIP: id = cmd.get_16(); var tag = cmd.get_32(); cmdRoundtrip(id, tag); break; - case 'm': // Move a surface + case BROADWAY_OP_MOVE_RESIZE: id = cmd.get_16(); var ops = cmd.get_flags(); var has_pos = ops & 1; @@ -909,30 +947,30 @@ function handleCommands(cmd) } break; - case 'r': // Raise a surface + case BROADWAY_OP_RAISE_SURFACE: id = cmd.get_16(); cmdRaiseSurface(id); need_restack = true; break; - case 'R': // Lower a surface + case BROADWAY_OP_LOWER_SURFACE: id = cmd.get_16(); cmdLowerSurface(id); need_restack = true; break; - case 't': // Upload texture + case BROADWAY_OP_UPLOAD_TEXTURE: id = cmd.get_32(); var data = cmd.get_data(); var texure = new Texture (id, data); // Stores a ref in textures break; - case 'T': // Release texture + case BROADWAY_OP_RELEASE_TEXTURE: id = cmd.get_32(); textures[id].unref(); break; - case 'n': // Set nodes + case BROADWAY_OP_SET_NODES: id = cmd.get_16(); var node_data = cmd.get_nodes (); surface = surfaces[id]; @@ -940,18 +978,18 @@ function handleCommands(cmd) transform_nodes.execute(); break; - case 'g': // Grab + case BROADWAY_OP_GRAB_POINTER: id = cmd.get_16(); var ownerEvents = cmd.get_bool (); cmdGrabPointer(id, ownerEvents); break; - case 'u': // Ungrab + case BROADWAY_OP_UNGRAB_POINTER: cmdUngrabPointer(); break; - case 'k': // show keyboard + case BROADWAY_OP_SET_SHOW_KEYBOARD: showKeyboard = cmd.get_16() != 0; showKeyboardChanged = true; break; @@ -1124,7 +1162,7 @@ function onMouseMove (ev) { var id = getSurfaceId(ev); id = getEffectiveEventTarget (id); var pos = getPositionsFromEvent(ev, id); - sendInput ("m", [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]); + sendInput (BROADWAY_EVENT_POINTER_MOVE, [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]); } function onMouseOver (ev) { @@ -1136,7 +1174,7 @@ function onMouseOver (ev) { var pos = getPositionsFromEvent(ev, id); surfaceWithMouse = id; if (surfaceWithMouse != 0) { - sendInput ("e", [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]); + sendInput (BROADWAY_EVENT_ENTER, [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]); } } @@ -1148,7 +1186,7 @@ function onMouseOut (ev) { var pos = getPositionsFromEvent(ev, id); if (id != 0) { - sendInput ("l", [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]); + sendInput (BROADWAY_EVENT_LEAVE, [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]); } realSurfaceWithMouse = 0; surfaceWithMouse = 0; @@ -1160,10 +1198,10 @@ function doGrab(id, ownerEvents, implicit) { if (surfaceWithMouse != id) { if (surfaceWithMouse != 0) { pos = getPositionsFromAbsCoord(lastX, lastY, surfaceWithMouse); - sendInput ("l", [realSurfaceWithMouse, surfaceWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_GRAB]); + sendInput (BROADWAY_EVENT_LEAVE, [realSurfaceWithMouse, surfaceWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_GRAB]); } pos = getPositionsFromAbsCoord(lastX, lastY, id); - sendInput ("e", [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_GRAB]); + sendInput (BROADWAY_EVENT_ENTER, [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_GRAB]); surfaceWithMouse = id; } @@ -1177,11 +1215,11 @@ function doUngrab() { if (realSurfaceWithMouse != surfaceWithMouse) { if (surfaceWithMouse != 0) { pos = getPositionsFromAbsCoord(lastX, lastY, surfaceWithMouse); - sendInput ("l", [realSurfaceWithMouse, surfaceWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_UNGRAB]); + sendInput (BROADWAY_EVENT_LEAVE, [realSurfaceWithMouse, surfaceWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_UNGRAB]); } if (realSurfaceWithMouse != 0) { pos = getPositionsFromAbsCoord(lastX, lastY, realSurfaceWithMouse); - sendInput ("e", [realSurfaceWithMouse, realSurfaceWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_UNGRAB]); + sendInput (BROADWAY_EVENT_ENTER, [realSurfaceWithMouse, realSurfaceWithMouse, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_UNGRAB]); } surfaceWithMouse = realSurfaceWithMouse; } @@ -1198,7 +1236,7 @@ function onMouseDown (ev) { var pos = getPositionsFromEvent(ev, id); if (grab.surface == null) doGrab (id, false, true); - sendInput ("b", [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, button]); + sendInput (BROADWAY_EVENT_BUTTON_PRESS, [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, button]); return false; } @@ -1210,7 +1248,7 @@ function onMouseUp (ev) { id = getEffectiveEventTarget (evId); var pos = getPositionsFromEvent(ev, id); - sendInput ("B", [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, button]); + sendInput (BROADWAY_EVENT_BUTTON_RELEASE, [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, button]); if (grab.surface != null && grab.implicit) doUngrab(); @@ -2691,7 +2729,7 @@ function handleKeyDown(e) { // browser behaviors or it has no corresponding keyPress // event, then send it immediately if (!ignoreKeyEvent(ev)) - sendInput("k", [keysym, lastState]); + sendInput(BROADWAY_EVENT_KEY_PRESS, [keysym, lastState]); suppress = true; } @@ -2736,7 +2774,7 @@ function handleKeyPress(e) { // Send the translated keysym if (keysym > 0) - sendInput ("k", [keysym, lastState]); + sendInput (BROADWAY_EVENT_KEY_PRESS, [keysym, lastState]); // Stop keypress events just in case return cancelEvent(ev); @@ -2755,7 +2793,7 @@ function handleKeyUp(e) { } if (keysym > 0) - sendInput ("K", [keysym, lastState]); + sendInput (BROADWAY_EVENT_KEY_RELEASE, [keysym, lastState]); return cancelEvent(ev); } @@ -2799,7 +2837,7 @@ function onMouseWheel(ev) var dir = 0; if (offset > 0) dir = 1; - sendInput ("s", [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, dir]); + sendInput (BROADWAY_EVENT_SCROLL, [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, dir]); return cancelEvent(ev); } @@ -2824,17 +2862,17 @@ function onTouchStart(ev) { if (realSurfaceWithMouse != origId || id != surfaceWithMouse) { if (id != 0) { - sendInput ("l", [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]); + sendInput (BROADWAY_EVENT_LEAVE, [realSurfaceWithMouse, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]); } surfaceWithMouse = id; realSurfaceWithMouse = origId; - sendInput ("e", [origId, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]); + sendInput (BROADWAY_EVENT_ENTER, [origId, id, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState, GDK_CROSSING_NORMAL]); } } - sendInput ("t", [0, id, touch.identifier, isEmulated, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]); + sendInput (BROADWAY_EVENT_TOUCH, [0, id, touch.identifier, isEmulated, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]); } } @@ -2856,7 +2894,7 @@ function onTouchMove(ev) { isEmulated = 1; } - sendInput ("t", [1, id, touch.identifier, isEmulated, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]); + sendInput (BROADWAY_EVENT_TOUCH, [1, id, touch.identifier, isEmulated, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]); } } @@ -2879,7 +2917,7 @@ function onTouchEnd(ev) { firstTouchDownId = null; } - sendInput ("t", [2, id, touch.identifier, isEmulated, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]); + sendInput (BROADWAY_EVENT_TOUCH, [2, id, touch.identifier, isEmulated, pos.rootX, pos.rootY, pos.winX, pos.winY, lastState]); } } @@ -2917,9 +2955,9 @@ function start() var w, h; w = window.innerWidth; h = window.innerHeight; - sendInput ("d", [w, h]); + sendInput (BROADWAY_EVENT_SCREEN_SIZE_CHANGED, [w, h]); }; - sendInput ("d", [w, h]); + sendInput (BROADWAY_EVENT_SCREEN_SIZE_CHANGED, [w, h]); } function connect() From cf4226586ac64073fe3902e44b4b4159c8cd8fd1 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Tue, 26 Mar 2019 16:29:45 +0100 Subject: [PATCH 13/14] broadway: Load all textures before applying display ops, fixing flickers --- gdk/broadway/broadway.js | 130 +++++++++++++++++++++++++++++++-------- 1 file changed, 104 insertions(+), 26 deletions(-) diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js index a0636aadf2..00c341c393 100644 --- a/gdk/broadway/broadway.js +++ b/gdk/broadway/broadway.js @@ -62,6 +62,8 @@ const DISPLAY_OP_HIDE_SURFACE = 4; const DISPLAY_OP_DELETE_NODE = 5; const DISPLAY_OP_MOVE_NODE = 6; const DISPLAY_OP_RESIZE_NODE = 7; +const DISPLAY_OP_RESTACK_SURFACES = 8; +const DISPLAY_OP_DELETE_SURFACE = 9; // GdkCrossingMode const GDK_CROSSING_NORMAL = 0; @@ -173,6 +175,7 @@ var surfaces = {}; var textures = {}; var stackingOrder = []; var outstandingCommands = new Array(); +var outstandingDisplayCommands = null; var inputSocket = null; var debugDecoding = false; var fakeInput = null; @@ -199,6 +202,10 @@ function Texture(id, data) { this.url = window.URL.createObjectURL(blob); this.refcount = 1; this.id = id; + + var image = new Image(); + image.src = this.url; + this.image = image; textures[id] = this; } @@ -278,14 +285,15 @@ function cmdRoundtrip(id, tag) function cmdRaiseSurface(id) { var surface = surfaces[id]; - - moveToHelper(surface); + if (surface) + moveToHelper(surface); } function cmdLowerSurface(id) { var surface = surfaces[id]; - moveToHelper(surface, 0); + if (surface) + moveToHelper(surface, 0); } function TransformNodes(node_data, div, display_commands) { @@ -491,9 +499,8 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode) image.height = rect.height; image.style["position"] = "absolute"; set_rect_style(image, rect); - var texture = textures[texture_id]; + var texture = textures[texture_id].ref(); image.src = texture.url; - texture.ref(); // Unref blob url when loaded image.onload = function() { texture.unref(); }; newNode = image; @@ -833,25 +840,28 @@ function handleDisplayCommands(display_commands) div.style["height"] = cmd[3] + "px"; break; + case DISPLAY_OP_RESTACK_SURFACES: + restackSurfaces(); + break; + case DISPLAY_OP_DELETE_SURFACE: + var id = cmd[1]; + delete surfaces[id]; + break; + default: alert("Unknown display op " + command); } } } -var active = false; -function handleCommands(cmd) +function handleCommands(cmd, display_commands, new_textures, modified_trees) { - if (!active) { - start(); - active = true; - } - - var display_commands = new Array(); + var res = true; var need_restack = false; - while (cmd.pos < cmd.length) { + while (res && cmd.pos < cmd.length) { var id, x, y, w, h, q, surface; + var saved_pos = cmd.pos; var command = cmd.get_char(); lastSerial = cmd.get_32(); switch (command) { @@ -918,7 +928,8 @@ function handleCommands(cmd) var div = surface.div; display_commands.push([DISPLAY_OP_DELETE_NODE, div]); - delete surfaces[id]; + // We need to delay this until its really deleted because we can still get events to it + display_commands.push([DISPLAY_OP_DELETE_SURFACE, id]); break; case BROADWAY_OP_ROUNDTRIP: @@ -962,7 +973,8 @@ function handleCommands(cmd) case BROADWAY_OP_UPLOAD_TEXTURE: id = cmd.get_32(); var data = cmd.get_data(); - var texure = new Texture (id, data); // Stores a ref in textures + var texture = new Texture (id, data); // Stores a ref in global textures array + new_textures.push(texture); break; case BROADWAY_OP_RELEASE_TEXTURE: @@ -972,10 +984,18 @@ function handleCommands(cmd) case BROADWAY_OP_SET_NODES: id = cmd.get_16(); - var node_data = cmd.get_nodes (); - surface = surfaces[id]; - var transform_nodes = new TransformNodes (node_data, surface.div, display_commands); - transform_nodes.execute(); + if (id in modified_trees) { + // Can't modify the same dom tree in the same loop, bail out and do the first one + cmd.pos = saved_pos; + res = false; + } else { + modified_trees[id] = true; + + var node_data = cmd.get_nodes (); + surface = surfaces[id]; + var transform_nodes = new TransformNodes (node_data, surface.div, display_commands); + transform_nodes.execute(); + } break; case BROADWAY_OP_GRAB_POINTER: @@ -1000,22 +1020,74 @@ function handleCommands(cmd) } if (need_restack) - restackSurfaces(); + display_commands.push([DISPLAY_OP_RESTACK_SURFACES]); - handleDisplayCommands(display_commands); - - return true; + return res; } +function handleOutstandingDisplayCommands() +{ + if (outstandingDisplayCommands) { + window.requestAnimationFrame( + function () { + handleDisplayCommands(outstandingDisplayCommands); + outstandingDisplayCommands = null; + + if (outstandingCommands.length > 0) + setTimeout(handleOutstanding); + }); + } else { + if (outstandingCommands.length > 0) + handleOutstanding (); + } +} + +/* Mode of operation. + * We run all outstandingCommands, until either we run out of things + * to process, or we update the dom nodes of the same surface twice. + * Then we wait for all textures to load, and then we request am + * animation frame and apply the display changes. Then we loop back and + * handle outstanding commands again. + * + * The reason for stopping if we update the same tree twice is that + * the delta operations generally assume that the previous dom tree + * is in pristine condition. + */ function handleOutstanding() { + var display_commands = new Array(); + var new_textures = new Array(); + var modified_trees = {}; + + if (outstandingDisplayCommands != null) + return; + while (outstandingCommands.length > 0) { var cmd = outstandingCommands.shift(); - if (!handleCommands(cmd)) { + if (!handleCommands(cmd, display_commands, new_textures, modified_trees)) { outstandingCommands.unshift(cmd); - return; + break; } } + + if (display_commands.length > 0) + outstandingDisplayCommands = display_commands; + + if (new_textures.length > 0) { + var n_textures = new_textures.length; + for (var i = 0; i < new_textures.length; i++) { + var t = new_textures[i]; + t.image.onload = function() { + n_textures -= 1; + if (n_textures == 0) { + handleOutstandingDisplayCommands(); + } + }; + } + } else { + handleOutstandingDisplayCommands(); + } + } function BinCommands(message) { @@ -1062,8 +1134,14 @@ BinCommands.prototype.get_data = function() { return data; }; +var active = false; function handleMessage(message) { + if (!active) { + start(); + active = true; + } + var cmd = new BinCommands(message); outstandingCommands.push(cmd); if (outstandingCommands.length == 1) { From 6fce18e1a15910c4c74b929604946c0bbc3d325d Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Tue, 26 Mar 2019 17:09:41 +0100 Subject: [PATCH 14/14] broadway: Remove some spew --- gdk/broadway/gdksurface-broadway.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/gdk/broadway/gdksurface-broadway.c b/gdk/broadway/gdksurface-broadway.c index b9fbec68c6..4a3b02d8b1 100644 --- a/gdk/broadway/gdksurface-broadway.c +++ b/gdk/broadway/gdksurface-broadway.c @@ -1273,8 +1273,6 @@ gdk_broadway_surface_begin_move_drag (GdkSurface *surface, if (impl->maximized) return; - g_print ("gdk_broadway_surface_begin_move_drag\n"); - mv_resize = get_move_resize_data (gdk_surface_get_display (surface), TRUE); if (mv_resize->moveresize_surface != NULL)