feat: make all nodes work with new runtime

This commit is contained in:
Max Richter
2026-01-23 01:14:09 +01:00
committed by Max Richter
parent 25ceb6e94f
commit b384348e70
22 changed files with 346 additions and 209 deletions

View File

@@ -616,11 +616,14 @@ export class GraphManager extends EventEmitter<{
return;
}
const fromType = from.state.type || this.registry.getNode(from.type);
const toType = to.state.type || this.registry.getNode(to.type);
// check if socket types match
const fromSocketType = from.state?.type?.outputs?.[fromSocket];
const toSocketType = [to.state?.type?.inputs?.[toSocket]?.type];
if (to.state?.type?.inputs?.[toSocket]?.accepts) {
toSocketType.push(...(to?.state?.type?.inputs?.[toSocket]?.accepts || []));
const fromSocketType = fromType?.outputs?.[fromSocket];
const toSocketType = [toType?.inputs?.[toSocket]?.type];
if (toType?.inputs?.[toSocket]?.accepts) {
toSocketType.push(...(toType?.inputs?.[toSocket]?.accepts || []));
}
if (!areSocketsCompatible(fromSocketType, toSocketType)) {
@@ -743,9 +746,9 @@ export class GraphManager extends EventEmitter<{
}
getPossibleSockets({ node, index }: Socket): [NodeInstance, string | number][] {
const nodeType = node?.state?.type;
console.log({ node: $state.snapshot(node), index, nodeType });
const nodeType = this.registry.getNode(node.type);
if (!nodeType) return [];
console.log({ index });
const sockets: [NodeInstance, string | number][] = [];
@@ -760,7 +763,7 @@ export class GraphManager extends EventEmitter<{
const ownType = nodeType?.inputs?.[index].type;
for (const node of nodes) {
const nodeType = node?.state?.type;
const nodeType = this.registry.getNode(node.type);
const inputs = nodeType?.outputs;
if (!inputs) continue;
for (let index = 0; index < inputs.length; index++) {
@@ -792,7 +795,7 @@ export class GraphManager extends EventEmitter<{
const ownType = nodeType.outputs?.[index];
for (const node of nodes) {
const inputs = node?.state?.type?.inputs;
const inputs = this.registry.getNode(node.type)?.inputs;
if (!inputs) continue;
for (const key in inputs) {
const otherType = [inputs[key].type];

View File

@@ -57,9 +57,18 @@ function getValue(input: NodeInput, value?: unknown) {
throw new Error(`Unknown input type ${input.type}`);
}
type Pointer = {
function compareInt32(a: Int32Array, b: Int32Array) {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
export type Pointer = {
start: number;
end: number;
_title?: string;
};
private seed = Math.floor(Math.random() * 100000000);
@@ -67,6 +76,10 @@ type Pointer = {
perf?: PerformanceStore;
public getMemory() {
return new Int32Array(this.memory.buffer);
}
constructor(
private registry: NodeRegistry,
public cache?: SyncCache<Int32Array>
@@ -118,7 +131,8 @@ type Pointer = {
const outputNode = graphNodes.find((node) => node.type.endsWith('/output'));
if (!outputNode) {
throw new Error('No output node found');
// throw new Error('No output node found');
console.log('No output node found');
}
const nodeMap = new Map(
@@ -169,14 +183,15 @@ type Pointer = {
return [outputNode, _nodes] as const;
}
private writeToMemory(v: number | number[] | Int32Array) {
private writeToMemory(v: number | number[] | Int32Array, title?: string) {
let length = 1;
const view = new Int32Array(this.memory.buffer);
if (typeof v === 'number') {
view[this.offset] = v;
this.memoryView[this.offset] = v;
console.log('MEM: writing number', v, ' to', this.offset);
length = 1;
} else {
view.set(v, this.offset);
this.memoryView.set(v, this.offset);
length = v.length;
}
@@ -184,7 +199,7 @@ type Pointer = {
this.debugData = {};
// Then we add some metadata to the graph
const [outputNode, nodes] = await this.addMetaData(graph);
const [_outputNode, nodes] = await this.addMetaData(graph);
/*
* Here we sort the nodes into buckets, which we then execute one by one
@@ -202,14 +217,14 @@ type Pointer = {
(a, b) => (b.state?.depth || 0) - (a.state?.depth || 0)
);
// here we store the intermediate results of the nodes
const results: Record<number, Pointer> = {};
for (const node of sortedNodes) {
const node_type = this.nodes.get(node.type)!;
console.log('EXECUTING NODE', node_type.definition.id);
console.log(node_type.definition.inputs);
console.log('---------------');
console.log('STARTING NODE EXECUTION', node_type.definition.id);
this.printMemory();
// console.log(node_type.definition.inputs);
const inputs = Object.entries(node_type.definition.inputs || {}).map(
([key, input]) => {
// We should probably initially write this to memory
@@ -217,6 +232,8 @@ type Pointer = {
return this.writeToMemory(this.seed);
}
const title = `${node.id}.${key}`;
// We should probably initially write this to memory
// If the input is linked to a setting, we use that value
// if (input.setting) {
@@ -226,31 +243,37 @@ type Pointer = {
// check if the input is connected to another node
const inputNode = node.state.inputNodes[key];
if (inputNode) {
if (results[inputNode.id] === undefined) {
if (this.results[inputNode.id] === undefined) {
throw new Error(
`Node ${node.type} is missing input from node ${inputNode.type}`
);
}
return results[inputNode.id];
return this.results[inputNode.id];
}
// If the value is stored in the node itself, we use that value
if (node.props?.[key] !== undefined) {
return this.writeToMemory(getValue(input, node.props[key]));
const value = getValue(input, node.props[key]);
console.log(`Writing prop for ${node.id} -> ${key} to memory`, node.props[key], value);
return this.writeToMemory(value, title);
}
return this.writeToMemory(getValue(input));
return this.writeToMemory(getValue(input), title);
}
);
this.printMemory();
if (!node_type || !node.state || !node_type.execute) {
log.warn(`Node ${node.id} has no definition`);
continue;
}
this.inputPtrs[node.id] = inputs;
const args = inputs.map(s => [s.start, s.end]).flat();
console.log('ARGS', args);
console.log('ARGS', inputs);
this.printMemory();
try {
a = performance.now();
const encoded_inputs = concatEncodedArrays(inputs);
@@ -298,19 +321,21 @@ type Pointer = {
log.log('Result:', results[node.id]);
log.groupEnd();
} catch (e) {
console.error(e);
console.error(`Failed to execute node ${node.type}/${node.id}`, e);
this.isRunning = false;
}
}
const mem = new Int32Array(this.memory.buffer);
console.log('OUT', mem.slice(0, 10));
// const mem = new Int32Array(this.memory.buffer);
// console.log('OUT', mem.slice(0, 10));
// return the result of the parent of the output node
const res = results[outputNode.id];
// const res = this.results[outputNode.id];
this.perf?.endPoint('runtime');
return res as unknown as Int32Array;
this.isRunning = false;
return undefined as unknown as Int32Array;
}
getDebugData() {

View File

@@ -62,10 +62,68 @@
});
</script>
<svelte:window
bind:innerHeight={windowHeight}
onkeydown={(ev) => ev.key === "r" && handleResult()}
/>
<Grid.Row>
<Grid.Cell>
{#if result}
<pre><code>{JSON.stringify(decodeNestedArray(result))}</code></pre>
{#if visibleRows?.length}
<table
class="min-w-full select-none overflow-hidden text-left text-sm flex-1"
>
<thead class="">
<tr>
<th class="px-4 py-2 border-b border-[var(--outline)]">i</th>
<th
class="px-4 py-2 border-b border-[var(--outline)] w-[50px]"
style:width="50px">Ptrs</th
>
<th class="px-4 py-2 border-b border-[var(--outline)]">Value</th>
<th class="px-4 py-2 border-b border-[var(--outline)]">Float</th>
</tr>
</thead>
<tbody>
{#each visibleRows as r, i}
{@const index = i + start}
{@const ptr = ptrs[i]}
<tr class="h-[40px] odd:bg-[var(--layer-1)]">
<td class="px-4 border-b border-[var(--outline)] w-8">{index}</td>
<td
class="w-[50px] border-b border-[var(--outline)]
{ptr?._title?.includes('->')
? 'bg-red-500'
: 'bg-blue-500'}"
>
<span>{ptr?._title}</span>
</td>
<td
class="px-4 border-b border-[var(--outline)] cursor-pointer text-blue-600 hover:text-blue-800"
onclick={() =>
(rowIsFloat.value[index] = !rowIsFloat.value[index])}
>
{decodeValue(r, rowIsFloat.value[index])}
</td>
<td class="px-4 border-b border-[var(--outline)] italic w-5">
<input
type="checkbox"
checked={rowIsFloat.value[index]}
onclick={() =>
(rowIsFloat.value[index] = !rowIsFloat.value[index])}
/>
</td>
</tr>
{/each}
</tbody>
</table>
<input
class="absolute bottom-4 left-4 bg-white"
bind:value={start}
min="0"
type="number"
step="1"
/>
{/if}
</Grid.Cell>