[gtk/wip/alexl/broadway5: 13/13] broadway: Load all textures before applying display ops, fixing flickers
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/alexl/broadway5: 13/13] broadway: Load all textures before applying display ops, fixing flickers
- Date: Tue, 26 Mar 2019 15:54:00 +0000 (UTC)
commit 5c656da5ce732e08a9ea03711b4f87415ae42bf4
Author: Alexander Larsson <alexl redhat com>
Date: Tue Mar 26 16:29:45 2019 +0100
broadway: Load all textures before applying display ops, fixing flickers
gdk/broadway/broadway.js | 128 ++++++++++++++++++++++++++++++++++++++---------
1 file changed, 103 insertions(+), 25 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 res;
+}
- return true;
+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) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]