mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 22:41:43 +00:00
broadway: Load all textures before applying display ops, fixing flickers
This commit is contained in:
parent
0481aa10e7
commit
cf4226586a
@ -62,6 +62,8 @@ const DISPLAY_OP_HIDE_SURFACE = 4;
|
|||||||
const DISPLAY_OP_DELETE_NODE = 5;
|
const DISPLAY_OP_DELETE_NODE = 5;
|
||||||
const DISPLAY_OP_MOVE_NODE = 6;
|
const DISPLAY_OP_MOVE_NODE = 6;
|
||||||
const DISPLAY_OP_RESIZE_NODE = 7;
|
const DISPLAY_OP_RESIZE_NODE = 7;
|
||||||
|
const DISPLAY_OP_RESTACK_SURFACES = 8;
|
||||||
|
const DISPLAY_OP_DELETE_SURFACE = 9;
|
||||||
|
|
||||||
// GdkCrossingMode
|
// GdkCrossingMode
|
||||||
const GDK_CROSSING_NORMAL = 0;
|
const GDK_CROSSING_NORMAL = 0;
|
||||||
@ -173,6 +175,7 @@ var surfaces = {};
|
|||||||
var textures = {};
|
var textures = {};
|
||||||
var stackingOrder = [];
|
var stackingOrder = [];
|
||||||
var outstandingCommands = new Array();
|
var outstandingCommands = new Array();
|
||||||
|
var outstandingDisplayCommands = null;
|
||||||
var inputSocket = null;
|
var inputSocket = null;
|
||||||
var debugDecoding = false;
|
var debugDecoding = false;
|
||||||
var fakeInput = null;
|
var fakeInput = null;
|
||||||
@ -199,6 +202,10 @@ function Texture(id, data) {
|
|||||||
this.url = window.URL.createObjectURL(blob);
|
this.url = window.URL.createObjectURL(blob);
|
||||||
this.refcount = 1;
|
this.refcount = 1;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|
||||||
|
var image = new Image();
|
||||||
|
image.src = this.url;
|
||||||
|
this.image = image;
|
||||||
textures[id] = this;
|
textures[id] = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,13 +285,14 @@ function cmdRoundtrip(id, tag)
|
|||||||
function cmdRaiseSurface(id)
|
function cmdRaiseSurface(id)
|
||||||
{
|
{
|
||||||
var surface = surfaces[id];
|
var surface = surfaces[id];
|
||||||
|
if (surface)
|
||||||
moveToHelper(surface);
|
moveToHelper(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
function cmdLowerSurface(id)
|
function cmdLowerSurface(id)
|
||||||
{
|
{
|
||||||
var surface = surfaces[id];
|
var surface = surfaces[id];
|
||||||
|
if (surface)
|
||||||
moveToHelper(surface, 0);
|
moveToHelper(surface, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,9 +499,8 @@ TransformNodes.prototype.insertNode = function(parent, posInParent, oldNode)
|
|||||||
image.height = rect.height;
|
image.height = rect.height;
|
||||||
image.style["position"] = "absolute";
|
image.style["position"] = "absolute";
|
||||||
set_rect_style(image, rect);
|
set_rect_style(image, rect);
|
||||||
var texture = textures[texture_id];
|
var texture = textures[texture_id].ref();
|
||||||
image.src = texture.url;
|
image.src = texture.url;
|
||||||
texture.ref();
|
|
||||||
// Unref blob url when loaded
|
// Unref blob url when loaded
|
||||||
image.onload = function() { texture.unref(); };
|
image.onload = function() { texture.unref(); };
|
||||||
newNode = image;
|
newNode = image;
|
||||||
@ -833,25 +840,28 @@ function handleDisplayCommands(display_commands)
|
|||||||
div.style["height"] = cmd[3] + "px";
|
div.style["height"] = cmd[3] + "px";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DISPLAY_OP_RESTACK_SURFACES:
|
||||||
|
restackSurfaces();
|
||||||
|
break;
|
||||||
|
case DISPLAY_OP_DELETE_SURFACE:
|
||||||
|
var id = cmd[1];
|
||||||
|
delete surfaces[id];
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
alert("Unknown display op " + command);
|
alert("Unknown display op " + command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var active = false;
|
function handleCommands(cmd, display_commands, new_textures, modified_trees)
|
||||||
function handleCommands(cmd)
|
|
||||||
{
|
{
|
||||||
if (!active) {
|
var res = true;
|
||||||
start();
|
|
||||||
active = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var display_commands = new Array();
|
|
||||||
var need_restack = false;
|
var need_restack = false;
|
||||||
|
|
||||||
while (cmd.pos < cmd.length) {
|
while (res && cmd.pos < cmd.length) {
|
||||||
var id, x, y, w, h, q, surface;
|
var id, x, y, w, h, q, surface;
|
||||||
|
var saved_pos = cmd.pos;
|
||||||
var command = cmd.get_char();
|
var command = cmd.get_char();
|
||||||
lastSerial = cmd.get_32();
|
lastSerial = cmd.get_32();
|
||||||
switch (command) {
|
switch (command) {
|
||||||
@ -918,7 +928,8 @@ function handleCommands(cmd)
|
|||||||
var div = surface.div;
|
var div = surface.div;
|
||||||
|
|
||||||
display_commands.push([DISPLAY_OP_DELETE_NODE, 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;
|
break;
|
||||||
|
|
||||||
case BROADWAY_OP_ROUNDTRIP:
|
case BROADWAY_OP_ROUNDTRIP:
|
||||||
@ -962,7 +973,8 @@ function handleCommands(cmd)
|
|||||||
case BROADWAY_OP_UPLOAD_TEXTURE:
|
case BROADWAY_OP_UPLOAD_TEXTURE:
|
||||||
id = cmd.get_32();
|
id = cmd.get_32();
|
||||||
var data = cmd.get_data();
|
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;
|
break;
|
||||||
|
|
||||||
case BROADWAY_OP_RELEASE_TEXTURE:
|
case BROADWAY_OP_RELEASE_TEXTURE:
|
||||||
@ -972,10 +984,18 @@ function handleCommands(cmd)
|
|||||||
|
|
||||||
case BROADWAY_OP_SET_NODES:
|
case BROADWAY_OP_SET_NODES:
|
||||||
id = cmd.get_16();
|
id = cmd.get_16();
|
||||||
|
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 ();
|
var node_data = cmd.get_nodes ();
|
||||||
surface = surfaces[id];
|
surface = surfaces[id];
|
||||||
var transform_nodes = new TransformNodes (node_data, surface.div, display_commands);
|
var transform_nodes = new TransformNodes (node_data, surface.div, display_commands);
|
||||||
transform_nodes.execute();
|
transform_nodes.execute();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BROADWAY_OP_GRAB_POINTER:
|
case BROADWAY_OP_GRAB_POINTER:
|
||||||
@ -1000,22 +1020,74 @@ function handleCommands(cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (need_restack)
|
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()
|
function handleOutstanding()
|
||||||
{
|
{
|
||||||
|
var display_commands = new Array();
|
||||||
|
var new_textures = new Array();
|
||||||
|
var modified_trees = {};
|
||||||
|
|
||||||
|
if (outstandingDisplayCommands != null)
|
||||||
|
return;
|
||||||
|
|
||||||
while (outstandingCommands.length > 0) {
|
while (outstandingCommands.length > 0) {
|
||||||
var cmd = outstandingCommands.shift();
|
var cmd = outstandingCommands.shift();
|
||||||
if (!handleCommands(cmd)) {
|
if (!handleCommands(cmd, display_commands, new_textures, modified_trees)) {
|
||||||
outstandingCommands.unshift(cmd);
|
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) {
|
function BinCommands(message) {
|
||||||
@ -1062,8 +1134,14 @@ BinCommands.prototype.get_data = function() {
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var active = false;
|
||||||
function handleMessage(message)
|
function handleMessage(message)
|
||||||
{
|
{
|
||||||
|
if (!active) {
|
||||||
|
start();
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
|
||||||
var cmd = new BinCommands(message);
|
var cmd = new BinCommands(message);
|
||||||
outstandingCommands.push(cmd);
|
outstandingCommands.push(cmd);
|
||||||
if (outstandingCommands.length == 1) {
|
if (outstandingCommands.length == 1) {
|
||||||
|
Loading…
Reference in New Issue
Block a user