You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
6.8 KiB
153 lines
6.8 KiB
async function init_wasm(state) { |
|
const results = await WebAssembly.instantiateStreaming(fetch('wasm/lod.wasm')); |
|
|
|
state.wasm.exports = results.instance.exports; |
|
state.wasm.exports.memory.grow(4096); |
|
|
|
state.wasm.stroke_bytes = 4096; |
|
state.wasm.coords_bytes = 4096; |
|
state.wasm.buffers = { |
|
'xs': { |
|
'offset': state.wasm.exports.alloc_static(state.wasm.coords_bytes / 2), |
|
'used': 0 |
|
}, |
|
'ys': { |
|
'offset': state.wasm.exports.alloc_static(state.wasm.coords_bytes / 2), |
|
'used': 0 |
|
}, |
|
'coords_from': { |
|
'offset': state.wasm.exports.alloc_static(state.wasm.stroke_bytes), |
|
'used': 0, |
|
}, |
|
'line_threshold': { |
|
'offset': state.wasm.exports.alloc_static(state.wasm.stroke_bytes), |
|
'used': 0, |
|
}, |
|
'pressures': { |
|
'offset': state.wasm.exports.alloc_static(state.wasm.coords_bytes / 8), |
|
'used': 0 |
|
}, |
|
}; |
|
|
|
const mem = state.wasm.exports.memory.buffer; |
|
|
|
state.wasm.buffers['xs'].tv = tv_create_on(Float32Array, state.wasm.coords_bytes / 8, |
|
mem, state.wasm.buffers['xs'].offset); |
|
state.wasm.buffers['ys'].tv = tv_create_on(Float32Array, state.wasm.coords_bytes / 8, |
|
mem, state.wasm.buffers['ys'].offset); |
|
state.wasm.buffers['coords_from'].tv = tv_create_on(Uint32Array, state.wasm.stroke_bytes / 4, |
|
mem, state.wasm.buffers['coords_from'].offset); |
|
state.wasm.buffers['line_threshold'].tv = tv_create_on(Float32Array, state.wasm.stroke_bytes / 4, |
|
mem, state.wasm.buffers['line_threshold'].offset); |
|
state.wasm.buffers['pressures'].tv = tv_create_on(Uint8Array, state.wasm.coords_bytes / 8, |
|
mem, state.wasm.buffers['pressures'].offset); |
|
|
|
tv_add(state.wasm.buffers['coords_from'].tv, 0); |
|
state.wasm.buffers['coords_from'].used = 4; |
|
} |
|
|
|
function wasm_ensure_by(state, nstrokes, ncoords) { |
|
const buffers = state.wasm.buffers; |
|
|
|
const old_coords_from_offset = buffers['coords_from'].offset; |
|
const old_line_threshold_offset = buffers['line_threshold'].offset; |
|
const old_pressures_offset = buffers['pressures'].offset; |
|
|
|
const old_size_coords = state.wasm.coords_bytes; |
|
const old_size_strokes = state.wasm.stroke_bytes; |
|
|
|
let realloc = false; |
|
|
|
if (buffers['xs'].used + ncoords * 4 > state.wasm.coords_bytes / 2) { |
|
state.wasm.coords_bytes += round_to_pow2(ncoords * 4, 4096 * 16); // 1 wasm page (although it doesn't matter here) |
|
realloc = true; |
|
} |
|
|
|
if (buffers['coords_from'].used + nstrokes * 4 > state.wasm.stroke_bytes / 2) { |
|
state.wasm.stroke_bytes += round_to_pow2(nstrokes * 4, 4096 * 16); |
|
realloc = true; |
|
} |
|
|
|
if (realloc) { |
|
// TODO: we do memory.grow() somewhere here if needed |
|
|
|
state.wasm.exports.free_static(); |
|
|
|
const mem = state.wasm.exports.memory.buffer; |
|
const memv = new Uint8Array(mem); |
|
|
|
buffers['xs'].offset = state.wasm.exports.alloc_static(state.wasm.coords_bytes / 2); |
|
buffers['ys'].offset = state.wasm.exports.alloc_static(state.wasm.coords_bytes / 2); |
|
buffers['coords_from'].offset = state.wasm.exports.alloc_static(state.wasm.stroke_bytes); |
|
buffers['line_threshold'].offset = state.wasm.exports.alloc_static(state.wasm.stroke_bytes); |
|
buffers['pressures'].offset = state.wasm.exports.alloc_static(state.wasm.coords_bytes / 8); |
|
|
|
buffers['xs'].tv = tv_create_on(Float32Array, state.wasm.coords_bytes / 8, mem, buffers['xs'].offset); |
|
buffers['ys'].tv = tv_create_on(Float32Array, state.wasm.coords_bytes / 8, mem, buffers['ys'].offset); |
|
buffers['coords_from'].tv = tv_create_on(Uint32Array, state.wasm.stroke_bytes / 4, mem, buffers['coords_from'].offset); |
|
buffers['line_threshold'].tv = tv_create_on(Float32Array, state.wasm.stroke_bytes / 4, mem, buffers['line_threshold'].offset); |
|
buffers['pressures'].tv = tv_create_on(Uint8Array, state.wasm.coords_bytes / 8, mem, buffers['pressures'].offset); |
|
|
|
// TODO: this should have been automatic maybe? |
|
buffers['xs'].tv.size = buffers['xs'].used / 4; |
|
buffers['ys'].tv.size = buffers['ys'].used / 4; |
|
buffers['coords_from'].tv.size = buffers['coords_from'].used / 4; |
|
buffers['line_threshold'].tv.size = buffers['line_threshold'].used / 4; |
|
buffers['pressures'].tv.size = buffers['pressures'].used; |
|
|
|
const tmp = new Uint8Array(Math.max(state.wasm.coords_bytes, state.wasm.stroke_bytes)); // TODO: needed? |
|
|
|
// Copy from back to front (otherwise we will overwrite) |
|
tmp.set(new Uint8Array(mem, old_pressures_offset, buffers['pressures'].used)); |
|
memv.set(new Uint8Array(tmp.buffer, 0, buffers['pressures'].used), buffers['pressures'].offset); |
|
|
|
tmp.set(new Uint8Array(mem, old_line_threshold_offset, old_size_strokes)); |
|
memv.set(new Uint8Array(tmp.buffer, 0, old_size_strokes), buffers['line_threshold'].offset); |
|
|
|
tmp.set(new Uint8Array(mem, old_coords_from_offset, old_size_strokes)); |
|
memv.set(new Uint8Array(tmp.buffer, 0, old_size_strokes), buffers['coords_from'].offset); |
|
} |
|
} |
|
|
|
function do_lod(state, context) { |
|
state.wasm.exports.free_dynamic(); |
|
|
|
const clipped_indices = state.wasm.exports.alloc_dynamic(context.clipped_indices.size * 4); |
|
const mem = new Uint8Array(state.wasm.exports.memory.buffer); |
|
|
|
// Dynamic input data that should (by design) never be too big |
|
mem.set(tv_bytes(context.clipped_indices), clipped_indices); |
|
|
|
const buffers = state.wasm.buffers; |
|
const segment_count = state.wasm.exports.do_lod( |
|
clipped_indices, context.clipped_indices.size, state.canvas.zoom, |
|
buffers['coords_from'].offset, |
|
buffers['line_threshold'].offset, |
|
buffers['xs'].offset, |
|
buffers['ys'].offset, |
|
buffers['pressures'].offset, |
|
buffers['xs'].used / 4, |
|
); |
|
|
|
// Use results without copying from WASM memory |
|
const result_offset = clipped_indices + context.clipped_indices.size * 4 |
|
+ (context.clipped_indices.size + 1) * 4 + buffers['xs'].used; |
|
|
|
const wasm_points = new Float32Array(state.wasm.exports.memory.buffer, |
|
result_offset, segment_count * 2); |
|
const wasm_ids = new Uint32Array(state.wasm.exports.memory.buffer, |
|
result_offset + segment_count * 2 * 4, segment_count); |
|
const wasm_pressures = new Uint8Array(state.wasm.exports.memory.buffer, |
|
result_offset + segment_count * 2 * 4 + segment_count * 4, segment_count); |
|
|
|
context.instance_data_points.data = wasm_points; |
|
context.instance_data_points.size = segment_count * 2; |
|
|
|
context.instance_data_ids.data = wasm_ids; |
|
context.instance_data_ids.size = segment_count; |
|
|
|
context.instance_data_pressures.data = wasm_pressures; |
|
context.instance_data_pressures.size = segment_count; |
|
|
|
return segment_count; |
|
}
|
|
|