add radial gpu option (work in progress)

This commit is contained in:
Stewart Allen 2025-10-31 17:35:26 -04:00
commit 49a63fad04
8 changed files with 118 additions and 24 deletions

2
app.js
View file

@ -578,6 +578,8 @@ function rewriteHtmlVersion(req, res, next) {
if ([
"/kiri/",
"/mesh/",
"/lib/gpu/raster.js",
"/lib/gpu/raster-worker.js",
"/lib/mesh/work.js",
"/lib/kiri/run/worker.js",
"/lib/kiri/run/minion.js",

View file

@ -39,6 +39,7 @@
"@gridspace/app-server": "github:gridspace/app-server#v0.0.19",
"@gridspace/basic-ftp": "github:gridspace/basic-ftp#v5.0.5-gridspace",
"@gridspace/net-level-client": "^0.2.3",
"@gridspace/raster-path": "github:gridspace/raster-path#main",
"@tracespace/parser": "^5.0.0-next.0",
"@tweenjs/tween.js": "^16.6.0",
"base64-js": "^1.5.1",

1
src/gpu/raster-worker.js Symbolic link
View file

@ -0,0 +1 @@
../../node_modules/@gridspace/raster-path/src/web/webgpu-worker.js

1
src/gpu/raster.js Symbolic link
View file

@ -0,0 +1 @@
../../node_modules/@gridspace/raster-path/src/index.js

View file

@ -943,6 +943,7 @@ export const conf = {
threaded: true,
units: "mm",
view: null,
webGPU: false,
zoomSpeed: 1.0,
},
// default hidden ui groups

View file

@ -142,26 +142,27 @@ function booleanSave() {
if (control.antiAlias != ui.antiAlias.checked) {
api.show.alert('Page Reload Required to Change Aliasing');
}
control.shiny = ui.shiny.checked;
control.antiAlias = ui.antiAlias.checked;
control.assembly = ui.assembly.checked;
control.autoLayout = ui.autoLayout.checked;
control.autoSave = ui.autoSave.checked;
control.dark = ui.dark.checked;
control.devel = ui.devel.checked;
control.drawer = ui.drawer.checked;
control.exportOcto = ui.exportOcto.checked;
control.exportPreview = ui.exportPreview.checked;
control.exportThumb = ui.exportThumb.checked;
control.freeLayout = ui.freeLayout.checked;
control.healMesh = ui.healMesh.checked;
control.ortho = ui.ortho.checked;
control.reverseZoom = ui.reverseZoom.checked;
control.scrolls = ui.scrolls.checked;
control.shiny = ui.shiny.checked;
control.showOrigin = ui.showOrigin.checked;
control.showRulers = ui.showRulers.checked;
control.autoLayout = ui.autoLayout.checked;
control.freeLayout = ui.freeLayout.checked;
control.spaceRandoX = ui.spaceRandoX.checked;
control.autoSave = ui.autoSave.checked;
control.antiAlias = ui.antiAlias.checked;
control.reverseZoom = ui.reverseZoom.checked;
control.dark = ui.dark.checked;
control.exportOcto = ui.exportOcto.checked;
control.exportThumb = ui.exportThumb.checked;
control.exportPreview = ui.exportPreview.checked;
control.healMesh = ui.healMesh.checked;
control.threaded = setThreaded(ui.threaded.checked);
control.assembly = ui.assembly.checked;
control.ortho = ui.ortho.checked;
control.devel = ui.devel.checked;
control.webGPU = ui.webGPU.checked;
space.view.setZoom(control.reverseZoom, control.zoomSpeed);
// platform.layout();
api.conf.save();
@ -1063,6 +1064,7 @@ function init_one() {
healMesh: newBoolean(LANG.pt_heal_s, booleanSave, {title: LANG.pt_heal_l}),
threaded: newBoolean(LANG.pt_thrd_s, booleanSave, {title: LANG.pt_thrd_l, modes:THREED}),
assembly: newBoolean(LANG.pt_assy_s, booleanSave, {title: LANG.pt_assy_l, modes:THREED}),
webGPU: newBoolean(LANG.pt_wgpu_s, booleanSave, {title: LANG.pt_wgpu_l, modes:THREED}),
prefadd: uc.checkpoint($('prefs-add')),
@ -1630,20 +1632,22 @@ function init_two() {
space.platform.setZOff(0.05);
// restore UI state from settings
ui.antiAlias.checked = control.antiAlias;
ui.assembly.checked = control.assembly;
ui.autoLayout.checked = control.autoLayout;
ui.autoSave.checked = control.autoSave;
ui.devel.checked = control.devel;
ui.freeLayout.checked = control.freeLayout;
ui.healMesh.checked = control.healMesh;
ui.ortho.checked = control.ortho;
ui.reverseZoom.checked = control.reverseZoom;
ui.showOrigin.checked = control.showOrigin;
ui.showRulers.checked = control.showRulers;
ui.showSpeeds.checked = control.showSpeeds;
ui.freeLayout.checked = control.freeLayout;
ui.autoLayout.checked = control.autoLayout;
ui.spaceRandoX.checked = control.spaceRandoX;
ui.antiAlias.checked = control.antiAlias;
ui.reverseZoom.checked = control.reverseZoom;
ui.autoSave.checked = control.autoSave;
ui.healMesh.checked = control.healMesh;
ui.threaded.checked = setThreaded(control.threaded);
ui.assembly.checked = control.assembly;
ui.ortho.checked = control.ortho;
ui.devel.checked = control.devel;
ui.webGPU.checked = control.webGPU;
lineTypeSave();
detailSave();
updateStats();

View file

@ -7,6 +7,7 @@ import { sliceConnect } from '../../../geo/slicer.js';
import { newSlice } from '../../core/slice.js';
import { Tool } from './tool.js';
import { Slicer as topo_slicer } from './slicer_topo.js';
import { RasterPath } from '../../../gpu/raster.js';
const RAD2DEG = 180 / Math.PI;
const DEG2RAD = Math.PI / 180;
@ -24,6 +25,7 @@ export class Topo {
let { state, op, onupdate, ondone } = opt;
let { widget, settings, tabs } = opt.state;
let { controller, process } = settings;
let { webGPU } = controller;
let axis = op.axis.toLowerCase(),
tool = new Tool(settings, op.tool),
@ -65,11 +67,14 @@ export class Topo {
this.lineColor = state.settings.controller.dark ? 0xffff00 : 0x555500;
this.offStart = op.offStart ?? 0;
this.offEnd = op.offEnd ?? 0;
this.bounds = bounds;
this.gpu = webGPU ?? false;
onupdate(0, "lathe");
const range = this.range = { min: Infinity, max: -Infinity };
const slices = this.sliced = await this.slice(scale(onupdate, 0.25, 0));
for (let slice of slices) {
range.min = Math.min(range.min, slice.z);
range.max = Math.max(range.max, slice.z);
@ -91,7 +96,6 @@ export class Topo {
const { vertices, resolution, tabverts, zoff, offStart, offEnd, tool, unit } = this;
const { minions } = self.kiri_worker;
const range = this.range = { min: Infinity, max: -Infinity };
const box = this.box = new THREE.Box2();
// swap XZ in shared array
for (let i = 0, l = vertices.length; i < l; i += 3) {
@ -119,6 +123,11 @@ export class Topo {
// re-create shared vertex array for workers
this.vertices = [].appendAll(vertices).appendAll(tabverts).toFloat32().toShared();
// rp.rasterizeMesh(vertices, resolution).then(rpo => console.log({ rpo }));
if (this.gpu) {
return await this.sliceGPU(onupdate);
}
const zSpan = range.max - range.min;
const shards = Math.ceil(Math.min(25, vertices.length / 27000));
const totalSteps = Math.ceil(zSpan / resolution);
@ -151,6 +160,73 @@ export class Topo {
}
}
async sliceGPU(onupdate) {
const { angle, linear, offStart, offEnd, resolution, tool, unit, vertices, zBottom } = this;
let gpu = new RasterPath({ workerName: "/lib/gpu/raster-worker.js" });
await gpu.init();
await gpu.initWorkerPool();
let tickperstep = Math.round(this.step / resolution);
let bounds = this.bounds.clone();
bounds.min.x += offStart * unit;
bounds.max.x -= offEnd * unit;
let output = await gpu.generateRadialToolpath(
vertices,
tool,
angle,
tickperstep,
zBottom,
resolution,
bounds,
(pct, msg) => { console.log({ pct, msg }) }
);
// console.log({ tool, output, tickperstep });
// const axis = new THREE.Vector3(1, 0, 0);
let { numRotations, pointsPerLine, pathData } = output;
let degPerRow = 360 / numRotations;
let slices = this.gpu_slices = [];
let xmult = tickperstep * resolution;
let xoff = bounds.min.x;
let rows = [];
for (let i=0; i<numRotations; i++) {
let lineData = pathData.slice(i * pointsPerLine, i * pointsPerLine + pointsPerLine);
let points = Array.from(lineData).map((v,j) => newPoint(j * xmult + xoff, 0, v).setA(-i * degPerRow));
// let points = Array.from(lineData).map((v,i) => [ i * xmult + xoff, 0, v ]).flat().toFloat32();
// let rot = new THREE.Matrix4().makeRotationAxis(axis, (Math.PI / numRotations * 2) * i);
// new THREE.BufferAttribute(points, 3).applyMatrix4(rot);
// points = Array.from(points).group(3).map((v,i) => newPoint(v[0], v[1], v[2]));
rows.push(points);
}
if (linear) {
for (let i=0; i<rows.length; i++) {
let slice = newSlice(i);
slice.index = i;
slice.camLines = [ newPolygon(rows[i]).setOpen() ];
if (i % 2 === 1) slice.camLines[0].reverse();
slices.push(slice);
}
} else {
for (let i=0; i<pointsPerLine; i++) {
let slice = newSlice(i);
let points = rows.map(row => row[i]);
// points.push(points[0].setA(points[0].a - 360));
if (i % 2 === 1) points.reverse();
slice.index = i;
slice.camLines = [ newPolygon(points).setOpen() ];
slices.push(slice);
}
}
for (let slice of slices) {
slice.output()
.setLayer("lathe", { line: this.lineColor })
.addPoly(slice.camLines[0].clone().applyRotations());
}
// console.log({ webGPU: output, slices });
return slices;
}
async sliceWorker(onupdate) {
const { vertices, slices, resolution } = this;
@ -215,13 +291,19 @@ export class Topo {
async lathe(onupdate) {
const { minions } = self.kiri_worker;
if (minions?.running > 1) {
if (this.gpu) {
return await this.latheGPU(onupdate);
} else if (minions?.running > 1) {
return await this.latheMinions(onupdate);
} else {
return await this.latheWorker(onupdate);
}
}
async latheGPU(onupdate) {
return this.gpu_slices;
}
lathePath(slices, tool) {
const { resolution, step, zBottom, maxo } = this;

View file

@ -323,6 +323,8 @@ self.lang['en-us'] = {
pt_thrd_l: ["use parallel processing when browser supports nested workers. may increase memory pressure on larger models. disable if you are getting out of memory errors"],
pt_assy_s: "assembly",
pt_assy_l: ["use web assembly when supported by browser. if you experience artifacts or memory errors, try disabling this."],
pt_wgpu_s: "web gpu",
pt_wgpu_l: ["use web gpu when supported by browser"],
xp_menu: "exports",