@forgeax/engine-render-graph 0.0.0-dev.8d955ade1c79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +184 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/__tests__/observation.unit.test.d.ts +2 -0
- package/dist/__tests__/observation.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-graph-alias-source.unit.test.d.ts +2 -0
- package/dist/__tests__/render-graph-alias-source.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-graph-builder.unit.test.d.ts +2 -0
- package/dist/__tests__/render-graph-builder.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-graph-errors.test-d.d.ts +2 -0
- package/dist/__tests__/render-graph-errors.test-d.d.ts.map +1 -0
- package/dist/__tests__/render-graph-regressions.unit.test.d.ts +2 -0
- package/dist/__tests__/render-graph-regressions.unit.test.d.ts.map +1 -0
- package/dist/__tests__/render-graph-rhi-null.integration.test.d.ts +2 -0
- package/dist/__tests__/render-graph-rhi-null.integration.test.d.ts.map +1 -0
- package/dist/__tests__/render-graph.unit.test.d.ts +2 -0
- package/dist/__tests__/render-graph.unit.test.d.ts.map +1 -0
- package/dist/__tests__/resource-declaration-collision.test.d.ts +2 -0
- package/dist/__tests__/resource-declaration-collision.test.d.ts.map +1 -0
- package/dist/builder.d.ts +42 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/compiled-graph.d.ts +23 -0
- package/dist/compiled-graph.d.ts.map +1 -0
- package/dist/errors.d.ts +148 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/graph.d.ts +403 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +2256 -0
- package/dist/index.mjs.map +1 -0
- package/dist/kernel-internal.d.ts +84 -0
- package/dist/kernel-internal.d.ts.map +1 -0
- package/dist/observation.d.ts +38 -0
- package/dist/observation.d.ts.map +1 -0
- package/dist/pass-registry.d.ts +12 -0
- package/dist/pass-registry.d.ts.map +1 -0
- package/dist/pipeline/__tests__/color-value-domain.test.d.ts +2 -0
- package/dist/pipeline/__tests__/color-value-domain.test.d.ts.map +1 -0
- package/dist/pipeline/color-value-domain.d.ts +35 -0
- package/dist/pipeline/color-value-domain.d.ts.map +1 -0
- package/dist/resource-registry.d.ts +62 -0
- package/dist/resource-registry.d.ts.map +1 -0
- package/dist/types.d.ts +171 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +61 -0
- package/src/__tests__/observation.unit.test.ts +103 -0
- package/src/__tests__/render-graph-alias-source.unit.test.ts +118 -0
- package/src/__tests__/render-graph-builder.unit.test.ts +673 -0
- package/src/__tests__/render-graph-errors.test-d.ts +207 -0
- package/src/__tests__/render-graph-regressions.unit.test.ts +126 -0
- package/src/__tests__/render-graph-rhi-null.integration.test.ts +86 -0
- package/src/__tests__/render-graph.unit.test.ts +2551 -0
- package/src/__tests__/resource-declaration-collision.test.ts +151 -0
- package/src/builder.ts +1009 -0
- package/src/compiled-graph.ts +383 -0
- package/src/errors.ts +205 -0
- package/src/graph.ts +1269 -0
- package/src/index.ts +97 -0
- package/src/kernel-internal.ts +148 -0
- package/src/observation.ts +134 -0
- package/src/pass-registry.ts +43 -0
- package/src/pipeline/__tests__/color-value-domain.test.ts +43 -0
- package/src/pipeline/color-value-domain.ts +139 -0
- package/src/resource-registry.ts +174 -0
- package/src/types.ts +216 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import type { DuplicateResourceDetail } from '../errors.js';
|
|
3
|
+
import { RenderGraph } from '../graph.js';
|
|
4
|
+
import { ResourceRegistry } from '../resource-registry.js';
|
|
5
|
+
|
|
6
|
+
const firstDescriptor = {
|
|
7
|
+
format: 'rgba8unorm',
|
|
8
|
+
size: { w: 4, h: 4 },
|
|
9
|
+
usage: 0,
|
|
10
|
+
} as const;
|
|
11
|
+
|
|
12
|
+
const replacementDescriptor = {
|
|
13
|
+
format: 'rgba16float',
|
|
14
|
+
size: { w: 8, h: 8 },
|
|
15
|
+
usage: 0,
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
type DeclarationResult = {
|
|
19
|
+
readonly ok: boolean;
|
|
20
|
+
readonly value?: unknown;
|
|
21
|
+
readonly error?: {
|
|
22
|
+
readonly code: string;
|
|
23
|
+
readonly detail?: DuplicateResourceDetail;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function expectDuplicate(result: unknown, resourceKey: string): void {
|
|
28
|
+
const declaration = result as DeclarationResult;
|
|
29
|
+
expect(declaration.ok).toBe(false);
|
|
30
|
+
expect(declaration.error?.code).toBe('duplicate-resource');
|
|
31
|
+
expect(declaration.error?.detail).toEqual({ resourceKey });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function makeDevice(): {
|
|
35
|
+
readonly device: unknown;
|
|
36
|
+
readonly counts: { created: number; views: number; destroyed: number };
|
|
37
|
+
} {
|
|
38
|
+
const counts = { created: 0, views: 0, destroyed: 0 };
|
|
39
|
+
const device = {
|
|
40
|
+
createTexture: () => {
|
|
41
|
+
counts.created += 1;
|
|
42
|
+
return { ok: true as const, value: { id: `texture-${counts.created}` } };
|
|
43
|
+
},
|
|
44
|
+
createTextureView: () => {
|
|
45
|
+
counts.views += 1;
|
|
46
|
+
return { ok: true as const, value: { id: `view-${counts.views}` } };
|
|
47
|
+
},
|
|
48
|
+
destroyTexture: () => {
|
|
49
|
+
counts.destroyed += 1;
|
|
50
|
+
return { ok: true as const, value: undefined };
|
|
51
|
+
},
|
|
52
|
+
queue: { onSubmittedWorkDone: () => Promise.resolve(undefined) },
|
|
53
|
+
};
|
|
54
|
+
return { device, counts };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const compileOptions = {
|
|
58
|
+
backendKind: 'webgpu' as const,
|
|
59
|
+
caps: { backendKind: 'webgpu', compute: true, storageBuffer: true } as never,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
describe('resource declaration collision preflight', () => {
|
|
63
|
+
it.each([
|
|
64
|
+
['target/target', 'target-target'],
|
|
65
|
+
['resource/target', 'resource-target'],
|
|
66
|
+
['source/reused-alias-key', 'source-alias'],
|
|
67
|
+
['alias/target', 'alias-target'],
|
|
68
|
+
])('ResourceRegistry rejects %s without replacing the first entry', (kind, key) => {
|
|
69
|
+
const registry = new ResourceRegistry();
|
|
70
|
+
let first: unknown;
|
|
71
|
+
let duplicate: unknown;
|
|
72
|
+
|
|
73
|
+
if (kind === 'target/target') {
|
|
74
|
+
first = registry.addColorTarget(key, firstDescriptor);
|
|
75
|
+
duplicate = registry.addColorTarget(key, replacementDescriptor);
|
|
76
|
+
} else if (kind === 'resource/target') {
|
|
77
|
+
first = registry.add(key, { kind: 'texture', lifetime: 'persistent' });
|
|
78
|
+
duplicate = registry.addColorTarget(key, replacementDescriptor);
|
|
79
|
+
} else if (kind === 'source/reused-alias-key') {
|
|
80
|
+
first = registry.addColorTarget(key, firstDescriptor);
|
|
81
|
+
duplicate = registry.addColorTargetAlias(key, key);
|
|
82
|
+
} else {
|
|
83
|
+
registry.addColorTarget('source', firstDescriptor);
|
|
84
|
+
first = registry.addColorTargetAlias(key, 'source');
|
|
85
|
+
duplicate = registry.addColorTarget(key, replacementDescriptor);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
expectDuplicate(duplicate, key);
|
|
89
|
+
const firstEntry = (first as { readonly value?: unknown }).value ?? first;
|
|
90
|
+
expect(registry.get(key)).toBe(firstEntry);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it.each([
|
|
94
|
+
['target/target', 'target-target'],
|
|
95
|
+
['resource/target', 'resource-target'],
|
|
96
|
+
['source/reused-alias-key', 'source-alias'],
|
|
97
|
+
['alias/target', 'alias-target'],
|
|
98
|
+
])('RenderGraph rejects %s before allocation and keeps the active graph', (kind, key) => {
|
|
99
|
+
const graph = new RenderGraph();
|
|
100
|
+
const { device, counts } = makeDevice();
|
|
101
|
+
|
|
102
|
+
if (kind === 'target/target') {
|
|
103
|
+
graph.addColorTarget(key, firstDescriptor);
|
|
104
|
+
} else if (kind === 'resource/target') {
|
|
105
|
+
graph.addResource(key, { kind: 'texture', lifetime: 'persistent' });
|
|
106
|
+
} else if (kind === 'source/reused-alias-key') {
|
|
107
|
+
graph.addColorTarget(key, firstDescriptor);
|
|
108
|
+
} else {
|
|
109
|
+
graph.addColorTarget('source', firstDescriptor);
|
|
110
|
+
graph.addColorTargetAlias(key, 'source');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const executed: string[] = [];
|
|
114
|
+
graph.addPass('first-pass', {
|
|
115
|
+
reads: [],
|
|
116
|
+
writes: [key],
|
|
117
|
+
execute: () => executed.push('first-pass'),
|
|
118
|
+
});
|
|
119
|
+
const initial = graph.compile({ ...compileOptions, device: device as never });
|
|
120
|
+
expect(initial.ok).toBe(true);
|
|
121
|
+
const initialResources = graph.listResources();
|
|
122
|
+
const initialPasses = graph.listPasses();
|
|
123
|
+
const initialTexture = graph.getColorTargetTexture(key);
|
|
124
|
+
const initialView = graph.getColorTargetView(key);
|
|
125
|
+
const countsBeforeCollision = { ...counts };
|
|
126
|
+
|
|
127
|
+
let duplicate: unknown;
|
|
128
|
+
if (kind === 'target/target' || kind === 'alias/target') {
|
|
129
|
+
duplicate = graph.addColorTarget(key, replacementDescriptor);
|
|
130
|
+
} else if (kind === 'resource/target') {
|
|
131
|
+
duplicate = graph.addColorTarget(key, replacementDescriptor);
|
|
132
|
+
} else {
|
|
133
|
+
duplicate = graph.addColorTargetAlias(key, key);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
expectDuplicate(duplicate, key);
|
|
137
|
+
expect(counts).toEqual(countsBeforeCollision);
|
|
138
|
+
|
|
139
|
+
const repaired = graph.compile({ ...compileOptions, device: device as never });
|
|
140
|
+
expect(repaired.ok).toBe(true);
|
|
141
|
+
expect(graph.listResources()).toEqual(initialResources);
|
|
142
|
+
expect(graph.listPasses()).toEqual(initialPasses);
|
|
143
|
+
expect(graph.getColorTargetTexture(key)).toBe(initialTexture);
|
|
144
|
+
expect(graph.getColorTargetView(key)).toBe(initialView);
|
|
145
|
+
|
|
146
|
+
graph.execute(undefined);
|
|
147
|
+
expect(executed).toEqual(['first-pass']);
|
|
148
|
+
graph.drain();
|
|
149
|
+
expect(counts.destroyed).toBe(countsBeforeCollision.created);
|
|
150
|
+
});
|
|
151
|
+
});
|