Ship continuous color/size and density_val as u8 on the live drill wire#221
Conversation
Continuous color/size channels and the per-point density_val crossfade weight are unit scalars that only ever index a colormap texture or a ~16px size ramp, but they shipped as normalized f32 — 4 bytes/point per channel. Quantize them to u8 LUT coordinates (dtype: "u8" marker, absent means f32) on the live drill/sample wire, mirroring what categorical codes already do. A 190k-point drill payload drops 45% (5,070 kB -> 2,789 kB b64-in-JSON; 20 -> 11 bytes/point raw, inside the dossier's 12-24 B/pt direct-mode budget). The build payload deliberately keeps unit f32: the client retains those columns CPU-side (_cpu.color/_cpu.size) and denormalizes them for tooltip readouts, where 8-bit steps would surface as wrong digits. Live paths are safe precisely because hover/pick answers come from the kernel's canonical columns. The contract is recorded in spec/design/wire-protocol.md (density_update, mode: points). Client side, u8 uploads of unit scalars bind as normalized attributes (the shader keeps seeing [0,1]; categorical codes stay un-normalized), and a dtype change re-ids the buffer so cached VAOs rebuild instead of misreading bytes. f32 stays accepted for compatibility.
Merging this PR will not alter performance
Comparing Footnotes
|
Greptile SummaryThis PR reduces live drill and sample-overlay payload sizes with u8 channel coordinates. The main changes are:
Confidence Score: 5/5This looks safe to merge. The VAO cache now reacts to both element-type and normalization changes. Live continuous channels are tagged and bound as normalized u8 values. Build payloads retain f32 values for client-side readback. No blocking issues were found in the changed code.
What T-Rex did
Important Files Changed
Reviews (2): Last reviewed commit: "Re-id channel buffers on normalization c..." | Re-trigger Greptile |
4cc1b68 to
f814f17
Compare
_tagChannelBuf bumped _fcId only when the element type changed, but the pointer config a VAO caches includes the normalized flag — and that flag can flip with the dtype unchanged: a reused cBuf crossing categorical (u8 codes, un-normalized) <-> continuous (u8 LUT coordinates, normalized) stays UNSIGNED_BYTE both ways. The cached VAO then kept the old normalization and drew continuous values clamped at the LUT top (or codes as coordinates). Any pointer-config change now re-ids the buffer.
Live drill and sample-overlay updates ship continuous color/size channels and the
density_valcrossfade weight as u8 LUT coordinates (dtype: "u8"marker; absent means f32 — the client accepts both), mirroring what categorical codes already do. Base:main. No build artifacts in the diff — bundles regenerate vianode js/build.mjs/ packaging (#214).Measured impact
Same 190,105-point drill window on the FastAPI
/drilldownexample (100M-point source), before/after captures diffed buffer-by-buffer:Where quantization is safe — and where it is forbidden
The split is by readback, enforced by making u8 opt-in per call site (
quantize_continuousonship_channels):_cpu.color/_cpu.size) and denormalizes them for tooltip readouts, where 8-bit steps would surface as wrong digits. Pinned by test.How
channels.py:quantize_unit_u8+quantize_continuousthreading throughship_channels/ship_color_channel; the two live-interaction call sites ininteraction.pyopt in;density_valquantizes via_quantize_dval([0,1] by construction)._tagChannelBufre-ids a buffer on dtype change so cached VAOs rebuild rather than misread bytes. f32 remains accepted, so the encoding is backward-detectable per message.wire-protocol.mddocuments the live-wire channel encodings and the durable/ephemeral contract.Relation to the #186–188 append stack (not yet on main)
ship_continuouschokepoint asenc: "u8"alongsideenc: "raw"with a protocol bump — that variant is implemented and verified on branchalek/u8-drill-wire-stacked(protocol v9), ready to swap in._raw_wire_okguard (P1 f32-collapsed domains, P2seterr(over="raise")crash) live on branchalek/raw-wire-f32-guard— they patch code that doesn't exist on main, so they ride separately when the stack rolls up.Verified
tyclean (no new diagnostics);node js/build.mjs.dtypemarker.UNSIGNED_BYTE, x/y byte-identical to the pre-change capture, all three u8 channels within the 0.5/255 bound, zero console errors.