From 849a55439bdb8866618cd90de67ff0ea3a92695d Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Mon, 9 Jan 2023 14:55:17 -0500 Subject: [PATCH] checkpoint prototype --- src/add/array.js | 6 +++ src/kiri-mode/cam/driver.js | 2 +- src/kiri-mode/cam/ops.js | 2 +- src/kiri-mode/cam/slice.js | 2 +- src/kiri-mode/cam/slicer2.js | 71 +++++++++++++++++++++++++++++++----- src/kiri-mode/cam/topo.js | 14 ++++++- src/kiri-run/minion.js | 29 +++++++++------ src/kiri-run/worker.js | 42 ++++++++++++++------- src/kiri/client.js | 25 ++++++++++++- src/kiri/files.js | 2 + src/kiri/widget.js | 21 ++++++----- src/moto/broker.js | 3 +- 12 files changed, 169 insertions(+), 50 deletions(-) diff --git a/src/add/array.js b/src/add/array.js index 7d645a38..c9c603ce 100644 --- a/src/add/array.js +++ b/src/add/array.js @@ -227,6 +227,12 @@ for (let i in AP) { }); } +Float32Array.prototype.toShared = function() { + const newvert = new Float32Array(new SharedArrayBuffer(this.buffer.byteLength)); + newvert.set(this); + return newvert; +}; + String.prototype.reverse = function() { return this.split('').reverse().join(''); }; diff --git a/src/kiri-mode/cam/driver.js b/src/kiri-mode/cam/driver.js index 3ee61216..96550378 100644 --- a/src/kiri-mode/cam/driver.js +++ b/src/kiri-mode/cam/driver.js @@ -82,7 +82,7 @@ kiri.load(api => { if (!widget.tool) { let tool = widget.tool = new mesh.tool(); let translate = index ? true : false; - tool.index(widget.getGeoVertices(true, translate)); + tool.index(widget.getGeoVertices({ unroll: true, translate })); } }; diff --git a/src/kiri-mode/cam/ops.js b/src/kiri-mode/cam/ops.js index 9f2b60ac..9a4072c7 100644 --- a/src/kiri-mode/cam/ops.js +++ b/src/kiri-mode/cam/ops.js @@ -1136,7 +1136,7 @@ class OpPocket extends CamOp { } } let surfaces = op.surfaces[widget.id] || []; - let vert = widget.getGeoVertices(true,true).map(v => v.round(4)); + let vert = widget.getGeoVertices({ unroll: true, translate: true }).map(v => v.round(4)); // let vert = widget.getVertices().array.map(v => v.round(4)); let outline = []; let faces = CAM.surface_find(widget, surfaces); diff --git a/src/kiri-mode/cam/slice.js b/src/kiri-mode/cam/slice.js index c12f7ce3..1282046d 100644 --- a/src/kiri-mode/cam/slice.js +++ b/src/kiri-mode/cam/slice.js @@ -245,7 +245,7 @@ CAM.slice = async function(settings, widget, onupdate, ondone) { tracker.rotation = isIndexed ? axisRotation : 0; // setup new state when indexing the workspace if (true && op.op.type === "index") { - let points = base.verticesToPoints(widget.getGeoVertices(true, true)); + let points = base.verticesToPoints(widget.getGeoVertices({ unroll: true, translate: true })); state.slicer = new kiri.cam_slicer(points, { zlist: true, zline: true diff --git a/src/kiri-mode/cam/slicer2.js b/src/kiri-mode/cam/slicer2.js index 2c3a033a..39c9ae49 100644 --- a/src/kiri-mode/cam/slicer2.js +++ b/src/kiri-mode/cam/slicer2.js @@ -3,8 +3,10 @@ "use strict"; /** - * Slicing engine used by CAM + * Slicing engine used by CAM Topo */ + +// dep: moto.broker // dep: kiri.slice gapp.register("kiri-mode.cam.slicer2", [], (root, exports) => { @@ -13,6 +15,10 @@ const { config, newOrderedLine, newPoint } = base; class Slicer { + static intersectPoints = intersectPoints; + static checkOverUnderOn = checkOverUnderOn; + static removeDuplicateLines = removeDuplicateLines; + constructor() { this.min = Infinity; this.max = -Infinity; @@ -80,13 +86,13 @@ class Slicer { const zMax = this.max; const phash = {}; const lines = []; - + let { under, over, both } = options; let p1, p2, p3; - + // default to 'over' selection with 2 points on a line if (!under && !both) over = true; - + // iterate over matching buckets for this z offset for (let i = 0; i < points.length; ) { p1 = points[i++]; @@ -127,11 +133,11 @@ class Slicer { } } } - + if (lines.length == 0 && options.noEmpty) { return; } - + return removeDuplicateLines(lines); } @@ -311,9 +317,56 @@ function removeDuplicateLines(lines, debug) { return output; } -Slicer.checkOverUnderOn = checkOverUnderOn; -Slicer.intersectPoints = intersectPoints; +moto.broker.subscribe("worker.started", msg => { + const { dispatch, minions } = msg; + // console.log({ cam_slicer2_worker: dispatch }); + kiri.topo_slice = async (widget, resolution) => { + console.log({ topo_slice: widget, resolution }); + const vertices = widget.getGeoVertices().toShared(); + const range = { min: Infinity, max: -Infinity }; + for (let i=0,l=vertices.length; i { + console.log({ put_cache_done: data }); + }}); -kiri.cam_slicer2 = Slicer; + dispatch.clearCache({}, { done: data => { + console.log({ clear_cache_done: data }); + }}); + return []; + } else { + console.time('nuslice'); + // iterate over shards, merge output + const output = new Slicer() + .setFromArray(vertices) + .slice(resolution) + .map(rec => { + const slice = kiri.newSlice(rec.z); + slice.lines = rec.lines; + for (let line of rec.lines) { + const { p1, p2 } = line; + if (!p1.swapped) { p1.swapXZ(); p1.swapped = true } + if (!p2.swapped) { p2.swapXZ(); p2.swapped = true } + } + return slice; + }); + console.log({ output }); + console.timeEnd('nuslice'); + return output; + } + }; +}); + +moto.broker.subscribe("minion.started", funcs => { + // console.log({ cam_slicer2_minion: funcs }); +}); }); diff --git a/src/kiri-mode/cam/topo.js b/src/kiri-mode/cam/topo.js index 6251b1e9..505b2866 100644 --- a/src/kiri-mode/cam/topo.js +++ b/src/kiri-mode/cam/topo.js @@ -439,7 +439,16 @@ class Topo { ondone(newslices); } - let points = base.verticesToPoints(widget.getGeoVertices(true, true)); + console.log('get vertices and points'); + let points = base.verticesToPoints(widget.getGeoVertices({ unroll: true, translate: true })); + + console.log('topo slice 2'); + const slices2 = await kiri.topo_slice(widget, resolution); + console.log({ topo_slice_done: slices2 }); + processSlices(slices2); + return this; + + console.log('old slice setup') let slicer = new kiri.cam_slicer(points, { swapX: true, emptyok: true, notopok: true }); @@ -448,12 +457,15 @@ class Topo { if (contourX) stepsTotal += Math.round((maxY-minY) / toolStep); if (contourY) stepsTotal += Math.round((maxX-minX) / toolStep); + console.log('old slice run', stepsTotal) let slices = topo.slices = topo.slices || slicer.slice(sindex, { each: (data, index, total) => { onupdate(++stepsTaken, stepsTotal, "topo slice"); }, genso: true }); + console.log('process slices', stepsTaken) processSlices(slices.filter(s => s.lines).map(data => data.slice)); + console.log('process done', stepsTaken) // const t0 = Date.now(); // for (let point of points) point.swapXZ(); // let lines = new kiri.cam_slicer2().setFromPoints(points).slice(resolution); diff --git a/src/kiri-run/minion.js b/src/kiri-run/minion.js index 0c926504..3f91f600 100644 --- a/src/kiri-run/minion.js +++ b/src/kiri-run/minion.js @@ -3,6 +3,7 @@ "use strict"; // dep: moto.license +// dep: moto.broker // dep: geo.base // dep: geo.polygons // dep: geo.slicer @@ -10,6 +11,7 @@ // dep: kiri.codec // dep: kiri-mode.fdm.post // use: kiri-mode.cam.slicer +// dep: kiri-mode.cam.slicer2 // dep: ext.clip2 gapp.register("kiri-run.minion", [], (root, exports) => { @@ -22,8 +24,8 @@ const clib = self.ClipperLib; const ctyp = clib.ClipType; const ptyp = clib.PolyType; const cfil = clib.PolyFillType; -const cache = self.cache = {}; +let cache = self.cache = {}; let name = "unknown"; // catch clipper alerts and convert to console messages @@ -45,7 +47,7 @@ function log() { console.log(`[${name}]`, ...arguments); } -const funcs = { +const funcs = self.minion = { label(data, seq) { name = data.name; }, @@ -138,19 +140,20 @@ const funcs = { }); }, - camSetPoints: data => { - const points = new Float32Array(data.data); - let i = 0, p = 0, realp = new Array(points.length / 3); - while (i < points.length) { - realp[p++] = base.newPoint(points[i++], points[i++], points[i++]).round(3); + putCache: msg => { + const { key, data } = msg; + log({ minion_putCache: key, data }); + if (data) { + console.log({ minion_put_cache: key, data }); + cache[key] = data; + } else { + console.log({ minion_del_cache: key }); + delete cache[key]; } - // log({ camSetPoints: points, realp }); - cache.camPoints = realp; }, - camClearPoints: data => { - // log({ camClearPoints: data }); - delete cache.camPoints; + clearCache: msg => { + cache = self.cache = []; }, wasm: data => { @@ -166,4 +169,6 @@ const funcs = { } }; +moto.broker.publish("minion.started", funcs); + }); diff --git a/src/kiri-run/worker.js b/src/kiri-run/worker.js index 513946e6..933c5a5d 100644 --- a/src/kiri-run/worker.js +++ b/src/kiri-run/worker.js @@ -8,6 +8,7 @@ // dep: kiri.codec // dep: kiri.slice // dep: moto.license +// dep: moto.broker // use: load.png // use: ext.jszip // use: kiri.render @@ -230,19 +231,10 @@ kiri.minions = { } }, - wasm(enable) { - for (let minion of minions) { - minion.postMessage({ - cmd: "wasm", - enable - }); - } - }, - broadcast(cmd, data, direct) { for (let minion of minions) { minion.postMessage({ - cmd, data + cmd, ...data }, direct); } } @@ -252,6 +244,7 @@ console.log(`kiri | init work | ${gapp.version || "rogue"}`); // code is running in the worker / server context const dispatch = +self.worker = kiri.server = kiri.worker = { pool_start(data, send) { @@ -326,8 +319,11 @@ kiri.worker = { group.id = data.group; wgroup[data.group] = group; } - let vertices = new Float32Array(data.vertices), - widget = kiri.newWidget(data.id, group).loadVertices(vertices).setInWorker(); + + let vertices = data.vertices, + widget = kiri.newWidget(data.id, group) + .setInWorker() + .loadVertices(vertices); // do it here so cancel can work wcache[data.id] = widget; @@ -623,8 +619,26 @@ kiri.worker = { } else { wasm_ctrl.disable(); } - minwork.wasm(data.enable); + minwork.broadcast("wasm", { enable: data.enable ? true : false }); send.done({ wasm: data }); + }, + + putCache(msg, send) { + const { key, data } = msg; + console.log({ worker_putCache: key, data }); + if (data) { + pcache[key] = data; + } else { + delete pcache[key]; + } + minwork.broadcast("putCache", msg); + send.done({ ok: true }); + }, + + clearCache(msg, send) { + pcache = {}; + minwork.broadcast("clearCache", msg); + send.done({ ok: true }); } }; @@ -686,6 +700,8 @@ dispatch.onmessage = self.onmessage = function(e) { } }; +moto.broker.publish("worker.started", { dispatch, minions: minwork }); + }); // load kiri modules diff --git a/src/kiri/client.js b/src/kiri/client.js index 1c1c1dc2..a40d2feb 100644 --- a/src/kiri/client.js +++ b/src/kiri/client.js @@ -18,6 +18,7 @@ let loc = self.location, syncd = {}, running = {}, worker = null, + minions = false, restarting = false // occ = new Worker("/kiri/ext/occ-worker.js", {type:"module"}), ; @@ -56,10 +57,12 @@ const client = exports({ pool: { start() { + minions = true; send("pool_start", {}, noop); }, stop() { + minions = false; send("pool_stop", {}, noop); } }, @@ -126,6 +129,11 @@ const client = exports({ } }; + // restart minions if they were running + if (minions) { + client.pool.start(); + } + restarting = false; }, @@ -166,7 +174,7 @@ const client = exports({ widgets.forEach(widget => { if (widget.modified || !syncd[widget.id]) { syncd[widget.id] = true; - let vertices = widget.getGeoVertices().buffer.slice(0); + let vertices = widget.getGeoVertices(); send("sync", { id: widget.id, meta: widget.meta, @@ -176,7 +184,7 @@ const client = exports({ position: widget.mesh.position, }, done => { widget.modified = false; - }, [vertices]); + }); } }); }, @@ -303,6 +311,19 @@ const client = exports({ send("wasm", {enable}, reply => { // console.log({wasm_worker_said: reply}); }); + }, + + putCache(key, data) { + console.log({ putCache: key, data }); + send("putCache", {key, data}, reply => { + // console.log({ putCache_reply: reply }); + }); + }, + + clearCache() { + send("clearCache", {}, reply => { + // console.log({ clearCache_reply: reply }); + }); } }); diff --git a/src/kiri/files.js b/src/kiri/files.js index 3d17e544..609d49e7 100644 --- a/src/kiri/files.js +++ b/src/kiri/files.js @@ -73,6 +73,8 @@ class Files { * @param {Function} [callback] */ putFile(name, vertices, callback) { + console.log({ putFile: name, vertices }); + let mark = Date.now(); let store = this; let pdb = store.db.promise(); diff --git a/src/kiri/widget.js b/src/kiri/widget.js index 196c6e31..828cbe23 100644 --- a/src/kiri/widget.js +++ b/src/kiri/widget.js @@ -104,7 +104,7 @@ class Widget { } const widget = this; const mark = time(); - const vertices = this.getGeoVertices(true); + const vertices = widget.getGeoVertices({ unroll: true }).slice(); widget.meta.file = filename; widget.meta.save = mark; catalog().putFile(filename, vertices, () => { @@ -123,8 +123,9 @@ class Widget { return; } const widget = this; + console.log({ saveState: widget.id }); index().put('ws-save-'+this.id, { - geo: widget.getGeoVertices(false), + geo: widget.getGeoVertices({ unroll: false }).slice(), track: widget.track, group: this.group.id, meta: this.meta, @@ -152,6 +153,7 @@ class Widget { * @returns {Widget} */ loadVertices(data, options = { index: false }) { + // console.log({ loadVertices: this.id, worker: this.inWorker, data }); let vertices, autoscale = false; if (ArrayBuffer.isView(data) || typeof(data) != 'object') { @@ -160,12 +162,12 @@ class Widget { vertices = data.vertices; throw "deprecated vertex data format"; } - // will not serialize into indexeddb -- need a performance sensitive workaround - // if (window.SharedArrayBuffer) { - // let newvert = new Float32Array(new SharedArrayBuffer(vertices.buffer.byteLength)); - // newvert.set(vertices); - // vertices = newvert; - // } + if (!(vertices.buffer && vertices.buffer instanceof SharedArrayBuffer)) { + // console.log('converting to shared vertices'); + let newvert = new Float32Array(new SharedArrayBuffer(vertices.buffer.byteLength)); + newvert.set(vertices); + vertices = newvert; + } switch (typeof(autoscale)) { case 'boolean': autoscale = options; @@ -610,7 +612,8 @@ class Widget { this.points = null; } - getGeoVertices(unroll, translate) { + getGeoVertices(opt = {}) { + const { unroll, translate } = opt; let geo = this.mesh.geometry; let pos = geo.getAttribute('position'); // if indexed, return points rotated about X and then offset diff --git a/src/moto/broker.js b/src/moto/broker.js index 6b26f9cb..81b7b728 100644 --- a/src/moto/broker.js +++ b/src/moto/broker.js @@ -39,7 +39,7 @@ class Broker { for (let t of topic) { this.subscribe(t, listener); } - return; + return this; } if (typeof topic !== 'string') { console.trace({invalid_topic: topic}); @@ -57,6 +57,7 @@ class Broker { channel.push(listener); this.publish(".topic.add", topic); } + return this; } unsubscribe(topic, listener) {