refactor: consolidate render graph architecture

Amp-Thread-ID: https://ampcode.com/threads/T-019f9d91-77c1-7206-a60f-ed6554ce92ab

Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
This commit is contained in:
Amp
2026-07-27 21:11:54 +00:00
co-authored by heaust
parent 05311e564c
commit fc8c16daec
25 changed files with 4907 additions and 7711 deletions
+2 -2
View File
@@ -85,7 +85,7 @@ function fixture() {
version: 1,
};
}
test("catalog exhaustively mirrors all current V2 contracts", () => {
test("catalog exhaustively mirrors all current contracts", () => {
assert.deepEqual(
Object.keys(semanticCatalog).sort(),
[
@@ -115,7 +115,7 @@ test("catalog exhaustively mirrors all current V2 contracts", () => {
assert.ok(c.parameters);
}
});
test("adapter deterministically emits strict V2, permits repeated types, omits muted links and maps sources", () => {
test("adapter deterministically emits the canonical schema, permits repeated types, omits muted links and maps sources", () => {
const x = fixture(),
a = adaptFxNodeSnapshot(x, 7);
x.nodes.reverse();
+6 -13
View File
@@ -7,7 +7,7 @@ import {
midnight,
renderGraphPresets,
} from "../static/render-graph/presets.js";
test("Phase 4 unit 4 presets preserve V1 graphs and add the V2 HDR fullscreen topology", () => {
test("presets use canonical node graphs", () => {
assert.deepEqual(Object.keys(renderGraphPresets), [
"midnight",
"ember",
@@ -22,20 +22,13 @@ test("Phase 4 unit 4 presets preserve V1 graphs and add the V2 HDR fullscreen to
[midnight.graphId, ember.graphId],
["preset_midnight", "preset_ember"],
);
assert.notDeepEqual(
midnight.passes[0].writes[0].access.load.value,
ember.passes[0].writes[0].access.load.value,
);
assert.notDeepEqual(midnight.nodes[6].parameters.clearColor, ember.nodes[6].parameters.clearColor);
for (const graph of [midnight, ember]) {
assert.equal(graph.schemaVersion, 1);
assert.equal(graph.schemaVersion, 2);
assert.equal(graph.revision, 1);
assert.equal(graph.passes.length, 1);
assert.equal(graph.passes[0].state, "enabled");
assert.deepEqual(graph.passes[0].executor, {
key: "scene_forward",
version: 1,
});
assert.equal(graph.outputs[0].name, "present");
assert.equal(graph.nodes[6].executor.key, "legacy_forward");
assert.deepEqual(graph.nodes[6].inputs.colorTarget, { node: "surface", socket: "surface" });
assert.equal(graph.nodes.at(-1).executor.key, "present");
}
assert.equal(hdr.schemaVersion, 2);
assert.equal(hdr.revision, 1);
+2 -2
View File
@@ -114,7 +114,7 @@ test("import rejects when disposed during asynchronous source loading", async ()
});
test("compile transfers payload and waits for ready before opcode 7", async()=>{
const f=fixture(), pending=f.client.compileGraph({schemaVersion:1});
const f=fixture(), pending=f.client.compileGraph({schemaVersion:2});
assert.equal(f.worker.transfers[0].length,1); assert.equal(Atomics.load(f.header,5),0);
f.worker.reply({type:"payload-ready",id:1}); await Promise.resolve();
assert.equal(new Int32Array(f.memory.buffer,64,24)[1],7);
@@ -133,7 +133,7 @@ test("compile rejects oversized encoding", async()=>{const f=fixture();await ass
test("drop graph emits opcode 8 and validates id", async()=>{const f=fixture(),p=f.client.dropCompiledGraph([9,4]);const slot=new Int32Array(f.memory.buffer,64,24);assert.deepEqual([...slot.slice(1,5)],[8,1,9,4]);f.worker.reply({type:"reply",request:1,ok:true});await p;assert.throws(()=>f.client.dropCompiledGraph([1]),TypeError);});
test("ring-full graph compile releases staged payload", async()=>{const f=fixture();Atomics.store(f.header,5,1024);const p=f.client.compileGraph({});f.worker.reply({type:"payload-ready",id:1});await assert.rejects(p,e=>e.code==="RING_FULL");assert.equal(f.worker.messages.at(-1).type,"payload-release");});
test("disposal while graph payload is pending releases and rejects", async()=>{const f=fixture(),p=f.client.compileGraph({});f.client.dispose();await assert.rejects(p,e=>e.code==="DISPOSED");assert.equal(f.worker.messages.at(-1).type,"payload-release");});
test("payload transfer uses the exact encoded ArrayBuffer", async()=>{const f=fixture(),graph={schemaVersion:1};const expected=new TextEncoder().encode(JSON.stringify(graph));const p=f.client.compileGraph(graph);const transferred=f.worker.transfers[0][0];assert.strictEqual(f.worker.messages[0].buffer,transferred);assert.deepEqual(new Uint8Array(transferred),expected);f.client.dispose();await assert.rejects(p);});
test("payload transfer uses the exact encoded ArrayBuffer", async()=>{const f=fixture(),graph={schemaVersion:2};const expected=new TextEncoder().encode(JSON.stringify(graph));const p=f.client.compileGraph(graph);const transferred=f.worker.transfers[0][0];assert.strictEqual(f.worker.messages[0].buffer,transferred);assert.deepEqual(new Uint8Array(transferred),expected);f.client.dispose();await assert.rejects(p);});
test("cycle error details are preserved exactly", async()=>{const f=fixture(),p=f.client.compileGraph({});f.worker.reply({type:"payload-ready",id:1});await Promise.resolve();const details={message:"cycle",kind:"cycle",edges:[{from:"a",resource:{id:"r",version:0},to:"b"}]};f.worker.reply({type:"reply",request:1,ok:false,code:"GRAPH_CYCLE",details});await assert.rejects(p,e=>e.details===details&&e.details.edges[0].from==="a");});
test("error without details leaves details undefined", async()=>{const f=fixture(),p=f.client.dropCompiledGraph([1,1]);f.worker.reply({type:"reply",request:1,ok:false,code:"STALE_GRAPH_ID"});await assert.rejects(p,e=>e instanceof RendererError&&e.details===undefined&&e.message==="STALE_GRAPH_ID");});
test("switch methods emit exact opcode 9 words", async()=>{const f=fixture();const a=f.client.switchCompiledGraph([9,4]);assert.deepEqual([...new Int32Array(f.memory.buffer,64,24).slice(1,7)],[9,1,1,9,4,0]);f.worker.reply({type:"reply",request:1,ok:true});await a;await new Promise(queueMicrotask);const b=f.client.switchToImmediate();assert.deepEqual([...new Int32Array(f.memory.buffer,160,24).slice(1,7)],[9,2,0,0,0,0]);f.worker.reply({type:"reply",request:2,ok:true});await b;assert.throws(()=>f.client.switchCompiledGraph([0,0]),TypeError);});