Browse Source

Pass stroke widths to wasm (not actually writing any values right now,

just some busywork to allocate memory and pass pointers)
sdf
A.Olokhtonov 2 weeks ago
parent
commit
ce824a8e31
  1. 1
      client/lod_worker.js
  2. 19
      client/speed.js
  3. 21
      client/wasm/lod.c
  4. BIN
      client/wasm/lod.wasm
  5. 2
      client/webgl_draw.js

1
client/lod_worker.js

@ -19,6 +19,7 @@ function work(indices_base, indices_count, zoom, offsets) {
exports.do_lod( exports.do_lod(
indices_base, indices_count, zoom, indices_base, indices_count, zoom,
offsets['coords_from'], offsets['coords_from'],
offsets['width'],
offsets['xs'], offsets['xs'],
offsets['ys'], offsets['ys'],
offsets['pressures'], offsets['pressures'],

19
client/speed.js

@ -80,12 +80,17 @@ async function init_wasm(state) {
'used': 0, 'used': 0,
'cap': initial 'cap': initial
}, },
'width': {
'used': 0,
'cap': initial
}
}; };
state.wasm.buffers['xs'].offset = state.wasm.exports.alloc_static(initial); state.wasm.buffers['xs'].offset = state.wasm.exports.alloc_static(initial);
state.wasm.buffers['ys'].offset = state.wasm.exports.alloc_static(initial); state.wasm.buffers['ys'].offset = state.wasm.exports.alloc_static(initial);
state.wasm.buffers['pressures'].offset = state.wasm.exports.alloc_static(initial); state.wasm.buffers['pressures'].offset = state.wasm.exports.alloc_static(initial);
state.wasm.buffers['coords_from'].offset = state.wasm.exports.alloc_static(initial); state.wasm.buffers['coords_from'].offset = state.wasm.exports.alloc_static(initial);
state.wasm.buffers['width'].offset = state.wasm.exports.alloc_static(initial);
const mem = state.wasm.memory.buffer; const mem = state.wasm.memory.buffer;
@ -97,6 +102,8 @@ async function init_wasm(state) {
mem, state.wasm.buffers['pressures'].offset); mem, state.wasm.buffers['pressures'].offset);
state.wasm.buffers['coords_from'].tv = tv_create_on(Uint32Array, initial / 4, state.wasm.buffers['coords_from'].tv = tv_create_on(Uint32Array, initial / 4,
mem, state.wasm.buffers['coords_from'].offset); mem, state.wasm.buffers['coords_from'].offset);
state.wasm.buffers['width'].tv = tv_create_on(Uint32Array, initial / 4,
mem, state.wasm.buffers['width'].offset);
tv_add(state.wasm.buffers['coords_from'].tv, 0); tv_add(state.wasm.buffers['coords_from'].tv, 0);
state.wasm.buffers['coords_from'].used = 4; state.wasm.buffers['coords_from'].used = 4;
@ -108,6 +115,7 @@ function wasm_ensure_by(state, nstrokes, ncoords) {
const old_ys_offset = buffers['ys'].offset; const old_ys_offset = buffers['ys'].offset;
const old_coords_from_offset = buffers['coords_from'].offset; const old_coords_from_offset = buffers['coords_from'].offset;
const old_pressures_offset = buffers['pressures'].offset; const old_pressures_offset = buffers['pressures'].offset;
const old_width_offset = buffers['width'].offset;
let realloc = false; let realloc = false;
let coords_bytes = buffers['xs'].cap; let coords_bytes = buffers['xs'].cap;
@ -135,23 +143,31 @@ function wasm_ensure_by(state, nstrokes, ncoords) {
buffers['ys'].offset = state.wasm.exports.alloc_static(coords_bytes); buffers['ys'].offset = state.wasm.exports.alloc_static(coords_bytes);
buffers['pressures'].offset = state.wasm.exports.alloc_static(coords_bytes); buffers['pressures'].offset = state.wasm.exports.alloc_static(coords_bytes);
buffers['coords_from'].offset = state.wasm.exports.alloc_static(stroke_bytes); buffers['coords_from'].offset = state.wasm.exports.alloc_static(stroke_bytes);
buffers['width'].offset = state.wasm.exports.alloc_static(stroke_bytes);
buffers['xs'].tv = tv_create_on(Float32Array, coords_bytes / 4, mem, buffers['xs'].offset); buffers['xs'].tv = tv_create_on(Float32Array, coords_bytes / 4, mem, buffers['xs'].offset);
buffers['ys'].tv = tv_create_on(Float32Array, coords_bytes / 4, mem, buffers['ys'].offset); buffers['ys'].tv = tv_create_on(Float32Array, coords_bytes / 4, mem, buffers['ys'].offset);
buffers['pressures'].tv = tv_create_on(Uint8Array, coords_bytes, mem, buffers['pressures'].offset); buffers['pressures'].tv = tv_create_on(Uint8Array, coords_bytes, mem, buffers['pressures'].offset);
buffers['coords_from'].tv = tv_create_on(Uint32Array, stroke_bytes / 4, mem, buffers['coords_from'].offset); buffers['coords_from'].tv = tv_create_on(Uint32Array, stroke_bytes / 4, mem, buffers['coords_from'].offset);
buffers['width'].tv = tv_create_on(Uint32Array, stroke_bytes / 4, mem, buffers['width'].offset);
// TODO: this should have been automatic maybe? // TODO: this should have been automatic maybe?
buffers['xs'].tv.size = buffers['xs'].used / 4; buffers['xs'].tv.size = buffers['xs'].used / 4;
buffers['ys'].tv.size = buffers['ys'].used / 4; buffers['ys'].tv.size = buffers['ys'].used / 4;
buffers['pressures'].tv.size = buffers['pressures'].used; buffers['pressures'].tv.size = buffers['pressures'].used;
buffers['coords_from'].tv.size = buffers['coords_from'].used / 4; buffers['coords_from'].tv.size = buffers['coords_from'].used / 4;
buffers['width'].tv.size = buffers['width'].used / 4;
// TODO: this is SUS, should all the caps really be coords_bytes?
buffers['xs'].cap = buffers['ys'].cap = buffers['pressures'].cap = coords_bytes; buffers['xs'].cap = buffers['ys'].cap = buffers['pressures'].cap = coords_bytes;
buffers['coords_from'].cap = stroke_bytes; buffers['coords_from'].cap = buffers['width'].cap = stroke_bytes;
const tmp = new Uint8Array(Math.max(coords_bytes, stroke_bytes)); const tmp = new Uint8Array(Math.max(coords_bytes, stroke_bytes));
// Copy from back to front (otherwise we will overwrite) // Copy from back to front (otherwise we will overwrite)
tmp.set(new Uint8Array(mem, old_width_offset, buffers['width'].used));
memv.set(new Uint8Array(tmp.buffer, 0, buffers['width'].used), buffers['width'].offset);
tmp.set(new Uint8Array(mem, old_coords_from_offset, buffers['coords_from'].used)); tmp.set(new Uint8Array(mem, old_coords_from_offset, buffers['coords_from'].used));
memv.set(new Uint8Array(tmp.buffer, 0, buffers['coords_from'].used), buffers['coords_from'].offset); memv.set(new Uint8Array(tmp.buffer, 0, buffers['coords_from'].used), buffers['coords_from'].offset);
@ -180,6 +196,7 @@ async function do_lod(state, context) {
const indices_per_thread = Math.floor(context.clipped_indices.size / state.wasm.workers.length); const indices_per_thread = Math.floor(context.clipped_indices.size / state.wasm.workers.length);
const offsets = { const offsets = {
'coords_from': buffers['coords_from'].offset, 'coords_from': buffers['coords_from'].offset,
'width': buffers['width'].offset,
'xs': buffers['xs'].offset, 'xs': buffers['xs'].offset,
'ys': buffers['ys'].offset, 'ys': buffers['ys'].offset,
'pressures': buffers['pressures'].offset, 'pressures': buffers['pressures'].offset,

21
client/wasm/lod.c

@ -197,6 +197,7 @@ rdp_find_max(float *xs, float *ys, unsigned char *pressures, float zoom, int coo
void void
do_lod(int *clipped_indices, int clipped_count, float zoom, do_lod(int *clipped_indices, int clipped_count, float zoom,
int *stroke_coords_from, int *stroke_coords_from,
int *width,
float *xs, float *xs,
float *ys, float *ys,
unsigned char *pressures, unsigned char *pressures,
@ -280,18 +281,20 @@ do_lod(int *clipped_indices, int clipped_count, float zoom,
// Write actual coordinates (points) and stroke ids // Write actual coordinates (points) and stroke ids
// Do this in one allocation so that they're not interleaved between threads // Do this in one allocation so that they're not interleaved between threads
char *output = alloc_dynamic(segments_head * (3 * 4 + 1)); char *output = alloc_dynamic(segments_head * (3 * 4 + 1) + clipped_count * 4);
float *points = (float *) output; float *points = (float *) output;
int *ids = (int *) (output + segments_head * 4 * 2); int *ids = (int *) (output + segments_head * 4 * 2);
unsigned char *pressures_res = (unsigned char *) (output + segments_head * 4 * 3); unsigned char *pressures_res = (unsigned char *) (output + segments_head * 4 * 3);
unsigned int *batches = (unsigned int *) (output + segments_head * (4 * 3 + 1));
int phead = 0; int phead = 0;
int ihead = 0; int ihead = 0;
float sqrt_zoom = __builtin_sqrtf(zoom);
int last_lod = -1;
for (int i = 0; i < clipped_count; ++i) { for (int i = 0; i < clipped_count; ++i) {
int stroke_index = clipped_indices[i]; int stroke_index = clipped_indices[i];
// TODO: convert to a proper CSR, save half the memory
int base_stroke = stroke_coords_from[stroke_index]; int base_stroke = stroke_coords_from[stroke_index];
int from = segments_from[i]; int from = segments_from[i];
int to = segments_from[i + 1]; int to = segments_from[i + 1];
@ -312,6 +315,20 @@ do_lod(int *clipped_indices, int clipped_count, float zoom,
ids[ihead++] = stroke_index | (1 << 31); ids[ihead++] = stroke_index | (1 << 31);
} }
} }
// Compute recommended LOD level, add to current batch or start new batch
float sqrt_width = __builtin_sqrtf(width[stroke_index]); // TOOD: pass in stroke width
int lod = __builtin_round(sqrt_zoom * sqrt_width * 0.3333f);
#if 0
if (__builtin_abs(lod - last_lod) > 2) {
// Start new batch
} else {
// Add to existing batch
}
last_lod = lod;
#endif
} }
result_buffer[0] = output; result_buffer[0] = output;

BIN
client/wasm/lod.wasm

Binary file not shown.

2
client/webgl_draw.js

@ -305,7 +305,7 @@ async function draw(state, context, animate, ts) {
}); });
if (i % 2 == 1) { if (i % 2 == 1) {
batches[batches.length - 1].lod = Math.max(0, batches[batches.length - 1].lod - 4); batches[batches.length - 1].lod = Math.max(0, batches[batches.length - 1].lod);
} }
} }
batches.push({'index': segment_count, 'lod': -1}); // lod unused batches.push({'index': segment_count, 'lod': -1}); // lod unused

Loading…
Cancel
Save