@forgeax/engine-render-graph 0.1.19 → 0.1.21
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/README.md +9 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/render-graph-gpu-timing-instrumentation.unit.test.d.ts +2 -0
- package/dist/__tests__/render-graph-gpu-timing-instrumentation.unit.test.d.ts.map +1 -0
- package/dist/__tests__/texture-dimensions-lifecycle.unit.test.d.ts +2 -0
- package/dist/__tests__/texture-dimensions-lifecycle.unit.test.d.ts.map +1 -0
- package/dist/__tests__/texture-dimensions.unit.test.d.ts +2 -0
- package/dist/__tests__/texture-dimensions.unit.test.d.ts.map +1 -0
- package/dist/builder.d.ts.map +1 -1
- package/dist/compiled-graph.d.ts +2 -2
- package/dist/compiled-graph.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +220 -126
- package/dist/index.mjs.map +1 -1
- package/dist/resource-registry.d.ts +2 -0
- package/dist/resource-registry.d.ts.map +1 -1
- package/dist/types.d.ts +33 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/__tests__/render-graph-builder.unit.test.ts +23 -0
- package/src/__tests__/render-graph-gpu-timing-instrumentation.unit.test.ts +183 -0
- package/src/__tests__/texture-dimensions-lifecycle.unit.test.ts +95 -0
- package/src/__tests__/texture-dimensions.unit.test.ts +99 -0
- package/src/builder.ts +159 -26
- package/src/compiled-graph.ts +25 -6
- package/src/index.ts +2 -0
- package/src/resource-registry.ts +10 -0
- package/src/types.ts +40 -2
|
@@ -2,6 +2,8 @@ import type { TextureFormat } from '@forgeax/engine-rhi';
|
|
|
2
2
|
import { type CapMissingDetail, type DanglingReadDetail, type DuplicateResourceDetail, RenderGraphError, type Result } from './errors.js';
|
|
3
3
|
import type { ColorTargetDescriptor, ColorTargetSize, ResourceDescriptor, ResourceLifetime } from './graph.js';
|
|
4
4
|
import type { ColorValueDomain } from './pipeline/color-value-domain.js';
|
|
5
|
+
/** Check the only allocation/view dimension combinations supported by WebGPU. */
|
|
6
|
+
export declare function isTextureViewDimensionCompatible(allocationDimension: GPUTextureDimension, viewDimension: GPUTextureViewDimension | undefined): boolean;
|
|
5
7
|
/**
|
|
6
8
|
* Per-resource GPU allocation metadata carried through compile.
|
|
7
9
|
* When the resource was registered via addColorTarget, colorTarget
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-registry.d.ts","sourceRoot":"","sources":["../src/resource-registry.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAG5B,gBAAgB,EAChB,KAAK,MAAM,EACZ,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEzE;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC/C;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,aAAa,EAAE,GAAG,SAAS,CAAC;IAC5D;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,wEAAwE;IACxE,QAAQ,CAAC,WAAW,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;CAC5D;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAE9D,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC;IASzF;;;;OAIG;IACH,cAAc,CACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,qBAAqB,GAC1B,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC;IAmB1C;;;;OAIG;IACH,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC;IA8B1F,OAAO,CAAC,iBAAiB;IAWzB,OAAO,CAAC,QAAQ;IAMhB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI3C,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS;IAIpE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,OAAO,IAAI,gBAAgB,CAAC,aAAa,CAAC;CAG3C;AAGD,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"resource-registry.d.ts","sourceRoot":"","sources":["../src/resource-registry.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAG5B,gBAAgB,EAChB,KAAK,MAAM,EACZ,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEzE,iFAAiF;AACjF,wBAAgB,gCAAgC,CAC9C,mBAAmB,EAAE,mBAAmB,EACxC,aAAa,EAAE,uBAAuB,GAAG,SAAS,GACjD,OAAO,CAIT;AAED;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC/C;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,aAAa,EAAE,GAAG,SAAS,CAAC;IAC5D;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,wEAAwE;IACxE,QAAQ,CAAC,WAAW,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;CAC5D;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAE9D,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC;IASzF;;;;OAIG;IACH,cAAc,CACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,qBAAqB,GAC1B,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC;IAmB1C;;;;OAIG;IACH,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC;IA8B1F,OAAO,CAAC,iBAAiB;IAWzB,OAAO,CAAC,QAAQ;IAMhB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI3C,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS;IAIpE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,OAAO,IAAI,gBAAgB,CAAC,aAAa,CAAC;CAG3C;AAGD,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Buffer, ComputePassDescriptor, RhiCommandEncoder, RhiComputePassEncoder, RhiDevice, RhiRenderPassEncoder, Texture, TextureFormat, TextureView } from '@forgeax/engine-rhi';
|
|
1
|
+
import type { Buffer, ComputePassDescriptor, RenderPassDescriptor, RhiCommandEncoder, RhiComputePassEncoder, RhiDevice, RhiRenderPassEncoder, Texture, TextureFormat, TextureView } from '@forgeax/engine-rhi';
|
|
2
2
|
import type { RenderGraphError, Result } from './errors.js';
|
|
3
3
|
import type { ColorValueDomain } from './pipeline/color-value-domain.js';
|
|
4
4
|
declare const graphTextureBrand: unique symbol;
|
|
@@ -25,7 +25,7 @@ export type GraphExtent = 'surface' | 'half-surface' | {
|
|
|
25
25
|
export interface GraphTextureDescriptor {
|
|
26
26
|
readonly format: TextureFormat;
|
|
27
27
|
readonly size: GraphExtent;
|
|
28
|
-
/** Additional RHI usage required by an external diagnostic consumer. */
|
|
28
|
+
/** Additional RHI usage required by an external diagnostic consumer such as readback. */
|
|
29
29
|
readonly usage?: number | undefined;
|
|
30
30
|
readonly mipLevelCount?: number | undefined;
|
|
31
31
|
readonly sampleCount?: number | undefined;
|
|
@@ -56,7 +56,7 @@ export interface ImportedBufferDescriptor extends GraphBufferDescriptor {
|
|
|
56
56
|
readonly usage: number;
|
|
57
57
|
}
|
|
58
58
|
export type GraphBufferAccess = 'uniform-read' | 'storage-read' | 'storage-write' | 'storage-read-write' | 'indirect-read' | 'vertex-read' | 'index-read' | 'copy-src' | 'copy-dst';
|
|
59
|
-
export type GraphTextureAccess = 'sampled-read' | 'storage-read' | 'storage-write' | 'storage-read-write' | 'color-attachment' | 'depth-stencil-read' | 'depth-stencil-write' | 'copy-src' | 'copy-dst';
|
|
59
|
+
export type GraphTextureAccess = 'sampled-read' | 'storage-read' | 'storage-write' | 'storage-read-write' | 'sampled-storage-read-write' | 'color-attachment' | 'depth-stencil-read' | 'depth-stencil-write' | 'copy-src' | 'copy-dst';
|
|
60
60
|
export type GraphAccess = {
|
|
61
61
|
readonly resource: GraphBuffer;
|
|
62
62
|
readonly usage: GraphBufferAccess;
|
|
@@ -167,7 +167,22 @@ export interface CompiledRenderGraphInfo {
|
|
|
167
167
|
readonly firstUse: number | null;
|
|
168
168
|
readonly lastUse: number | null;
|
|
169
169
|
readonly derivedUsage: number;
|
|
170
|
+
/** Stable compile-local identity of the physical RHI allocation. */
|
|
171
|
+
readonly physicalAllocationKey?: string | undefined;
|
|
172
|
+
/** Descriptor-derived byte size when the format is uncompressed and known. */
|
|
173
|
+
readonly byteSize?: number | undefined;
|
|
174
|
+
/** Texture format retained for producer-owned resource inspection. */
|
|
175
|
+
readonly format?: TextureFormat | undefined;
|
|
176
|
+
/** Texture allocation facts retained for capability/lifetime inspection. */
|
|
177
|
+
readonly dimension?: GPUTextureDimension | undefined;
|
|
178
|
+
readonly extent?: {
|
|
179
|
+
readonly width: number;
|
|
180
|
+
readonly height: number;
|
|
181
|
+
readonly depthOrArrayLayers: number;
|
|
182
|
+
} | undefined;
|
|
170
183
|
}[];
|
|
184
|
+
/** Monotonic graph generation assigned when this graph was compiled. */
|
|
185
|
+
readonly generation: number;
|
|
171
186
|
}
|
|
172
187
|
export interface RenderGraphFrame {
|
|
173
188
|
readonly encoder: RhiCommandEncoder;
|
|
@@ -178,6 +193,20 @@ export interface RenderGraphPassExecution {
|
|
|
178
193
|
readonly executionIndex: number;
|
|
179
194
|
}
|
|
180
195
|
export type RenderGraphPassRunner = (pass: RenderGraphPassExecution, encode: () => void) => void;
|
|
196
|
+
/**
|
|
197
|
+
* The graph-neutral boundary for observing and decorating an actual pass.
|
|
198
|
+
* Render owns the policy supplied here; the graph only preserves pass
|
|
199
|
+
* provenance and the existing encoder boundaries.
|
|
200
|
+
*/
|
|
201
|
+
export interface RenderGraphPassInstrumentationScope {
|
|
202
|
+
readonly renderPassDescriptor?: (descriptor: RenderPassDescriptor) => RenderPassDescriptor;
|
|
203
|
+
readonly computePassDescriptor?: (descriptor: ComputePassDescriptor) => ComputePassDescriptor;
|
|
204
|
+
readonly beforeCopy?: (encoder: RhiCommandEncoder) => void;
|
|
205
|
+
readonly afterCopy?: (encoder: RhiCommandEncoder) => void;
|
|
206
|
+
}
|
|
207
|
+
export interface RenderGraphPassInstrumentation<FrameCtx extends RenderGraphFrame> {
|
|
208
|
+
begin(pass: RenderGraphPassExecution, frame: FrameCtx): RenderGraphPassInstrumentationScope | undefined;
|
|
209
|
+
}
|
|
181
210
|
export interface RenderGraphCompileOptions {
|
|
182
211
|
readonly device: RhiDevice;
|
|
183
212
|
readonly surfaceSize: {
|
|
@@ -186,7 +215,7 @@ export interface RenderGraphCompileOptions {
|
|
|
186
215
|
};
|
|
187
216
|
}
|
|
188
217
|
export interface CompiledRenderGraph<FrameCtx extends RenderGraphFrame> {
|
|
189
|
-
execute(frame: FrameCtx, runPass?: RenderGraphPassRunner): Result<void, RenderGraphError>;
|
|
218
|
+
execute(frame: FrameCtx, runPass?: RenderGraphPassRunner, instrumentation?: RenderGraphPassInstrumentation<FrameCtx>): Result<void, RenderGraphError>;
|
|
190
219
|
inspect(): CompiledRenderGraphInfo;
|
|
191
220
|
retire(): Promise<Result<void, RenderGraphError>>;
|
|
192
221
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EACN,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,SAAS,EACT,oBAAoB,EACpB,OAAO,EACP,aAAa,EACb,WAAW,EACZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEzE,OAAO,CAAC,MAAM,iBAAiB,EAAE,OAAO,MAAM,CAAC;AAC/C,OAAO,CAAC,MAAM,qBAAqB,EAAE,OAAO,MAAM,CAAC;AACnD,OAAO,CAAC,MAAM,gBAAgB,EAAE,OAAO,MAAM,CAAC;AAE9C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,CAAC,iBAAiB,CAAC,EAAE,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,CAAC,qBAAqB,CAAC,EAAE,IAAI,CAAC;CACxC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,CAAC,gBAAgB,CAAC,EAAE,IAAI,CAAC;CACnC;AAED,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,gBAAgB,GAAG,WAAW,CAAC;AAC1E,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,UAAU,CAAC;AACzD,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,QAAQ,CAAC;AACrD,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAE1D,MAAM,MAAM,WAAW,GACnB,SAAS,GACT,cAAc,GACd;IACE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClD,CAAC;AAEN,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgeax/engine-render-graph",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -22,12 +22,12 @@
|
|
|
22
22
|
"LICENSE"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@forgeax/engine-rhi": "0.1.
|
|
26
|
-
"@forgeax/engine-types": "0.1.
|
|
25
|
+
"@forgeax/engine-rhi": "0.1.21",
|
|
26
|
+
"@forgeax/engine-types": "0.1.21",
|
|
27
27
|
"@webgpu/types": "^0.1.71"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@forgeax/engine-rhi-null": "0.1.
|
|
30
|
+
"@forgeax/engine-rhi-null": "0.1.21"
|
|
31
31
|
},
|
|
32
32
|
"forgeax": {
|
|
33
33
|
"metrics": {
|
|
@@ -448,6 +448,29 @@ describe('RenderGraphBuilder capability, execution, and lifecycle contracts', ()
|
|
|
448
448
|
);
|
|
449
449
|
});
|
|
450
450
|
|
|
451
|
+
it('keeps declared created-texture usage alongside graph-derived usage', () => {
|
|
452
|
+
const graph = new RenderGraphBuilder<Frame>();
|
|
453
|
+
const texture = value(
|
|
454
|
+
graph.createTexture('readback-target', {
|
|
455
|
+
format: 'rgba8unorm',
|
|
456
|
+
size: 'surface',
|
|
457
|
+
usage: 0x01,
|
|
458
|
+
}),
|
|
459
|
+
);
|
|
460
|
+
const view = value(graph.view(texture));
|
|
461
|
+
graph.addRasterPass('write', {
|
|
462
|
+
accesses: [{ resource: view, usage: 'color-attachment' }],
|
|
463
|
+
colorAttachments: [{ view, loadOp: 'clear', storeOp: 'store' }],
|
|
464
|
+
encode: () => undefined,
|
|
465
|
+
});
|
|
466
|
+
const compiled = value(
|
|
467
|
+
graph.compile({ device: mockDevice(), surfaceSize: { width: 1, height: 1 } }),
|
|
468
|
+
);
|
|
469
|
+
expect(compiled.inspect().resources).toContainEqual(
|
|
470
|
+
expect.objectContaining({ label: 'readback-target', derivedUsage: 0x11 }),
|
|
471
|
+
);
|
|
472
|
+
});
|
|
473
|
+
|
|
451
474
|
it('derives compute and storage capabilities from pass/access declarations', () => {
|
|
452
475
|
const graph = new RenderGraphBuilder<Frame>();
|
|
453
476
|
const buffer = value(
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Buffer,
|
|
3
|
+
ComputePassDescriptor,
|
|
4
|
+
RenderPassDescriptor,
|
|
5
|
+
RhiCommandEncoder,
|
|
6
|
+
RhiComputePassEncoder,
|
|
7
|
+
RhiDevice,
|
|
8
|
+
RhiRenderPassEncoder,
|
|
9
|
+
Texture,
|
|
10
|
+
TextureView,
|
|
11
|
+
} from '@forgeax/engine-rhi';
|
|
12
|
+
import { describe, expect, it } from 'vitest';
|
|
13
|
+
import { RenderGraphBuilder } from '../builder.js';
|
|
14
|
+
import type { RenderGraphFrame, RenderGraphPassInstrumentation } from '../types.js';
|
|
15
|
+
|
|
16
|
+
interface Frame extends RenderGraphFrame {
|
|
17
|
+
readonly source: Buffer;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function mockDevice(): RhiDevice {
|
|
21
|
+
let nextId = 0;
|
|
22
|
+
return {
|
|
23
|
+
caps: {
|
|
24
|
+
backendKind: 'null',
|
|
25
|
+
compute: true,
|
|
26
|
+
storageBuffer: true,
|
|
27
|
+
storageTexture: true,
|
|
28
|
+
timestampQuery: false,
|
|
29
|
+
timestampPeriodNanoseconds: null,
|
|
30
|
+
indirectDrawing: true,
|
|
31
|
+
textureCompressionBc: false,
|
|
32
|
+
textureCompressionEtc2: false,
|
|
33
|
+
textureCompressionAstc: false,
|
|
34
|
+
multiDrawIndirect: false,
|
|
35
|
+
pushConstants: false,
|
|
36
|
+
textureBindingArray: false,
|
|
37
|
+
samplerAliasing: true,
|
|
38
|
+
firstInstanceIndirect: false,
|
|
39
|
+
rgba16floatRenderable: true,
|
|
40
|
+
rg11b10ufloatRenderable: true,
|
|
41
|
+
float32Filterable: true,
|
|
42
|
+
maxColorAttachments: 8,
|
|
43
|
+
},
|
|
44
|
+
limits: {} as never,
|
|
45
|
+
features: new Set() as never,
|
|
46
|
+
queue: { onSubmittedWorkDone: async () => undefined } as never,
|
|
47
|
+
createTexture: () => ({ ok: true, value: { id: nextId++ } as unknown as Texture }),
|
|
48
|
+
createTextureView: () => ({ ok: true, value: { id: nextId++ } as unknown as TextureView }),
|
|
49
|
+
createBuffer: () => ({ ok: true, value: { id: nextId++ } as unknown as Buffer }),
|
|
50
|
+
destroyTexture: () => ({ ok: true, value: undefined }),
|
|
51
|
+
destroyBuffer: () => ({ ok: true, value: undefined }),
|
|
52
|
+
} as unknown as RhiDevice;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function buildGraph() {
|
|
56
|
+
const graph = new RenderGraphBuilder<Frame>();
|
|
57
|
+
const color = graph.createTexture('color', { format: 'rgba8unorm', size: 'surface' });
|
|
58
|
+
if (!color.ok) throw color.error;
|
|
59
|
+
const view = graph.view(color.value);
|
|
60
|
+
if (!view.ok) throw view.error;
|
|
61
|
+
graph.addRasterPass('raster', {
|
|
62
|
+
accesses: [{ resource: view.value, usage: 'color-attachment' }],
|
|
63
|
+
colorAttachments: [{ view: view.value, loadOp: 'clear', storeOp: 'store' }],
|
|
64
|
+
encode: () => undefined,
|
|
65
|
+
});
|
|
66
|
+
graph.addComputePass('compute', { accesses: [], encode: () => undefined });
|
|
67
|
+
graph.addCopyPass('copy', { accesses: [], encode: () => undefined });
|
|
68
|
+
graph.addComputePass('skipped', {
|
|
69
|
+
accesses: [],
|
|
70
|
+
executeIf: () => false,
|
|
71
|
+
encode: () => undefined,
|
|
72
|
+
});
|
|
73
|
+
return graph;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function mockEncoder(events: string[]): RhiCommandEncoder {
|
|
77
|
+
return {
|
|
78
|
+
beginRenderPass: (descriptor: RenderPassDescriptor) => {
|
|
79
|
+
events.push(`begin-raster:${descriptor.timestampWrites === undefined ? 'none' : 'timed'}`);
|
|
80
|
+
return { end: () => events.push('end-raster') } as unknown as RhiRenderPassEncoder;
|
|
81
|
+
},
|
|
82
|
+
beginComputePass: (descriptor: ComputePassDescriptor = {}) => {
|
|
83
|
+
events.push(`begin-compute:${descriptor.timestampWrites === undefined ? 'none' : 'timed'}`);
|
|
84
|
+
return { end: () => events.push('end-compute') } as unknown as RhiComputePassEncoder;
|
|
85
|
+
},
|
|
86
|
+
clearBuffer: () => events.push('clear-buffer'),
|
|
87
|
+
} as unknown as RhiCommandEncoder;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function value<T>(result: { readonly ok: true; readonly value: T } | { readonly ok: false }): T {
|
|
91
|
+
if (!result.ok) throw new Error('expected ok result');
|
|
92
|
+
return result.value;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
describe('RenderGraph actual-pass timing instrumentation', () => {
|
|
96
|
+
it('reports only actual passes with compiled provenance and injects at pass boundaries', () => {
|
|
97
|
+
const graph = buildGraph();
|
|
98
|
+
const compiled = graph.compile({
|
|
99
|
+
device: mockDevice(),
|
|
100
|
+
surfaceSize: { width: 1, height: 1 },
|
|
101
|
+
});
|
|
102
|
+
expect(compiled.ok).toBe(true);
|
|
103
|
+
if (!compiled.ok) return;
|
|
104
|
+
|
|
105
|
+
const events: string[] = [];
|
|
106
|
+
const actualPasses: string[] = [];
|
|
107
|
+
const instrumentation: RenderGraphPassInstrumentation<Frame> = {
|
|
108
|
+
begin(pass) {
|
|
109
|
+
actualPasses.push(`${pass.executionIndex}:${pass.kind}:${pass.name}`);
|
|
110
|
+
return {
|
|
111
|
+
renderPassDescriptor: (descriptor) => ({
|
|
112
|
+
...descriptor,
|
|
113
|
+
timestampWrites: {
|
|
114
|
+
querySet: {} as never,
|
|
115
|
+
beginningOfPassWriteIndex: 0,
|
|
116
|
+
endOfPassWriteIndex: 1,
|
|
117
|
+
},
|
|
118
|
+
}),
|
|
119
|
+
computePassDescriptor: (descriptor) => ({
|
|
120
|
+
...descriptor,
|
|
121
|
+
timestampWrites: {
|
|
122
|
+
querySet: {} as never,
|
|
123
|
+
beginningOfPassWriteIndex: 2,
|
|
124
|
+
endOfPassWriteIndex: 3,
|
|
125
|
+
},
|
|
126
|
+
}),
|
|
127
|
+
beforeCopy: () => events.push('before-copy'),
|
|
128
|
+
afterCopy: () => events.push('after-copy'),
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const result = value(compiled).execute(
|
|
134
|
+
{ encoder: mockEncoder(events), source: {} as Buffer },
|
|
135
|
+
undefined,
|
|
136
|
+
instrumentation,
|
|
137
|
+
);
|
|
138
|
+
expect(result.ok).toBe(true);
|
|
139
|
+
expect(actualPasses).toEqual(['0:raster:raster', '1:compute:compute', '2:copy:copy']);
|
|
140
|
+
expect(events).toEqual([
|
|
141
|
+
'begin-raster:timed',
|
|
142
|
+
'end-raster',
|
|
143
|
+
'begin-compute:timed',
|
|
144
|
+
'end-compute',
|
|
145
|
+
'before-copy',
|
|
146
|
+
'after-copy',
|
|
147
|
+
]);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('keeps the no-hook graph and command ledger equivalent', () => {
|
|
151
|
+
const graph = buildGraph();
|
|
152
|
+
const compiled = graph.compile({
|
|
153
|
+
device: mockDevice(),
|
|
154
|
+
surfaceSize: { width: 1, height: 1 },
|
|
155
|
+
});
|
|
156
|
+
expect(compiled.ok).toBe(true);
|
|
157
|
+
if (!compiled.ok) return;
|
|
158
|
+
|
|
159
|
+
const events: string[] = [];
|
|
160
|
+
const result = value(compiled).execute({ encoder: mockEncoder(events), source: {} as Buffer });
|
|
161
|
+
expect(result.ok).toBe(true);
|
|
162
|
+
expect(events).toEqual([
|
|
163
|
+
'begin-raster:none',
|
|
164
|
+
'end-raster',
|
|
165
|
+
'begin-compute:none',
|
|
166
|
+
'end-compute',
|
|
167
|
+
]);
|
|
168
|
+
expect(
|
|
169
|
+
value(compiled)
|
|
170
|
+
.inspect()
|
|
171
|
+
.passes.map(({ name, kind, executionIndex }) => ({
|
|
172
|
+
name,
|
|
173
|
+
kind,
|
|
174
|
+
executionIndex,
|
|
175
|
+
})),
|
|
176
|
+
).toEqual([
|
|
177
|
+
{ name: 'raster', kind: 'raster', executionIndex: 0 },
|
|
178
|
+
{ name: 'compute', kind: 'compute', executionIndex: 1 },
|
|
179
|
+
{ name: 'copy', kind: 'copy', executionIndex: 2 },
|
|
180
|
+
{ name: 'skipped', kind: 'compute', executionIndex: 3 },
|
|
181
|
+
]);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { RhiDevice, TextureView } from '@forgeax/engine-rhi';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { RenderGraphBuilder } from '../builder.js';
|
|
4
|
+
import type { RenderGraphFrame } from '../types.js';
|
|
5
|
+
|
|
6
|
+
interface Frame extends RenderGraphFrame {}
|
|
7
|
+
|
|
8
|
+
function caps(storageTexture: boolean): RhiDevice['caps'] {
|
|
9
|
+
return {
|
|
10
|
+
backendKind: 'null',
|
|
11
|
+
compute: true,
|
|
12
|
+
storageBuffer: true,
|
|
13
|
+
storageTexture,
|
|
14
|
+
timestampQuery: false,
|
|
15
|
+
timestampPeriodNanoseconds: null,
|
|
16
|
+
indirectDrawing: false,
|
|
17
|
+
textureCompressionBc: false,
|
|
18
|
+
textureCompressionEtc2: false,
|
|
19
|
+
textureCompressionAstc: false,
|
|
20
|
+
multiDrawIndirect: false,
|
|
21
|
+
pushConstants: false,
|
|
22
|
+
textureBindingArray: false,
|
|
23
|
+
samplerAliasing: true,
|
|
24
|
+
firstInstanceIndirect: false,
|
|
25
|
+
rgba16floatRenderable: true,
|
|
26
|
+
rg11b10ufloatRenderable: true,
|
|
27
|
+
float32Filterable: true,
|
|
28
|
+
maxColorAttachments: 8,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function mockDevice(storageTexture: boolean): RhiDevice {
|
|
33
|
+
return {
|
|
34
|
+
caps: caps(storageTexture),
|
|
35
|
+
limits: {} as never,
|
|
36
|
+
features: new Set() as never,
|
|
37
|
+
queue: { onSubmittedWorkDone: async () => undefined } as never,
|
|
38
|
+
createTexture: () => ({ ok: true, value: {} as never }),
|
|
39
|
+
createTextureView: () => ({ ok: true, value: {} as TextureView }),
|
|
40
|
+
destroyTexture: () => ({ ok: true, value: undefined }),
|
|
41
|
+
destroyBuffer: () => ({ ok: true, value: undefined }),
|
|
42
|
+
} as unknown as RhiDevice;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
describe('RenderGraph texture dimension lifecycle', () => {
|
|
46
|
+
it('returns a structured capability result for unsupported storage texture access', () => {
|
|
47
|
+
const graph = new RenderGraphBuilder<Frame>();
|
|
48
|
+
const texture = graph.createTexture('volume-storage', {
|
|
49
|
+
format: 'rgba8unorm',
|
|
50
|
+
size: { width: 2, height: 2, depthOrArrayLayers: 2 },
|
|
51
|
+
dimension: '3d',
|
|
52
|
+
});
|
|
53
|
+
expect(texture.ok).toBe(true);
|
|
54
|
+
if (!texture.ok) return;
|
|
55
|
+
const view = graph.view(texture.value, { dimension: '3d' });
|
|
56
|
+
expect(view.ok).toBe(true);
|
|
57
|
+
if (!view.ok) return;
|
|
58
|
+
graph.addCopyPass('seed', {
|
|
59
|
+
accesses: [{ resource: view.value, usage: 'copy-dst' }],
|
|
60
|
+
encode: () => undefined,
|
|
61
|
+
});
|
|
62
|
+
graph.addComputePass('write-volume', {
|
|
63
|
+
accesses: [{ resource: view.value, usage: 'storage-write' }],
|
|
64
|
+
encode: () => undefined,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const result = graph.compile({
|
|
68
|
+
device: mockDevice(false),
|
|
69
|
+
surfaceSize: { width: 1, height: 1 },
|
|
70
|
+
});
|
|
71
|
+
expect(result.ok).toBe(false);
|
|
72
|
+
if (result.ok) return;
|
|
73
|
+
expect(result.error.code).toBe('capability-missing');
|
|
74
|
+
expect(result.error.detail).toMatchObject({ capability: 'storage-texture' });
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('rejects a non-positive volume extent with structured descriptor detail', () => {
|
|
78
|
+
const graph = new RenderGraphBuilder<Frame>();
|
|
79
|
+
const texture = graph.createTexture('invalid-volume', {
|
|
80
|
+
format: 'rgba8unorm',
|
|
81
|
+
size: { width: 2, height: 2, depthOrArrayLayers: 0 },
|
|
82
|
+
dimension: '3d',
|
|
83
|
+
});
|
|
84
|
+
expect(texture.ok).toBe(true);
|
|
85
|
+
if (!texture.ok) return;
|
|
86
|
+
const result = graph.compile({
|
|
87
|
+
device: mockDevice(true),
|
|
88
|
+
surfaceSize: { width: 1, height: 1 },
|
|
89
|
+
});
|
|
90
|
+
expect(result.ok).toBe(false);
|
|
91
|
+
if (result.ok) return;
|
|
92
|
+
expect(result.error.code).toBe('resource-descriptor-invalid');
|
|
93
|
+
expect(result.error.detail).toMatchObject({ resourceLabel: 'invalid-volume', field: 'size' });
|
|
94
|
+
});
|
|
95
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { ok, type RhiDevice, type Texture, type TextureView } from '@forgeax/engine-rhi';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { RenderGraphBuilder } from '../builder.js';
|
|
4
|
+
import type { RenderGraphFrame } from '../types.js';
|
|
5
|
+
|
|
6
|
+
interface Frame extends RenderGraphFrame {}
|
|
7
|
+
|
|
8
|
+
function device(overrides: Partial<RhiDevice> = {}): RhiDevice {
|
|
9
|
+
return {
|
|
10
|
+
caps: {
|
|
11
|
+
backendKind: 'null',
|
|
12
|
+
compute: true,
|
|
13
|
+
storageBuffer: true,
|
|
14
|
+
storageTexture: true,
|
|
15
|
+
timestampQuery: false,
|
|
16
|
+
timestampPeriodNanoseconds: null,
|
|
17
|
+
indirectDrawing: true,
|
|
18
|
+
textureCompressionBc: false,
|
|
19
|
+
textureCompressionEtc2: false,
|
|
20
|
+
textureCompressionAstc: false,
|
|
21
|
+
multiDrawIndirect: false,
|
|
22
|
+
pushConstants: false,
|
|
23
|
+
textureBindingArray: false,
|
|
24
|
+
samplerAliasing: true,
|
|
25
|
+
firstInstanceIndirect: false,
|
|
26
|
+
rgba16floatRenderable: true,
|
|
27
|
+
rg11b10ufloatRenderable: true,
|
|
28
|
+
float32Filterable: true,
|
|
29
|
+
maxColorAttachments: 8,
|
|
30
|
+
},
|
|
31
|
+
limits: {} as never,
|
|
32
|
+
features: new Set() as never,
|
|
33
|
+
queue: { onSubmittedWorkDone: async () => undefined } as never,
|
|
34
|
+
createTexture: () => ok({} as Texture),
|
|
35
|
+
createTextureView: () => ok({} as TextureView),
|
|
36
|
+
destroyTexture: () => ok(undefined),
|
|
37
|
+
destroyBuffer: () => ok(undefined),
|
|
38
|
+
...overrides,
|
|
39
|
+
} as unknown as RhiDevice;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
describe('RenderGraph texture dimension contract', () => {
|
|
43
|
+
it('keeps 2d-array and 3d allocation dimensions through graph-owned resources', () => {
|
|
44
|
+
const created: unknown[] = [];
|
|
45
|
+
const views: unknown[] = [];
|
|
46
|
+
const graph = new RenderGraphBuilder<Frame>();
|
|
47
|
+
const arrayTexture = graph.createTexture('layers', {
|
|
48
|
+
format: 'rgba8unorm',
|
|
49
|
+
size: { width: 2, height: 2, depthOrArrayLayers: 3 },
|
|
50
|
+
dimension: '2d',
|
|
51
|
+
});
|
|
52
|
+
const volumeTexture = graph.createTexture('volume', {
|
|
53
|
+
format: 'rgba8unorm',
|
|
54
|
+
size: { width: 2, height: 2, depthOrArrayLayers: 3 },
|
|
55
|
+
dimension: '3d',
|
|
56
|
+
});
|
|
57
|
+
expect(arrayTexture.ok && volumeTexture.ok).toBe(true);
|
|
58
|
+
if (!arrayTexture.ok || !volumeTexture.ok) return;
|
|
59
|
+
const arrayView = graph.view(arrayTexture.value, { dimension: '2d-array' });
|
|
60
|
+
const volumeView = graph.view(volumeTexture.value, { dimension: '3d' });
|
|
61
|
+
expect(arrayView.ok && volumeView.ok).toBe(true);
|
|
62
|
+
if (!arrayView.ok || !volumeView.ok) return;
|
|
63
|
+
graph.addCopyPass('seed-array', {
|
|
64
|
+
accesses: [{ resource: arrayView.value, usage: 'copy-dst' }],
|
|
65
|
+
encode: () => undefined,
|
|
66
|
+
});
|
|
67
|
+
graph.addCopyPass('seed-volume', {
|
|
68
|
+
accesses: [{ resource: volumeView.value, usage: 'copy-dst' }],
|
|
69
|
+
encode: () => undefined,
|
|
70
|
+
});
|
|
71
|
+
const compiled = graph.compile({
|
|
72
|
+
device: device({
|
|
73
|
+
createTexture: (descriptor: unknown) => {
|
|
74
|
+
created.push(descriptor);
|
|
75
|
+
return ok({} as Texture);
|
|
76
|
+
},
|
|
77
|
+
createTextureView: (_texture: Texture, descriptor: unknown) => {
|
|
78
|
+
views.push(descriptor);
|
|
79
|
+
return ok({} as TextureView);
|
|
80
|
+
},
|
|
81
|
+
}),
|
|
82
|
+
surfaceSize: { width: 1, height: 1 },
|
|
83
|
+
});
|
|
84
|
+
expect(compiled.ok).toBe(true);
|
|
85
|
+
expect(created).toEqual(
|
|
86
|
+
expect.arrayContaining([
|
|
87
|
+
expect.objectContaining({
|
|
88
|
+
dimension: '2d',
|
|
89
|
+
size: { width: 2, height: 2, depthOrArrayLayers: 3 },
|
|
90
|
+
}),
|
|
91
|
+
expect.objectContaining({
|
|
92
|
+
dimension: '3d',
|
|
93
|
+
size: { width: 2, height: 2, depthOrArrayLayers: 3 },
|
|
94
|
+
}),
|
|
95
|
+
]),
|
|
96
|
+
);
|
|
97
|
+
expect(views).toEqual(expect.arrayContaining([{ dimension: '2d-array' }, { dimension: '3d' }]));
|
|
98
|
+
});
|
|
99
|
+
});
|