Skip to content

Commit ba4eb35

Browse files
author
Chris Lord
committed
Handle Worker transactions progressively
Handle Worker tile decompression 10ms at a time and allow messages to be processed between tile decompression. This should have no immediate effect, but lays the groundwork for transactions to be interrupted or cancelled. Signed-off-by: Chris Lord <chris.lord@collabora.com> Change-Id: I91c04510411a3bb2124ccb08a923615cf7b99199
1 parent a2695ff commit ba4eb35

File tree

1 file changed

+87
-45
lines changed

1 file changed

+87
-45
lines changed

browser/src/layer/tile/CanvasTileWorkerSrc.js

Lines changed: 87 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,86 @@
1313
/* eslint no-unused-vars: ["warn", { "argsIgnorePattern": "^_" }] */
1414
/* global importScripts Uint8Array */
1515

16+
// Amount of time to spend decompressing deltas before returning to the main loop
17+
const PROCESS_TIME = 10;
18+
19+
let transactionHandlerId = null;
20+
const transactions = [];
21+
22+
function transactionCallback(start_time = null) {
23+
if (start_time === null) start_time = performance.now();
24+
else if (performance.now() - start_time >= PROCESS_TIME) {
25+
transactionHandlerId = setTimeout(() => transactionCallback(), 0);
26+
return;
27+
}
28+
29+
const transaction = transactions.shift();
30+
const tileByteSize =
31+
transaction.data.tileSize * transaction.data.tileSize * 4;
32+
33+
while (transaction.data.deltas.length) {
34+
const tile = transaction.data.deltas.pop();
35+
36+
transaction.decompressed.push(tile);
37+
transaction.buffers.push(tile.rawDelta.buffer);
38+
39+
const deltas = self.fzstd.decompress(tile.rawDelta);
40+
tile.keyframeDeltaSize = 0;
41+
42+
// Decompress the keyframe buffer
43+
if (tile.isKeyframe) {
44+
const keyframeBuffer = new Uint8Array(tileByteSize);
45+
tile.keyframeDeltaSize = L.CanvasTileUtils.unrle(
46+
deltas,
47+
transaction.data.tileSize,
48+
transaction.data.tileSize,
49+
keyframeBuffer,
50+
);
51+
tile.keyframeBuffer = new Uint8ClampedArray(
52+
keyframeBuffer.buffer,
53+
keyframeBuffer.byteOffset,
54+
keyframeBuffer.byteLength,
55+
);
56+
transaction.buffers.push(tile.keyframeBuffer.buffer);
57+
}
58+
59+
// Now wrap as Uint8ClampedArray as that's what ImageData requires. Don't do
60+
// it earlier to avoid unnecessarily incurring bounds-checking penalties.
61+
tile.deltas = new Uint8ClampedArray(
62+
deltas.buffer,
63+
deltas.byteOffset,
64+
deltas.length,
65+
);
66+
67+
transaction.buffers.push(tile.deltas.buffer);
68+
if (performance.now() - start_time >= PROCESS_TIME) break;
69+
}
70+
71+
if (transaction.data.deltas.length) {
72+
transactions.unshift(transaction);
73+
transactionHandlerId = setTimeout(() => transactionCallback(), 0);
74+
return;
75+
}
76+
77+
// Transaction is complete, send it back.
78+
postMessage(
79+
{
80+
message: transaction.data.message,
81+
deltas: transaction.decompressed,
82+
tileSize: transaction.data.tileSize,
83+
},
84+
transaction.buffers,
85+
);
86+
87+
if (transactions.length === 0) {
88+
transactionHandlerId = null;
89+
return;
90+
}
91+
92+
// See if we have time to process further transactions
93+
transactionCallback(start_time);
94+
}
95+
1696
if ('undefined' === typeof window) {
1797
self.L = {};
1898

@@ -24,51 +104,13 @@ if ('undefined' === typeof window) {
24104
function onMessage(e) {
25105
switch (e.data.message) {
26106
case 'endTransaction':
27-
var tileByteSize = e.data.tileSize * e.data.tileSize * 4;
28-
var decompressed = [];
29-
var buffers = [];
30-
for (var tile of e.data.deltas) {
31-
var deltas = self.fzstd.decompress(tile.rawDelta);
32-
tile.keyframeDeltaSize = 0;
33-
34-
// Decompress the keyframe buffer
35-
if (tile.isKeyframe) {
36-
var keyframeBuffer = new Uint8Array(tileByteSize);
37-
tile.keyframeDeltaSize = L.CanvasTileUtils.unrle(
38-
deltas,
39-
e.data.tileSize,
40-
e.data.tileSize,
41-
keyframeBuffer,
42-
);
43-
tile.keyframeBuffer = new Uint8ClampedArray(
44-
keyframeBuffer.buffer,
45-
keyframeBuffer.byteOffset,
46-
keyframeBuffer.byteLength,
47-
);
48-
buffers.push(tile.keyframeBuffer.buffer);
49-
}
50-
51-
// Now wrap as Uint8ClampedArray as that's what ImageData requires. Don't do
52-
// it earlier to avoid unnecessarily incurring bounds-checking penalties.
53-
tile.deltas = new Uint8ClampedArray(
54-
deltas.buffer,
55-
deltas.byteOffset,
56-
deltas.length,
57-
);
58-
59-
decompressed.push(tile);
60-
buffers.push(tile.rawDelta.buffer);
61-
buffers.push(tile.deltas.buffer);
62-
}
63-
64-
postMessage(
65-
{
66-
message: e.data.message,
67-
deltas: decompressed,
68-
tileSize: e.data.tileSize,
69-
},
70-
buffers,
71-
);
107+
transactions.push({
108+
data: e.data,
109+
decompressed: [],
110+
buffers: [],
111+
});
112+
if (transactionHandlerId !== null) clearTimeout(transactionHandlerId);
113+
transactionCallback();
72114
break;
73115

74116
default:

0 commit comments

Comments
 (0)