This commit is contained in:
parent
cafe9bff84
commit
10e99754d0
@ -7,12 +7,10 @@
|
|||||||
Float32BufferAttribute,
|
Float32BufferAttribute,
|
||||||
Vector3,
|
Vector3,
|
||||||
} from "three";
|
} from "three";
|
||||||
import { decodeFloat } from "@nodes/utils";
|
import { decodeFloat, fastHashArrayBuffer } from "@nodes/utils";
|
||||||
import type { PerformanceStore } from "$lib/performance";
|
import type { PerformanceStore } from "$lib/performance";
|
||||||
import { AppSettings } from "$lib/settings/app-settings";
|
import { AppSettings } from "$lib/settings/app-settings";
|
||||||
|
|
||||||
export let result: Int32Array;
|
|
||||||
|
|
||||||
export let centerCamera: boolean = true;
|
export let centerCamera: boolean = true;
|
||||||
export let perf: PerformanceStore;
|
export let perf: PerformanceStore;
|
||||||
|
|
||||||
@ -22,6 +20,22 @@
|
|||||||
let totalVertices = 0;
|
let totalVertices = 0;
|
||||||
let totalFaces = 0;
|
let totalFaces = 0;
|
||||||
|
|
||||||
|
function fastArrayHash(arr: ArrayBuffer) {
|
||||||
|
let ints = new Uint8Array(arr);
|
||||||
|
|
||||||
|
const sampleDistance = Math.max(Math.floor(ints.length / 100), 1);
|
||||||
|
const sampleCount = Math.floor(ints.length / sampleDistance);
|
||||||
|
|
||||||
|
let hash = new Uint8Array(sampleCount);
|
||||||
|
|
||||||
|
for (let i = 0; i < sampleCount; i++) {
|
||||||
|
const index = i * sampleDistance;
|
||||||
|
hash[i] = ints[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
return fastHashArrayBuffer(hash.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
function createGeometryFromEncodedData(
|
function createGeometryFromEncodedData(
|
||||||
encodedData: Int32Array,
|
encodedData: Int32Array,
|
||||||
geometry = new BufferGeometry(),
|
geometry = new BufferGeometry(),
|
||||||
@ -47,6 +61,10 @@
|
|||||||
vertexCount * 3,
|
vertexCount * 3,
|
||||||
);
|
);
|
||||||
index = index + vertexCount * 3;
|
index = index + vertexCount * 3;
|
||||||
|
let hash = fastArrayHash(vertices);
|
||||||
|
if (geometry.userData?.hash === hash) {
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
|
|
||||||
const normals = new Float32Array(
|
const normals = new Float32Array(
|
||||||
encodedData.buffer,
|
encodedData.buffer,
|
||||||
@ -90,6 +108,7 @@
|
|||||||
geometry.userData = {
|
geometry.userData = {
|
||||||
vertexCount,
|
vertexCount,
|
||||||
faceCount,
|
faceCount,
|
||||||
|
hash,
|
||||||
};
|
};
|
||||||
|
|
||||||
return geometry;
|
return geometry;
|
||||||
@ -153,11 +172,11 @@
|
|||||||
return positions;
|
return positions;
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if (result) {
|
export const update = function updateGeometries(result: Int32Array) {
|
||||||
let a = performance.now();
|
let a = performance.now();
|
||||||
const inputs = parse_args(result);
|
const inputs = parse_args(result);
|
||||||
let b = performance.now();
|
let b = performance.now();
|
||||||
perf?.addPoint("parse-args", b - a);
|
perf?.addPoint("split-result", b - a);
|
||||||
|
|
||||||
totalVertices = 0;
|
totalVertices = 0;
|
||||||
totalFaces = 0;
|
totalFaces = 0;
|
||||||
@ -185,14 +204,9 @@
|
|||||||
.filter(Boolean) as BufferGeometry[];
|
.filter(Boolean) as BufferGeometry[];
|
||||||
b = performance.now();
|
b = performance.now();
|
||||||
perf?.addPoint("create-geometries", b - a);
|
perf?.addPoint("create-geometries", b - a);
|
||||||
|
|
||||||
for (const geometry of geometries) {
|
|
||||||
geometry.needsUpdate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
perf?.addPoint("total-vertices", totalVertices);
|
perf?.addPoint("total-vertices", totalVertices);
|
||||||
perf?.addPoint("total-faces", totalFaces);
|
perf?.addPoint("total-faces", totalFaces);
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Canvas>
|
<Canvas>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { Graph, NodeRegistry, NodeDefinition, RuntimeExecutor, NodeInput } from "@nodes/types";
|
import type { Graph, NodeRegistry, NodeDefinition, RuntimeExecutor, NodeInput } from "@nodes/types";
|
||||||
import { concatEncodedArrays, encodeFloat, fastHashArray } from "@nodes/utils"
|
import { concatEncodedArrays, encodeFloat, fastHashArrayBuffer } from "@nodes/utils"
|
||||||
import { createLogger } from "./helpers";
|
import { createLogger } from "./helpers";
|
||||||
import type { RuntimeCache } from "@nodes/types";
|
import type { RuntimeCache } from "@nodes/types";
|
||||||
import type { PerformanceStore } from "./performance";
|
import type { PerformanceStore } from "./performance";
|
||||||
@ -138,7 +138,7 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
|
|||||||
const [outputNode, nodes] = await this.addMetaData(graph);
|
const [outputNode, nodes] = await this.addMetaData(graph);
|
||||||
let b = performance.now();
|
let b = performance.now();
|
||||||
|
|
||||||
this.perf?.addPoint("metadata", b - a);
|
this.perf?.addPoint("collect-metadata", b - a);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Here we sort the nodes into buckets, which we then execute one by one
|
* Here we sort the nodes into buckets, which we then execute one by one
|
||||||
@ -211,7 +211,10 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
|
|||||||
b = performance.now();
|
b = performance.now();
|
||||||
this.perf?.addPoint("encoded-inputs", b - a);
|
this.perf?.addPoint("encoded-inputs", b - a);
|
||||||
|
|
||||||
let inputHash = `node-${node.id}-${fastHashArray(encoded_inputs)}`;
|
a = performance.now();
|
||||||
|
let inputHash = `node-${node.id}-${fastHashArrayBuffer(encoded_inputs)}`;
|
||||||
|
b = performance.now();
|
||||||
|
this.perf?.addPoint("hash-inputs", b - a);
|
||||||
let cachedValue = this.cache?.get(inputHash);
|
let cachedValue = this.cache?.get(inputHash);
|
||||||
if (cachedValue !== undefined) {
|
if (cachedValue !== undefined) {
|
||||||
log.log(`Using cached value for ${node_type.id || node.id}`);
|
log.log(`Using cached value for ${node_type.id || node.id}`);
|
||||||
|
@ -14,11 +14,6 @@
|
|||||||
import NodeStore from "$lib/node-store/NodeStore.svelte";
|
import NodeStore from "$lib/node-store/NodeStore.svelte";
|
||||||
import type { GraphManager } from "$lib/graph-interface/graph-manager";
|
import type { GraphManager } from "$lib/graph-interface/graph-manager";
|
||||||
import { setContext } from "svelte";
|
import { setContext } from "svelte";
|
||||||
import {
|
|
||||||
decodeFloat,
|
|
||||||
decodeNestedArray,
|
|
||||||
encodeNestedArray,
|
|
||||||
} from "@nodes/utils";
|
|
||||||
import ActiveNodeSettings from "$lib/settings/panels/ActiveNodeSettings.svelte";
|
import ActiveNodeSettings from "$lib/settings/panels/ActiveNodeSettings.svelte";
|
||||||
import PerformanceViewer from "$lib/performance/PerformanceViewer.svelte";
|
import PerformanceViewer from "$lib/performance/PerformanceViewer.svelte";
|
||||||
import Panel from "$lib/settings/Panel.svelte";
|
import Panel from "$lib/settings/Panel.svelte";
|
||||||
@ -26,28 +21,22 @@
|
|||||||
import NestedSettings from "$lib/settings/panels/NestedSettings.svelte";
|
import NestedSettings from "$lib/settings/panels/NestedSettings.svelte";
|
||||||
import { createPerformanceStore } from "$lib/performance";
|
import { createPerformanceStore } from "$lib/performance";
|
||||||
import { type PerformanceData } from "$lib/performance/store";
|
import { type PerformanceData } from "$lib/performance/store";
|
||||||
import { RemoteRuntimeExecutor } from "$lib/remote-runtime-executor";
|
|
||||||
|
|
||||||
const nodeRegistry = new RemoteNodeRegistry("");
|
const nodeRegistry = new RemoteNodeRegistry("");
|
||||||
const workerRuntime = new WorkerRuntimeExecutor();
|
const workerRuntime = new WorkerRuntimeExecutor();
|
||||||
// const remoteRuntime = new RemoteRuntimeExecutor("/runtime");
|
|
||||||
|
|
||||||
let performanceData: PerformanceData;
|
let performanceData: PerformanceData;
|
||||||
let viewerPerformance = createPerformanceStore();
|
let viewerPerformance = createPerformanceStore();
|
||||||
|
|
||||||
globalThis.decode = decodeNestedArray;
|
|
||||||
globalThis.encode = encodeNestedArray;
|
|
||||||
globalThis.decodeFloat = decodeFloat;
|
|
||||||
|
|
||||||
let res: Int32Array;
|
let res: Int32Array;
|
||||||
let activeNode: Node | undefined;
|
let activeNode: Node | undefined;
|
||||||
|
|
||||||
|
let updateViewer: (arg: Int32Array) => void;
|
||||||
|
|
||||||
let graph = localStorage.getItem("graph")
|
let graph = localStorage.getItem("graph")
|
||||||
? JSON.parse(localStorage.getItem("graph")!)
|
? JSON.parse(localStorage.getItem("graph")!)
|
||||||
: templates.plant;
|
: templates.plant;
|
||||||
|
|
||||||
console.log({ graph });
|
|
||||||
|
|
||||||
let manager: GraphManager;
|
let manager: GraphManager;
|
||||||
let managerStatus: Writable<"loading" | "error" | "idle">;
|
let managerStatus: Writable<"loading" | "error" | "idle">;
|
||||||
$: if (manager) {
|
$: if (manager) {
|
||||||
@ -80,8 +69,9 @@
|
|||||||
try {
|
try {
|
||||||
let a = performance.now();
|
let a = performance.now();
|
||||||
// res = await remoteRuntime.execute(_graph, _settings);
|
// res = await remoteRuntime.execute(_graph, _settings);
|
||||||
res = await workerRuntime.execute(_graph, _settings);
|
let res = await workerRuntime.execute(_graph, _settings);
|
||||||
let b = performance.now();
|
let b = performance.now();
|
||||||
|
updateViewer(res);
|
||||||
let perfData = await workerRuntime.getPerformanceData();
|
let perfData = await workerRuntime.getPerformanceData();
|
||||||
let lastRun = perfData.runs?.at(-1);
|
let lastRun = perfData.runs?.at(-1);
|
||||||
if (lastRun) {
|
if (lastRun) {
|
||||||
@ -125,7 +115,7 @@
|
|||||||
<Grid.Row>
|
<Grid.Row>
|
||||||
<Grid.Cell>
|
<Grid.Cell>
|
||||||
<Viewer
|
<Viewer
|
||||||
result={res}
|
bind:update={updateViewer}
|
||||||
perf={viewerPerformance}
|
perf={viewerPerformance}
|
||||||
centerCamera={$AppSettings.centerCamera}
|
centerCamera={$AppSettings.centerCamera}
|
||||||
/>
|
/>
|
||||||
|
@ -13,7 +13,7 @@ export interface NodeRegistry {
|
|||||||
* @throws An error if the nodes could not be loaded
|
* @throws An error if the nodes could not be loaded
|
||||||
* @remarks This method should be called before calling getNode or getAllNodes
|
* @remarks This method should be called before calling getNode or getAllNodes
|
||||||
*/
|
*/
|
||||||
load: (nodeIds: (NodeId | string)[]) => Promise<NodeDefinition[]>;
|
load: (nodeIds: NodeId[]) => Promise<NodeDefinition[]>;
|
||||||
/**
|
/**
|
||||||
* Get a node by id
|
* Get a node by id
|
||||||
* @param id - The id of the node to get
|
* @param id - The id of the node to get
|
||||||
|
@ -14,10 +14,10 @@ test("fastHashArray doesnt product collisions", () => {
|
|||||||
|
|
||||||
const a = new Int32Array(1000);
|
const a = new Int32Array(1000);
|
||||||
|
|
||||||
const hash_a = fastHashArray(a);
|
const hash_a = fastHashArray(a.buffer);
|
||||||
a[0] = 1;
|
a[0] = 1;
|
||||||
|
|
||||||
const hash_b = fastHashArray(a);
|
const hash_b = fastHashArray(a.buffer);
|
||||||
|
|
||||||
expect(hash_a).not.toEqual(hash_b);
|
expect(hash_a).not.toEqual(hash_b);
|
||||||
|
|
||||||
@ -28,13 +28,13 @@ test('fastHashArray is fast(ish) < 20ms', () => {
|
|||||||
const a = new Int32Array(10_000);
|
const a = new Int32Array(10_000);
|
||||||
|
|
||||||
const t0 = performance.now();
|
const t0 = performance.now();
|
||||||
fastHashArray(a);
|
fastHashArray(a.buffer);
|
||||||
|
|
||||||
const t1 = performance.now();
|
const t1 = performance.now();
|
||||||
|
|
||||||
a[0] = 1;
|
a[0] = 1;
|
||||||
|
|
||||||
fastHashArray(a);
|
fastHashArray(a.buffer);
|
||||||
|
|
||||||
const t2 = performance.now();
|
const t2 = performance.now();
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ test('fastHashArray is deterministic', () => {
|
|||||||
a[42] = 69;
|
a[42] = 69;
|
||||||
const b = new Int32Array(1000);
|
const b = new Int32Array(1000);
|
||||||
b[42] = 69;
|
b[42] = 69;
|
||||||
const hashA = fastHashArray(a);
|
const hashA = fastHashArray(a.buffer);
|
||||||
const hashB = fastHashArray(b);
|
const hashB = fastHashArray(b.buffer);
|
||||||
expect(hashA).toEqual(hashB);
|
expect(hashA).toEqual(hashB);
|
||||||
});
|
});
|
||||||
|
@ -83,8 +83,8 @@ function sha256(data?: string | Uint8Array) {
|
|||||||
return { add, digest };
|
return { add, digest };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fastHashArray(arr: Int32Array): string {
|
export function fastHashArrayBuffer(buffer: ArrayBuffer): string {
|
||||||
return sha256(new Uint8Array(arr.buffer)).digest();
|
return sha256(new Uint8Array(buffer)).digest();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shamelessly copied from
|
// Shamelessly copied from
|
||||||
|
Loading…
Reference in New Issue
Block a user