delta: optimize away re-fetching of pixel data as we apply.
Avoid fetching and putting pixel data back to the canvas when we apply a series of deltas to a single keyframe. Also split high-level from low-level delta debugging. Change-Id: If4c308b695fb236e0753490d0d20a0fef0a9a470 Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
This commit is contained in:
parent
2def6dc3d5
commit
e7b57b2fad
1 changed files with 54 additions and 41 deletions
|
@ -4884,7 +4884,8 @@ L.CanvasTileLayer = L.Layer.extend({
|
||||||
this._debugLoadDelta = 0;
|
this._debugLoadDelta = 0;
|
||||||
this._debugInvalidateCount = 0;
|
this._debugInvalidateCount = 0;
|
||||||
this._debugRenderCount = 0;
|
this._debugRenderCount = 0;
|
||||||
this._debugDeltas = true; // FIXME - turn me off before pushing ...
|
this._debugDeltas = true;
|
||||||
|
this._debugDeltasDetail = false;
|
||||||
if (!this._debugData) {
|
if (!this._debugData) {
|
||||||
this._debugData = {};
|
this._debugData = {};
|
||||||
this._debugDataNames = ['tileCombine', 'fromKeyInputToInvalidate', 'ping', 'loadCount', 'postMessage'];
|
this._debugDataNames = ['tileCombine', 'fromKeyInputToInvalidate', 'ping', 'loadCount', 'postMessage'];
|
||||||
|
@ -6654,6 +6655,9 @@ L.CanvasTileLayer = L.Layer.extend({
|
||||||
// FIXME:used clamped array ... as a 2nd parameter
|
// FIXME:used clamped array ... as a 2nd parameter
|
||||||
var allDeltas = window.fzstd.decompress(rawDelta);
|
var allDeltas = window.fzstd.decompress(rawDelta);
|
||||||
|
|
||||||
|
var imgData;
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
while (offset < allDeltas.length)
|
while (offset < allDeltas.length)
|
||||||
{
|
{
|
||||||
if (this._debugDeltas)
|
if (this._debugDeltas)
|
||||||
|
@ -6669,47 +6673,58 @@ L.CanvasTileLayer = L.Layer.extend({
|
||||||
delta.length + ' vs. ' + (canvas.width * canvas.height * 4));
|
delta.length + ' vs. ' + (canvas.width * canvas.height * 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: it is a nonsense to keep fetching the data from the canvas
|
|
||||||
// and putting it back if we apply multiple deltas - horribly wasteful.
|
if (isKeyframe)
|
||||||
// we should move that outside the loop.
|
{
|
||||||
var len = this._applyDeltaChunk(canvas, tile, initCanvas, delta, isKeyframe);
|
// FIXME: use zstd to de-compress directly into a Uint8ClampedArray
|
||||||
if (this._debugDeltas)
|
len = canvas.width * canvas.height * 4;
|
||||||
window.app.console.log('Applied chunk ' + i++ + ' of total size ' + delta.length +
|
var pixelArray = new Uint8ClampedArray(delta.subarray(0, len));
|
||||||
' at stream offset ' + offset + ' size ' + len);
|
imgData = new ImageData(pixelArray, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
if (this._debugDeltas)
|
||||||
|
window.app.console.log('Applied keyframe ' + i++ + ' of total size ' + delta.length +
|
||||||
|
' at stream offset ' + offset + ' size ' + len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (initCanvas && tile.el) // render old image data to the canvas
|
||||||
|
ctx.drawImage(tile.el, 0, 0);
|
||||||
|
|
||||||
|
if (!imgData) // no keyframe
|
||||||
|
{
|
||||||
|
if (this._debugDeltas)
|
||||||
|
window.app.console.log('Fetch canvas contents');
|
||||||
|
imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy old data to work from:
|
||||||
|
var oldData = new Uint8ClampedArray(imgData.data);
|
||||||
|
|
||||||
|
var len = this._applyDeltaChunk(imgData, delta, oldData, canvas.width, canvas.height);
|
||||||
|
if (this._debugDeltas)
|
||||||
|
window.app.console.log('Applied chunk ' + i++ + ' of total size ' + delta.length +
|
||||||
|
' at stream offset ' + offset + ' size ' + len);
|
||||||
|
}
|
||||||
|
|
||||||
initCanvas = false;
|
initCanvas = false;
|
||||||
isKeyframe = false;
|
isKeyframe = false;
|
||||||
offset += len;
|
offset += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (imgData)
|
||||||
|
ctx.putImageData(imgData, 0, 0);
|
||||||
|
|
||||||
|
return i;
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_applyDeltaChunk: function(canvas, tile, initCanvas, delta, isKeyframe) {
|
_applyDeltaChunk: function(imgData, delta, oldData, width, height) {
|
||||||
var ctx = canvas.getContext('2d');
|
var pixSize = width * height * 4;
|
||||||
|
|
||||||
var pixSize = canvas.width * canvas.height * 4;
|
|
||||||
if (this._debugDeltas)
|
if (this._debugDeltas)
|
||||||
window.app.console.log('Applying a ' + (isKeyframe ? 'keyframe' : 'delta') +
|
window.app.console.log('Applying a delta of length ' +
|
||||||
' of length ' + delta.length + ' canvas size: ' + pixSize);
|
delta.length + ' canvas size: ' + pixSize);
|
||||||
// + ' hex: ' + hex2string(delta));
|
// + ' hex: ' + hex2string(delta));
|
||||||
|
|
||||||
if (delta.length === 0)
|
|
||||||
return; // that was easy!
|
|
||||||
|
|
||||||
if (isKeyframe)
|
|
||||||
{
|
|
||||||
// FIXME: use zstd to de-compress directly into a Uint8ClampedArray
|
|
||||||
ctx.putImageData(new ImageData(new Uint8ClampedArray(delta.subarray(0, pixSize)),
|
|
||||||
canvas.width, canvas.height), 0, 0);
|
|
||||||
return pixSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initCanvas && tile.el) // render old image data to the canvas
|
|
||||||
ctx.drawImage(tile.el, 0, 0);
|
|
||||||
|
|
||||||
// FIXME; can we operate directly on the image ?
|
|
||||||
var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
||||||
// FIXME: can we just keep a ptr to imgData.data (?) ... =)
|
|
||||||
var oldData = new Uint8ClampedArray(imgData.data);
|
|
||||||
|
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
|
|
||||||
// Green-tinge the old-Data ...
|
// Green-tinge the old-Data ...
|
||||||
|
@ -6736,14 +6751,14 @@ L.CanvasTileLayer = L.Layer.extend({
|
||||||
var count = delta[i+1];
|
var count = delta[i+1];
|
||||||
var srcRow = delta[i+2];
|
var srcRow = delta[i+2];
|
||||||
var destRow = delta[i+3];
|
var destRow = delta[i+3];
|
||||||
if (this._debugDeltas)
|
if (this._debugDeltasDetail)
|
||||||
window.app.console.log('[' + i + ']: copy ' + count + ' row(s) ' + srcRow + ' to ' + destRow);
|
window.app.console.log('[' + i + ']: copy ' + count + ' row(s) ' + srcRow + ' to ' + destRow);
|
||||||
i+= 4;
|
i+= 4;
|
||||||
for (var cnt = 0; cnt < count; ++cnt)
|
for (var cnt = 0; cnt < count; ++cnt)
|
||||||
{
|
{
|
||||||
var src = (srcRow + cnt) * canvas.width * 4;
|
var src = (srcRow + cnt) * width * 4;
|
||||||
var dest = (destRow + cnt) * canvas.width * 4;
|
var dest = (destRow + cnt) * width * 4;
|
||||||
for (var j = 0; j < canvas.width * 4; ++j)
|
for (var j = 0; j < width * 4; ++j)
|
||||||
{
|
{
|
||||||
imgData.data[dest + j] = oldData[src + j];
|
imgData.data[dest + j] = oldData[src + j];
|
||||||
}
|
}
|
||||||
|
@ -6753,8 +6768,8 @@ L.CanvasTileLayer = L.Layer.extend({
|
||||||
destRow = delta[i+1];
|
destRow = delta[i+1];
|
||||||
var destCol = delta[i+2];
|
var destCol = delta[i+2];
|
||||||
var span = delta[i+3];
|
var span = delta[i+3];
|
||||||
offset = destRow * canvas.width * 4 + destCol * 4;
|
offset = destRow * width * 4 + destCol * 4;
|
||||||
if (this._debugDeltas)
|
if (this._debugDeltasDetail)
|
||||||
window.app.console.log('[' + i + ']: apply new span of size ' + span +
|
window.app.console.log('[' + i + ']: apply new span of size ' + span +
|
||||||
' at pos ' + destCol + ', ' + destRow + ' into delta at byte: ' + offset);
|
' at pos ' + destCol + ', ' + destRow + ' into delta at byte: ' + offset);
|
||||||
i += 4;
|
i += 4;
|
||||||
|
@ -6776,8 +6791,6 @@ L.CanvasTileLayer = L.Layer.extend({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.putImageData(imgData, 0, 0);
|
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue