From 3bf812df397365163c79814c559561e07c020473 Mon Sep 17 00:00:00 2001 From: "A.Olokhtonov" Date: Sat, 13 Jan 2024 14:26:27 +0300 Subject: [PATCH] Move point writes to WASM, already a lot faster!!!! --- client/speed.js | 55 +++++++++++++++++++++++++++++++++++++-- client/wasm/lod.c | 31 ++++++++++++++++++++++ client/wasm/lod.wasm | Bin 1272 -> 1558 bytes client/webgl_geometry.js | 40 +--------------------------- 4 files changed, 85 insertions(+), 41 deletions(-) diff --git a/client/speed.js b/client/speed.js index 0cff410..28406d0 100644 --- a/client/speed.js +++ b/client/speed.js @@ -52,7 +52,6 @@ function do_lod_wasm(state, context) { const segments_from = state.wasm.exports.alloc((context.clipped_indices.size + 1) * 4); const segments = state.wasm.exports.alloc(state.segments.capacity * 4); const coordinates = state.wasm.exports.alloc(state.coordinates.size * 4); - const mem = new Uint8Array(state.wasm.exports.memory.buffer); mem.set(tv_bytes(context.clipped_indices), clipped_indices); @@ -71,6 +70,8 @@ function do_lod_wasm(state, context) { // copy result back const wasm_segments = new Uint32Array(state.wasm.exports.memory.buffer, segments, segment_count); const wasm_segments_from = new Uint32Array(state.wasm.exports.memory.buffer, segments_from, context.clipped_indices.size + 1); + const wasm_points = new Float32Array(state.wasm.exports.memory.buffer, coordinates + state.coordinates.size * 4, segment_count * 2); + const wasm_ids = new Uint32Array(state.wasm.exports.memory.buffer, coordinates + (state.coordinates.size + segment_count * 2) * 4, segment_count); state.segments.data.set(wasm_segments); state.segments.size = segment_count; @@ -78,8 +79,16 @@ function do_lod_wasm(state, context) { state.segments_from.data.set(wasm_segments_from); state.segments_from.size = context.clipped_indices.size + 1; - state.wasm.exports.total_free(); + tv_ensure(context.instance_data_points, segment_count * 2); + tv_ensure(context.instance_data_ids, segment_count); + context.instance_data_points.data.set(wasm_points); + context.instance_data_points.size = segment_count * 2; + + context.instance_data_ids.data.set(wasm_ids); + context.instance_data_ids.size = segment_count; + + state.wasm.exports.total_free(); return segment_count; } @@ -164,5 +173,47 @@ function do_lod(state, context) { state.segments_from.size = context.clipped_indices.size + 1; state.segments.size = segments_head; + write_coordinates(state, context); + return segments_head; } + +function write_coordinates(state, context) { + tv_ensure(context.instance_data_points, state.segments.size * 2); + tv_ensure(context.instance_data_ids, state.segments.size); + + tv_clear(context.instance_data_points); + tv_clear(context.instance_data_ids); + + const clipped = context.clipped_indices.data; + const segments_from = state.segments_from.data; + const segments = state.segments.data; + const coords = state.coordinates.data; + const events = state.events; + + // TODO: move this loop to WASM + for (let i = 0; i < state.segments_from.size - 1; ++i) { + const stroke_index = clipped[i]; + const coords_from = state.events[stroke_index].coords_from; + const from = segments_from[i]; + const to = segments_from[i + 1]; + + for (let j = from; j < to; ++j) { + const base_this = segments[j]; + + const ax = coords[coords_from + base_this * 2 + 0]; + const ay = coords[coords_from + base_this * 2 + 1]; + + tv_add(context.instance_data_points, ax); + tv_add(context.instance_data_points, ay); + + // Pack 1 into highest bit of stroke_index if we should not draw a segemtn from this + // point to the next one + if (j != to - 1) { + tv_add(context.instance_data_ids, stroke_index); + } else { + tv_add(context.instance_data_ids, stroke_index | (1 << 31)); + } + } + } +} diff --git a/client/wasm/lod.c b/client/wasm/lod.c index d911079..eddf487 100644 --- a/client/wasm/lod.c +++ b/client/wasm/lod.c @@ -130,6 +130,37 @@ do_lod(int *clipped_indices, int clipped_count, float zoom, } segments_from[clipped_count] = segments_head; + + // Write actual coordinates (points) and stroke ids + float *points = alloc(segments_head * 2 * 4); + int *ids = alloc(segments_head * 4); + + int phead = 0; + int ihead = 0; + + for (int i = 0; i < clipped_count; ++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 from = segments_from[i]; + int to = segments_from[i + 1]; + + for (int j = from; j < to; ++j) { + int point_index = segments[j]; + float x = coordinates[base_stroke + point_index * 2 + 0]; + float y = coordinates[base_stroke + point_index * 2 + 1]; + + points[phead++] = x; + points[phead++] = y; + + if (j != to - 1) { + ids[ihead++] = stroke_index; + } else { + ids[ihead++] = stroke_index | (1 << 31); + } + } + } return(segments_head); } diff --git a/client/wasm/lod.wasm b/client/wasm/lod.wasm index 9c0c4f3afbec8bd83913d27dbc601ef795928d7e..67a51637c639c79427e1b1f192d1e25b9f18de34 100755 GIT binary patch literal 1558 zcmZuxOH#tiQ!ek32`JdnH@E<>^dtRnORE} z7}b&`g{nTcGwFYLUvV;Vx8!x+yes}cl>eo@H00$X*hxCIzvXgu5>00Fw@P?H@CJtm z!*DzfhUsjc2w|tQG#m%7=TRi&5)8AUP)-n>M&U(p943(^tD{*ko{fan41!TI3r@r7 zXdGF}#x_jDAexRW3n57w4$tBF#;U-x+?}4CoLWn*AUGM%j&V+rv5LqdKS$PJECH6r zI%3oCcpR16hW%H)qJ+~DK7M;Df1l^V*_JZn{Z6?zl0>|)5%cvf7qRnCty;p?O2qZ3OCG-m1JkGOx%SAVe$3MPB72+Nb)QzrEhLu&l}S4&KhLk`dV}iJ zEsR~VsI$ng2Ss%rN?X@%Q#sV9m6)p31tMRjG>F;rkrL08z_GA(XoGqK)K5J>E719s zSa+%K*BOGxN+4vVO8^$@c2hWxLluBpMmE#q%2@DNK#T=?Sn8nsUP&&{7A*1v2!QIG z`)UFzY+r)OqK!+4G7r80bDxnq{1GM8X_e6yz!1g_ZoClBEJ2MzXFlIkbzkXCYL*Ou zKud3^eRO2QtoZWhmZTL%HlRjqJpU>-HUn#80vfPf$7X|1Fl$_a4(Oi7fxR}pIm&0hD$R@;LlqAt;_xP=B z{tz9Xg;N@i!|93hbnnU6Pxff%>35IBmu?!)Pogw<9fj%TJWAAKcXC6I*8BU z5BL;*gAUG}MHy)|cklC@bLV^UC;j3Z*xft_lx~5~CKwj*+0ZCfG$4kewTa5i+I( zujFTp$vbb}+lo#d>@*G@v@COb4~=sBFq`M46iuZFm2U&<1W5L_d84v_|z`A@+e39xw_lQMQ4+_9v)6G5(D^rPB1Yc2q%5f+YZ!Epfmm2^nP+UnvXU+A3M2hKP0*JDhe{ZgGY<)OOpOFV3OZfc-Wf+;~oXr8Nz( zX2f1tppH~XS$I)cA>UJJafC|PpY&TwaVYX>aS7-?D2*=u^3<#79|uIqGQa;nqw&LF z8_Yz*Sx&jtD^9yxCU>S7G%}crek+UKgLz_>Op3y1d{@-Fgls0y`HFO0jXb38&EVHR DzXo#j diff --git a/client/webgl_geometry.js b/client/webgl_geometry.js index 0b252bd..da0740b 100644 --- a/client/webgl_geometry.js +++ b/client/webgl_geometry.js @@ -49,47 +49,9 @@ function geometry_write_instances(state, context) { const segment_count = do_lod(state, context); - tv_ensure(context.instance_data_points, state.segments.size * 2); - tv_ensure(context.instance_data_ids, state.segments.size); - - tv_clear(context.instance_data_points); - tv_clear(context.instance_data_ids); - - const clipped = context.clipped_indices.data; - const segments_from = state.segments_from.data; - const segments = state.segments.data; - const coords = state.coordinates.data; - const events = state.events; - - // TODO: move this loop to WASM - for (let i = 0; i < state.segments_from.size - 1; ++i) { - const stroke_index = clipped[i]; - const coords_from = state.events[stroke_index].coords_from; - const from = segments_from[i]; - const to = segments_from[i + 1]; - - for (let j = from; j < to; ++j) { - const base_this = segments[j]; - - const ax = coords[coords_from + base_this * 2 + 0]; - const ay = coords[coords_from + base_this * 2 + 1]; - - tv_add(context.instance_data_points, ax); - tv_add(context.instance_data_points, ay); - - // Pack 1 into highest bit of stroke_index if we should not draw a segemtn from this - // point to the next one - if (j != to - 1) { - tv_add(context.instance_data_ids, stroke_index); - } else { - tv_add(context.instance_data_ids, stroke_index | (1 << 31)); - } - } - } - if (config.debug_print) console.debug('instances:', state.segments.count, 'rdp max:', state.stats.rdp_max_count, 'rdp segments:', state.stats.rdp_segments); - return state.segments.size; + return segment_count; } function geometry_add_stroke(state, context, stroke, stroke_index, skip_bvh = false) {