@forgeax/engine-render-graph 0.1.20 → 0.1.23
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 +43 -0
- 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/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 +23 -8
- package/dist/index.mjs.map +1 -1
- package/dist/types.d.ts +20 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/__tests__/render-graph-builder.unit.test.ts +115 -1
- package/src/__tests__/render-graph-gpu-timing-instrumentation.unit.test.ts +183 -0
- package/src/builder.ts +6 -2
- package/src/compiled-graph.ts +32 -6
- package/src/index.ts +2 -0
- package/src/types.ts +30 -2
- package/dist/.tsbuildinfo +0 -1
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, QuerySet, 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;
|
|
@@ -92,6 +92,8 @@ export interface RasterGraphPass<FrameCtx> {
|
|
|
92
92
|
readonly accesses: readonly GraphAccess[];
|
|
93
93
|
readonly colorAttachments: readonly RasterColorAttachment<FrameCtx>[];
|
|
94
94
|
readonly depthStencilAttachment?: RasterDepthStencilAttachment | undefined;
|
|
95
|
+
/** Optional producer-owned occlusion query set for this raster pass. */
|
|
96
|
+
readonly occlusionQuerySet?: QuerySet | undefined;
|
|
95
97
|
readonly executeIf?: ((frame: FrameCtx) => boolean) | undefined;
|
|
96
98
|
encode(context: {
|
|
97
99
|
readonly pass: RhiRenderPassEncoder;
|
|
@@ -193,6 +195,21 @@ export interface RenderGraphPassExecution {
|
|
|
193
195
|
readonly executionIndex: number;
|
|
194
196
|
}
|
|
195
197
|
export type RenderGraphPassRunner = (pass: RenderGraphPassExecution, encode: () => void) => void;
|
|
198
|
+
/**
|
|
199
|
+
* The graph-neutral boundary for observing and decorating an actual pass.
|
|
200
|
+
* Render owns the policy supplied here; the graph only preserves pass
|
|
201
|
+
* provenance and applies the decorated descriptor at the real pass-open
|
|
202
|
+
* boundary. Timestamp policy and acceptance remain outside the graph.
|
|
203
|
+
*/
|
|
204
|
+
export interface RenderGraphPassInstrumentationScope {
|
|
205
|
+
readonly renderPassDescriptor?: (descriptor: RenderPassDescriptor) => RenderPassDescriptor;
|
|
206
|
+
readonly computePassDescriptor?: (descriptor: ComputePassDescriptor) => ComputePassDescriptor;
|
|
207
|
+
readonly beforeCopy?: (encoder: RhiCommandEncoder) => void;
|
|
208
|
+
readonly afterCopy?: (encoder: RhiCommandEncoder) => void;
|
|
209
|
+
}
|
|
210
|
+
export interface RenderGraphPassInstrumentation<FrameCtx extends RenderGraphFrame> {
|
|
211
|
+
begin(pass: RenderGraphPassExecution, frame: FrameCtx): RenderGraphPassInstrumentationScope | undefined;
|
|
212
|
+
}
|
|
196
213
|
export interface RenderGraphCompileOptions {
|
|
197
214
|
readonly device: RhiDevice;
|
|
198
215
|
readonly surfaceSize: {
|
|
@@ -201,7 +218,7 @@ export interface RenderGraphCompileOptions {
|
|
|
201
218
|
};
|
|
202
219
|
}
|
|
203
220
|
export interface CompiledRenderGraph<FrameCtx extends RenderGraphFrame> {
|
|
204
|
-
execute(frame: FrameCtx, runPass?: RenderGraphPassRunner): Result<void, RenderGraphError>;
|
|
221
|
+
execute(frame: FrameCtx, runPass?: RenderGraphPassRunner, instrumentation?: RenderGraphPassInstrumentation<FrameCtx>): Result<void, RenderGraphError>;
|
|
205
222
|
inspect(): CompiledRenderGraphInfo;
|
|
206
223
|
retire(): Promise<Result<void, RenderGraphError>>;
|
|
207
224
|
}
|
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":"AAAA,OAAO,KAAK,EACV,MAAM,EACN,qBAAqB,EACrB,QAAQ,EACR,oBAAoB,EACpB,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,yFAAyF;IACzF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACrD,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,aAAa,EAAE,GAAG,SAAS,CAAC;IAC5D,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAChD;AAED,MAAM,WAAW,yBAA0B,SAAQ,sBAAsB;IACvE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,SAAS,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;IACzD,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,MAAM,2BAA2B,CAAC,QAAQ,IAAI,CAAC,KAAK,EAAE,QAAQ,KAAK,WAAW,CAAC;AAErF,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACjD;AAED,MAAM,WAAW,wBAAyB,SAAQ,qBAAqB;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,iBAAiB,GACzB,cAAc,GACd,cAAc,GACd,eAAe,GACf,oBAAoB,GACpB,eAAe,GACf,aAAa,GACb,YAAY,GACZ,UAAU,GACV,UAAU,CAAC;AAEf,MAAM,MAAM,kBAAkB,GAC1B,cAAc,GACd,cAAc,GACd,eAAe,GACf,oBAAoB,GACpB,4BAA4B,GAC5B,kBAAkB,GAClB,oBAAoB,GACpB,qBAAqB,GACrB,UAAU,GACV,UAAU,CAAC;AAEf,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,GACrE;IAAE,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAEhF,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAChE,OAAO,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IACnE,WAAW,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;CAChF;AAED,MAAM,WAAW,qBAAqB,CAAC,QAAQ;IAC7C,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,aAAa,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,KAAK,EAAE,QAAQ,KAAK,QAAQ,CAAC,GAAG,SAAS,CAAC;IAC7E,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,YAAY,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,cAAc,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAChD;AAED,MAAM,WAAW,eAAe,CAAC,QAAQ;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,gBAAgB,EAAE,SAAS,qBAAqB,CAAC,QAAQ,CAAC,EAAE,CAAC;IACtE,QAAQ,CAAC,sBAAsB,CAAC,EAAE,4BAA4B,GAAG,SAAS,CAAC;IAC3E,wEAAwE;IACxE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAClD,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC;IAChE,MAAM,CAAC,OAAO,EAAE;QACd,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;QACpC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;QACzB,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC;KAC3C,GAAG,IAAI,CAAC;CACV;AAED,MAAM,WAAW,gBAAgB,CAAC,QAAQ;IACxC,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC;IAChE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,KAAK,qBAAqB,CAAC,GAAG,SAAS,CAAC;IAC1E,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAChF,MAAM,CAAC,OAAO,EAAE;QACd,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;QACrC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;QACzB,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC;KAC3C,GAAG,IAAI,CAAC;IACT,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAC1D;AAED,MAAM,WAAW,aAAa,CAAC,QAAQ;IACrC,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC;IAChE,MAAM,CAAC,OAAO,EAAE;QACd,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;QACpC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;QACzB,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC;KAC3C,GAAG,IAAI,CAAC;CACV;AAED,MAAM,MAAM,SAAS,CAAC,QAAQ,IAC1B;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAA;CAAE,GAC3E;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;CAAE,GAC7E;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;CAAE,CAAC;AAE5E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,kBAAkB,CAAC;CACxD;AAED,0EAA0E;AAC1E,MAAM,MAAM,0BAA0B,GAClC;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,uEAAuE;IACvE,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC/C,kFAAkF;IAClF,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEN,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,MAAM,EAAE,SAAS;QACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;QAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;QAC9C,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;KAC1C,EAAE,CAAC;IACJ,QAAQ,CAAC,SAAS,EAAE,SAAS;QAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;QACjC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;QACrC,QAAQ,CAAC,UAAU,EAAE,0BAA0B,CAAC;QAChD,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;QAC9B,oEAAoE;QACpE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QACpD,8EAA8E;QAC9E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QACvC,sEAAsE;QACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;QAC5C,4EAA4E;QAC5E,QAAQ,CAAC,SAAS,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;QACrD,QAAQ,CAAC,MAAM,CAAC,EACZ;YAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAA;SAAE,GACxF,SAAS,CAAC;KACf,EAAE,CAAC;IACJ,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;CACrC;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,MAAM,qBAAqB,GAAG,CAAC,IAAI,EAAE,wBAAwB,EAAE,MAAM,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;AAEjG;;;;;GAKG;AACH,MAAM,WAAW,mCAAmC;IAClD,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC,UAAU,EAAE,oBAAoB,KAAK,oBAAoB,CAAC;IAC3F,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC,UAAU,EAAE,qBAAqB,KAAK,qBAAqB,CAAC;IAC9F,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC3D,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC3D;AAED,MAAM,WAAW,8BAA8B,CAAC,QAAQ,SAAS,gBAAgB;IAC/E,KAAK,CACH,IAAI,EAAE,wBAAwB,EAC9B,KAAK,EAAE,QAAQ,GACd,mCAAmC,GAAG,SAAS,CAAC;CACpD;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3E;AAED,MAAM,WAAW,mBAAmB,CAAC,QAAQ,SAAS,gBAAgB;IACpE,OAAO,CACL,KAAK,EAAE,QAAQ,EACf,OAAO,CAAC,EAAE,qBAAqB,EAC/B,eAAe,CAAC,EAAE,8BAA8B,CAAC,QAAQ,CAAC,GACzD,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;IAClC,OAAO,IAAI,uBAAuB,CAAC;IACnC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC;CACnD"}
|
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.23",
|
|
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.23",
|
|
26
|
+
"@forgeax/engine-types": "0.1.23",
|
|
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.23"
|
|
31
31
|
},
|
|
32
32
|
"forgeax": {
|
|
33
33
|
"metrics": {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
Buffer,
|
|
3
3
|
ComputePassDescriptor,
|
|
4
|
+
QuerySet,
|
|
4
5
|
RhiCommandEncoder,
|
|
5
6
|
RhiComputePassEncoder,
|
|
6
7
|
RhiDevice,
|
|
@@ -10,7 +11,7 @@ import type {
|
|
|
10
11
|
import { describe, expect, it } from 'vitest';
|
|
11
12
|
import { RenderGraphBuilder } from '../builder.js';
|
|
12
13
|
import { ok } from '../errors.js';
|
|
13
|
-
import type { RenderGraphFrame } from '../types.js';
|
|
14
|
+
import type { RenderGraphFrame, RenderGraphPassInstrumentation } from '../types.js';
|
|
14
15
|
|
|
15
16
|
interface Frame extends RenderGraphFrame {
|
|
16
17
|
readonly imported: Buffer;
|
|
@@ -448,6 +449,29 @@ describe('RenderGraphBuilder capability, execution, and lifecycle contracts', ()
|
|
|
448
449
|
);
|
|
449
450
|
});
|
|
450
451
|
|
|
452
|
+
it('keeps declared created-texture usage alongside graph-derived usage', () => {
|
|
453
|
+
const graph = new RenderGraphBuilder<Frame>();
|
|
454
|
+
const texture = value(
|
|
455
|
+
graph.createTexture('readback-target', {
|
|
456
|
+
format: 'rgba8unorm',
|
|
457
|
+
size: 'surface',
|
|
458
|
+
usage: 0x01,
|
|
459
|
+
}),
|
|
460
|
+
);
|
|
461
|
+
const view = value(graph.view(texture));
|
|
462
|
+
graph.addRasterPass('write', {
|
|
463
|
+
accesses: [{ resource: view, usage: 'color-attachment' }],
|
|
464
|
+
colorAttachments: [{ view, loadOp: 'clear', storeOp: 'store' }],
|
|
465
|
+
encode: () => undefined,
|
|
466
|
+
});
|
|
467
|
+
const compiled = value(
|
|
468
|
+
graph.compile({ device: mockDevice(), surfaceSize: { width: 1, height: 1 } }),
|
|
469
|
+
);
|
|
470
|
+
expect(compiled.inspect().resources).toContainEqual(
|
|
471
|
+
expect.objectContaining({ label: 'readback-target', derivedUsage: 0x11 }),
|
|
472
|
+
);
|
|
473
|
+
});
|
|
474
|
+
|
|
451
475
|
it('derives compute and storage capabilities from pass/access declarations', () => {
|
|
452
476
|
const graph = new RenderGraphBuilder<Frame>();
|
|
453
477
|
const buffer = value(
|
|
@@ -501,6 +525,96 @@ describe('RenderGraphBuilder capability, execution, and lifecycle contracts', ()
|
|
|
501
525
|
]);
|
|
502
526
|
});
|
|
503
527
|
|
|
528
|
+
it('applies pass timestamp instrumentation at the real raster and compute boundaries', () => {
|
|
529
|
+
const graph = new RenderGraphBuilder<Frame>();
|
|
530
|
+
const texture = value(
|
|
531
|
+
graph.importTexture(
|
|
532
|
+
'surface',
|
|
533
|
+
{ format: 'rgba8unorm', size: 'surface', usage: 0x10 },
|
|
534
|
+
(frame) => frame.importedTexture as Texture,
|
|
535
|
+
),
|
|
536
|
+
);
|
|
537
|
+
const view = value(
|
|
538
|
+
graph.importView(
|
|
539
|
+
texture,
|
|
540
|
+
{ label: 'surface.view' },
|
|
541
|
+
(frame) => frame.importedView as TextureView,
|
|
542
|
+
),
|
|
543
|
+
);
|
|
544
|
+
graph.addRasterPass('timed-raster', {
|
|
545
|
+
accesses: [{ resource: view, usage: 'color-attachment' }],
|
|
546
|
+
colorAttachments: [{ view, loadOp: 'clear', storeOp: 'store' }],
|
|
547
|
+
encode: () => undefined,
|
|
548
|
+
});
|
|
549
|
+
graph.addComputePass('timed-compute', {
|
|
550
|
+
accesses: [],
|
|
551
|
+
encode: () => undefined,
|
|
552
|
+
});
|
|
553
|
+
const compiled = value(
|
|
554
|
+
graph.compile({ device: mockDevice(), surfaceSize: { width: 1, height: 1 } }),
|
|
555
|
+
);
|
|
556
|
+
const querySet = {} as QuerySet;
|
|
557
|
+
const rasterWrites = {
|
|
558
|
+
querySet,
|
|
559
|
+
beginningOfPassWriteIndex: 4,
|
|
560
|
+
endOfPassWriteIndex: 5,
|
|
561
|
+
} as const;
|
|
562
|
+
const computeWrites = {
|
|
563
|
+
querySet,
|
|
564
|
+
beginningOfPassWriteIndex: 6,
|
|
565
|
+
endOfPassWriteIndex: 7,
|
|
566
|
+
} as const;
|
|
567
|
+
let rasterDescriptor: { readonly timestampWrites?: unknown } | undefined;
|
|
568
|
+
const computeDescriptors: Array<{ readonly timestampWrites?: unknown }> = [];
|
|
569
|
+
const encoder = {
|
|
570
|
+
...mockEncoder(),
|
|
571
|
+
beginRenderPass: (descriptor: { readonly timestampWrites?: unknown }) => {
|
|
572
|
+
rasterDescriptor = descriptor;
|
|
573
|
+
return { end: () => undefined } as never;
|
|
574
|
+
},
|
|
575
|
+
beginComputePass: (descriptor: ComputePassDescriptor = {}) => {
|
|
576
|
+
computeDescriptors.push(descriptor);
|
|
577
|
+
return {
|
|
578
|
+
setPipeline: () => undefined,
|
|
579
|
+
setBindGroup: () => undefined,
|
|
580
|
+
dispatchWorkgroups: () => undefined,
|
|
581
|
+
dispatchWorkgroupsIndirect: () => undefined,
|
|
582
|
+
end: () => undefined,
|
|
583
|
+
} as unknown as RhiComputePassEncoder;
|
|
584
|
+
},
|
|
585
|
+
} as unknown as RhiCommandEncoder;
|
|
586
|
+
const instrumentation: RenderGraphPassInstrumentation<Frame> = {
|
|
587
|
+
begin: (pass) =>
|
|
588
|
+
pass.kind === 'raster'
|
|
589
|
+
? {
|
|
590
|
+
renderPassDescriptor: (descriptor) => ({
|
|
591
|
+
...descriptor,
|
|
592
|
+
timestampWrites: rasterWrites,
|
|
593
|
+
}),
|
|
594
|
+
}
|
|
595
|
+
: {
|
|
596
|
+
computePassDescriptor: (descriptor) => ({
|
|
597
|
+
...descriptor,
|
|
598
|
+
timestampWrites: computeWrites,
|
|
599
|
+
}),
|
|
600
|
+
},
|
|
601
|
+
};
|
|
602
|
+
const executed = compiled.execute(
|
|
603
|
+
{
|
|
604
|
+
encoder,
|
|
605
|
+
imported: {} as Buffer,
|
|
606
|
+
importedTexture: {} as Texture,
|
|
607
|
+
importedView: {} as TextureView,
|
|
608
|
+
},
|
|
609
|
+
undefined,
|
|
610
|
+
instrumentation,
|
|
611
|
+
);
|
|
612
|
+
expect(executed.ok).toBe(true);
|
|
613
|
+
expect(rasterDescriptor?.timestampWrites).toBe(rasterWrites);
|
|
614
|
+
expect(computeDescriptors).toHaveLength(1);
|
|
615
|
+
expect(computeDescriptors[0]?.timestampWrites).toBe(computeWrites);
|
|
616
|
+
});
|
|
617
|
+
|
|
504
618
|
it('reports a graph-owned compute pass begin failure to the pass owner', () => {
|
|
505
619
|
const events: string[] = [];
|
|
506
620
|
const graph = new RenderGraphBuilder<Frame>();
|
|
@@ -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
|
+
});
|
package/src/builder.ts
CHANGED
|
@@ -597,10 +597,14 @@ export class RenderGraphBuilder<FrameCtx extends RenderGraphFrame> {
|
|
|
597
597
|
const item = this.normalizeAccess(passIndex, pass, access);
|
|
598
598
|
if (!item.ok) return item;
|
|
599
599
|
normalized.push(item.value);
|
|
600
|
+
const resource = this.resources.get(item.value.resourceId);
|
|
600
601
|
const usage =
|
|
601
|
-
|
|
602
|
+
(resource?.kind === 'texture' && resource.origin === 'created'
|
|
603
|
+
? (resource.descriptor.usage ?? 0)
|
|
604
|
+
: 0) |
|
|
605
|
+
(resource?.kind === 'buffer'
|
|
602
606
|
? bufferUsage(access.usage as GraphBufferAccess)
|
|
603
|
-
: textureUsage(access.usage as GraphTextureAccess);
|
|
607
|
+
: textureUsage(access.usage as GraphTextureAccess));
|
|
604
608
|
usageByResource.set(
|
|
605
609
|
item.value.resourceId,
|
|
606
610
|
(usageByResource.get(item.value.resourceId) ?? 0) | usage,
|
package/src/compiled-graph.ts
CHANGED
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
GraphTexture,
|
|
25
25
|
GraphTextureView,
|
|
26
26
|
RenderGraphFrame,
|
|
27
|
+
RenderGraphPassInstrumentation,
|
|
27
28
|
RenderGraphPassRunner,
|
|
28
29
|
} from './types.js';
|
|
29
30
|
|
|
@@ -82,7 +83,11 @@ export class CompiledRenderGraphImpl<FrameCtx extends RenderGraphFrame>
|
|
|
82
83
|
return this.colorTargetDescriptors.get(name);
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
execute(
|
|
86
|
+
execute(
|
|
87
|
+
frame: FrameCtx,
|
|
88
|
+
runPass?: RenderGraphPassRunner,
|
|
89
|
+
instrumentation?: RenderGraphPassInstrumentation<FrameCtx>,
|
|
90
|
+
): Result<void, RenderGraphError> {
|
|
86
91
|
if (this.retired) {
|
|
87
92
|
return err(
|
|
88
93
|
new RenderGraphError({
|
|
@@ -101,8 +106,14 @@ export class CompiledRenderGraphImpl<FrameCtx extends RenderGraphFrame>
|
|
|
101
106
|
const resolver = this.createPassResolver(pass, resolved.value);
|
|
102
107
|
try {
|
|
103
108
|
if (pass.pass.descriptor.executeIf?.(frame) === false) continue;
|
|
109
|
+
const execution = { name: pass.name, kind: pass.pass.kind, executionIndex };
|
|
104
110
|
let encodeResult: Result<void, RenderGraphError> = ok(undefined);
|
|
105
111
|
const encode = () => {
|
|
112
|
+
// Resolve instrumentation only when the runner actually enters the
|
|
113
|
+
// pass. A runner may inspect or skip a pass without calling encode;
|
|
114
|
+
// such a pass must not reserve timestamp queries that it never
|
|
115
|
+
// writes.
|
|
116
|
+
const scope = instrumentation?.begin(execution, frame);
|
|
106
117
|
switch (pass.pass.kind) {
|
|
107
118
|
case 'raster': {
|
|
108
119
|
const descriptor = pass.pass.descriptor;
|
|
@@ -172,11 +183,17 @@ export class CompiledRenderGraphImpl<FrameCtx extends RenderGraphFrame>
|
|
|
172
183
|
: { stencilReadOnly: attachment.stencilReadOnly }),
|
|
173
184
|
};
|
|
174
185
|
}
|
|
175
|
-
const
|
|
186
|
+
const baseDescriptor = {
|
|
176
187
|
label: pass.name,
|
|
177
188
|
colorAttachments,
|
|
178
189
|
...(depthStencilAttachment === undefined ? {} : { depthStencilAttachment }),
|
|
179
|
-
|
|
190
|
+
...(pass.pass.descriptor.occlusionQuerySet === undefined
|
|
191
|
+
? {}
|
|
192
|
+
: { occlusionQuerySet: pass.pass.descriptor.occlusionQuerySet }),
|
|
193
|
+
};
|
|
194
|
+
const instrumentedDescriptor =
|
|
195
|
+
scope?.renderPassDescriptor?.(baseDescriptor) ?? baseDescriptor;
|
|
196
|
+
const encoder = frame.encoder.beginRenderPass(instrumentedDescriptor);
|
|
180
197
|
try {
|
|
181
198
|
descriptor.encode({ pass: encoder, frame, resources: resolver });
|
|
182
199
|
} finally {
|
|
@@ -186,9 +203,13 @@ export class CompiledRenderGraphImpl<FrameCtx extends RenderGraphFrame>
|
|
|
186
203
|
}
|
|
187
204
|
case 'compute': {
|
|
188
205
|
const begin = pass.pass.descriptor.begin?.(frame);
|
|
206
|
+
const instrumentedBegin = scope?.computePassDescriptor?.(begin ?? {}) ?? begin;
|
|
189
207
|
let encoder: RhiComputePassEncoder;
|
|
190
208
|
try {
|
|
191
|
-
encoder = frame.encoder.beginComputePass({
|
|
209
|
+
encoder = frame.encoder.beginComputePass({
|
|
210
|
+
...(instrumentedBegin ?? {}),
|
|
211
|
+
label: pass.name,
|
|
212
|
+
});
|
|
192
213
|
} catch (cause) {
|
|
193
214
|
pass.pass.descriptor.onBeginError?.(frame, cause);
|
|
194
215
|
throw cause;
|
|
@@ -202,14 +223,19 @@ export class CompiledRenderGraphImpl<FrameCtx extends RenderGraphFrame>
|
|
|
202
223
|
break;
|
|
203
224
|
}
|
|
204
225
|
case 'copy':
|
|
205
|
-
|
|
226
|
+
scope?.beforeCopy?.(frame.encoder);
|
|
227
|
+
try {
|
|
228
|
+
pass.pass.descriptor.encode({ encoder: frame.encoder, frame, resources: resolver });
|
|
229
|
+
} finally {
|
|
230
|
+
scope?.afterCopy?.(frame.encoder);
|
|
231
|
+
}
|
|
206
232
|
break;
|
|
207
233
|
}
|
|
208
234
|
};
|
|
209
235
|
if (runPass === undefined) {
|
|
210
236
|
encode();
|
|
211
237
|
} else {
|
|
212
|
-
runPass(
|
|
238
|
+
runPass(execution, encode);
|
|
213
239
|
}
|
|
214
240
|
if (!encodeResult.ok) return encodeResult;
|
|
215
241
|
} catch (cause) {
|
package/src/index.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
Buffer,
|
|
3
3
|
ComputePassDescriptor,
|
|
4
|
+
QuerySet,
|
|
5
|
+
RenderPassDescriptor,
|
|
4
6
|
RhiCommandEncoder,
|
|
5
7
|
RhiComputePassEncoder,
|
|
6
8
|
RhiDevice,
|
|
@@ -45,7 +47,7 @@ export type GraphExtent =
|
|
|
45
47
|
export interface GraphTextureDescriptor {
|
|
46
48
|
readonly format: TextureFormat;
|
|
47
49
|
readonly size: GraphExtent;
|
|
48
|
-
/** Additional RHI usage required by an external diagnostic consumer. */
|
|
50
|
+
/** Additional RHI usage required by an external diagnostic consumer such as readback. */
|
|
49
51
|
readonly usage?: number | undefined;
|
|
50
52
|
readonly mipLevelCount?: number | undefined;
|
|
51
53
|
readonly sampleCount?: number | undefined;
|
|
@@ -139,6 +141,8 @@ export interface RasterGraphPass<FrameCtx> {
|
|
|
139
141
|
readonly accesses: readonly GraphAccess[];
|
|
140
142
|
readonly colorAttachments: readonly RasterColorAttachment<FrameCtx>[];
|
|
141
143
|
readonly depthStencilAttachment?: RasterDepthStencilAttachment | undefined;
|
|
144
|
+
/** Optional producer-owned occlusion query set for this raster pass. */
|
|
145
|
+
readonly occlusionQuerySet?: QuerySet | undefined;
|
|
142
146
|
readonly executeIf?: ((frame: FrameCtx) => boolean) | undefined;
|
|
143
147
|
encode(context: {
|
|
144
148
|
readonly pass: RhiRenderPassEncoder;
|
|
@@ -244,13 +248,37 @@ export interface RenderGraphPassExecution {
|
|
|
244
248
|
|
|
245
249
|
export type RenderGraphPassRunner = (pass: RenderGraphPassExecution, encode: () => void) => void;
|
|
246
250
|
|
|
251
|
+
/**
|
|
252
|
+
* The graph-neutral boundary for observing and decorating an actual pass.
|
|
253
|
+
* Render owns the policy supplied here; the graph only preserves pass
|
|
254
|
+
* provenance and applies the decorated descriptor at the real pass-open
|
|
255
|
+
* boundary. Timestamp policy and acceptance remain outside the graph.
|
|
256
|
+
*/
|
|
257
|
+
export interface RenderGraphPassInstrumentationScope {
|
|
258
|
+
readonly renderPassDescriptor?: (descriptor: RenderPassDescriptor) => RenderPassDescriptor;
|
|
259
|
+
readonly computePassDescriptor?: (descriptor: ComputePassDescriptor) => ComputePassDescriptor;
|
|
260
|
+
readonly beforeCopy?: (encoder: RhiCommandEncoder) => void;
|
|
261
|
+
readonly afterCopy?: (encoder: RhiCommandEncoder) => void;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export interface RenderGraphPassInstrumentation<FrameCtx extends RenderGraphFrame> {
|
|
265
|
+
begin(
|
|
266
|
+
pass: RenderGraphPassExecution,
|
|
267
|
+
frame: FrameCtx,
|
|
268
|
+
): RenderGraphPassInstrumentationScope | undefined;
|
|
269
|
+
}
|
|
270
|
+
|
|
247
271
|
export interface RenderGraphCompileOptions {
|
|
248
272
|
readonly device: RhiDevice;
|
|
249
273
|
readonly surfaceSize: { readonly width: number; readonly height: number };
|
|
250
274
|
}
|
|
251
275
|
|
|
252
276
|
export interface CompiledRenderGraph<FrameCtx extends RenderGraphFrame> {
|
|
253
|
-
execute(
|
|
277
|
+
execute(
|
|
278
|
+
frame: FrameCtx,
|
|
279
|
+
runPass?: RenderGraphPassRunner,
|
|
280
|
+
instrumentation?: RenderGraphPassInstrumentation<FrameCtx>,
|
|
281
|
+
): Result<void, RenderGraphError>;
|
|
254
282
|
inspect(): CompiledRenderGraphInfo;
|
|
255
283
|
retire(): Promise<Result<void, RenderGraphError>>;
|
|
256
284
|
}
|