Read every range of one attribute, then pack them into ONE buffer so the
decode runs as a single worker call instead of one call per range.
Every worker-decoded range encoding (per-channel, quantized, log/geolog
scalar, LUT) decodes element-wise: element j of the output depends only on
stored code j (and, for per-channel, on its GLOBAL column g % cols). So
decoding the concatenation is identical to decoding each range on its own,
provided each range lands at its own destination offset — which also keeps
the per-channel column phase exact (g is the packed index itself).
The pack is laid out in OUTPUT order, in STORED units (offsets / perElement,
since LUT row mode decodes k values per stored index). A malformed range
that decodes SHORT leaves a gap in the pack; the gap decodes to junk that
scatterDecoded never copies, so its output span stays untouched —
the same "remainder unfilled" contract clampRangeData gives a per-range
write. A LONG range is truncated to its span, again as before.
Measured motivation: the per-range dispatch sent ~40k worker messages per
6 s loop on a Points timelapse, most a few hundred elements each.
Read every range of one attribute, then pack them into ONE buffer so the decode runs as a single worker call instead of one call per range.
Every worker-decoded range encoding (per-channel, quantized, log/geolog scalar, LUT) decodes element-wise: element
jof the output depends only on stored codej(and, for per-channel, on its GLOBAL columng % cols). So decoding the concatenation is identical to decoding each range on its own, provided each range lands at its own destination offset — which also keeps the per-channel column phase exact (gis the packed index itself).The pack is laid out in OUTPUT order, in STORED units (
offsets / perElement, since LUT row mode decodeskvalues per stored index). A malformed range that decodes SHORT leaves a gap in the pack; the gap decodes to junk that scatterDecoded never copies, so its output span stays untouched — the same "remainder unfilled" contractclampRangeDatagives a per-range write. A LONG range is truncated to its span, again as before.Measured motivation: the per-range dispatch sent ~40k worker messages per 6 s loop on a Points timelapse, most a few hundred elements each.