GUACAMOLE-377: Revert to synchronous flush (asynchronous is slower).

The asynchronous flush mechanism leveraging requestAnimationFrame() does
not perform as well as the old synchronous flush. This appears to be due
to delays in when the browser actually allows the frame to proceed,
causing the client to lag behind.

The old synchronous flush mechanism does not suffer from such issues.
This commit is contained in:
Michael Jumper
2025-01-13 14:52:30 -08:00
parent 0460352401
commit 1454a5deae

View File

@@ -185,19 +185,6 @@ Guacamole.Display = function() {
*/
var frames = [];
/**
* The ID of the animation frame request returned by the last call to
* requestAnimationFrame(). This value will only be set if the browser
* supports requestAnimationFrame(), if a frame render is currently
* pending, and if the current browser tab is currently focused (likely to
* handle requests for animation frames). In all other cases, this will be
* null.
*
* @private
* @type {number}
*/
var inProgressFrame = null;
/**
* Flushes all pending frames synchronously. This function will block until
* all pending frames have rendered. If a frame is currently blocked by an
@@ -239,45 +226,6 @@ Guacamole.Display = function() {
};
/**
* Flushes all pending frames asynchronously. This function returns
* immediately, relying on requestAnimationFrame() to dictate when each
* frame should be flushed.
*
* @private
*/
var asyncFlush = function asyncFlush() {
var continueFlush = function continueFlush() {
// We're no longer waiting to render a frame
inProgressFrame = null;
// Nothing to do if there are no frames remaining
if (!frames.length)
return;
// Flush the next frame only if it is ready (not awaiting
// completion of some asynchronous operation like an image load)
if (frames[0].isReady()) {
var frame = frames.shift();
frame.flush();
notifyFlushed(frame.localTimestamp, frame.remoteTimestamp, frame.logicalFrames);
}
// Request yet another animation frame if frames remain to be
// flushed
if (frames.length)
inProgressFrame = window.requestAnimationFrame(continueFlush);
};
// Begin flushing frames if not already waiting to render a frame
if (!inProgressFrame)
inProgressFrame = window.requestAnimationFrame(continueFlush);
};
/**
* Recently-gathered display render statistics, as made available by calls
* to notifyFlushed(). The contents of this array will be trimmed to
@@ -373,33 +321,12 @@ Guacamole.Display = function() {
};
// Switch from asynchronous frame handling to synchronous frame handling if
// requestAnimationFrame() is unlikely to be usable (browsers may not
// invoke the animation frame callback if the relevant tab is not focused)
window.addEventListener('blur', function switchToSyncFlush() {
if (inProgressFrame && !document.hasFocus()) {
// Cancel pending asynchronous processing of frame ...
window.cancelAnimationFrame(inProgressFrame);
inProgressFrame = null;
// ... and instead process it synchronously
syncFlush();
}
}, true);
/**
* Flushes all pending frames.
* @private
*/
function __flush_frames() {
if (window.requestAnimationFrame && document.hasFocus())
asyncFlush();
else
syncFlush();
syncFlush();
}
/**