@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,38 @@
|
|
|
1
|
+
import type { Texture, TextureFormat } from '@forgeax/engine-rhi';
|
|
2
|
+
import { RenderGraphError, type Result } from './errors.js';
|
|
3
|
+
export { RenderGraphError } from './errors.js';
|
|
4
|
+
export interface ObservationSize {
|
|
5
|
+
readonly width: number;
|
|
6
|
+
readonly height: number;
|
|
7
|
+
}
|
|
8
|
+
/** Generic producer-owned metadata for one current-frame texture. */
|
|
9
|
+
export interface CurrentFrameObservationDescriptor {
|
|
10
|
+
readonly texture: Texture;
|
|
11
|
+
readonly format: TextureFormat;
|
|
12
|
+
readonly size: ObservationSize;
|
|
13
|
+
readonly usage: number;
|
|
14
|
+
readonly frameId: number;
|
|
15
|
+
}
|
|
16
|
+
export interface CurrentFrameObservationLifetime {
|
|
17
|
+
readonly frameId: number;
|
|
18
|
+
readonly state: 'active' | 'retired';
|
|
19
|
+
}
|
|
20
|
+
/** The only resource information a downstream copy consumer receives. */
|
|
21
|
+
export interface CurrentFrameObservationSource {
|
|
22
|
+
readonly texture: Texture;
|
|
23
|
+
readonly descriptor: CurrentFrameObservationDescriptor;
|
|
24
|
+
readonly lifetime: CurrentFrameObservationLifetime;
|
|
25
|
+
}
|
|
26
|
+
export interface CurrentFrameObservationLease {
|
|
27
|
+
readonly descriptor: CurrentFrameObservationDescriptor;
|
|
28
|
+
readonly lifetime: CurrentFrameObservationLifetime;
|
|
29
|
+
readonly state: 'active' | 'retired';
|
|
30
|
+
beginReadback(): Result<CurrentFrameObservationSource, RenderGraphError>;
|
|
31
|
+
retire(): void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Validate and lease a producer's current-frame texture without naming any
|
|
35
|
+
* semantic, pipeline, backend policy, or graph resource key.
|
|
36
|
+
*/
|
|
37
|
+
export declare function createCurrentFrameObservationLease(descriptor: CurrentFrameObservationDescriptor, currentFrameId: number): Result<CurrentFrameObservationLease, RenderGraphError>;
|
|
38
|
+
//# sourceMappingURL=observation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observation.d.ts","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAW,gBAAgB,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAI/C,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,qEAAqE;AACrE,MAAM,WAAW,iCAAiC;IAChD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;CACtC;AAED,yEAAyE;AACzE,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,iCAAiC,CAAC;IACvD,QAAQ,CAAC,QAAQ,EAAE,+BAA+B,CAAC;CACpD;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,UAAU,EAAE,iCAAiC,CAAC;IACvD,QAAQ,CAAC,QAAQ,EAAE,+BAA+B,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;IACrC,aAAa,IAAI,MAAM,CAAC,6BAA6B,EAAE,gBAAgB,CAAC,CAAC;IACzE,MAAM,IAAI,IAAI,CAAC;CAChB;AAeD;;;GAGG;AACH,wBAAgB,kCAAkC,CAChD,UAAU,EAAE,iCAAiC,EAC7C,cAAc,EAAE,MAAM,GACrB,MAAM,CAAC,4BAA4B,EAAE,gBAAgB,CAAC,CAwExD"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PassDescriptor } from './graph.js';
|
|
2
|
+
export interface PassEntry<Ctx = unknown> {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly descriptor: PassDescriptor<Ctx>;
|
|
5
|
+
}
|
|
6
|
+
export declare class PassRegistry<Ctx = unknown> {
|
|
7
|
+
private readonly passes;
|
|
8
|
+
add(name: string, descriptor: PassDescriptor<Ctx>, before?: string): PassEntry<Ctx>;
|
|
9
|
+
list(): readonly PassEntry<Ctx>[];
|
|
10
|
+
count(): number;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=pass-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pass-registry.d.ts","sourceRoot":"","sources":["../src/pass-registry.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,SAAS,CAAC,GAAG,GAAG,OAAO;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;CAC1C;AAED,qBAAa,YAAY,CAAC,GAAG,GAAG,OAAO;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;IAE/C,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC;IAiBnF,IAAI,IAAI,SAAS,SAAS,CAAC,GAAG,CAAC,EAAE;IAIjC,KAAK,IAAI,MAAM;CAGhB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color-value-domain.test.d.ts","sourceRoot":"","sources":["../../../src/pipeline/__tests__/color-value-domain.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { RenderGraphError, type Result } from '../errors.js';
|
|
2
|
+
export declare const COLOR_VALUE_DOMAINS: readonly ["linear-hdr", "linear-ldr", "display-encoded"];
|
|
3
|
+
export type ColorValueDomain = (typeof COLOR_VALUE_DOMAINS)[number];
|
|
4
|
+
export type ColorDomainConversion = {
|
|
5
|
+
readonly kind: 'encode-srgb';
|
|
6
|
+
} | {
|
|
7
|
+
readonly kind: 'decode-srgb';
|
|
8
|
+
} | {
|
|
9
|
+
readonly kind: 'tone-map';
|
|
10
|
+
};
|
|
11
|
+
export interface ColorResourceDescriptor {
|
|
12
|
+
readonly domain: ColorValueDomain;
|
|
13
|
+
readonly format: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ColorDomainConnection {
|
|
16
|
+
readonly source: string;
|
|
17
|
+
readonly destination: string;
|
|
18
|
+
readonly conversion?: ColorDomainConversion | undefined;
|
|
19
|
+
}
|
|
20
|
+
export type ColorDomainValidation = {
|
|
21
|
+
readonly ok: true;
|
|
22
|
+
} | {
|
|
23
|
+
readonly ok: false;
|
|
24
|
+
readonly error: RenderGraphError;
|
|
25
|
+
};
|
|
26
|
+
export declare function isColorValueDomain(value: unknown): value is ColorValueDomain;
|
|
27
|
+
declare function invalidDomain(value: unknown): RenderGraphError;
|
|
28
|
+
declare function missingDomain(resourceKey?: string): RenderGraphError;
|
|
29
|
+
export declare function serializeColorValueDomain(domain: ColorValueDomain): string;
|
|
30
|
+
export declare function deserializeColorValueDomain(value: unknown): Result<ColorValueDomain, RenderGraphError>;
|
|
31
|
+
export declare function serializeColorResourceDescriptor(descriptor: ColorResourceDescriptor): string;
|
|
32
|
+
export declare function deserializeColorResourceDescriptor(value: unknown): Result<ColorResourceDescriptor, RenderGraphError>;
|
|
33
|
+
export declare function validateColorDomainConnection(source: unknown, destination: unknown, conversion?: ColorDomainConversion): ColorDomainValidation;
|
|
34
|
+
export { invalidDomain, missingDomain };
|
|
35
|
+
//# sourceMappingURL=color-value-domain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color-value-domain.d.ts","sourceRoot":"","sources":["../../src/pipeline/color-value-domain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,gBAAgB,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtE,eAAO,MAAM,mBAAmB,0DAA2D,CAAC;AAE5F,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpE,MAAM,MAAM,qBAAqB,GAC7B;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AAElC,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;CACzD;AAED,MAAM,MAAM,qBAAqB,GAC7B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAE,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAE7D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAED,iBAAS,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAOvD;AAED,iBAAS,aAAa,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAO7D;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAG1E;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,OAAO,GACb,MAAM,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAU5C;AAED,wBAAgB,gCAAgC,CAAC,UAAU,EAAE,uBAAuB,GAAG,MAAM,CAG5F;AAED,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,OAAO,GACb,MAAM,CAAC,uBAAuB,EAAE,gBAAgB,CAAC,CAgBnD;AAsBD,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,OAAO,EACf,WAAW,EAAE,OAAO,EACpB,UAAU,CAAC,EAAE,qBAAqB,GACjC,qBAAqB,CAoBvB;AAED,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { TextureFormat } from '@forgeax/engine-rhi';
|
|
2
|
+
import { type CapMissingDetail, type DanglingReadDetail, type DuplicateResourceDetail, RenderGraphError, type Result } from './errors.js';
|
|
3
|
+
import type { ColorTargetDescriptor, ColorTargetSize, ResourceDescriptor, ResourceLifetime } from './graph.js';
|
|
4
|
+
import type { ColorValueDomain } from './pipeline/color-value-domain.js';
|
|
5
|
+
/**
|
|
6
|
+
* Per-resource GPU allocation metadata carried through compile.
|
|
7
|
+
* When the resource was registered via addColorTarget, colorTarget
|
|
8
|
+
* carries the format/size/sample/usage fields (w5); when via
|
|
9
|
+
* addResource it is undefined.
|
|
10
|
+
*/
|
|
11
|
+
export interface ColorTargetResourceMeta {
|
|
12
|
+
readonly format: TextureFormat;
|
|
13
|
+
readonly size: ColorTargetSize;
|
|
14
|
+
readonly sample: number;
|
|
15
|
+
readonly usage: number;
|
|
16
|
+
/** Explicit semantic color domain; never derived from format. */
|
|
17
|
+
readonly domain?: ColorValueDomain | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Extra texture view formats pre-declared at GPU texture creation. Mirrors
|
|
20
|
+
* GPUTextureDescriptor.viewFormats. Used by the LDR MSAA path which needs a
|
|
21
|
+
* `bgra8unorm` storage texture plus a `bgra8unorm-srgb` view of the same
|
|
22
|
+
* texture for hardware sRGB encoding on store.
|
|
23
|
+
*/
|
|
24
|
+
readonly viewFormats?: readonly TextureFormat[] | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* When set, this resource is an alias of the given source resource.
|
|
27
|
+
* The compile allocation phase folds the alias into the source's
|
|
28
|
+
* physical texture (KB-1 MoveNode pattern, D-2).
|
|
29
|
+
*/
|
|
30
|
+
readonly aliasedFrom?: string | undefined;
|
|
31
|
+
}
|
|
32
|
+
export interface ResourceEntry {
|
|
33
|
+
readonly key: string;
|
|
34
|
+
readonly descriptor: ResourceDescriptor;
|
|
35
|
+
readonly lifetime: ResourceLifetime;
|
|
36
|
+
/** Present when the resource was registered via addColorTarget (w5). */
|
|
37
|
+
readonly colorTarget?: ColorTargetResourceMeta | undefined;
|
|
38
|
+
}
|
|
39
|
+
export declare class ResourceRegistry {
|
|
40
|
+
private readonly resources;
|
|
41
|
+
add(key: string, descriptor: ResourceDescriptor): Result<ResourceEntry, RenderGraphError>;
|
|
42
|
+
/**
|
|
43
|
+
* Register a color target resource (D-8).
|
|
44
|
+
* Same semantics as addResource with kind:'texture' plus GPU texture
|
|
45
|
+
* allocation metadata. Existing callers default to a transient target.
|
|
46
|
+
*/
|
|
47
|
+
addColorTarget(name: string, desc: ColorTargetDescriptor): Result<ResourceEntry, RenderGraphError>;
|
|
48
|
+
/**
|
|
49
|
+
* Register a color target alias that folds into the source's physical
|
|
50
|
+
* texture at compile time (KB-1 MoveNode pattern, D-2).
|
|
51
|
+
* The source must already be registered via addColorTarget.
|
|
52
|
+
*/
|
|
53
|
+
addColorTargetAlias(name: string, source: string): Result<ResourceEntry, RenderGraphError>;
|
|
54
|
+
private duplicateResource;
|
|
55
|
+
private register;
|
|
56
|
+
get(key: string): ResourceEntry | undefined;
|
|
57
|
+
getColorTargetMeta(key: string): ColorTargetResourceMeta | undefined;
|
|
58
|
+
has(key: string): boolean;
|
|
59
|
+
entries(): IterableIterator<ResourceEntry>;
|
|
60
|
+
}
|
|
61
|
+
export type { CapMissingDetail, DanglingReadDetail, DuplicateResourceDetail };
|
|
62
|
+
//# sourceMappingURL=resource-registry.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import type { Buffer, ComputePassDescriptor, RhiCommandEncoder, RhiComputePassEncoder, RhiDevice, RhiRenderPassEncoder, Texture, TextureFormat, TextureView } from '@forgeax/engine-rhi';
|
|
2
|
+
import type { RenderGraphError, Result } from './errors.js';
|
|
3
|
+
declare const graphTextureBrand: unique symbol;
|
|
4
|
+
declare const graphTextureViewBrand: unique symbol;
|
|
5
|
+
declare const graphBufferBrand: unique symbol;
|
|
6
|
+
export interface GraphTexture {
|
|
7
|
+
readonly [graphTextureBrand]: true;
|
|
8
|
+
}
|
|
9
|
+
export interface GraphTextureView {
|
|
10
|
+
readonly [graphTextureViewBrand]: true;
|
|
11
|
+
}
|
|
12
|
+
export interface GraphBuffer {
|
|
13
|
+
readonly [graphBufferBrand]: true;
|
|
14
|
+
}
|
|
15
|
+
export type GraphResource = GraphTexture | GraphTextureView | GraphBuffer;
|
|
16
|
+
export type GraphResourceOrigin = 'created' | 'imported';
|
|
17
|
+
export type GraphResourceKind = 'texture' | 'buffer';
|
|
18
|
+
export type GraphPassKind = 'raster' | 'compute' | 'copy';
|
|
19
|
+
export type GraphExtent = 'surface' | 'half-surface' | {
|
|
20
|
+
readonly width: number;
|
|
21
|
+
readonly height: number;
|
|
22
|
+
readonly depthOrArrayLayers?: number | undefined;
|
|
23
|
+
};
|
|
24
|
+
export interface GraphTextureDescriptor {
|
|
25
|
+
readonly format: TextureFormat;
|
|
26
|
+
readonly size: GraphExtent;
|
|
27
|
+
readonly mipLevelCount?: number | undefined;
|
|
28
|
+
readonly sampleCount?: number | undefined;
|
|
29
|
+
readonly dimension?: GPUTextureDimension | undefined;
|
|
30
|
+
readonly viewFormats?: readonly TextureFormat[] | undefined;
|
|
31
|
+
}
|
|
32
|
+
export interface ImportedTextureDescriptor extends GraphTextureDescriptor {
|
|
33
|
+
readonly usage: number;
|
|
34
|
+
}
|
|
35
|
+
export interface GraphTextureViewDescriptor {
|
|
36
|
+
readonly label?: string | undefined;
|
|
37
|
+
readonly format?: TextureFormat | undefined;
|
|
38
|
+
readonly dimension?: GPUTextureViewDimension | undefined;
|
|
39
|
+
readonly aspect?: GPUTextureAspect | undefined;
|
|
40
|
+
readonly baseMipLevel?: number | undefined;
|
|
41
|
+
readonly mipLevelCount?: number | undefined;
|
|
42
|
+
readonly baseArrayLayer?: number | undefined;
|
|
43
|
+
readonly arrayLayerCount?: number | undefined;
|
|
44
|
+
}
|
|
45
|
+
export type ImportedTextureViewResolver<FrameCtx> = (frame: FrameCtx) => TextureView;
|
|
46
|
+
export interface GraphBufferDescriptor {
|
|
47
|
+
readonly size: number;
|
|
48
|
+
readonly mappedAtCreation?: boolean | undefined;
|
|
49
|
+
}
|
|
50
|
+
export interface ImportedBufferDescriptor extends GraphBufferDescriptor {
|
|
51
|
+
readonly usage: number;
|
|
52
|
+
}
|
|
53
|
+
export type GraphBufferAccess = 'uniform-read' | 'storage-read' | 'storage-write' | 'storage-read-write' | 'indirect-read' | 'vertex-read' | 'index-read' | 'copy-src' | 'copy-dst';
|
|
54
|
+
export type GraphTextureAccess = 'sampled-read' | 'storage-read' | 'storage-write' | 'storage-read-write' | 'color-attachment' | 'depth-stencil-read' | 'depth-stencil-write' | 'copy-src' | 'copy-dst';
|
|
55
|
+
export type GraphAccess = {
|
|
56
|
+
readonly resource: GraphBuffer;
|
|
57
|
+
readonly usage: GraphBufferAccess;
|
|
58
|
+
} | {
|
|
59
|
+
readonly resource: GraphTextureView;
|
|
60
|
+
readonly usage: GraphTextureAccess;
|
|
61
|
+
};
|
|
62
|
+
export interface GraphResourceResolver {
|
|
63
|
+
buffer(resource: GraphBuffer): Result<Buffer, RenderGraphError>;
|
|
64
|
+
texture(resource: GraphTexture): Result<Texture, RenderGraphError>;
|
|
65
|
+
textureView(resource: GraphTextureView): Result<TextureView, RenderGraphError>;
|
|
66
|
+
}
|
|
67
|
+
export interface RasterColorAttachment<FrameCtx> {
|
|
68
|
+
readonly view: GraphTextureView;
|
|
69
|
+
readonly resolveTarget?: GraphTextureView | undefined;
|
|
70
|
+
readonly clearValue?: GPUColor | ((frame: FrameCtx) => GPUColor) | undefined;
|
|
71
|
+
readonly loadOp: GPULoadOp;
|
|
72
|
+
readonly storeOp: GPUStoreOp;
|
|
73
|
+
readonly depthSlice?: number | undefined;
|
|
74
|
+
}
|
|
75
|
+
export interface RasterDepthStencilAttachment {
|
|
76
|
+
readonly view: GraphTextureView;
|
|
77
|
+
readonly depthClearValue?: number | undefined;
|
|
78
|
+
readonly depthLoadOp?: GPULoadOp | undefined;
|
|
79
|
+
readonly depthStoreOp?: GPUStoreOp | undefined;
|
|
80
|
+
readonly depthReadOnly?: boolean | undefined;
|
|
81
|
+
readonly stencilClearValue?: number | undefined;
|
|
82
|
+
readonly stencilLoadOp?: GPULoadOp | undefined;
|
|
83
|
+
readonly stencilStoreOp?: GPUStoreOp | undefined;
|
|
84
|
+
readonly stencilReadOnly?: boolean | undefined;
|
|
85
|
+
}
|
|
86
|
+
export interface RasterGraphPass<FrameCtx> {
|
|
87
|
+
readonly accesses: readonly GraphAccess[];
|
|
88
|
+
readonly colorAttachments: readonly RasterColorAttachment<FrameCtx>[];
|
|
89
|
+
readonly depthStencilAttachment?: RasterDepthStencilAttachment | undefined;
|
|
90
|
+
readonly executeIf?: ((frame: FrameCtx) => boolean) | undefined;
|
|
91
|
+
encode(context: {
|
|
92
|
+
readonly pass: RhiRenderPassEncoder;
|
|
93
|
+
readonly frame: FrameCtx;
|
|
94
|
+
readonly resources: GraphResourceResolver;
|
|
95
|
+
}): void;
|
|
96
|
+
}
|
|
97
|
+
export interface ComputeGraphPass<FrameCtx> {
|
|
98
|
+
readonly accesses: readonly GraphAccess[];
|
|
99
|
+
readonly executeIf?: ((frame: FrameCtx) => boolean) | undefined;
|
|
100
|
+
readonly begin?: ((frame: FrameCtx) => ComputePassDescriptor) | undefined;
|
|
101
|
+
readonly onBeginError?: ((frame: FrameCtx, cause: unknown) => void) | undefined;
|
|
102
|
+
encode(context: {
|
|
103
|
+
readonly pass: RhiComputePassEncoder;
|
|
104
|
+
readonly frame: FrameCtx;
|
|
105
|
+
readonly resources: GraphResourceResolver;
|
|
106
|
+
}): void;
|
|
107
|
+
readonly after?: ((frame: FrameCtx) => void) | undefined;
|
|
108
|
+
}
|
|
109
|
+
export interface CopyGraphPass<FrameCtx> {
|
|
110
|
+
readonly accesses: readonly GraphAccess[];
|
|
111
|
+
readonly executeIf?: ((frame: FrameCtx) => boolean) | undefined;
|
|
112
|
+
encode(context: {
|
|
113
|
+
readonly encoder: RhiCommandEncoder;
|
|
114
|
+
readonly frame: FrameCtx;
|
|
115
|
+
readonly resources: GraphResourceResolver;
|
|
116
|
+
}): void;
|
|
117
|
+
}
|
|
118
|
+
export type GraphPass<FrameCtx> = {
|
|
119
|
+
readonly kind: 'raster';
|
|
120
|
+
readonly descriptor: RasterGraphPass<FrameCtx>;
|
|
121
|
+
} | {
|
|
122
|
+
readonly kind: 'compute';
|
|
123
|
+
readonly descriptor: ComputeGraphPass<FrameCtx>;
|
|
124
|
+
} | {
|
|
125
|
+
readonly kind: 'copy';
|
|
126
|
+
readonly descriptor: CopyGraphPass<FrameCtx>;
|
|
127
|
+
};
|
|
128
|
+
export interface GraphAccessInfo {
|
|
129
|
+
readonly resource: string;
|
|
130
|
+
readonly usage: GraphBufferAccess | GraphTextureAccess;
|
|
131
|
+
}
|
|
132
|
+
export interface CompiledRenderGraphInfo {
|
|
133
|
+
readonly passes: readonly {
|
|
134
|
+
readonly name: string;
|
|
135
|
+
readonly kind: GraphPassKind;
|
|
136
|
+
readonly executionIndex: number;
|
|
137
|
+
readonly accesses: readonly GraphAccessInfo[];
|
|
138
|
+
readonly dependencies: readonly string[];
|
|
139
|
+
}[];
|
|
140
|
+
readonly resources: readonly {
|
|
141
|
+
readonly label: string;
|
|
142
|
+
readonly kind: GraphResourceKind;
|
|
143
|
+
readonly origin: GraphResourceOrigin;
|
|
144
|
+
readonly firstUse: number | null;
|
|
145
|
+
readonly lastUse: number | null;
|
|
146
|
+
readonly derivedUsage: number;
|
|
147
|
+
}[];
|
|
148
|
+
}
|
|
149
|
+
export interface RenderGraphFrame {
|
|
150
|
+
readonly encoder: RhiCommandEncoder;
|
|
151
|
+
}
|
|
152
|
+
export interface RenderGraphPassExecution {
|
|
153
|
+
readonly name: string;
|
|
154
|
+
readonly kind: GraphPassKind;
|
|
155
|
+
readonly executionIndex: number;
|
|
156
|
+
}
|
|
157
|
+
export type RenderGraphPassRunner = (pass: RenderGraphPassExecution, encode: () => void) => void;
|
|
158
|
+
export interface RenderGraphCompileOptions {
|
|
159
|
+
readonly device: RhiDevice;
|
|
160
|
+
readonly surfaceSize: {
|
|
161
|
+
readonly width: number;
|
|
162
|
+
readonly height: number;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
export interface CompiledRenderGraph<FrameCtx extends RenderGraphFrame> {
|
|
166
|
+
execute(frame: FrameCtx, runPass?: RenderGraphPassRunner): Result<void, RenderGraphError>;
|
|
167
|
+
inspect(): CompiledRenderGraphInfo;
|
|
168
|
+
retire(): Promise<Result<void, RenderGraphError>>;
|
|
169
|
+
}
|
|
170
|
+
export {};
|
|
171
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@forgeax/engine-render-graph",
|
|
3
|
+
"version": "0.0.0-dev.8d955ade1c79",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"description": "RHI-pure typed GPU work graph: resource access declaration, immutable compilation, execution, and retirement.",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"main": "./dist/index.mjs",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"src",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@forgeax/engine-rhi": "0.0.0-dev.8d955ade1c79",
|
|
26
|
+
"@forgeax/engine-types": "0.0.0-dev.8d955ade1c79",
|
|
27
|
+
"@webgpu/types": "^0.1.71"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@forgeax/engine-rhi-null": "0.0.0-dev.8d955ade1c79"
|
|
31
|
+
},
|
|
32
|
+
"forgeax": {
|
|
33
|
+
"metrics": {
|
|
34
|
+
"bundle-size": {
|
|
35
|
+
"enabled": true,
|
|
36
|
+
"path": "dist/index.mjs",
|
|
37
|
+
"compression": "gzip"
|
|
38
|
+
},
|
|
39
|
+
"fps": {
|
|
40
|
+
"enabled": false,
|
|
41
|
+
"reason": "render-graph is a compile-time / orchestration layer without canvas; fps reported by consuming runtime apps"
|
|
42
|
+
},
|
|
43
|
+
"bench": {
|
|
44
|
+
"enabled": false,
|
|
45
|
+
"reason": "compile path is not perf-critical; bench focus stays on @forgeax/engine-math and runtime render loop"
|
|
46
|
+
},
|
|
47
|
+
"gate": {
|
|
48
|
+
"enabled": false,
|
|
49
|
+
"reason": "physical-isolation grep gate (check-render-graph-no-runtime-import) is a repo-root script wired into ci.yml lint job, not a per-package gate"
|
|
50
|
+
},
|
|
51
|
+
"spike-report": {
|
|
52
|
+
"enabled": false,
|
|
53
|
+
"reason": "not a spike package"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsup",
|
|
59
|
+
"test": "vitest run"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { Texture } from '@forgeax/engine-rhi';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import {
|
|
4
|
+
type CurrentFrameObservationDescriptor,
|
|
5
|
+
type CurrentFrameObservationLease,
|
|
6
|
+
createCurrentFrameObservationLease,
|
|
7
|
+
RenderGraphError,
|
|
8
|
+
} from '../observation.js';
|
|
9
|
+
|
|
10
|
+
const COPY_SRC = 0x01;
|
|
11
|
+
const RENDER_ATTACHMENT = 0x10;
|
|
12
|
+
const TEXTURE_BINDING = 0x04;
|
|
13
|
+
|
|
14
|
+
const texture = {} as Texture;
|
|
15
|
+
|
|
16
|
+
function descriptor(
|
|
17
|
+
overrides: Partial<CurrentFrameObservationDescriptor> = {},
|
|
18
|
+
): CurrentFrameObservationDescriptor {
|
|
19
|
+
return {
|
|
20
|
+
texture,
|
|
21
|
+
format: 'rgba16float',
|
|
22
|
+
size: { width: 32, height: 16 },
|
|
23
|
+
usage: RENDER_ATTACHMENT | TEXTURE_BINDING | COPY_SRC,
|
|
24
|
+
frameId: 7,
|
|
25
|
+
...overrides,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function expectError(
|
|
30
|
+
result: { readonly ok: true } | { readonly ok: false; readonly error: { readonly code: string } },
|
|
31
|
+
code: string,
|
|
32
|
+
): void {
|
|
33
|
+
expect(result.ok).toBe(false);
|
|
34
|
+
if (!result.ok) expect(result.error.code).toBe(code);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
describe('current-frame observation lease', () => {
|
|
38
|
+
it('accepts an opaque texture descriptor with a fresh frame lifetime', () => {
|
|
39
|
+
const result = createCurrentFrameObservationLease(descriptor(), 7);
|
|
40
|
+
|
|
41
|
+
expect(result.ok).toBe(true);
|
|
42
|
+
if (!result.ok) return;
|
|
43
|
+
expect(result.value.descriptor).toEqual(descriptor());
|
|
44
|
+
expect(result.value.state).toBe('active');
|
|
45
|
+
expect(result.value.beginReadback().ok).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('rejects missing or incompatible observation descriptors', () => {
|
|
49
|
+
expectError(
|
|
50
|
+
createCurrentFrameObservationLease(descriptor({ format: 'bgra8unorm' }), 7),
|
|
51
|
+
'observation-invalid-format',
|
|
52
|
+
);
|
|
53
|
+
expectError(
|
|
54
|
+
createCurrentFrameObservationLease(descriptor({ size: { width: 0, height: 16 } }), 7),
|
|
55
|
+
'observation-invalid-size',
|
|
56
|
+
);
|
|
57
|
+
expectError(
|
|
58
|
+
createCurrentFrameObservationLease(descriptor({ usage: RENDER_ATTACHMENT }), 7),
|
|
59
|
+
'observation-missing-copy-src',
|
|
60
|
+
);
|
|
61
|
+
expectError(
|
|
62
|
+
createCurrentFrameObservationLease(descriptor({ texture: undefined as never }), 7),
|
|
63
|
+
'observation-absent',
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('rejects stale frame descriptors before a lease is created', () => {
|
|
68
|
+
expectError(
|
|
69
|
+
createCurrentFrameObservationLease(descriptor({ frameId: 6 }), 7),
|
|
70
|
+
'observation-stale',
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('fails closed after retirement and exposes no graph key or policy', () => {
|
|
75
|
+
const result = createCurrentFrameObservationLease(descriptor(), 7);
|
|
76
|
+
expect(result.ok).toBe(true);
|
|
77
|
+
if (!result.ok) return;
|
|
78
|
+
|
|
79
|
+
const lease: CurrentFrameObservationLease = result.value;
|
|
80
|
+
lease.retire();
|
|
81
|
+
expect(lease.state).toBe('retired');
|
|
82
|
+
expectError(lease.beginReadback(), 'observation-retired');
|
|
83
|
+
expect('graphKey' in lease).toBe(false);
|
|
84
|
+
expect('pipelineId' in lease).toBe(false);
|
|
85
|
+
expect('backendHandle' in lease).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('keeps the graph package isolated from semantic owners', async () => {
|
|
89
|
+
const source = await import('../observation.js');
|
|
90
|
+
const sourceText = Object.keys(source).join(' ');
|
|
91
|
+
expect(sourceText).not.toMatch(/linear-hdr|URP|HDRP|parity/i);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('uses the structured RenderGraphError surface', () => {
|
|
95
|
+
expect(
|
|
96
|
+
new RenderGraphError({
|
|
97
|
+
code: 'observation-stale',
|
|
98
|
+
expected: 'current frame observation',
|
|
99
|
+
hint: 'capture the current frame before the producer retires it',
|
|
100
|
+
}),
|
|
101
|
+
).toBeInstanceOf(Error);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { RenderGraph } from '../graph.js';
|
|
3
|
+
|
|
4
|
+
const colorTarget = {
|
|
5
|
+
format: 'rgba8unorm',
|
|
6
|
+
size: { w: 4, h: 4 },
|
|
7
|
+
} as const;
|
|
8
|
+
|
|
9
|
+
function makeDevice(): {
|
|
10
|
+
readonly device: object;
|
|
11
|
+
readonly created: object[];
|
|
12
|
+
readonly destroyed: object[];
|
|
13
|
+
} {
|
|
14
|
+
const created: object[] = [];
|
|
15
|
+
const destroyed: object[] = [];
|
|
16
|
+
const device = {
|
|
17
|
+
createTexture: () => {
|
|
18
|
+
const texture = { id: `texture-${created.length + 1}` };
|
|
19
|
+
created.push(texture);
|
|
20
|
+
return { ok: true as const, value: texture };
|
|
21
|
+
},
|
|
22
|
+
createTextureView: (texture: object) => ({
|
|
23
|
+
ok: true as const,
|
|
24
|
+
value: { texture },
|
|
25
|
+
}),
|
|
26
|
+
destroyTexture: (texture: object) => {
|
|
27
|
+
destroyed.push(texture);
|
|
28
|
+
return { ok: true as const, value: undefined };
|
|
29
|
+
},
|
|
30
|
+
queue: { onSubmittedWorkDone: () => Promise.resolve(undefined) },
|
|
31
|
+
};
|
|
32
|
+
return { device, created, destroyed };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const compileOptions = {
|
|
36
|
+
backendKind: 'webgpu' as const,
|
|
37
|
+
caps: { backendKind: 'webgpu', compute: true, storageBuffer: true } as never,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
describe('RenderGraph alias-source refusal and recovery', () => {
|
|
41
|
+
it('refuses an absent source without mutation, then repairs on the same graph', () => {
|
|
42
|
+
const graph = new RenderGraph();
|
|
43
|
+
const { device, created, destroyed } = makeDevice();
|
|
44
|
+
const executed: string[] = [];
|
|
45
|
+
|
|
46
|
+
expect(graph.addColorTarget('active', colorTarget).ok).toBe(true);
|
|
47
|
+
expect(graph.addColorTarget('sibling', colorTarget).ok).toBe(true);
|
|
48
|
+
graph.addPass('active-pass', {
|
|
49
|
+
reads: [],
|
|
50
|
+
writes: ['active'],
|
|
51
|
+
execute: () => executed.push('active-pass'),
|
|
52
|
+
});
|
|
53
|
+
graph.addPass('sibling-pass', {
|
|
54
|
+
reads: [],
|
|
55
|
+
writes: ['sibling'],
|
|
56
|
+
execute: () => executed.push('sibling-pass'),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
expect(graph.compile({ ...compileOptions, device: device as never }).ok).toBe(true);
|
|
60
|
+
const initialResources = graph.listResources();
|
|
61
|
+
const initialPasses = graph.listPasses();
|
|
62
|
+
const initialActiveTexture = graph.getColorTargetTexture('active');
|
|
63
|
+
const initialSiblingTexture = graph.getColorTargetTexture('sibling');
|
|
64
|
+
const initialCreatedCount = created.length;
|
|
65
|
+
|
|
66
|
+
const refused = graph.addColorTargetAlias('alias', 'missing-source');
|
|
67
|
+
expect(refused.ok).toBe(false);
|
|
68
|
+
if (refused.ok) throw new Error('expected an absent alias source to be refused');
|
|
69
|
+
expect(refused.error.code).toBe('alias-source-missing');
|
|
70
|
+
expect(refused.error.detail).toEqual({
|
|
71
|
+
aliasKey: 'alias',
|
|
72
|
+
sourceKey: 'missing-source',
|
|
73
|
+
});
|
|
74
|
+
expect(graph.listResources()).toEqual(initialResources);
|
|
75
|
+
expect(graph.listPasses()).toEqual(initialPasses);
|
|
76
|
+
expect(graph.getColorTargetTexture('alias')).toBeUndefined();
|
|
77
|
+
expect(graph.getColorTargetView('alias')).toBeUndefined();
|
|
78
|
+
expect(created).toHaveLength(initialCreatedCount);
|
|
79
|
+
|
|
80
|
+
graph.execute(undefined);
|
|
81
|
+
expect(executed).toEqual(['active-pass', 'sibling-pass']);
|
|
82
|
+
|
|
83
|
+
expect(graph.addColorTarget('source', colorTarget).ok).toBe(true);
|
|
84
|
+
expect(graph.addColorTargetAlias('alias', 'source').ok).toBe(true);
|
|
85
|
+
graph.addPass('source-pass', {
|
|
86
|
+
reads: [],
|
|
87
|
+
writes: ['source'],
|
|
88
|
+
execute: () => executed.push('source-pass'),
|
|
89
|
+
});
|
|
90
|
+
graph.addPass('alias-pass', {
|
|
91
|
+
reads: ['source'],
|
|
92
|
+
writes: ['alias'],
|
|
93
|
+
execute: () => executed.push('alias-pass'),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const repaired = graph.compile({ ...compileOptions, device: device as never });
|
|
97
|
+
expect(repaired.ok).toBe(true);
|
|
98
|
+
expect(graph.getColorTargetTexture('active')).toBe(initialActiveTexture);
|
|
99
|
+
expect(graph.getColorTargetTexture('sibling')).toBe(initialSiblingTexture);
|
|
100
|
+
expect(graph.getColorTargetTexture('alias')).toBe(graph.getColorTargetTexture('source'));
|
|
101
|
+
expect(graph.getColorTargetView('alias')).toBe(graph.getColorTargetView('source'));
|
|
102
|
+
|
|
103
|
+
graph.execute(undefined);
|
|
104
|
+
expect(executed).toEqual([
|
|
105
|
+
'active-pass',
|
|
106
|
+
'sibling-pass',
|
|
107
|
+
'active-pass',
|
|
108
|
+
'sibling-pass',
|
|
109
|
+
'source-pass',
|
|
110
|
+
'alias-pass',
|
|
111
|
+
]);
|
|
112
|
+
|
|
113
|
+
graph.drain();
|
|
114
|
+
graph.drain();
|
|
115
|
+
expect(destroyed).toHaveLength(created.length);
|
|
116
|
+
expect(new Set(destroyed)).toEqual(new Set(created));
|
|
117
|
+
});
|
|
118
|
+
});
|