@babylonjs/lite 1.6.0 → 1.8.0
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/CHANGELOG.md +735 -0
- package/README.md +26 -1
- package/THIRD_PARTY_NOTICES.txt +139 -0
- package/dist/index.js +321 -301
- package/dist/index.js.map +1 -1
- package/index.d.ts +294 -13
- package/lib/_chunks/vendor/{manifold-Sh8xE2da.js → manifold-DtI3BJoR.js} +2 -2
- package/lib/_chunks/vendor/{manifold-Sh8xE2da.js.map → manifold-DtI3BJoR.js.map} +1 -1
- package/lib/animation/animation-group-task.js +1 -1
- package/lib/animation/animation-group-task.js.map +1 -1
- package/lib/animation/animation-group.js +20 -15
- package/lib/animation/animation-group.js.map +1 -1
- package/lib/animation/animation-tick.js +10 -0
- package/lib/animation/animation-tick.js.map +1 -0
- package/lib/animation/property-animation.js +2 -1
- package/lib/animation/property-animation.js.map +1 -1
- package/lib/animation/weighted-gltf-mixer.js +1 -1
- package/lib/animation/weighted-gltf-mixer.js.map +1 -1
- package/lib/animation/weighted-pointer-mixer.js +1 -1
- package/lib/animation/weighted-pointer-mixer.js.map +1 -1
- package/lib/engine/device-lost-recovery.js +1 -0
- package/lib/engine/device-lost-recovery.js.map +1 -1
- package/lib/engine/engine.js +1 -1
- package/lib/engine/null-engine.js +29 -0
- package/lib/engine/null-engine.js.map +1 -0
- package/lib/frame-graph/depth-pyramid.js +158 -0
- package/lib/frame-graph/depth-pyramid.js.map +1 -0
- package/lib/frame-graph/depth-resolve-task.js +117 -0
- package/lib/frame-graph/depth-resolve-task.js.map +1 -0
- package/lib/frame-graph/frame-graph-actions.js +10 -1
- package/lib/frame-graph/frame-graph-actions.js.map +1 -1
- package/lib/frame-graph/render-task.js +7 -0
- package/lib/frame-graph/render-task.js.map +1 -1
- package/lib/frame-graph/transmission-depth-grab.js +88 -0
- package/lib/frame-graph/transmission-depth-grab.js.map +1 -0
- package/lib/frame-graph/transmission.js +34 -4
- package/lib/frame-graph/transmission.js.map +1 -1
- package/lib/gizmo/bounding-box-gizmo.js +1 -1
- package/lib/index.js +9 -6
- package/lib/index.js.map +1 -1
- package/lib/loader-gltf/gltf-feature-gpu-instancing.js +1 -1
- package/lib/loader-gltf/gltf-interleave.js +1 -1
- package/lib/loader-gltf/load-gltf.js +1 -1
- package/lib/material/shader/shader-material.js +4 -2
- package/lib/material/shader/shader-material.js.map +1 -1
- package/lib/material/shader/shader-pipeline.js +11 -1
- package/lib/material/shader/shader-pipeline.js.map +1 -1
- package/lib/material/shader/shader-renderable.js +42 -14
- package/lib/material/shader/shader-renderable.js.map +1 -1
- package/lib/material/shader/shader-thin-instance.js +1 -1
- package/lib/material/shader/shader-thin-instance.js.map +1 -1
- package/lib/math/aabb.js +1 -1
- package/lib/math/compute-aabb.js +63 -1
- package/lib/math/compute-aabb.js.map +1 -1
- package/lib/math/index.js +1 -1
- package/lib/mesh/csg2.js +3 -2
- package/lib/mesh/csg2.js.map +1 -1
- package/lib/mesh/mesh-factories.js +1 -1
- package/lib/mesh/thin-instance-gpu-culling.js +4 -2
- package/lib/mesh/thin-instance-gpu-culling.js.map +1 -1
- package/lib/mesh/thin-instance.js +8 -1
- package/lib/mesh/thin-instance.js.map +1 -1
- package/lib/navigation/index.js +1 -1
- package/lib/navigation/navigation.js +9 -1
- package/lib/navigation/navigation.js.map +1 -1
- package/lib/physics/character-controller.js +2 -2
- package/lib/physics/character-controller.js.map +1 -1
- package/lib/physics/havok-floating-origin.js +2 -2
- package/lib/physics/havok-floating-origin.js.map +1 -1
- package/lib/physics/havok.js +40 -13
- package/lib/physics/havok.js.map +1 -1
- package/lib/picking/gpu-picker.js +16 -2
- package/lib/picking/gpu-picker.js.map +1 -1
- package/lib/scene/scene-core.js +14 -5
- package/lib/scene/scene-core.js.map +1 -1
- package/lib/scene/scene-remove.js +8 -0
- package/lib/scene/scene-remove.js.map +1 -1
- package/lib/shadow/csm-shadow-task-hooks.js +14 -6
- package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
- package/lib/shadow/pcf-shadow-task-hooks.js +6 -0
- package/lib/shadow/pcf-shadow-task-hooks.js.map +1 -1
- package/lib/texture/pixels-texture.js +31 -1
- package/lib/texture/pixels-texture.js.map +1 -1
- package/lib/vat/vat-baker.js +41 -2
- package/lib/vat/vat-baker.js.map +1 -1
- package/package.json +15 -3
- package/lib/_chunks/__vite-browser-external-BFTKbDcV.js +0 -68
- package/lib/_chunks/__vite-browser-external-BFTKbDcV.js.map +0 -1
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { SS } from '../engine/gpu-flags.js';
|
|
2
|
+
import { buildRenderTarget } from '../engine/render-target.js';
|
|
3
|
+
|
|
4
|
+
const VERTEX_WGSL = `struct V{@builtin(position)p:vec4f};
|
|
5
|
+
@vertex fn vs(@builtin(vertex_index)i:u32)->V{
|
|
6
|
+
var pos=array<vec2f,3>(vec2f(-1,-1),vec2f(3,-1),vec2f(-1,3));
|
|
7
|
+
return V(vec4f(pos[i],0,1));}`;
|
|
8
|
+
const FRAGMENT_WGSL = `@group(0)@binding(0)var src:texture_depth_multisampled_2d;
|
|
9
|
+
@fragment fn fs(v:V)->@builtin(frag_depth)f32{return textureLoad(src,vec2i(v.p.xy),0);}`;
|
|
10
|
+
let _cacheDevice = null;
|
|
11
|
+
let _bgl = null;
|
|
12
|
+
let _pipelines = null;
|
|
13
|
+
function getOrCreatePipeline(engine, depthFormat) {
|
|
14
|
+
const device = engine._device;
|
|
15
|
+
if (_cacheDevice !== device) {
|
|
16
|
+
_cacheDevice = device;
|
|
17
|
+
_bgl = null;
|
|
18
|
+
_pipelines = /* @__PURE__ */ new Map();
|
|
19
|
+
}
|
|
20
|
+
const cached = _pipelines.get(depthFormat);
|
|
21
|
+
if (cached) {
|
|
22
|
+
return cached;
|
|
23
|
+
}
|
|
24
|
+
_bgl ??= device.createBindGroupLayout({
|
|
25
|
+
label: "depth-resolve-bgl",
|
|
26
|
+
entries: [{ binding: 0, visibility: SS.FRAGMENT, texture: { sampleType: "depth", multisampled: true } }]
|
|
27
|
+
});
|
|
28
|
+
const module = device.createShaderModule({ code: `${VERTEX_WGSL}
|
|
29
|
+
${FRAGMENT_WGSL}`, label: "depth-resolve" });
|
|
30
|
+
const pipeline = device.createRenderPipeline({
|
|
31
|
+
label: `depth-resolve-${depthFormat}`,
|
|
32
|
+
layout: device.createPipelineLayout({ label: "depth-resolve-layout", bindGroupLayouts: [_bgl] }),
|
|
33
|
+
vertex: { module, entryPoint: "vs" },
|
|
34
|
+
fragment: { module, entryPoint: "fs", targets: [] },
|
|
35
|
+
// depth-only: no colour target
|
|
36
|
+
primitive: { topology: "triangle-list" },
|
|
37
|
+
depthStencil: { format: depthFormat, depthWriteEnabled: true, depthCompare: "always" }
|
|
38
|
+
});
|
|
39
|
+
_pipelines.set(depthFormat, pipeline);
|
|
40
|
+
return pipeline;
|
|
41
|
+
}
|
|
42
|
+
function createDepthResolveTask(config, engine, scene) {
|
|
43
|
+
const eng = engine;
|
|
44
|
+
const depthAttachment = {
|
|
45
|
+
view: void 0,
|
|
46
|
+
depthClearValue: 0,
|
|
47
|
+
// every fragment overwrites it (depthCompare "always"), so the clear value is moot
|
|
48
|
+
depthLoadOp: "clear",
|
|
49
|
+
depthStoreOp: "store"
|
|
50
|
+
};
|
|
51
|
+
const renderPassDescriptor = {
|
|
52
|
+
label: config.name ?? "depth-resolve",
|
|
53
|
+
colorAttachments: [],
|
|
54
|
+
depthStencilAttachment: depthAttachment
|
|
55
|
+
};
|
|
56
|
+
let pipeline = null;
|
|
57
|
+
let bindGroup = null;
|
|
58
|
+
let boundSrc = null;
|
|
59
|
+
let boundDst = null;
|
|
60
|
+
const build = () => {
|
|
61
|
+
const source = config.sourceTexture;
|
|
62
|
+
const target = config.targetTexture;
|
|
63
|
+
if (!source._depthTexture) {
|
|
64
|
+
throw new Error(`DepthResolveTask "${config.name}": sourceTexture has no depth attachment.`);
|
|
65
|
+
}
|
|
66
|
+
if ((source._descriptor.samples ?? 1) < 2) {
|
|
67
|
+
throw new Error(`DepthResolveTask "${config.name}": sourceTexture must be multisampled (sampleCount > 1).`);
|
|
68
|
+
}
|
|
69
|
+
if (!target._depthTexture || target._width !== (source._width || 0) || target._height !== (source._height || 0)) {
|
|
70
|
+
buildRenderTarget(target, eng);
|
|
71
|
+
if (target._width !== source._width || target._height !== source._height) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
`DepthResolveTask "${config.name}": targetTexture size ${target._width}×${target._height} must match sourceTexture size ${source._width}×${source._height} (size the target's descriptor like the source, e.g. both \`size: surface\`).`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const depthFormat = target._descriptor.dFormat;
|
|
78
|
+
if (!depthFormat) {
|
|
79
|
+
throw new Error(`DepthResolveTask "${config.name}": targetTexture has no depth format.`);
|
|
80
|
+
}
|
|
81
|
+
pipeline = getOrCreatePipeline(eng, depthFormat);
|
|
82
|
+
const srcView = source._depthTexture.createView({ aspect: "depth-only" });
|
|
83
|
+
bindGroup = eng._device.createBindGroup({ label: `${config.name ?? "depth-resolve"}-bg`, layout: _bgl, entries: [{ binding: 0, resource: srcView }] });
|
|
84
|
+
depthAttachment.view = target._depthView;
|
|
85
|
+
boundSrc = source._depthTexture;
|
|
86
|
+
boundDst = target._depthTexture;
|
|
87
|
+
};
|
|
88
|
+
return {
|
|
89
|
+
name: config.name ?? "depth-resolve",
|
|
90
|
+
engine: eng,
|
|
91
|
+
scene,
|
|
92
|
+
_passes: [],
|
|
93
|
+
record() {
|
|
94
|
+
build();
|
|
95
|
+
},
|
|
96
|
+
execute() {
|
|
97
|
+
if (config.sourceTexture._depthTexture !== boundSrc || config.targetTexture._depthTexture !== boundDst) {
|
|
98
|
+
build();
|
|
99
|
+
}
|
|
100
|
+
const pass = eng._currentEncoder.beginRenderPass(renderPassDescriptor);
|
|
101
|
+
pass.setPipeline(pipeline);
|
|
102
|
+
pass.setBindGroup(0, bindGroup);
|
|
103
|
+
pass.draw(3);
|
|
104
|
+
pass.end();
|
|
105
|
+
return 1;
|
|
106
|
+
},
|
|
107
|
+
dispose() {
|
|
108
|
+
pipeline = null;
|
|
109
|
+
bindGroup = null;
|
|
110
|
+
boundSrc = null;
|
|
111
|
+
boundDst = null;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export { createDepthResolveTask };
|
|
117
|
+
//# sourceMappingURL=depth-resolve-task.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"depth-resolve-task.js","sources":["../../../src/frame-graph/depth-resolve-task.ts"],"sourcesContent":["/**\n * DepthResolveTask — resolve a multisampled depth attachment into a single-sample depth texture.\n *\n * A multisampled depth texture can't be bound to a normal shader (no sampler/textureSample path), so any pass\n * that SAMPLES the scene depth (a screen-space shadow stabiliser, screen-space contact shadows, SSAO — all of\n * which reconstruct world position from depth) breaks once the scene renders to an MSAA target. This task\n * bridges that: a full-screen triangle reads sample 0 of the source `texture_depth_multisampled_2d` and writes\n * it to `@builtin(frag_depth)` through a depth-only render pass (no colour attachment) targeting a single-sample\n * destination depth.\n *\n * Sample 0 (not an average) is deliberate — depth is non-linear, so averaging samples is meaningless; sample 0\n * is a real surface depth at each pixel, which is exactly what depth-reconstruction consumers need. Modelled on\n * copy-to-texture-task's raw-pipeline pattern (cached pipeline + bind-group layout per device).\n */\n\nimport { SS } from \"../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { RenderTarget } from \"../engine/render-target.js\";\nimport { buildRenderTarget } from \"../engine/render-target.js\";\nimport type { SceneContext } from \"../scene/scene-core.js\";\nimport type { Task } from \"./task.js\";\n\n/** Options for a depth-resolve frame-graph task. */\nexport interface DepthResolveTaskConfig {\n name?: string;\n /** Multisampled source render target whose DEPTH attachment is resolved (must have sampleCount \\> 1). */\n sourceTexture: RenderTarget;\n /** Single-sample destination render target whose DEPTH attachment receives the resolved depth. */\n targetTexture: RenderTarget;\n}\n\nconst VERTEX_WGSL = `struct V{@builtin(position)p:vec4f};\n@vertex fn vs(@builtin(vertex_index)i:u32)->V{\nvar pos=array<vec2f,3>(vec2f(-1,-1),vec2f(3,-1),vec2f(-1,3));\nreturn V(vec4f(pos[i],0,1));}`;\nconst FRAGMENT_WGSL = `@group(0)@binding(0)var src:texture_depth_multisampled_2d;\n@fragment fn fs(v:V)->@builtin(frag_depth)f32{return textureLoad(src,vec2i(v.p.xy),0);}`;\n\n// Per-device cache (keyed by GPUDevice identity), lazily built on first use so scenes that never resolve depth\n// pay nothing.\nlet _cacheDevice: GPUDevice | null = null;\nlet _bgl: GPUBindGroupLayout | null = null;\nlet _pipelines: Map<GPUTextureFormat, GPURenderPipeline> | null = null;\n\nfunction getOrCreatePipeline(engine: EngineContext, depthFormat: GPUTextureFormat): GPURenderPipeline {\n const device = engine._device;\n if (_cacheDevice !== device) {\n _cacheDevice = device;\n _bgl = null;\n _pipelines = new Map();\n }\n const cached = _pipelines!.get(depthFormat);\n if (cached) {\n return cached;\n }\n _bgl ??= device.createBindGroupLayout({\n label: \"depth-resolve-bgl\",\n entries: [{ binding: 0, visibility: SS.FRAGMENT, texture: { sampleType: \"depth\", multisampled: true } }],\n });\n const module = device.createShaderModule({ code: `${VERTEX_WGSL}\\n${FRAGMENT_WGSL}`, label: \"depth-resolve\" });\n const pipeline = device.createRenderPipeline({\n label: `depth-resolve-${depthFormat}`,\n layout: device.createPipelineLayout({ label: \"depth-resolve-layout\", bindGroupLayouts: [_bgl] }),\n vertex: { module, entryPoint: \"vs\" },\n fragment: { module, entryPoint: \"fs\", targets: [] }, // depth-only: no colour target\n primitive: { topology: \"triangle-list\" },\n depthStencil: { format: depthFormat, depthWriteEnabled: true, depthCompare: \"always\" },\n });\n _pipelines!.set(depthFormat, pipeline);\n return pipeline;\n}\n\n/** Create a frame-graph task that resolves `sourceTexture`'s multisampled depth into `targetTexture`'s\n * single-sample depth. Add it AFTER the source render task and BEFORE any depth-sampling consumer. */\nexport function createDepthResolveTask(config: DepthResolveTaskConfig, engine: EngineContext, scene: SceneContext): Task {\n const eng = engine;\n const depthAttachment: GPURenderPassDepthStencilAttachment = {\n view: undefined!,\n depthClearValue: 0, // every fragment overwrites it (depthCompare \"always\"), so the clear value is moot\n depthLoadOp: \"clear\",\n depthStoreOp: \"store\",\n };\n const renderPassDescriptor: GPURenderPassDescriptor = {\n label: config.name ?? \"depth-resolve\",\n colorAttachments: [],\n depthStencilAttachment: depthAttachment,\n };\n let pipeline: GPURenderPipeline | null = null;\n let bindGroup: GPUBindGroup | null = null;\n let boundSrc: GPUTexture | null = null;\n let boundDst: GPUTexture | null = null;\n\n // (Re)build the pipeline, bind group and depth-attachment view from the live RT textures. Run at record()\n // and again whenever a resize reallocates either texture (checked in execute, mirroring the DoF getters).\n const build = (): void => {\n const source = config.sourceTexture;\n const target = config.targetTexture;\n if (!source._depthTexture) {\n throw new Error(`DepthResolveTask \"${config.name}\": sourceTexture has no depth attachment.`);\n }\n if ((source._descriptor.samples ?? 1) < 2) {\n throw new Error(`DepthResolveTask \"${config.name}\": sourceTexture must be multisampled (sampleCount > 1).`);\n }\n if (!target._depthTexture || target._width !== (source._width || 0) || target._height !== (source._height || 0)) {\n // Build (or REBUILD) the offscreen destination so it tracks the source size. No render task owns this\n // target, so the frame graph never resizes it on its own — without this, a window resize leaves the\n // resolved depth stuck at the OLD size, and every depth-reconstruction consumer (SSCS, SSAO, the\n // shadow-TAA stabiliser) then samples a mismatched-size depth → screen-space streaks until reload.\n buildRenderTarget(target, eng);\n // buildRenderTarget sizes the target from its OWN descriptor (resolveSize), not the source. The whole\n // point of this task is a 1:1 depth copy, so the target descriptor MUST resolve to the source size\n // (e.g. both `size: surface`). Fail fast on a mismatch instead of silently thrashing — otherwise this\n // branch's condition would stay true and rebuild/destroy the target on every build() call.\n if (target._width !== source._width || target._height !== source._height) {\n throw new Error(\n `DepthResolveTask \"${config.name}\": targetTexture size ${target._width}×${target._height} must match ` +\n `sourceTexture size ${source._width}×${source._height} (size the target's descriptor like the source, e.g. both \\`size: surface\\`).`\n );\n }\n }\n const depthFormat = target._descriptor.dFormat;\n if (!depthFormat) {\n throw new Error(`DepthResolveTask \"${config.name}\": targetTexture has no depth format.`);\n }\n pipeline = getOrCreatePipeline(eng, depthFormat);\n // A DEPTH-aspect view of the MSAA source: a depth-stencil texture must be bound through its depth aspect\n // to read as texture_depth_multisampled_2d.\n const srcView = source._depthTexture.createView({ aspect: \"depth-only\" });\n bindGroup = eng._device.createBindGroup({ label: `${config.name ?? \"depth-resolve\"}-bg`, layout: _bgl!, entries: [{ binding: 0, resource: srcView }] });\n depthAttachment.view = target._depthView!;\n boundSrc = source._depthTexture;\n boundDst = target._depthTexture;\n };\n\n return {\n name: config.name ?? \"depth-resolve\",\n engine: eng,\n scene,\n _passes: [],\n record(): void {\n build();\n },\n execute(): number {\n if (config.sourceTexture._depthTexture !== boundSrc || config.targetTexture._depthTexture !== boundDst) {\n build(); // a resize reallocated the MSAA depth and/or the resolve target — rebind to the new textures\n }\n const pass = eng._currentEncoder.beginRenderPass(renderPassDescriptor);\n pass.setPipeline(pipeline!);\n pass.setBindGroup(0, bindGroup!);\n pass.draw(3);\n pass.end();\n return 1;\n },\n dispose(): void {\n pipeline = null;\n bindGroup = null;\n boundSrc = null;\n boundDst = null;\n },\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -30,6 +30,15 @@ function addTaskBefore(target, task, before) {
|
|
|
30
30
|
fg._tasks.splice(i, 0, task);
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
+
function addTaskAfter(target, task, after) {
|
|
34
|
+
const fg = resolveFg(target);
|
|
35
|
+
const i = fg._tasks.indexOf(after);
|
|
36
|
+
if (i < 0) {
|
|
37
|
+
fg._tasks.push(task);
|
|
38
|
+
} else {
|
|
39
|
+
fg._tasks.splice(i + 1, 0, task);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
33
42
|
function addRenderPass(target, name) {
|
|
34
43
|
const fg = resolveFg(target);
|
|
35
44
|
const task = fg._currentProcessedTask;
|
|
@@ -39,5 +48,5 @@ function addRenderPass(target, name) {
|
|
|
39
48
|
return createRenderPass(name, task);
|
|
40
49
|
}
|
|
41
50
|
|
|
42
|
-
export { addRenderPass, addTask, addTaskAtStart, addTaskBefore };
|
|
51
|
+
export { addRenderPass, addTask, addTaskAfter, addTaskAtStart, addTaskBefore };
|
|
43
52
|
//# sourceMappingURL=frame-graph-actions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame-graph-actions.js","sources":["../../../src/frame-graph/frame-graph-actions.ts"],"sourcesContent":["import type { SceneContext } from \"../scene/scene-core.js\";\nimport type { Task } from \"./task.js\";\nimport type { FrameGraph } from \"./frame-graph.js\";\nimport { _appendTask } from \"./frame-graph.js\";\nimport type { RenderPass } from \"./render-pass.js\";\nimport { createRenderPass } from \"./render-pass.js\";\n\nfunction isFrameGraph(value: unknown): value is FrameGraph {\n return typeof value === \"object\" && value !== null && \"_tasks\" in value;\n}\n\nfunction resolveFg(target: FrameGraph | SceneContext): FrameGraph {\n if (isFrameGraph(target)) {\n return target;\n }\n if (\"_frameGraph\" in target && isFrameGraph(target._frameGraph)) {\n return target._frameGraph;\n }\n throw new Error(\"FrameGraph target does not expose a frame graph.\");\n}\n\n/** Add a task at the END of execute order. Accepts the scene's frame graph directly,\n * or a SceneContext (the scene's default frame graph is used). */\nexport function addTask(target: FrameGraph | SceneContext, task: Task): void {\n _appendTask(resolveFg(target), task);\n}\n\n/** Insert a task at the START of user execute order. Built-in system tasks that must\n * precede all user work, such as the shadow adapter, keep their leading slot. */\nexport function addTaskAtStart(target: FrameGraph | SceneContext, task: Task): void {\n const fg = resolveFg(target);\n const firstUserTask = fg._tasks[0]?.name === \"shadow\" ? 1 : 0;\n fg._tasks.splice(firstUserTask, 0, task);\n}\n\n/** Insert a task BEFORE another task in execute order. Accepts a FrameGraph or a SceneContext. */\nexport function addTaskBefore(target: FrameGraph | SceneContext, task: Task, before: Task): void {\n const fg = resolveFg(target);\n const i = fg._tasks.indexOf(before);\n if (i < 0) {\n fg._tasks.push(task);\n } else {\n fg._tasks.splice(i, 0, task);\n }\n}\n\n/** Create a `RenderPass`, wire it to the task currently recording, and return\n * it. Must be called from inside `Task.record()` so the FG can associate the\n * new pass with the right task (mirrors BJS `frameGraph.addRenderPass`).\n *\n * Configure the returned pass with `setRenderPassRenderTarget`,\n * `setRenderPassExecuteFunc`, etc. before the FG finishes building. */\nexport function addRenderPass(target: FrameGraph | SceneContext, name: string): RenderPass {\n const fg = resolveFg(target);\n const task = fg._currentProcessedTask;\n if (!task) {\n throw new Error(`addRenderPass(\"${name}\"): no task is currently recording (called outside Task.record?)`);\n }\n return createRenderPass(name, task);\n}\n"],"names":[],"mappings":";;;AAOA,SAAS,aAAa,KAAA,EAAqC;AACvD,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,QAAA,IAAY,KAAA;AACtE;AAEA,SAAS,UAAU,MAAA,EAA+C;AAC9D,EAAA,IAAI,YAAA,CAAa,MAAM,CAAA,EAAG;AACtB,IAAA,OAAO,MAAA;AAAA,EACX;AACA,EAAA,IAAI,aAAA,IAAiB,MAAA,IAAU,YAAA,CAAa,MAAA,CAAO,WAAW,CAAA,EAAG;AAC7D,IAAA,OAAO,MAAA,CAAO,WAAA;AAAA,EAClB;AACA,EAAA,MAAM,IAAI,MAAM,kDAAkD,CAAA;AACtE;AAIO,SAAS,OAAA,CAAQ,QAAmC,IAAA,EAAkB;AACzE,EAAA,WAAA,CAAY,SAAA,CAAU,MAAM,CAAA,EAAG,IAAI,CAAA;AACvC;AAIO,SAAS,cAAA,CAAe,QAAmC,IAAA,EAAkB;AAChF,EAAA,MAAM,EAAA,GAAK,UAAU,MAAM,CAAA;AAC3B,EAAA,MAAM,gBAAgB,EAAA,CAAG,MAAA,CAAO,CAAC,CAAA,EAAG,IAAA,KAAS,WAAW,CAAA,GAAI,CAAA;AAC5D,EAAA,EAAA,CAAG,MAAA,CAAO,MAAA,CAAO,aAAA,EAAe,CAAA,EAAG,IAAI,CAAA;AAC3C;AAGO,SAAS,aAAA,CAAc,MAAA,EAAmC,IAAA,EAAY,MAAA,EAAoB;AAC7F,EAAA,MAAM,EAAA,GAAK,UAAU,MAAM,CAAA;AAC3B,EAAA,MAAM,CAAA,GAAI,EAAA,CAAG,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA;AAClC,EAAA,IAAI,IAAI,CAAA,EAAG;AACP,IAAA,EAAA,CAAG,MAAA,CAAO,KAAK,IAAI,CAAA;AAAA,EACvB,CAAA,MAAO;AACH,IAAA,EAAA,CAAG,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,CAAA,EAAG,IAAI,CAAA;AAAA,EAC/B;AACJ;AAQO,SAAS,aAAA,CAAc,QAAmC,IAAA,EAA0B;AACvF,EAAA,MAAM,EAAA,GAAK,UAAU,MAAM,CAAA;AAC3B,EAAA,MAAM,OAAO,EAAA,CAAG,qBAAA;AAChB,EAAA,IAAI,CAAC,IAAA,EAAM;AACP,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,IAAI,CAAA,gEAAA,CAAkE,CAAA;AAAA,EAC5G;AACA,EAAA,OAAO,gBAAA,CAAiB,MAAM,IAAI,CAAA;AACtC;;;;"}
|
|
1
|
+
{"version":3,"file":"frame-graph-actions.js","sources":["../../../src/frame-graph/frame-graph-actions.ts"],"sourcesContent":["import type { SceneContext } from \"../scene/scene-core.js\";\nimport type { Task } from \"./task.js\";\nimport type { FrameGraph } from \"./frame-graph.js\";\nimport { _appendTask } from \"./frame-graph.js\";\nimport type { RenderPass } from \"./render-pass.js\";\nimport { createRenderPass } from \"./render-pass.js\";\n\nfunction isFrameGraph(value: unknown): value is FrameGraph {\n return typeof value === \"object\" && value !== null && \"_tasks\" in value;\n}\n\nfunction resolveFg(target: FrameGraph | SceneContext): FrameGraph {\n if (isFrameGraph(target)) {\n return target;\n }\n if (\"_frameGraph\" in target && isFrameGraph(target._frameGraph)) {\n return target._frameGraph;\n }\n throw new Error(\"FrameGraph target does not expose a frame graph.\");\n}\n\n/** Add a task at the END of execute order. Accepts the scene's frame graph directly,\n * or a SceneContext (the scene's default frame graph is used). */\nexport function addTask(target: FrameGraph | SceneContext, task: Task): void {\n _appendTask(resolveFg(target), task);\n}\n\n/** Insert a task at the START of user execute order. Built-in system tasks that must\n * precede all user work, such as the shadow adapter, keep their leading slot. */\nexport function addTaskAtStart(target: FrameGraph | SceneContext, task: Task): void {\n const fg = resolveFg(target);\n const firstUserTask = fg._tasks[0]?.name === \"shadow\" ? 1 : 0;\n fg._tasks.splice(firstUserTask, 0, task);\n}\n\n/** Insert a task BEFORE another task in execute order. Accepts a FrameGraph or a SceneContext. */\nexport function addTaskBefore(target: FrameGraph | SceneContext, task: Task, before: Task): void {\n const fg = resolveFg(target);\n const i = fg._tasks.indexOf(before);\n if (i < 0) {\n fg._tasks.push(task);\n } else {\n fg._tasks.splice(i, 0, task);\n }\n}\n\n/** Insert a task immediately AFTER another task in execute order. Accepts a FrameGraph or a SceneContext.\n * If `after` is not found, the task is appended at the end (matching `addTaskBefore`'s fallback). */\nexport function addTaskAfter(target: FrameGraph | SceneContext, task: Task, after: Task): void {\n const fg = resolveFg(target);\n const i = fg._tasks.indexOf(after);\n if (i < 0) {\n fg._tasks.push(task);\n } else {\n fg._tasks.splice(i + 1, 0, task);\n }\n}\n\n/** Create a `RenderPass`, wire it to the task currently recording, and return\n * it. Must be called from inside `Task.record()` so the FG can associate the\n * new pass with the right task (mirrors BJS `frameGraph.addRenderPass`).\n *\n * Configure the returned pass with `setRenderPassRenderTarget`,\n * `setRenderPassExecuteFunc`, etc. before the FG finishes building. */\nexport function addRenderPass(target: FrameGraph | SceneContext, name: string): RenderPass {\n const fg = resolveFg(target);\n const task = fg._currentProcessedTask;\n if (!task) {\n throw new Error(`addRenderPass(\"${name}\"): no task is currently recording (called outside Task.record?)`);\n }\n return createRenderPass(name, task);\n}\n"],"names":[],"mappings":";;;AAOA,SAAS,aAAa,KAAA,EAAqC;AACvD,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,QAAA,IAAY,KAAA;AACtE;AAEA,SAAS,UAAU,MAAA,EAA+C;AAC9D,EAAA,IAAI,YAAA,CAAa,MAAM,CAAA,EAAG;AACtB,IAAA,OAAO,MAAA;AAAA,EACX;AACA,EAAA,IAAI,aAAA,IAAiB,MAAA,IAAU,YAAA,CAAa,MAAA,CAAO,WAAW,CAAA,EAAG;AAC7D,IAAA,OAAO,MAAA,CAAO,WAAA;AAAA,EAClB;AACA,EAAA,MAAM,IAAI,MAAM,kDAAkD,CAAA;AACtE;AAIO,SAAS,OAAA,CAAQ,QAAmC,IAAA,EAAkB;AACzE,EAAA,WAAA,CAAY,SAAA,CAAU,MAAM,CAAA,EAAG,IAAI,CAAA;AACvC;AAIO,SAAS,cAAA,CAAe,QAAmC,IAAA,EAAkB;AAChF,EAAA,MAAM,EAAA,GAAK,UAAU,MAAM,CAAA;AAC3B,EAAA,MAAM,gBAAgB,EAAA,CAAG,MAAA,CAAO,CAAC,CAAA,EAAG,IAAA,KAAS,WAAW,CAAA,GAAI,CAAA;AAC5D,EAAA,EAAA,CAAG,MAAA,CAAO,MAAA,CAAO,aAAA,EAAe,CAAA,EAAG,IAAI,CAAA;AAC3C;AAGO,SAAS,aAAA,CAAc,MAAA,EAAmC,IAAA,EAAY,MAAA,EAAoB;AAC7F,EAAA,MAAM,EAAA,GAAK,UAAU,MAAM,CAAA;AAC3B,EAAA,MAAM,CAAA,GAAI,EAAA,CAAG,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA;AAClC,EAAA,IAAI,IAAI,CAAA,EAAG;AACP,IAAA,EAAA,CAAG,MAAA,CAAO,KAAK,IAAI,CAAA;AAAA,EACvB,CAAA,MAAO;AACH,IAAA,EAAA,CAAG,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,CAAA,EAAG,IAAI,CAAA;AAAA,EAC/B;AACJ;AAIO,SAAS,YAAA,CAAa,MAAA,EAAmC,IAAA,EAAY,KAAA,EAAmB;AAC3F,EAAA,MAAM,EAAA,GAAK,UAAU,MAAM,CAAA;AAC3B,EAAA,MAAM,CAAA,GAAI,EAAA,CAAG,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA;AACjC,EAAA,IAAI,IAAI,CAAA,EAAG;AACP,IAAA,EAAA,CAAG,MAAA,CAAO,KAAK,IAAI,CAAA;AAAA,EACvB,CAAA,MAAO;AACH,IAAA,EAAA,CAAG,MAAA,CAAO,MAAA,CAAO,CAAA,GAAI,CAAA,EAAG,GAAG,IAAI,CAAA;AAAA,EACnC;AACJ;AAQO,SAAS,aAAA,CAAc,QAAmC,IAAA,EAA0B;AACvF,EAAA,MAAM,EAAA,GAAK,UAAU,MAAM,CAAA;AAC3B,EAAA,MAAM,OAAO,EAAA,CAAG,qBAAA;AAChB,EAAA,IAAI,CAAC,IAAA,EAAM;AACP,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,IAAI,CAAA,gEAAA,CAAkE,CAAA;AAAA,EAC5G;AACA,EAAA,OAAO,gBAAA,CAAiB,MAAM,IAAI,CAAA;AACtC;;;;"}
|
|
@@ -45,6 +45,7 @@ function createRenderTask(config, engine, scene) {
|
|
|
45
45
|
_opaqueBundles: [],
|
|
46
46
|
_lastVersion: -1,
|
|
47
47
|
_lastVis: 0,
|
|
48
|
+
_recorded: false,
|
|
48
49
|
_renderPassDescriptor: { colorAttachments: [colorAttachment] },
|
|
49
50
|
_colorAttachment: colorAttachment,
|
|
50
51
|
_depthSrc: config.depth,
|
|
@@ -62,6 +63,11 @@ function createRenderTask(config, engine, scene) {
|
|
|
62
63
|
return;
|
|
63
64
|
}
|
|
64
65
|
task._pendingMeshes.push({ mesh, material });
|
|
66
|
+
if (task._recorded) {
|
|
67
|
+
resolvePendingMeshes(task, sc);
|
|
68
|
+
task._autoFromScene = false;
|
|
69
|
+
buildBindings(task, engine, targetSignature);
|
|
70
|
+
}
|
|
65
71
|
},
|
|
66
72
|
record() {
|
|
67
73
|
if (task._autoFromScene) {
|
|
@@ -85,6 +91,7 @@ function createRenderTask(config, engine, scene) {
|
|
|
85
91
|
refreshTaskSceneBindGroup(task, engine);
|
|
86
92
|
buildBindings(task, engine, targetSignature);
|
|
87
93
|
buildRenderPassDescriptor(task, rt);
|
|
94
|
+
task._recorded = true;
|
|
88
95
|
},
|
|
89
96
|
execute() {
|
|
90
97
|
return executePass(task, engine, targetSignature, updateContext);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-task.js","sources":["../../../src/frame-graph/render-task.ts"],"sourcesContent":["/**\n * RenderTask — a frame-graph task that records a single `RenderPass`,\n * binds the scene's `RenderTarget`, and draws renderables into it.\n *\n * - `record()` builds bucketed `DrawBinding` lists from `_renderables`\n * (opaque / direct / transparent), sorts opaque + direct by\n * `order`, then creates a `RenderPass` wired to the task's render target.\n * The pass owns its\n * `GPURenderPassDescriptor` and the per-pass-encoder body lives in a\n * closure passed to `setRenderPassExecuteFunc`.\n * - Before `RenderPass._execute()` begins the GPU pass: writes the scene UBO, refreshes lights, updates\n * per-binding UBOs, mirrors live `scene.clearColor` + `clr` onto the\n * render pass. Shared task execution then calls `_execute()`. The\n * `RenderPass` itself patches the swapchain view + clearColor + loadOp\n * and brackets the body with `beginRenderPass` / `end`.\n *\n * Renderable population:\n * - Explicit: push into `_renderables` directly, or `addMesh(mesh, opts)`\n * which builds a (mesh, material) Renderable at `record()` time.\n * - Auto scene mirror: when `_renderables` is empty at record() time, copy the\n * scene's renderables. Re-sync happens automatically when the scene's\n * `_renderableVersion` changes between frames (mesh add/remove, material swap).\n *\n * The engine `scRT` is just another `RenderTarget` here: a task that\n * targets it (`rt`) or resolves into it (`rst`) re-reads its per-frame color view\n * at execute time (the swap texture is re-acquired each frame). `clr: false`\n * switches color + depth `loadOp` to `\"load\"` so multiple scenes can share the\n * swapchain in one frame (e.g., a 3D scene + a UI overlay scene).\n */\n\nimport { F32 } from \"../engine/typed-arrays.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport { _vis } from \"../engine/engine.js\";\nimport type { Mesh } from \"../mesh/mesh.js\";\nimport type { Camera } from \"../camera/camera.js\";\nimport type { Renderable, DrawBinding, DrawUpdateContext } from \"../render/renderable.js\";\nimport type { RenderTargetSignature } from \"../engine/render-target.js\";\nimport type { SceneContext } from \"../scene/scene-core.js\";\nimport type { Material } from \"../material/material.js\";\nimport type { RenderTarget } from \"../engine/render-target.js\";\nimport { buildRenderTarget, disposeRenderTarget } from \"../engine/render-target.js\";\nimport { getViewMatrix } from \"../camera/camera.js\";\nimport { getSceneBindGroupLayout } from \"../render/scene-helpers.js\";\nimport { _packSceneUniforms } from \"./scene-uniforms-pack.js\";\nimport { createEmptyUniformBuffer } from \"../resource/gpu-buffers.js\";\nimport { SCENE_UBO_BYTES } from \"../shader/scene-uniforms-size.js\";\nimport { ensureSceneLightState, refreshSceneLightsUBO } from \"../render/lights-ubo.js\";\nimport type { Task } from \"./task.js\";\n\n/** Configuration for `createRenderTask`: render target, clear state, optional camera override, and transmission settings. */\nexport interface RenderTaskConfig {\n name: string;\n /** TODO: rt should not live in this config long-term. Until texture\n * management is virtualized, callers must provide the concrete target; once\n * virtualized, the task should create/manage its own render target. */\n rt: RenderTarget;\n /** Optional single-sample resolve target. When `rt` is multisampled\n * (`sampleCount > 1`), the color attachment resolves into this target's\n * color texture at end-of-pass — letting an MSAA render feed a post-process\n * that requires a single-sample source, without an extra resolve pass.\n * Caller contract (not validated): must be single-sample with a color\n * format and size matching `rt`; WebGPU errors at pass-encode time if not.\n * Ignored when `rt` is single-sample. */\n rst?: RenderTarget;\n /** Optional separate depth/stencil attachment. The pass binds this target's\n * depth view instead of `rt`'s own, and uses its `depthStencilFormat` for\n * pipeline signature matching. The colour `rt` must omit `depthStencilFormat`\n * (so it allocates no internal depth) and match this target in size + sample\n * count. Two ownership modes, distinguished by `_eager`:\n * - `_eager` depth (e.g. a `GeometryRendererTask` output): the task neither\n * builds nor clears nor disposes it — it loads it (`loadOp: \"load\"`) and the\n * caller owns clearing. This is how scenes reuse a pre-rendered depth buffer.\n * - non-`_eager` depth: the task owns it — builds/rebuilds it in `record()`,\n * clears it (`loadOp: \"clear\"`), and disposes it. Used by the default\n * single-sample scene task, whose colour `rt` is the depth-less\n * engine `scRT`. */\n depth?: RenderTarget;\n /** Background clear color. May be mutated frame-to-frame. */\n clrColor?: GPUColorDict;\n /** When true, color `loadOp` is \"clear\"; when false, \"load\" (overlays previous\n * color content). Depth is always cleared when rt-owned and always loaded when\n * supplied via `depth`. */\n clr?: boolean;\n /** Per-pass camera override. Null/undefined uses `scene.camera`. */\n cam?: Camera | null;\n /** Use canvas dimensions, not render-target dimensions, for this pass's scene UBO aspect. */\n cs?: boolean;\n /** Scene-texture transmission settings. `copyCount: 0` copies before every transmissive draw.\n * `generateMipmaps: false` allocates only mip 0 for the refraction texture and skips mip generation.\n * `mipLevelCount` caps the generated chain when a material only samples low explicit LODs. */\n transmission?: { copyCount?: number; generateMipmaps?: boolean; mipLevelCount?: number };\n}\n\n/** A frame-graph task that records a single `RenderPass`, binds the scene's `RenderTarget`, and draws renderables into it. */\nexport interface RenderTask extends Task {\n readonly name: string;\n /** Render tasks are scene-bound because they consume scene camera, lights, and renderables. */\n readonly scene: SceneContext;\n /** Live task configuration. Mutating `clr` or `clrColor` affects subsequent frames. */\n /** @internal */\n readonly _config: RenderTaskConfig;\n /** @internal */\n _autoFromScene: boolean;\n\n /** Source-of-truth renderables. Bucketed binding lists below are derived from\n * this list at `record()` (or re-sync when auto-filled and `_renderableVersion` changes). */\n /** @internal */\n _renderables: Renderable[];\n /** @internal */\n _opaqueBindings: DrawBinding[];\n /** @internal */\n _directBindings: DrawBinding[];\n /** @internal */\n _transparentBindings: DrawBinding[];\n /** Cached opaque render bundle. Invalidated by renderable list mutations\n * (`_lastVersion`) and visibility changes (`_lastVis`). */\n /** @internal */\n _opaqueBundles: GPURenderBundle[];\n /** @internal */\n _lastVersion: number;\n /** @internal */\n _lastVis: number;\n\n /** @internal */\n _renderPassDescriptor: GPURenderPassDescriptor;\n /** @internal */\n _colorAttachment: GPURenderPassColorAttachment;\n /** @internal External depth source from `config.depth`. When unset,\n * the pass uses `config.rt._depthView`. */\n _depthSrc?: RenderTarget;\n /** @internal External depth/stencil `loadOp` (\"load\" when `config.depth` is\n * set). When unset, defaults to `\"clear\"`. */\n _depthLoadOp?: GPULoadOp;\n\n /** Per-task scene UBO + bind group. Created eagerly in createRenderTask\n * so renderables can reference `_sceneBG` at `bind()` time. Written each\n * frame by `writePassSceneUBO`. Destroyed in `dispose()`. */\n /** @internal */\n _sceneUBO: GPUBuffer;\n /** @internal */\n _sceneBG: GPUBindGroup;\n /** @internal */\n _lightsUBO: GPUBuffer;\n /** @internal */\n _suData: Float32Array;\n /** @internal */\n _su: unknown[];\n /** Optional transmission-enabled execute path: copies the scene texture for refraction and draws transmissive\n * renderables. Present only when the task was configured with `transmission`. Returns the number of draw calls issued. */\n /** @internal */\n _executeWithTransmission?(sampleCount: number): number;\n /** @internal */\n _targetSignature: RenderTargetSignature;\n\n /** Add a mesh to this task's explicit render list with an optional per-pass material override.\n * Resolved at `record()` time via `material._buildGroup._rebuildSingle`,\n * so the mesh's material family must already have been registered with\n * the scene (so its batch builder has run). */\n addMesh(mesh: Mesh, opts?: { material?: Material }): void;\n /** @internal */\n _pendingMeshes: { mesh: Mesh; material: Material }[];\n}\n\ninterface MutableDrawUpdateContext {\n targetWidth: number;\n targetHeight: number;\n _camera?: Camera | null;\n}\n\n/** Create a render pass task. GPU resources (target textures + descriptor)\n * are not allocated until `record()` runs (via `frameGraph.build()`).\n *\n * Swapchain-targeted tasks acquire the swap view per-frame at execute time. */\nexport function createRenderTask(config: RenderTaskConfig, engine: EngineContext, scene: SceneContext): RenderTask {\n const sc = scene as SceneContext;\n config.clrColor ??= { r: 0.2, g: 0.2, b: 0.3, a: 1.0 };\n config.clr ??= true;\n const desc = config.rt._descriptor;\n // Render upright: row 0 of the GPU texture is the top of the scene. Every\n // RT (offscreen or swapchain) renders without a projection Y-flip; pipelines\n // use the default ccw front face; downstream samplers see upright pixels.\n const targetSignature = {\n _colorFormat: desc.format,\n _depthStencilFormat: config.depth?._descriptor.dFormat ?? desc.dFormat,\n _depthCompare: desc._depthCompare,\n _sampleCount: desc.samples ?? 1,\n };\n\n const sceneBGL = getSceneBindGroupLayout(engine);\n const sceneUBO = createEmptyUniformBuffer(engine, SCENE_UBO_BYTES);\n const lightsUBO = ensureSceneLightState(engine, sc)._buffer;\n const sceneBG = engine._device.createBindGroup({\n layout: sceneBGL,\n entries: [\n { binding: 0, resource: { buffer: sceneUBO } },\n { binding: 1, resource: { buffer: lightsUBO } },\n ],\n });\n const colorAttachment = { loadOp: \"clear\", storeOp: \"store\" } as GPURenderPassColorAttachment;\n const updateContext: MutableDrawUpdateContext = { targetWidth: 0, targetHeight: 0 };\n const task: RenderTask = {\n name: config.name,\n _config: config,\n engine: engine,\n scene: sc,\n _passes: [],\n _autoFromScene: false,\n _renderables: [],\n _opaqueBindings: [],\n _directBindings: [],\n _transparentBindings: [],\n _opaqueBundles: [],\n _lastVersion: -1,\n _lastVis: 0,\n _renderPassDescriptor: { colorAttachments: [colorAttachment] },\n _colorAttachment: colorAttachment,\n _depthSrc: config.depth,\n _depthLoadOp: config.depth ? (config.depth._eager ? \"load\" : \"clear\") : undefined,\n _sceneUBO: sceneUBO,\n _sceneBG: sceneBG,\n _lightsUBO: lightsUBO,\n _suData: new F32(SCENE_UBO_BYTES / 4),\n _su: [],\n _targetSignature: targetSignature,\n _pendingMeshes: [],\n addMesh(mesh, opts) {\n const material = opts?.material ?? mesh.material;\n if (!material) {\n return;\n }\n task._pendingMeshes.push({ mesh, material });\n },\n record(): void {\n if (task._autoFromScene) {\n task._renderables.length = 0;\n }\n resolvePendingMeshes(task, sc);\n task._autoFromScene = task._renderables.length === 0;\n if (task._autoFromScene) {\n task._renderables.push(...sc._renderables);\n }\n // Read config.rt dynamically — transmission retargeting swaps it after\n // the task is created, and the engine scRT must never be rebuilt.\n const rt = config.rt;\n buildRenderTarget(rt, engine);\n if (config.rst && (rt._descriptor.samples ?? 1) > 1) {\n buildRenderTarget(config.rst, engine);\n }\n // A non-eager external depth (e.g. the default single-sample scene task's\n // depth, whose colour rt is the depth-less scRT) is task-managed:\n // build/rebuild it here. Eager depths (GeometryRendererTask outputs) are\n // pre-built and skipped by buildRenderTarget.\n if (config.depth && !config.depth._eager) {\n buildRenderTarget(config.depth, engine);\n }\n updateContext.targetWidth = rt._width;\n updateContext.targetHeight = rt._height;\n refreshTaskSceneBindGroup(task, engine);\n buildBindings(task, engine, targetSignature);\n buildRenderPassDescriptor(task, rt);\n },\n execute(): number {\n return executePass(task, engine, targetSignature, updateContext);\n },\n dispose(): void {\n task._passes.length = 0;\n // disposeRenderTarget no-ops on the engine scRT and on eager\n // GeometryRendererTask depth outputs (both `_eager`), and on an undefined\n // rst/depth — so these can be passed unconditionally.\n disposeRenderTarget(config.rt);\n disposeRenderTarget(config.rst);\n disposeRenderTarget(config.depth);\n task._opaqueBindings.length = 0;\n task._directBindings.length = 0;\n task._transparentBindings.length = 0;\n task._renderables.length = 0;\n task._opaqueBundles.length = 0;\n task._sceneUBO.destroy();\n },\n };\n return task;\n}\n\n/** Remove a mesh from this task's renderable + binding lists. Idempotent. */\nexport function removeMeshFromTask(task: RenderTask, mesh: object): void {\n // Not a renderable-bearing task (e.g. a post/effect task that also carries `_config`): nothing to\n // remove. Guard keeps callers that scan all frame-graph tasks (removeFromScene) shape-safe.\n if (!task._renderables) {\n return;\n }\n let removed = false;\n for (let i = task._renderables.length - 1; i >= 0; i--) {\n if (task._renderables[i]!.mesh === mesh) {\n task._renderables.splice(i, 1);\n removed = true;\n }\n }\n for (const arr of [task._opaqueBindings, task._directBindings, task._transparentBindings]) {\n for (let i = arr.length - 1; i >= 0; i--) {\n if (arr[i]!.renderable.mesh === mesh) {\n arr.splice(i, 1);\n removed = true;\n }\n }\n }\n if (removed) {\n task._opaqueBundles.length = 0;\n task._lastVersion = -1;\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction resolvePendingMeshes(task: RenderTask, sc: SceneContext): void {\n if (task._pendingMeshes.length === 0) {\n return;\n }\n for (const { mesh, material } of task._pendingMeshes) {\n const rebuild = material._buildGroup?._rebuildSingle;\n if (!rebuild) {\n throw new Error();\n }\n const renderable = rebuild(sc, mesh, material);\n if (!task._renderables.includes(renderable)) {\n task._renderables.push(renderable);\n }\n }\n task._pendingMeshes.length = 0;\n}\n\n/** Per-frame back-to-front sort for transparent bindings using the active camera. */\nfunction sortTransparentBindings(task: RenderTask, camera: Camera | null | undefined): void {\n const arr = task._transparentBindings;\n if (arr.length <= 1 || !camera) {\n return;\n }\n const v = getViewMatrix(camera);\n for (const b of arr) {\n const wc = b.renderable._worldCenter;\n b._sortDistance = wc ? wc[0]! * v[2]! + wc[1]! * v[6]! + wc[2]! * v[10]! + v[14]! : 0;\n }\n arr.sort((a, b) => b._sortDistance! - a._sortDistance! || a.renderable.order - b.renderable.order);\n}\n\n/** (Re)bucket task._renderables into bound lists. */\nfunction buildBindings(task: RenderTask, eng: EngineContext, targetSignature: RenderTargetSignature): void {\n const opaque = task._opaqueBindings;\n const direct = task._directBindings;\n const transparent = task._transparentBindings;\n opaque.length = 0;\n direct.length = 0;\n transparent.length = 0;\n for (const r of task._renderables) {\n const binding = r.bind(eng, targetSignature);\n if (r.isTransparent || r._transmissive) {\n transparent.push(binding);\n } else if (r._direct) {\n direct.push(binding);\n } else {\n opaque.push(binding);\n }\n }\n opaque.sort((a, b) => a.renderable.order - b.renderable.order);\n direct.sort((a, b) => a.renderable.order - b.renderable.order);\n task._opaqueBundles.length = 0;\n task._lastVersion = (task.scene as SceneContext)._renderableVersion;\n}\n\nfunction buildRenderPassDescriptor(task: RenderTask, rt: RenderTarget): void {\n const att = task._colorAttachment;\n att.view = rt._colorView!;\n // End-of-pass MSAA resolve into a caller-supplied single-sample target.\n // record() only builds the target's color view for an MSAA rt, so its\n // presence is the gate. The swapchain case is wired per-frame in\n // executePass (its view changes each frame); this custom view is stable.\n att.resolveTarget = task._config.rst?._colorView ?? undefined;\n task._renderPassDescriptor.colorAttachments = rt._colorView ? [att] : [];\n\n const depthSrc = task._depthSrc ?? rt;\n const depthView = depthSrc._depthView;\n let depthAttachment: GPURenderPassDepthStencilAttachment | undefined;\n if (depthView) {\n const dd = depthSrc._descriptor;\n const loadOp = task._depthLoadOp ?? \"clear\";\n depthAttachment = {\n view: depthView,\n depthClearValue: dd._depthClearValue ?? 0,\n depthLoadOp: loadOp,\n depthStoreOp: \"store\",\n };\n if (dd.dFormat?.includes(\"stencil\")) {\n depthAttachment.stencilClearValue = 0;\n depthAttachment.stencilLoadOp = loadOp;\n depthAttachment.stencilStoreOp = \"store\";\n }\n }\n\n task._renderPassDescriptor.depthStencilAttachment = depthAttachment;\n}\n\nfunction prepareRenderTaskPass(task: RenderTask, eng: EngineContext, targetSignature: RenderTargetSignature, context: DrawUpdateContext): void {\n const sc = task.scene as SceneContext;\n // Auto-resync when the source scene mutates.\n if (task._autoFromScene && task._lastVersion !== sc._renderableVersion) {\n task._renderables.length = 0;\n task._renderables.push(...sc._renderables);\n buildBindings(task, eng, targetSignature);\n }\n\n // Pre-pass work — runs before beginRenderPass. Updates the task-owned scene\n // UBO, scene-wide lights UBO, and per-binding UBOs. The scene bind group may\n // also need a refresh (lights buffer can be resized when glTF lights\n // extension raises MAX_LIGHTS after this task was first recorded).\n refreshTaskSceneBindGroup(task, eng);\n const camera = task._config.cam ?? sc.camera;\n sc._clusteredLightUpdater?.(camera, context.targetWidth, context.targetHeight);\n writePassSceneUBO(task, eng, sc, camera);\n refreshSceneLightsUBO(eng, sc);\n // Expose the active camera to per-binding `update()` calls. Some renderables\n // (e.g. transparent billboard systems) need it to compute view-space sort\n // depths during their update.\n (context as MutableDrawUpdateContext)._camera = camera;\n updateBindings(task._opaqueBindings, context);\n updateBindings(task._directBindings, context);\n updateBindings(task._transparentBindings, context);\n // Per-frame back-to-front sort for transparent bindings — must run AFTER\n // updateBindings so renderables that compute `_worldCenter` inside their\n // own `update()` (billboard systems) are seen with current values.\n sortTransparentBindings(task, camera);\n}\n\nfunction executePass(task: RenderTask, eng: EngineContext, targetSignature: RenderTargetSignature, context: DrawUpdateContext): number {\n const sc = task.scene;\n const sampleCount = targetSignature._sampleCount;\n prepareRenderTaskPass(task, eng, targetSignature, context);\n const att = task._colorAttachment;\n const cfg = task._config;\n if (cfg.rt._colorView) {\n // The engine scRT's color view is re-acquired every frame, so re-read\n // it here. Offscreen color views are stable between rebuilds — leaving att.view\n // untouched preserves an external override (swapchain-overlay shares the base\n // scene's MSAA color view). The resolve target (rst) is re-read each frame so an\n // `rst === scRT` picks up its fresh per-frame view.\n if (cfg.rt === eng.scRT) {\n att.view = cfg.rt._colorView;\n }\n att.resolveTarget = cfg.rst?._colorView ?? undefined;\n att.clearValue = task._autoFromScene ? sc.clearColor : cfg.clrColor!;\n att.loadOp = cfg.clr ? \"clear\" : \"load\";\n }\n if (task._executeWithTransmission) {\n return task._executeWithTransmission(sampleCount);\n }\n const pass = eng._currentEncoder.beginRenderPass(task._renderPassDescriptor);\n const draws = executePassBody(task, pass);\n pass.end();\n return draws;\n}\n\n/** Body of the registered `RenderPass`. Receives the live render-pass encoder\n * and issues all draws (viewport/scissor, group(0) bind, opaque bundle replay,\n * then direct-draws non-transparent direct + transparent). Returns the draw count. */\nfunction executePassBody(task: RenderTask, pass: GPURenderPassEncoder): number {\n const eng = task.engine as EngineContext;\n const cfg = task._config;\n const rt = cfg.rt;\n const scene = task.scene as SceneContext;\n const opaqueBindings = task._opaqueBindings;\n const opaqueBundles = task._opaqueBundles;\n const sceneBG = task._sceneBG;\n\n const camera = cfg.cam ?? scene.camera;\n const v = camera?.viewport;\n if (v) {\n const rw = rt._width;\n const rh = rt._height;\n const x = Math.floor(v.x * rw);\n const y = Math.floor((1 - v.y - v.height) * rh);\n const w = Math.ceil((v.x + v.width) * rw) - x;\n const h = Math.ceil((1 - v.y) * rh) - y;\n pass.setViewport(x, y, w, h, 0, 1);\n pass.setScissorRect(x, y, w, h);\n }\n // Scene bind group (group 0) is task-owned and identical for every draw in this pass.\n pass.setBindGroup(0, sceneBG);\n\n // Opaque: cached render bundle. Invalidated by scene mutation (_renderableVersion)\n // or visibility version (_vis). The bundle records group(0) at its start so it can\n // be replayed standalone (executeBundles inherits no inherited state).\n if (task._lastVersion !== scene._renderableVersion || task._lastVis !== _vis || opaqueBundles.length === 0) {\n const desc = rt._descriptor;\n const be = eng._device.createRenderBundleEncoder({\n colorFormats: desc.format ? [desc.format] : [],\n // Use the task's target signature, not the RT descriptor: a depth\n // override (config.depth) supplies the depth format externally, so\n // the cached opaque pipelines are built with it while the colour RT\n // carries no depthStencilFormat of its own. The bundle encoder's\n // attachment state must match those pipelines exactly.\n depthStencilFormat: task._targetSignature._depthStencilFormat,\n sampleCount: desc.samples ?? 1,\n });\n be.setBindGroup(0, sceneBG);\n drawList(be, opaqueBindings, eng);\n opaqueBundles[0] = be.finish();\n task._lastVersion = scene._renderableVersion;\n task._lastVis = _vis;\n }\n let draws = opaqueBindings.length;\n pass.executeBundles(opaqueBundles);\n // executeBundles invalidates pass bind-group state — rebind group 0 before further draws.\n pass.setBindGroup(0, sceneBG);\n draws += drawList(pass, task._directBindings, eng);\n draws += drawList(pass, task._transparentBindings, eng);\n return draws;\n}\n\nfunction refreshTaskSceneBindGroup(task: RenderTask, eng: EngineContext): void {\n const lightsUBO = ensureSceneLightState(eng, task.scene as SceneContext)._buffer;\n if (lightsUBO === task._lightsUBO) {\n return;\n }\n task._lightsUBO = lightsUBO;\n task._sceneBG = eng._device.createBindGroup({\n layout: getSceneBindGroupLayout(eng),\n entries: [\n { binding: 0, resource: { buffer: task._sceneUBO } },\n { binding: 1, resource: { buffer: lightsUBO } },\n ],\n });\n task._opaqueBundles.length = 0;\n task._lastVersion = -1;\n}\n\n/** Write the canonical SceneUniforms struct to the task-owned scene UBO.\n * Bails before touching scratch/GPU when all inputs are unchanged. */\nfunction writePassSceneUBO(task: RenderTask, eng: EngineContext, scene: SceneContext, camera: Camera | null): void {\n if (!camera) {\n return;\n }\n\n const v = camera.viewport;\n const rt = task._config.rt;\n const aspect = (task._config.cs ? eng.canvas.width / eng.canvas.height : rt._width / rt._height) * (v ? v.width / v.height : 1);\n const fog = scene.fog;\n const img = scene.imageProcessing;\n const envRotationY = scene.envRotationY || 0;\n const wv = camera.worldMatrixVersion;\n const s = task._su;\n if (s[0] === camera && s[1] === fog && s[2] === wv && s[3] === aspect && s[4] === envRotationY && s[5] === img.exposure && s[6] === img.contrast) {\n return;\n }\n s[0] = camera;\n s[1] = fog;\n s[2] = wv;\n s[3] = aspect;\n s[4] = envRotationY;\n s[5] = img.exposure;\n s[6] = img.contrast;\n\n const data = task._suData;\n _packSceneUniforms(data, eng, scene, camera, aspect);\n const contribs = scene._sceneUboContributors;\n if (contribs) {\n for (const c of contribs) {\n c(data, scene);\n }\n }\n eng._device.queue.writeBuffer(task._sceneUBO, 0, data as Float32Array<ArrayBuffer>);\n}\n\nfunction updateBindings(list: readonly DrawBinding[], context: DrawUpdateContext): void {\n for (const b of list) {\n b.update?.(context);\n }\n}\n\n/** Iterate DrawBindings, deduping setPipeline. */\nfunction drawList(enc: GPURenderPassEncoder | GPURenderBundleEncoder, list: readonly DrawBinding[], engine: EngineContext): number {\n let lp: GPURenderPipeline | null = null;\n let draws = 0;\n for (const b of list) {\n const mesh = b.renderable.mesh;\n if (mesh && mesh.visible === false) {\n continue;\n }\n if (b.pipeline !== lp) {\n enc.setPipeline(b.pipeline);\n lp = b.pipeline;\n }\n draws += b.draw(enc, engine);\n }\n return draws;\n}\n"],"names":[],"mappings":";;;;;;;;;;AA6KO,SAAS,gBAAA,CAAiB,MAAA,EAA0B,MAAA,EAAuB,KAAA,EAAiC;AAC/G,EAAA,MAAM,EAAA,GAAK,KAAA;AACX,EAAA,MAAA,CAAO,QAAA,KAAa,EAAE,CAAA,EAAG,GAAA,EAAK,GAAG,GAAA,EAAK,CAAA,EAAG,GAAA,EAAK,CAAA,EAAG,CAAA,EAAI;AACrD,EAAA,MAAA,CAAO,GAAA,KAAQ,IAAA;AACf,EAAA,MAAM,IAAA,GAAO,OAAO,EAAA,CAAG,WAAA;AAIvB,EAAA,MAAM,eAAA,GAAkB;AAAA,IACpB,cAAc,IAAA,CAAK,MAAA;AAAA,IACnB,mBAAA,EAAqB,MAAA,CAAO,KAAA,EAAO,WAAA,CAAY,WAAW,IAAA,CAAK,OAAA;AAAA,IAC/D,eAAe,IAAA,CAAK,aAAA;AAAA,IACpB,YAAA,EAAc,KAAK,OAAA,IAAW;AAAA,GAClC;AAEA,EAAA,MAAM,QAAA,GAAW,wBAAwB,MAAM,CAAA;AAC/C,EAAA,MAAM,QAAA,GAAW,wBAAA,CAAyB,MAAA,EAAQ,eAAe,CAAA;AACjE,EAAA,MAAM,SAAA,GAAY,qBAAA,CAAsB,MAAA,EAAQ,EAAE,CAAA,CAAE,OAAA;AACpD,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,OAAA,CAAQ,eAAA,CAAgB;AAAA,IAC3C,MAAA,EAAQ,QAAA;AAAA,IACR,OAAA,EAAS;AAAA,MACL,EAAE,OAAA,EAAS,CAAA,EAAG,UAAU,EAAE,MAAA,EAAQ,UAAS,EAAE;AAAA,MAC7C,EAAE,OAAA,EAAS,CAAA,EAAG,UAAU,EAAE,MAAA,EAAQ,WAAU;AAAE;AAClD,GACH,CAAA;AACD,EAAA,MAAM,eAAA,GAAkB,EAAE,MAAA,EAAQ,OAAA,EAAS,SAAS,OAAA,EAAQ;AAC5D,EAAA,MAAM,aAAA,GAA0C,EAAE,WAAA,EAAa,CAAA,EAAG,cAAc,CAAA,EAAE;AAClF,EAAA,MAAM,IAAA,GAAmB;AAAA,IACrB,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,OAAA,EAAS,MAAA;AAAA,IACT,MAAA;AAAA,IACA,KAAA,EAAO,EAAA;AAAA,IACP,SAAS,EAAC;AAAA,IACV,cAAA,EAAgB,KAAA;AAAA,IAChB,cAAc,EAAC;AAAA,IACf,iBAAiB,EAAC;AAAA,IAClB,iBAAiB,EAAC;AAAA,IAClB,sBAAsB,EAAC;AAAA,IACvB,gBAAgB,EAAC;AAAA,IACjB,YAAA,EAAc,EAAA;AAAA,IACd,QAAA,EAAU,CAAA;AAAA,IACV,qBAAA,EAAuB,EAAE,gBAAA,EAAkB,CAAC,eAAe,CAAA,EAAE;AAAA,IAC7D,gBAAA,EAAkB,eAAA;AAAA,IAClB,WAAW,MAAA,CAAO,KAAA;AAAA,IAClB,cAAc,MAAA,CAAO,KAAA,GAAS,OAAO,KAAA,CAAM,MAAA,GAAS,SAAS,OAAA,GAAW,MAAA;AAAA,IACxE,SAAA,EAAW,QAAA;AAAA,IACX,QAAA,EAAU,OAAA;AAAA,IACV,UAAA,EAAY,SAAA;AAAA,IACZ,OAAA,EAAS,IAAI,GAAA,CAAI,eAAA,GAAkB,CAAC,CAAA;AAAA,IACpC,KAAK,EAAC;AAAA,IACN,gBAAA,EAAkB,eAAA;AAAA,IAClB,gBAAgB,EAAC;AAAA,IACjB,OAAA,CAAQ,MAAM,IAAA,EAAM;AAChB,MAAA,MAAM,QAAA,GAAW,IAAA,EAAM,QAAA,IAAY,IAAA,CAAK,QAAA;AACxC,MAAA,IAAI,CAAC,QAAA,EAAU;AACX,QAAA;AAAA,MACJ;AACA,MAAA,IAAA,CAAK,cAAA,CAAe,IAAA,CAAK,EAAE,IAAA,EAAM,UAAU,CAAA;AAAA,IAC/C,CAAA;AAAA,IACA,MAAA,GAAe;AACX,MAAA,IAAI,KAAK,cAAA,EAAgB;AACrB,QAAA,IAAA,CAAK,aAAa,MAAA,GAAS,CAAA;AAAA,MAC/B;AACA,MAAA,oBAAA,CAAqB,MAAM,EAAE,CAAA;AAC7B,MAAA,IAAA,CAAK,cAAA,GAAiB,IAAA,CAAK,YAAA,CAAa,MAAA,KAAW,CAAA;AACnD,MAAA,IAAI,KAAK,cAAA,EAAgB;AACrB,QAAA,IAAA,CAAK,YAAA,CAAa,IAAA,CAAK,GAAG,EAAA,CAAG,YAAY,CAAA;AAAA,MAC7C;AAGA,MAAA,MAAM,KAAK,MAAA,CAAO,EAAA;AAClB,MAAA,iBAAA,CAAkB,IAAI,MAAM,CAAA;AAC5B,MAAA,IAAI,OAAO,GAAA,IAAA,CAAQ,EAAA,CAAG,WAAA,CAAY,OAAA,IAAW,KAAK,CAAA,EAAG;AACjD,QAAA,iBAAA,CAAkB,MAAA,CAAO,KAAK,MAAM,CAAA;AAAA,MACxC;AAKA,MAAA,IAAI,MAAA,CAAO,KAAA,IAAS,CAAC,MAAA,CAAO,MAAM,MAAA,EAAQ;AACtC,QAAA,iBAAA,CAAkB,MAAA,CAAO,OAAO,MAAM,CAAA;AAAA,MAC1C;AACA,MAAA,aAAA,CAAc,cAAc,EAAA,CAAG,MAAA;AAC/B,MAAA,aAAA,CAAc,eAAe,EAAA,CAAG,OAAA;AAChC,MAAA,yBAAA,CAA0B,MAAM,MAAM,CAAA;AACtC,MAAA,aAAA,CAAc,IAAA,EAAM,QAAQ,eAAe,CAAA;AAC3C,MAAA,yBAAA,CAA0B,MAAM,EAAE,CAAA;AAAA,IACtC,CAAA;AAAA,IACA,OAAA,GAAkB;AACd,MAAA,OAAO,WAAA,CAAY,IAAA,EAAM,MAAA,EAAQ,eAAA,EAAiB,aAAa,CAAA;AAAA,IACnE,CAAA;AAAA,IACA,OAAA,GAAgB;AACZ,MAAA,IAAA,CAAK,QAAQ,MAAA,GAAS,CAAA;AAItB,MAAA,mBAAA,CAAoB,OAAO,EAAE,CAAA;AAC7B,MAAA,mBAAA,CAAoB,OAAO,GAAG,CAAA;AAC9B,MAAA,mBAAA,CAAoB,OAAO,KAAK,CAAA;AAChC,MAAA,IAAA,CAAK,gBAAgB,MAAA,GAAS,CAAA;AAC9B,MAAA,IAAA,CAAK,gBAAgB,MAAA,GAAS,CAAA;AAC9B,MAAA,IAAA,CAAK,qBAAqB,MAAA,GAAS,CAAA;AACnC,MAAA,IAAA,CAAK,aAAa,MAAA,GAAS,CAAA;AAC3B,MAAA,IAAA,CAAK,eAAe,MAAA,GAAS,CAAA;AAC7B,MAAA,IAAA,CAAK,UAAU,OAAA,EAAQ;AAAA,IAC3B;AAAA,GACJ;AACA,EAAA,OAAO,IAAA;AACX;AAGO,SAAS,kBAAA,CAAmB,MAAkB,IAAA,EAAoB;AAGrE,EAAA,IAAI,CAAC,KAAK,YAAA,EAAc;AACpB,IAAA;AAAA,EACJ;AACA,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,KAAA,IAAS,IAAI,IAAA,CAAK,YAAA,CAAa,SAAS,CAAA,EAAG,CAAA,IAAK,GAAG,CAAA,EAAA,EAAK;AACpD,IAAA,IAAI,IAAA,CAAK,YAAA,CAAa,CAAC,CAAA,CAAG,SAAS,IAAA,EAAM;AACrC,MAAA,IAAA,CAAK,YAAA,CAAa,MAAA,CAAO,CAAA,EAAG,CAAC,CAAA;AAC7B,MAAA,OAAA,GAAU,IAAA;AAAA,IACd;AAAA,EACJ;AACA,EAAA,KAAA,MAAW,GAAA,IAAO,CAAC,IAAA,CAAK,eAAA,EAAiB,KAAK,eAAA,EAAiB,IAAA,CAAK,oBAAoB,CAAA,EAAG;AACvF,IAAA,KAAA,IAAS,IAAI,GAAA,CAAI,MAAA,GAAS,CAAA,EAAG,CAAA,IAAK,GAAG,CAAA,EAAA,EAAK;AACtC,MAAA,IAAI,GAAA,CAAI,CAAC,CAAA,CAAG,UAAA,CAAW,SAAS,IAAA,EAAM;AAClC,QAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAC,CAAA;AACf,QAAA,OAAA,GAAU,IAAA;AAAA,MACd;AAAA,IACJ;AAAA,EACJ;AACA,EAAA,IAAI,OAAA,EAAS;AACT,IAAA,IAAA,CAAK,eAAe,MAAA,GAAS,CAAA;AAC7B,IAAA,IAAA,CAAK,YAAA,GAAe,EAAA;AAAA,EACxB;AACJ;AAIA,SAAS,oBAAA,CAAqB,MAAkB,EAAA,EAAwB;AACpE,EAAA,IAAI,IAAA,CAAK,cAAA,CAAe,MAAA,KAAW,CAAA,EAAG;AAClC,IAAA;AAAA,EACJ;AACA,EAAA,KAAA,MAAW,EAAE,IAAA,EAAM,QAAA,EAAS,IAAK,KAAK,cAAA,EAAgB;AAClD,IAAA,MAAM,OAAA,GAAU,SAAS,WAAA,EAAa,cAAA;AACtC,IAAA,IAAI,CAAC,OAAA,EAAS;AACV,MAAA,MAAM,IAAI,KAAA,EAAM;AAAA,IACpB;AACA,IAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,EAAA,EAAI,IAAA,EAAM,QAAQ,CAAA;AAC7C,IAAA,IAAI,CAAC,IAAA,CAAK,YAAA,CAAa,QAAA,CAAS,UAAU,CAAA,EAAG;AACzC,MAAA,IAAA,CAAK,YAAA,CAAa,KAAK,UAAU,CAAA;AAAA,IACrC;AAAA,EACJ;AACA,EAAA,IAAA,CAAK,eAAe,MAAA,GAAS,CAAA;AACjC;AAGA,SAAS,uBAAA,CAAwB,MAAkB,MAAA,EAAyC;AACxF,EAAA,MAAM,MAAM,IAAA,CAAK,oBAAA;AACjB,EAAA,IAAI,GAAA,CAAI,MAAA,IAAU,CAAA,IAAK,CAAC,MAAA,EAAQ;AAC5B,IAAA;AAAA,EACJ;AACA,EAAA,MAAM,CAAA,GAAI,cAAc,MAAM,CAAA;AAC9B,EAAA,KAAA,MAAW,KAAK,GAAA,EAAK;AACjB,IAAA,MAAM,EAAA,GAAK,EAAE,UAAA,CAAW,YAAA;AACxB,IAAA,CAAA,CAAE,aAAA,GAAgB,KAAK,EAAA,CAAG,CAAC,IAAK,CAAA,CAAE,CAAC,CAAA,GAAK,EAAA,CAAG,CAAC,CAAA,GAAK,EAAE,CAAC,CAAA,GAAK,GAAG,CAAC,CAAA,GAAK,EAAE,EAAE,CAAA,GAAK,CAAA,CAAE,EAAE,CAAA,GAAK,CAAA;AAAA,EACxF;AACA,EAAA,GAAA,CAAI,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,aAAA,GAAiB,CAAA,CAAE,aAAA,IAAkB,CAAA,CAAE,UAAA,CAAW,KAAA,GAAQ,CAAA,CAAE,WAAW,KAAK,CAAA;AACrG;AAGA,SAAS,aAAA,CAAc,IAAA,EAAkB,GAAA,EAAoB,eAAA,EAA8C;AACvG,EAAA,MAAM,SAAS,IAAA,CAAK,eAAA;AACpB,EAAA,MAAM,SAAS,IAAA,CAAK,eAAA;AACpB,EAAA,MAAM,cAAc,IAAA,CAAK,oBAAA;AACzB,EAAA,MAAA,CAAO,MAAA,GAAS,CAAA;AAChB,EAAA,MAAA,CAAO,MAAA,GAAS,CAAA;AAChB,EAAA,WAAA,CAAY,MAAA,GAAS,CAAA;AACrB,EAAA,KAAA,MAAW,CAAA,IAAK,KAAK,YAAA,EAAc;AAC/B,IAAA,MAAM,OAAA,GAAU,CAAA,CAAE,IAAA,CAAK,GAAA,EAAK,eAAe,CAAA;AAC3C,IAAA,IAAI,CAAA,CAAE,aAAA,IAAiB,CAAA,CAAE,aAAA,EAAe;AACpC,MAAA,WAAA,CAAY,KAAK,OAAO,CAAA;AAAA,IAC5B,CAAA,MAAA,IAAW,EAAE,OAAA,EAAS;AAClB,MAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AAAA,IACvB,CAAA,MAAO;AACH,MAAA,MAAA,CAAO,KAAK,OAAO,CAAA;AAAA,IACvB;AAAA,EACJ;AACA,EAAA,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,UAAA,CAAW,KAAA,GAAQ,CAAA,CAAE,UAAA,CAAW,KAAK,CAAA;AAC7D,EAAA,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,UAAA,CAAW,KAAA,GAAQ,CAAA,CAAE,UAAA,CAAW,KAAK,CAAA;AAC7D,EAAA,IAAA,CAAK,eAAe,MAAA,GAAS,CAAA;AAC7B,EAAA,IAAA,CAAK,YAAA,GAAgB,KAAK,KAAA,CAAuB,kBAAA;AACrD;AAEA,SAAS,yBAAA,CAA0B,MAAkB,EAAA,EAAwB;AACzE,EAAA,MAAM,MAAM,IAAA,CAAK,gBAAA;AACjB,EAAA,GAAA,CAAI,OAAO,EAAA,CAAG,UAAA;AAKd,EAAA,GAAA,CAAI,aAAA,GAAgB,IAAA,CAAK,OAAA,CAAQ,GAAA,EAAK,UAAA,IAAc,MAAA;AACpD,EAAA,IAAA,CAAK,sBAAsB,gBAAA,GAAmB,EAAA,CAAG,aAAa,CAAC,GAAG,IAAI,EAAC;AAEvE,EAAA,MAAM,QAAA,GAAW,KAAK,SAAA,IAAa,EAAA;AACnC,EAAA,MAAM,YAAY,QAAA,CAAS,UAAA;AAC3B,EAAA,IAAI,eAAA;AACJ,EAAA,IAAI,SAAA,EAAW;AACX,IAAA,MAAM,KAAK,QAAA,CAAS,WAAA;AACpB,IAAA,MAAM,MAAA,GAAS,KAAK,YAAA,IAAgB,OAAA;AACpC,IAAA,eAAA,GAAkB;AAAA,MACd,IAAA,EAAM,SAAA;AAAA,MACN,eAAA,EAAiB,GAAG,gBAAA,IAAoB,CAAA;AAAA,MACxC,WAAA,EAAa,MAAA;AAAA,MACb,YAAA,EAAc;AAAA,KAClB;AACA,IAAA,IAAI,EAAA,CAAG,OAAA,EAAS,QAAA,CAAS,SAAS,CAAA,EAAG;AACjC,MAAA,eAAA,CAAgB,iBAAA,GAAoB,CAAA;AACpC,MAAA,eAAA,CAAgB,aAAA,GAAgB,MAAA;AAChC,MAAA,eAAA,CAAgB,cAAA,GAAiB,OAAA;AAAA,IACrC;AAAA,EACJ;AAEA,EAAA,IAAA,CAAK,sBAAsB,sBAAA,GAAyB,eAAA;AACxD;AAEA,SAAS,qBAAA,CAAsB,IAAA,EAAkB,GAAA,EAAoB,eAAA,EAAwC,OAAA,EAAkC;AAC3I,EAAA,MAAM,KAAK,IAAA,CAAK,KAAA;AAEhB,EAAA,IAAI,IAAA,CAAK,cAAA,IAAkB,IAAA,CAAK,YAAA,KAAiB,GAAG,kBAAA,EAAoB;AACpE,IAAA,IAAA,CAAK,aAAa,MAAA,GAAS,CAAA;AAC3B,IAAA,IAAA,CAAK,YAAA,CAAa,IAAA,CAAK,GAAG,EAAA,CAAG,YAAY,CAAA;AACzC,IAAA,aAAA,CAAc,IAAA,EAAM,KAAK,eAAe,CAAA;AAAA,EAC5C;AAMA,EAAA,yBAAA,CAA0B,MAAM,GAAG,CAAA;AACnC,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,GAAA,IAAO,EAAA,CAAG,MAAA;AACtC,EAAA,EAAA,CAAG,sBAAA,GAAyB,MAAA,EAAQ,OAAA,CAAQ,WAAA,EAAa,QAAQ,YAAY,CAAA;AAC7E,EAAA,iBAAA,CAAkB,IAAA,EAAM,GAAA,EAAK,EAAA,EAAI,MAAM,CAAA;AACvC,EAAA,qBAAA,CAAsB,KAAK,EAAE,CAAA;AAI7B,EAAC,QAAqC,OAAA,GAAU,MAAA;AAChD,EAAA,cAAA,CAAe,IAAA,CAAK,iBAAiB,OAAO,CAAA;AAC5C,EAAA,cAAA,CAAe,IAAA,CAAK,iBAAiB,OAAO,CAAA;AAC5C,EAAA,cAAA,CAAe,IAAA,CAAK,sBAAsB,OAAO,CAAA;AAIjD,EAAA,uBAAA,CAAwB,MAAM,MAAM,CAAA;AACxC;AAEA,SAAS,WAAA,CAAY,IAAA,EAAkB,GAAA,EAAoB,eAAA,EAAwC,OAAA,EAAoC;AACnI,EAAA,MAAM,KAAK,IAAA,CAAK,KAAA;AAChB,EAAA,MAAM,cAAc,eAAA,CAAgB,YAAA;AACpC,EAAA,qBAAA,CAAsB,IAAA,EAAM,GAAA,EAAK,eAAA,EAAiB,OAAO,CAAA;AACzD,EAAA,MAAM,MAAM,IAAA,CAAK,gBAAA;AACjB,EAAA,MAAM,MAAM,IAAA,CAAK,OAAA;AACjB,EAAA,IAAI,GAAA,CAAI,GAAG,UAAA,EAAY;AAMnB,IAAA,IAAI,GAAA,CAAI,EAAA,KAAO,GAAA,CAAI,IAAA,EAAM;AACrB,MAAA,GAAA,CAAI,IAAA,GAAO,IAAI,EAAA,CAAG,UAAA;AAAA,IACtB;AACA,IAAA,GAAA,CAAI,aAAA,GAAgB,GAAA,CAAI,GAAA,EAAK,UAAA,IAAc,MAAA;AAC3C,IAAA,GAAA,CAAI,UAAA,GAAa,IAAA,CAAK,cAAA,GAAiB,EAAA,CAAG,aAAa,GAAA,CAAI,QAAA;AAC3D,IAAA,GAAA,CAAI,MAAA,GAAS,GAAA,CAAI,GAAA,GAAM,OAAA,GAAU,MAAA;AAAA,EACrC;AACA,EAAA,IAAI,KAAK,wBAAA,EAA0B;AAC/B,IAAA,OAAO,IAAA,CAAK,yBAAyB,WAAW,CAAA;AAAA,EACpD;AACA,EAAA,MAAM,IAAA,GAAO,GAAA,CAAI,eAAA,CAAgB,eAAA,CAAgB,KAAK,qBAAqB,CAAA;AAC3E,EAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,IAAA,EAAM,IAAI,CAAA;AACxC,EAAA,IAAA,CAAK,GAAA,EAAI;AACT,EAAA,OAAO,KAAA;AACX;AAKA,SAAS,eAAA,CAAgB,MAAkB,IAAA,EAAoC;AAC3E,EAAA,MAAM,MAAM,IAAA,CAAK,MAAA;AACjB,EAAA,MAAM,MAAM,IAAA,CAAK,OAAA;AACjB,EAAA,MAAM,KAAK,GAAA,CAAI,EAAA;AACf,EAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AACnB,EAAA,MAAM,iBAAiB,IAAA,CAAK,eAAA;AAC5B,EAAA,MAAM,gBAAgB,IAAA,CAAK,cAAA;AAC3B,EAAA,MAAM,UAAU,IAAA,CAAK,QAAA;AAErB,EAAA,MAAM,MAAA,GAAS,GAAA,CAAI,GAAA,IAAO,KAAA,CAAM,MAAA;AAChC,EAAA,MAAM,IAAI,MAAA,EAAQ,QAAA;AAClB,EAAA,IAAI,CAAA,EAAG;AACH,IAAA,MAAM,KAAK,EAAA,CAAG,MAAA;AACd,IAAA,MAAM,KAAK,EAAA,CAAG,OAAA;AACd,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,IAAI,EAAE,CAAA;AAC7B,IAAA,MAAM,CAAA,GAAI,KAAK,KAAA,CAAA,CAAO,CAAA,GAAI,EAAE,CAAA,GAAI,CAAA,CAAE,UAAU,EAAE,CAAA;AAC9C,IAAA,MAAM,CAAA,GAAI,KAAK,IAAA,CAAA,CAAM,CAAA,CAAE,IAAI,CAAA,CAAE,KAAA,IAAS,EAAE,CAAA,GAAI,CAAA;AAC5C,IAAA,MAAM,IAAI,IAAA,CAAK,IAAA,CAAA,CAAM,IAAI,CAAA,CAAE,CAAA,IAAK,EAAE,CAAA,GAAI,CAAA;AACtC,IAAA,IAAA,CAAK,YAAY,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAC,CAAA;AACjC,IAAA,IAAA,CAAK,cAAA,CAAe,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AAAA,EAClC;AAEA,EAAA,IAAA,CAAK,YAAA,CAAa,GAAG,OAAO,CAAA;AAK5B,EAAA,IAAI,IAAA,CAAK,iBAAiB,KAAA,CAAM,kBAAA,IAAsB,KAAK,QAAA,KAAa,IAAA,IAAQ,aAAA,CAAc,MAAA,KAAW,CAAA,EAAG;AACxG,IAAA,MAAM,OAAO,EAAA,CAAG,WAAA;AAChB,IAAA,MAAM,EAAA,GAAK,GAAA,CAAI,OAAA,CAAQ,yBAAA,CAA0B;AAAA,MAC7C,cAAc,IAAA,CAAK,MAAA,GAAS,CAAC,IAAA,CAAK,MAAM,IAAI,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAM7C,kBAAA,EAAoB,KAAK,gBAAA,CAAiB,mBAAA;AAAA,MAC1C,WAAA,EAAa,KAAK,OAAA,IAAW;AAAA,KAChC,CAAA;AACD,IAAA,EAAA,CAAG,YAAA,CAAa,GAAG,OAAO,CAAA;AAC1B,IAAA,QAAA,CAAS,EAAA,EAAI,gBAAgB,GAAG,CAAA;AAChC,IAAA,aAAA,CAAc,CAAC,CAAA,GAAI,EAAA,CAAG,MAAA,EAAO;AAC7B,IAAA,IAAA,CAAK,eAAe,KAAA,CAAM,kBAAA;AAC1B,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAAA,EACpB;AACA,EAAA,IAAI,QAAQ,cAAA,CAAe,MAAA;AAC3B,EAAA,IAAA,CAAK,eAAe,aAAa,CAAA;AAEjC,EAAA,IAAA,CAAK,YAAA,CAAa,GAAG,OAAO,CAAA;AAC5B,EAAA,KAAA,IAAS,QAAA,CAAS,IAAA,EAAM,IAAA,CAAK,eAAA,EAAiB,GAAG,CAAA;AACjD,EAAA,KAAA,IAAS,QAAA,CAAS,IAAA,EAAM,IAAA,CAAK,oBAAA,EAAsB,GAAG,CAAA;AACtD,EAAA,OAAO,KAAA;AACX;AAEA,SAAS,yBAAA,CAA0B,MAAkB,GAAA,EAA0B;AAC3E,EAAA,MAAM,SAAA,GAAY,qBAAA,CAAsB,GAAA,EAAK,IAAA,CAAK,KAAqB,CAAA,CAAE,OAAA;AACzE,EAAA,IAAI,SAAA,KAAc,KAAK,UAAA,EAAY;AAC/B,IAAA;AAAA,EACJ;AACA,EAAA,IAAA,CAAK,UAAA,GAAa,SAAA;AAClB,EAAA,IAAA,CAAK,QAAA,GAAW,GAAA,CAAI,OAAA,CAAQ,eAAA,CAAgB;AAAA,IACxC,MAAA,EAAQ,wBAAwB,GAAG,CAAA;AAAA,IACnC,OAAA,EAAS;AAAA,MACL,EAAE,SAAS,CAAA,EAAG,QAAA,EAAU,EAAE,MAAA,EAAQ,IAAA,CAAK,WAAU,EAAE;AAAA,MACnD,EAAE,OAAA,EAAS,CAAA,EAAG,UAAU,EAAE,MAAA,EAAQ,WAAU;AAAE;AAClD,GACH,CAAA;AACD,EAAA,IAAA,CAAK,eAAe,MAAA,GAAS,CAAA;AAC7B,EAAA,IAAA,CAAK,YAAA,GAAe,EAAA;AACxB;AAIA,SAAS,iBAAA,CAAkB,IAAA,EAAkB,GAAA,EAAoB,KAAA,EAAqB,MAAA,EAA6B;AAC/G,EAAA,IAAI,CAAC,MAAA,EAAQ;AACT,IAAA;AAAA,EACJ;AAEA,EAAA,MAAM,IAAI,MAAA,CAAO,QAAA;AACjB,EAAA,MAAM,EAAA,GAAK,KAAK,OAAA,CAAQ,EAAA;AACxB,EAAA,MAAM,UAAU,IAAA,CAAK,OAAA,CAAQ,KAAK,GAAA,CAAI,MAAA,CAAO,QAAQ,GAAA,CAAI,MAAA,CAAO,MAAA,GAAS,EAAA,CAAG,SAAS,EAAA,CAAG,OAAA,KAAY,IAAI,CAAA,CAAE,KAAA,GAAQ,EAAE,MAAA,GAAS,CAAA,CAAA;AAC7H,EAAA,MAAM,MAAM,KAAA,CAAM,GAAA;AAClB,EAAA,MAAM,MAAM,KAAA,CAAM,eAAA;AAClB,EAAA,MAAM,YAAA,GAAe,MAAM,YAAA,IAAgB,CAAA;AAC3C,EAAA,MAAM,KAAK,MAAA,CAAO,kBAAA;AAClB,EAAA,MAAM,IAAI,IAAA,CAAK,GAAA;AACf,EAAA,IAAI,CAAA,CAAE,CAAC,CAAA,KAAM,MAAA,IAAU,CAAA,CAAE,CAAC,CAAA,KAAM,GAAA,IAAO,CAAA,CAAE,CAAC,CAAA,KAAM,EAAA,IAAM,CAAA,CAAE,CAAC,CAAA,KAAM,MAAA,IAAU,CAAA,CAAE,CAAC,CAAA,KAAM,YAAA,IAAgB,CAAA,CAAE,CAAC,CAAA,KAAM,GAAA,CAAI,QAAA,IAAY,CAAA,CAAE,CAAC,CAAA,KAAM,IAAI,QAAA,EAAU;AAC9I,IAAA;AAAA,EACJ;AACA,EAAA,CAAA,CAAE,CAAC,CAAA,GAAI,MAAA;AACP,EAAA,CAAA,CAAE,CAAC,CAAA,GAAI,GAAA;AACP,EAAA,CAAA,CAAE,CAAC,CAAA,GAAI,EAAA;AACP,EAAA,CAAA,CAAE,CAAC,CAAA,GAAI,MAAA;AACP,EAAA,CAAA,CAAE,CAAC,CAAA,GAAI,YAAA;AACP,EAAA,CAAA,CAAE,CAAC,IAAI,GAAA,CAAI,QAAA;AACX,EAAA,CAAA,CAAE,CAAC,IAAI,GAAA,CAAI,QAAA;AAEX,EAAA,MAAM,OAAO,IAAA,CAAK,OAAA;AAClB,EAAA,kBAAA,CAAmB,IAAA,EAAM,GAAA,EAAK,KAAA,EAAO,MAAA,EAAQ,MAAM,CAAA;AACnD,EAAA,MAAM,WAAW,KAAA,CAAM,qBAAA;AACvB,EAAA,IAAI,QAAA,EAAU;AACV,IAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACtB,MAAA,CAAA,CAAE,MAAM,KAAK,CAAA;AAAA,IACjB;AAAA,EACJ;AACA,EAAA,GAAA,CAAI,QAAQ,KAAA,CAAM,WAAA,CAAY,IAAA,CAAK,SAAA,EAAW,GAAG,IAAiC,CAAA;AACtF;AAEA,SAAS,cAAA,CAAe,MAA8B,OAAA,EAAkC;AACpF,EAAA,KAAA,MAAW,KAAK,IAAA,EAAM;AAClB,IAAA,CAAA,CAAE,SAAS,OAAO,CAAA;AAAA,EACtB;AACJ;AAGA,SAAS,QAAA,CAAS,GAAA,EAAoD,IAAA,EAA8B,MAAA,EAA+B;AAC/H,EAAA,IAAI,EAAA,GAA+B,IAAA;AACnC,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,KAAA,MAAW,KAAK,IAAA,EAAM;AAClB,IAAA,MAAM,IAAA,GAAO,EAAE,UAAA,CAAW,IAAA;AAC1B,IAAA,IAAI,IAAA,IAAQ,IAAA,CAAK,OAAA,KAAY,KAAA,EAAO;AAChC,MAAA;AAAA,IACJ;AACA,IAAA,IAAI,CAAA,CAAE,aAAa,EAAA,EAAI;AACnB,MAAA,GAAA,CAAI,WAAA,CAAY,EAAE,QAAQ,CAAA;AAC1B,MAAA,EAAA,GAAK,CAAA,CAAE,QAAA;AAAA,IACX;AACA,IAAA,KAAA,IAAS,CAAA,CAAE,IAAA,CAAK,GAAA,EAAK,MAAM,CAAA;AAAA,EAC/B;AACA,EAAA,OAAO,KAAA;AACX;;;;"}
|
|
1
|
+
{"version":3,"file":"render-task.js","sources":["../../../src/frame-graph/render-task.ts"],"sourcesContent":["/**\n * RenderTask — a frame-graph task that records a single `RenderPass`,\n * binds the scene's `RenderTarget`, and draws renderables into it.\n *\n * - `record()` builds bucketed `DrawBinding` lists from `_renderables`\n * (opaque / direct / transparent), sorts opaque + direct by\n * `order`, then creates a `RenderPass` wired to the task's render target.\n * The pass owns its\n * `GPURenderPassDescriptor` and the per-pass-encoder body lives in a\n * closure passed to `setRenderPassExecuteFunc`.\n * - Before `RenderPass._execute()` begins the GPU pass: writes the scene UBO, refreshes lights, updates\n * per-binding UBOs, mirrors live `scene.clearColor` + `clr` onto the\n * render pass. Shared task execution then calls `_execute()`. The\n * `RenderPass` itself patches the swapchain view + clearColor + loadOp\n * and brackets the body with `beginRenderPass` / `end`.\n *\n * Renderable population:\n * - Explicit: push into `_renderables` directly, or `addMesh(mesh, opts)`\n * which builds a (mesh, material) Renderable at `record()` time.\n * - Auto scene mirror: when `_renderables` is empty at record() time, copy the\n * scene's renderables. Re-sync happens automatically when the scene's\n * `_renderableVersion` changes between frames (mesh add/remove, material swap).\n *\n * The engine `scRT` is just another `RenderTarget` here: a task that\n * targets it (`rt`) or resolves into it (`rst`) re-reads its per-frame color view\n * at execute time (the swap texture is re-acquired each frame). `clr: false`\n * switches color + depth `loadOp` to `\"load\"` so multiple scenes can share the\n * swapchain in one frame (e.g., a 3D scene + a UI overlay scene).\n */\n\nimport { F32 } from \"../engine/typed-arrays.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport { _vis } from \"../engine/engine.js\";\nimport type { Mesh } from \"../mesh/mesh.js\";\nimport type { Camera } from \"../camera/camera.js\";\nimport type { Renderable, DrawBinding, DrawUpdateContext } from \"../render/renderable.js\";\nimport type { RenderTargetSignature } from \"../engine/render-target.js\";\nimport type { SceneContext } from \"../scene/scene-core.js\";\nimport type { Material } from \"../material/material.js\";\nimport type { RenderTarget } from \"../engine/render-target.js\";\nimport { buildRenderTarget, disposeRenderTarget } from \"../engine/render-target.js\";\nimport { getViewMatrix } from \"../camera/camera.js\";\nimport { getSceneBindGroupLayout } from \"../render/scene-helpers.js\";\nimport { _packSceneUniforms } from \"./scene-uniforms-pack.js\";\nimport { createEmptyUniformBuffer } from \"../resource/gpu-buffers.js\";\nimport { SCENE_UBO_BYTES } from \"../shader/scene-uniforms-size.js\";\nimport { ensureSceneLightState, refreshSceneLightsUBO } from \"../render/lights-ubo.js\";\nimport type { Task } from \"./task.js\";\n\n/** Configuration for `createRenderTask`: render target, clear state, optional camera override, and transmission settings. */\nexport interface RenderTaskConfig {\n name: string;\n /** TODO: rt should not live in this config long-term. Until texture\n * management is virtualized, callers must provide the concrete target; once\n * virtualized, the task should create/manage its own render target. */\n rt: RenderTarget;\n /** Optional single-sample resolve target. When `rt` is multisampled\n * (`sampleCount > 1`), the color attachment resolves into this target's\n * color texture at end-of-pass — letting an MSAA render feed a post-process\n * that requires a single-sample source, without an extra resolve pass.\n * Caller contract (not validated): must be single-sample with a color\n * format and size matching `rt`; WebGPU errors at pass-encode time if not.\n * Ignored when `rt` is single-sample. */\n rst?: RenderTarget;\n /** Optional separate depth/stencil attachment. The pass binds this target's\n * depth view instead of `rt`'s own, and uses its `depthStencilFormat` for\n * pipeline signature matching. The colour `rt` must omit `depthStencilFormat`\n * (so it allocates no internal depth) and match this target in size + sample\n * count. Two ownership modes, distinguished by `_eager`:\n * - `_eager` depth (e.g. a `GeometryRendererTask` output): the task neither\n * builds nor clears nor disposes it — it loads it (`loadOp: \"load\"`) and the\n * caller owns clearing. This is how scenes reuse a pre-rendered depth buffer.\n * - non-`_eager` depth: the task owns it — builds/rebuilds it in `record()`,\n * clears it (`loadOp: \"clear\"`), and disposes it. Used by the default\n * single-sample scene task, whose colour `rt` is the depth-less\n * engine `scRT`. */\n depth?: RenderTarget;\n /** Background clear color. May be mutated frame-to-frame. */\n clrColor?: GPUColorDict;\n /** When true, color `loadOp` is \"clear\"; when false, \"load\" (overlays previous\n * color content). Depth is always cleared when rt-owned and always loaded when\n * supplied via `depth`. */\n clr?: boolean;\n /** Per-pass camera override. Null/undefined uses `scene.camera`. */\n cam?: Camera | null;\n /** Use canvas dimensions, not render-target dimensions, for this pass's scene UBO aspect. */\n cs?: boolean;\n /** Scene-texture transmission settings. `copyCount: 0` copies before every transmissive draw.\n * `generateMipmaps: false` allocates only mip 0 for the refraction texture and skips mip generation.\n * `mipLevelCount` caps the generated chain when a material only samples low explicit LODs.\n * `grabDepth: true` also snapshots the task's DEPTH attachment at the same mid-pass grab (see\n * `TransmissionOptions.grabDepth`). */\n transmission?: { copyCount?: number; generateMipmaps?: boolean; mipLevelCount?: number; grabDepth?: boolean };\n}\n\n/** A frame-graph task that records a single `RenderPass`, binds the scene's `RenderTarget`, and draws renderables into it. */\nexport interface RenderTask extends Task {\n readonly name: string;\n /** Render tasks are scene-bound because they consume scene camera, lights, and renderables. */\n readonly scene: SceneContext;\n /** Live task configuration. Mutating `clr` or `clrColor` affects subsequent frames. */\n /** @internal */\n readonly _config: RenderTaskConfig;\n /** @internal */\n _autoFromScene: boolean;\n\n /** Source-of-truth renderables. Bucketed binding lists below are derived from\n * this list at `record()` (or re-sync when auto-filled and `_renderableVersion` changes). */\n /** @internal */\n _renderables: Renderable[];\n /** @internal */\n _opaqueBindings: DrawBinding[];\n /** @internal */\n _directBindings: DrawBinding[];\n /** @internal */\n _transparentBindings: DrawBinding[];\n /** Cached opaque render bundle. Invalidated by renderable list mutations\n * (`_lastVersion`) and visibility changes (`_lastVis`). */\n /** @internal */\n _opaqueBundles: GPURenderBundle[];\n /** @internal */\n _lastVersion: number;\n /** @internal */\n _lastVis: number;\n /** @internal True once `record()` has run — the task is \"live\" (GPU target allocated, material batch builders\n * present). A runtime `addMesh` after this resolves + re-buckets THIS task immediately (no frame-graph rebuild). */\n _recorded: boolean;\n\n /** @internal */\n _renderPassDescriptor: GPURenderPassDescriptor;\n /** @internal */\n _colorAttachment: GPURenderPassColorAttachment;\n /** @internal External depth source from `config.depth`. When unset,\n * the pass uses `config.rt._depthView`. */\n _depthSrc?: RenderTarget;\n /** @internal External depth/stencil `loadOp` (\"load\" when `config.depth` is\n * set). When unset, defaults to `\"clear\"`. */\n _depthLoadOp?: GPULoadOp;\n\n /** Per-task scene UBO + bind group. Created eagerly in createRenderTask\n * so renderables can reference `_sceneBG` at `bind()` time. Written each\n * frame by `writePassSceneUBO`. Destroyed in `dispose()`. */\n /** @internal */\n _sceneUBO: GPUBuffer;\n /** @internal */\n _sceneBG: GPUBindGroup;\n /** @internal */\n _lightsUBO: GPUBuffer;\n /** @internal */\n _suData: Float32Array;\n /** @internal */\n _su: unknown[];\n /** Optional transmission-enabled execute path: copies the scene texture for refraction and draws transmissive\n * renderables. Present only when the task was configured with `transmission`. Returns the number of draw calls issued. */\n /** @internal */\n _executeWithTransmission?(sampleCount: number): number;\n /** @internal */\n _targetSignature: RenderTargetSignature;\n\n /** Add a mesh to this task's explicit render list with an optional per-pass material override. Resolved via\n * `material._buildGroup._rebuildSingle`, so the mesh's material family must already have been registered with the\n * scene (its batch builder has run). BEFORE the first `record()` the add is QUEUED and drained at record() time;\n * AFTER (a live/runtime add) it is resolved + re-bucketed into THIS task immediately, so the mesh renders on the\n * next frame without a `frameGraph.build()` (which would re-allocate shared GPU resources across all tasks). */\n addMesh(mesh: Mesh, opts?: { material?: Material }): void;\n /** @internal */\n _pendingMeshes: { mesh: Mesh; material: Material }[];\n}\n\ninterface MutableDrawUpdateContext {\n targetWidth: number;\n targetHeight: number;\n _camera?: Camera | null;\n}\n\n/** Create a render pass task. GPU resources (target textures + descriptor)\n * are not allocated until `record()` runs (via `frameGraph.build()`).\n *\n * Swapchain-targeted tasks acquire the swap view per-frame at execute time. */\nexport function createRenderTask(config: RenderTaskConfig, engine: EngineContext, scene: SceneContext): RenderTask {\n const sc = scene as SceneContext;\n config.clrColor ??= { r: 0.2, g: 0.2, b: 0.3, a: 1.0 };\n config.clr ??= true;\n const desc = config.rt._descriptor;\n // Render upright: row 0 of the GPU texture is the top of the scene. Every\n // RT (offscreen or swapchain) renders without a projection Y-flip; pipelines\n // use the default ccw front face; downstream samplers see upright pixels.\n const targetSignature = {\n _colorFormat: desc.format,\n _depthStencilFormat: config.depth?._descriptor.dFormat ?? desc.dFormat,\n _depthCompare: desc._depthCompare,\n _sampleCount: desc.samples ?? 1,\n };\n\n const sceneBGL = getSceneBindGroupLayout(engine);\n const sceneUBO = createEmptyUniformBuffer(engine, SCENE_UBO_BYTES);\n const lightsUBO = ensureSceneLightState(engine, sc)._buffer;\n const sceneBG = engine._device.createBindGroup({\n layout: sceneBGL,\n entries: [\n { binding: 0, resource: { buffer: sceneUBO } },\n { binding: 1, resource: { buffer: lightsUBO } },\n ],\n });\n const colorAttachment = { loadOp: \"clear\", storeOp: \"store\" } as GPURenderPassColorAttachment;\n const updateContext: MutableDrawUpdateContext = { targetWidth: 0, targetHeight: 0 };\n const task: RenderTask = {\n name: config.name,\n _config: config,\n engine: engine,\n scene: sc,\n _passes: [],\n _autoFromScene: false,\n _renderables: [],\n _opaqueBindings: [],\n _directBindings: [],\n _transparentBindings: [],\n _opaqueBundles: [],\n _lastVersion: -1,\n _lastVis: 0,\n _recorded: false,\n _renderPassDescriptor: { colorAttachments: [colorAttachment] },\n _colorAttachment: colorAttachment,\n _depthSrc: config.depth,\n _depthLoadOp: config.depth ? (config.depth._eager ? \"load\" : \"clear\") : undefined,\n _sceneUBO: sceneUBO,\n _sceneBG: sceneBG,\n _lightsUBO: lightsUBO,\n _suData: new F32(SCENE_UBO_BYTES / 4),\n _su: [],\n _targetSignature: targetSignature,\n _pendingMeshes: [],\n addMesh(mesh, opts) {\n const material = opts?.material ?? mesh.material;\n if (!material) {\n return;\n }\n task._pendingMeshes.push({ mesh, material });\n if (task._recorded) {\n // Live (post-record) add: resolve + re-bucket THIS task now — buildBindings clears its bundle cache\n // so it re-records on the next execute. Deliberately NOT a frame-graph rebuild (that re-allocates the\n // shared scene UBO + every task's render target mid-frame and crashes the in-flight submit).\n resolvePendingMeshes(task, sc);\n // A live add makes the render list explicit (mirrors record(), where a pending mesh forces\n // _autoFromScene = false). Without this, an auto-mirroring task's next scene-version resync in\n // prepareRenderTaskPass would clear _renderables and drop the just-added mesh.\n task._autoFromScene = false;\n buildBindings(task, engine, targetSignature);\n }\n },\n record(): void {\n if (task._autoFromScene) {\n task._renderables.length = 0;\n }\n resolvePendingMeshes(task, sc);\n task._autoFromScene = task._renderables.length === 0;\n if (task._autoFromScene) {\n task._renderables.push(...sc._renderables);\n }\n // Read config.rt dynamically — transmission retargeting swaps it after\n // the task is created, and the engine scRT must never be rebuilt.\n const rt = config.rt;\n buildRenderTarget(rt, engine);\n if (config.rst && (rt._descriptor.samples ?? 1) > 1) {\n buildRenderTarget(config.rst, engine);\n }\n // A non-eager external depth (e.g. the default single-sample scene task's\n // depth, whose colour rt is the depth-less scRT) is task-managed:\n // build/rebuild it here. Eager depths (GeometryRendererTask outputs) are\n // pre-built and skipped by buildRenderTarget.\n if (config.depth && !config.depth._eager) {\n buildRenderTarget(config.depth, engine);\n }\n updateContext.targetWidth = rt._width;\n updateContext.targetHeight = rt._height;\n refreshTaskSceneBindGroup(task, engine);\n buildBindings(task, engine, targetSignature);\n buildRenderPassDescriptor(task, rt);\n task._recorded = true; // task is now live — a subsequent addMesh resolves + re-buckets immediately\n },\n execute(): number {\n return executePass(task, engine, targetSignature, updateContext);\n },\n dispose(): void {\n task._passes.length = 0;\n // disposeRenderTarget no-ops on the engine scRT and on eager\n // GeometryRendererTask depth outputs (both `_eager`), and on an undefined\n // rst/depth — so these can be passed unconditionally.\n disposeRenderTarget(config.rt);\n disposeRenderTarget(config.rst);\n disposeRenderTarget(config.depth);\n task._opaqueBindings.length = 0;\n task._directBindings.length = 0;\n task._transparentBindings.length = 0;\n task._renderables.length = 0;\n task._opaqueBundles.length = 0;\n task._sceneUBO.destroy();\n },\n };\n return task;\n}\n\n/** Remove a mesh from this task's renderable + binding lists. Idempotent. */\nexport function removeMeshFromTask(task: RenderTask, mesh: object): void {\n // Not a renderable-bearing task (e.g. a post/effect task that also carries `_config`): nothing to\n // remove. Guard keeps callers that scan all frame-graph tasks (removeFromScene) shape-safe.\n if (!task._renderables) {\n return;\n }\n let removed = false;\n for (let i = task._renderables.length - 1; i >= 0; i--) {\n if (task._renderables[i]!.mesh === mesh) {\n task._renderables.splice(i, 1);\n removed = true;\n }\n }\n for (const arr of [task._opaqueBindings, task._directBindings, task._transparentBindings]) {\n for (let i = arr.length - 1; i >= 0; i--) {\n if (arr[i]!.renderable.mesh === mesh) {\n arr.splice(i, 1);\n removed = true;\n }\n }\n }\n if (removed) {\n task._opaqueBundles.length = 0;\n task._lastVersion = -1;\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction resolvePendingMeshes(task: RenderTask, sc: SceneContext): void {\n if (task._pendingMeshes.length === 0) {\n return;\n }\n for (const { mesh, material } of task._pendingMeshes) {\n const rebuild = material._buildGroup?._rebuildSingle;\n if (!rebuild) {\n throw new Error();\n }\n const renderable = rebuild(sc, mesh, material);\n if (!task._renderables.includes(renderable)) {\n task._renderables.push(renderable);\n }\n }\n task._pendingMeshes.length = 0;\n}\n\n/** Per-frame back-to-front sort for transparent bindings using the active camera. */\nfunction sortTransparentBindings(task: RenderTask, camera: Camera | null | undefined): void {\n const arr = task._transparentBindings;\n if (arr.length <= 1 || !camera) {\n return;\n }\n const v = getViewMatrix(camera);\n for (const b of arr) {\n const wc = b.renderable._worldCenter;\n b._sortDistance = wc ? wc[0]! * v[2]! + wc[1]! * v[6]! + wc[2]! * v[10]! + v[14]! : 0;\n }\n arr.sort((a, b) => b._sortDistance! - a._sortDistance! || a.renderable.order - b.renderable.order);\n}\n\n/** (Re)bucket task._renderables into bound lists. */\nfunction buildBindings(task: RenderTask, eng: EngineContext, targetSignature: RenderTargetSignature): void {\n const opaque = task._opaqueBindings;\n const direct = task._directBindings;\n const transparent = task._transparentBindings;\n opaque.length = 0;\n direct.length = 0;\n transparent.length = 0;\n for (const r of task._renderables) {\n const binding = r.bind(eng, targetSignature);\n if (r.isTransparent || r._transmissive) {\n transparent.push(binding);\n } else if (r._direct) {\n direct.push(binding);\n } else {\n opaque.push(binding);\n }\n }\n opaque.sort((a, b) => a.renderable.order - b.renderable.order);\n direct.sort((a, b) => a.renderable.order - b.renderable.order);\n task._opaqueBundles.length = 0;\n task._lastVersion = (task.scene as SceneContext)._renderableVersion;\n}\n\nfunction buildRenderPassDescriptor(task: RenderTask, rt: RenderTarget): void {\n const att = task._colorAttachment;\n att.view = rt._colorView!;\n // End-of-pass MSAA resolve into a caller-supplied single-sample target.\n // record() only builds the target's color view for an MSAA rt, so its\n // presence is the gate. The swapchain case is wired per-frame in\n // executePass (its view changes each frame); this custom view is stable.\n att.resolveTarget = task._config.rst?._colorView ?? undefined;\n task._renderPassDescriptor.colorAttachments = rt._colorView ? [att] : [];\n\n const depthSrc = task._depthSrc ?? rt;\n const depthView = depthSrc._depthView;\n let depthAttachment: GPURenderPassDepthStencilAttachment | undefined;\n if (depthView) {\n const dd = depthSrc._descriptor;\n const loadOp = task._depthLoadOp ?? \"clear\";\n depthAttachment = {\n view: depthView,\n depthClearValue: dd._depthClearValue ?? 0,\n depthLoadOp: loadOp,\n depthStoreOp: \"store\",\n };\n if (dd.dFormat?.includes(\"stencil\")) {\n depthAttachment.stencilClearValue = 0;\n depthAttachment.stencilLoadOp = loadOp;\n depthAttachment.stencilStoreOp = \"store\";\n }\n }\n\n task._renderPassDescriptor.depthStencilAttachment = depthAttachment;\n}\n\nfunction prepareRenderTaskPass(task: RenderTask, eng: EngineContext, targetSignature: RenderTargetSignature, context: DrawUpdateContext): void {\n const sc = task.scene as SceneContext;\n // Auto-resync when the source scene mutates.\n if (task._autoFromScene && task._lastVersion !== sc._renderableVersion) {\n task._renderables.length = 0;\n task._renderables.push(...sc._renderables);\n buildBindings(task, eng, targetSignature);\n }\n\n // Pre-pass work — runs before beginRenderPass. Updates the task-owned scene\n // UBO, scene-wide lights UBO, and per-binding UBOs. The scene bind group may\n // also need a refresh (lights buffer can be resized when glTF lights\n // extension raises MAX_LIGHTS after this task was first recorded).\n refreshTaskSceneBindGroup(task, eng);\n const camera = task._config.cam ?? sc.camera;\n sc._clusteredLightUpdater?.(camera, context.targetWidth, context.targetHeight);\n writePassSceneUBO(task, eng, sc, camera);\n refreshSceneLightsUBO(eng, sc);\n // Expose the active camera to per-binding `update()` calls. Some renderables\n // (e.g. transparent billboard systems) need it to compute view-space sort\n // depths during their update.\n (context as MutableDrawUpdateContext)._camera = camera;\n updateBindings(task._opaqueBindings, context);\n updateBindings(task._directBindings, context);\n updateBindings(task._transparentBindings, context);\n // Per-frame back-to-front sort for transparent bindings — must run AFTER\n // updateBindings so renderables that compute `_worldCenter` inside their\n // own `update()` (billboard systems) are seen with current values.\n sortTransparentBindings(task, camera);\n}\n\nfunction executePass(task: RenderTask, eng: EngineContext, targetSignature: RenderTargetSignature, context: DrawUpdateContext): number {\n const sc = task.scene;\n const sampleCount = targetSignature._sampleCount;\n prepareRenderTaskPass(task, eng, targetSignature, context);\n const att = task._colorAttachment;\n const cfg = task._config;\n if (cfg.rt._colorView) {\n // The engine scRT's color view is re-acquired every frame, so re-read\n // it here. Offscreen color views are stable between rebuilds — leaving att.view\n // untouched preserves an external override (swapchain-overlay shares the base\n // scene's MSAA color view). The resolve target (rst) is re-read each frame so an\n // `rst === scRT` picks up its fresh per-frame view.\n if (cfg.rt === eng.scRT) {\n att.view = cfg.rt._colorView;\n }\n att.resolveTarget = cfg.rst?._colorView ?? undefined;\n att.clearValue = task._autoFromScene ? sc.clearColor : cfg.clrColor!;\n att.loadOp = cfg.clr ? \"clear\" : \"load\";\n }\n if (task._executeWithTransmission) {\n return task._executeWithTransmission(sampleCount);\n }\n const pass = eng._currentEncoder.beginRenderPass(task._renderPassDescriptor);\n const draws = executePassBody(task, pass);\n pass.end();\n return draws;\n}\n\n/** Body of the registered `RenderPass`. Receives the live render-pass encoder\n * and issues all draws (viewport/scissor, group(0) bind, opaque bundle replay,\n * then direct-draws non-transparent direct + transparent). Returns the draw count. */\nfunction executePassBody(task: RenderTask, pass: GPURenderPassEncoder): number {\n const eng = task.engine as EngineContext;\n const cfg = task._config;\n const rt = cfg.rt;\n const scene = task.scene as SceneContext;\n const opaqueBindings = task._opaqueBindings;\n const opaqueBundles = task._opaqueBundles;\n const sceneBG = task._sceneBG;\n\n const camera = cfg.cam ?? scene.camera;\n const v = camera?.viewport;\n if (v) {\n const rw = rt._width;\n const rh = rt._height;\n const x = Math.floor(v.x * rw);\n const y = Math.floor((1 - v.y - v.height) * rh);\n const w = Math.ceil((v.x + v.width) * rw) - x;\n const h = Math.ceil((1 - v.y) * rh) - y;\n pass.setViewport(x, y, w, h, 0, 1);\n pass.setScissorRect(x, y, w, h);\n }\n // Scene bind group (group 0) is task-owned and identical for every draw in this pass.\n pass.setBindGroup(0, sceneBG);\n\n // Opaque: cached render bundle. Invalidated by scene mutation (_renderableVersion)\n // or visibility version (_vis). The bundle records group(0) at its start so it can\n // be replayed standalone (executeBundles inherits no inherited state).\n if (task._lastVersion !== scene._renderableVersion || task._lastVis !== _vis || opaqueBundles.length === 0) {\n const desc = rt._descriptor;\n const be = eng._device.createRenderBundleEncoder({\n colorFormats: desc.format ? [desc.format] : [],\n // Use the task's target signature, not the RT descriptor: a depth\n // override (config.depth) supplies the depth format externally, so\n // the cached opaque pipelines are built with it while the colour RT\n // carries no depthStencilFormat of its own. The bundle encoder's\n // attachment state must match those pipelines exactly.\n depthStencilFormat: task._targetSignature._depthStencilFormat,\n sampleCount: desc.samples ?? 1,\n });\n be.setBindGroup(0, sceneBG);\n drawList(be, opaqueBindings, eng);\n opaqueBundles[0] = be.finish();\n task._lastVersion = scene._renderableVersion;\n task._lastVis = _vis;\n }\n let draws = opaqueBindings.length;\n pass.executeBundles(opaqueBundles);\n // executeBundles invalidates pass bind-group state — rebind group 0 before further draws.\n pass.setBindGroup(0, sceneBG);\n draws += drawList(pass, task._directBindings, eng);\n draws += drawList(pass, task._transparentBindings, eng);\n return draws;\n}\n\nfunction refreshTaskSceneBindGroup(task: RenderTask, eng: EngineContext): void {\n const lightsUBO = ensureSceneLightState(eng, task.scene as SceneContext)._buffer;\n if (lightsUBO === task._lightsUBO) {\n return;\n }\n task._lightsUBO = lightsUBO;\n task._sceneBG = eng._device.createBindGroup({\n layout: getSceneBindGroupLayout(eng),\n entries: [\n { binding: 0, resource: { buffer: task._sceneUBO } },\n { binding: 1, resource: { buffer: lightsUBO } },\n ],\n });\n task._opaqueBundles.length = 0;\n task._lastVersion = -1;\n}\n\n/** Write the canonical SceneUniforms struct to the task-owned scene UBO.\n * Bails before touching scratch/GPU when all inputs are unchanged. */\nfunction writePassSceneUBO(task: RenderTask, eng: EngineContext, scene: SceneContext, camera: Camera | null): void {\n if (!camera) {\n return;\n }\n\n const v = camera.viewport;\n const rt = task._config.rt;\n const aspect = (task._config.cs ? eng.canvas.width / eng.canvas.height : rt._width / rt._height) * (v ? v.width / v.height : 1);\n const fog = scene.fog;\n const img = scene.imageProcessing;\n const envRotationY = scene.envRotationY || 0;\n const wv = camera.worldMatrixVersion;\n const s = task._su;\n if (s[0] === camera && s[1] === fog && s[2] === wv && s[3] === aspect && s[4] === envRotationY && s[5] === img.exposure && s[6] === img.contrast) {\n return;\n }\n s[0] = camera;\n s[1] = fog;\n s[2] = wv;\n s[3] = aspect;\n s[4] = envRotationY;\n s[5] = img.exposure;\n s[6] = img.contrast;\n\n const data = task._suData;\n _packSceneUniforms(data, eng, scene, camera, aspect);\n const contribs = scene._sceneUboContributors;\n if (contribs) {\n for (const c of contribs) {\n c(data, scene);\n }\n }\n eng._device.queue.writeBuffer(task._sceneUBO, 0, data as Float32Array<ArrayBuffer>);\n}\n\nfunction updateBindings(list: readonly DrawBinding[], context: DrawUpdateContext): void {\n for (const b of list) {\n b.update?.(context);\n }\n}\n\n/** Iterate DrawBindings, deduping setPipeline. */\nfunction drawList(enc: GPURenderPassEncoder | GPURenderBundleEncoder, list: readonly DrawBinding[], engine: EngineContext): number {\n let lp: GPURenderPipeline | null = null;\n let draws = 0;\n for (const b of list) {\n const mesh = b.renderable.mesh;\n if (mesh && mesh.visible === false) {\n continue;\n }\n if (b.pipeline !== lp) {\n enc.setPipeline(b.pipeline);\n lp = b.pipeline;\n }\n draws += b.draw(enc, engine);\n }\n return draws;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { TU, SS } from '../engine/gpu-flags.js';
|
|
2
|
+
import { getOrCreateSampler } from '../resource/gpu-pool.js';
|
|
3
|
+
import { _installDepthGrab } from './transmission.js';
|
|
4
|
+
|
|
5
|
+
const DEPTH_GRAB_SHADER = `@group(0)@binding(0)var t:texture_depth_2d;struct V{@builtin(position)p:vec4f};@vertex fn vs(@builtin(vertex_index)i:u32)->V{let p=array<vec2f,3>(vec2f(-1,-1),vec2f(3,-1),vec2f(-1,3))[i];return V(vec4f(p,0,1));}@fragment fn fs(@builtin(position)fc:vec4f)->@location(0)f32{return textureLoad(t,vec2<i32>(fc.xy),0);}`;
|
|
6
|
+
const DEPTH_GRAB_MSAA_SHADER = `@group(0)@binding(0)var t:texture_depth_multisampled_2d;struct V{@builtin(position)p:vec4f};@vertex fn vs(@builtin(vertex_index)i:u32)->V{let p=array<vec2f,3>(vec2f(-1,-1),vec2f(3,-1),vec2f(-1,3))[i];return V(vec4f(p,0,1));}@fragment fn fs(@builtin(position)fc:vec4f)->@location(0)f32{return textureLoad(t,vec2<i32>(fc.xy),0);}`;
|
|
7
|
+
let depthGrabPipelines = null;
|
|
8
|
+
let depthGrabShader = null;
|
|
9
|
+
let depthGrabMsaaShader = null;
|
|
10
|
+
let depthGrabBgl = null;
|
|
11
|
+
let depthGrabMsaaBgl = null;
|
|
12
|
+
let depthGrabDevice = null;
|
|
13
|
+
function getDepthGrabPipeline(engine, multisampled) {
|
|
14
|
+
const device = engine._device;
|
|
15
|
+
if (device !== depthGrabDevice) {
|
|
16
|
+
depthGrabPipelines?.clear();
|
|
17
|
+
depthGrabPipelines = null;
|
|
18
|
+
depthGrabShader = null;
|
|
19
|
+
depthGrabMsaaShader = null;
|
|
20
|
+
depthGrabBgl = null;
|
|
21
|
+
depthGrabMsaaBgl = null;
|
|
22
|
+
depthGrabDevice = device;
|
|
23
|
+
}
|
|
24
|
+
if (multisampled) {
|
|
25
|
+
depthGrabMsaaShader ??= device.createShaderModule({ code: DEPTH_GRAB_MSAA_SHADER });
|
|
26
|
+
depthGrabMsaaBgl ??= device.createBindGroupLayout({
|
|
27
|
+
entries: [{ binding: 0, visibility: SS.FRAGMENT, texture: { sampleType: "depth", multisampled: true } }]
|
|
28
|
+
});
|
|
29
|
+
} else {
|
|
30
|
+
depthGrabShader ??= device.createShaderModule({ code: DEPTH_GRAB_SHADER });
|
|
31
|
+
depthGrabBgl ??= device.createBindGroupLayout({
|
|
32
|
+
entries: [{ binding: 0, visibility: SS.FRAGMENT, texture: { sampleType: "depth" } }]
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
depthGrabPipelines ??= /* @__PURE__ */ new Map();
|
|
36
|
+
const key = multisampled ? "msaa" : "1x";
|
|
37
|
+
let pipeline = depthGrabPipelines.get(key);
|
|
38
|
+
if (!pipeline) {
|
|
39
|
+
const shader = multisampled ? depthGrabMsaaShader : depthGrabShader;
|
|
40
|
+
pipeline = device.createRenderPipeline({
|
|
41
|
+
label: "transmission-depth-grab",
|
|
42
|
+
layout: device.createPipelineLayout({ bindGroupLayouts: [multisampled ? depthGrabMsaaBgl : depthGrabBgl] }),
|
|
43
|
+
vertex: { module: shader, entryPoint: "vs" },
|
|
44
|
+
fragment: { module: shader, entryPoint: "fs", targets: [{ format: "r32float" }] },
|
|
45
|
+
primitive: { topology: "triangle-list" }
|
|
46
|
+
});
|
|
47
|
+
depthGrabPipelines.set(key, pipeline);
|
|
48
|
+
}
|
|
49
|
+
return pipeline;
|
|
50
|
+
}
|
|
51
|
+
function createDepthGrab(engine, source, width, height, multisampled) {
|
|
52
|
+
const device = engine._device;
|
|
53
|
+
const texture = device.createTexture({
|
|
54
|
+
label: "transmission-depth-grab",
|
|
55
|
+
size: { width, height },
|
|
56
|
+
format: "r32float",
|
|
57
|
+
usage: TU.RENDER_ATTACHMENT | TU.TEXTURE_BINDING
|
|
58
|
+
});
|
|
59
|
+
const view = texture.createView();
|
|
60
|
+
const tex = {
|
|
61
|
+
texture,
|
|
62
|
+
view,
|
|
63
|
+
sampler: getOrCreateSampler(engine, { magFilter: "nearest", minFilter: "nearest", addressModeU: "clamp-to-edge", addressModeV: "clamp-to-edge" }),
|
|
64
|
+
width,
|
|
65
|
+
height,
|
|
66
|
+
invertY: false,
|
|
67
|
+
_sampleType: "float"
|
|
68
|
+
// r32float samples as unfilterable float (read with textureLoad)
|
|
69
|
+
};
|
|
70
|
+
const pipeline = getDepthGrabPipeline(engine, multisampled);
|
|
71
|
+
const bindGroup = device.createBindGroup({
|
|
72
|
+
layout: multisampled ? depthGrabMsaaBgl : depthGrabBgl,
|
|
73
|
+
entries: [{ binding: 0, resource: source.createView({ aspect: "depth-only" }) }]
|
|
74
|
+
});
|
|
75
|
+
return { texture: tex, _view: view, _blit: { _pipeline: pipeline, _bindGroup: bindGroup } };
|
|
76
|
+
}
|
|
77
|
+
function recordDepthGrab(engine, depth) {
|
|
78
|
+
const pass = engine._currentEncoder.beginRenderPass({
|
|
79
|
+
label: "transmission-depth-grab",
|
|
80
|
+
colorAttachments: [{ view: depth._view, loadOp: "clear", storeOp: "store", clearValue: { r: 0, g: 0, b: 0, a: 0 } }]
|
|
81
|
+
});
|
|
82
|
+
pass.setPipeline(depth._blit._pipeline);
|
|
83
|
+
pass.setBindGroup(0, depth._blit._bindGroup);
|
|
84
|
+
pass.draw(3);
|
|
85
|
+
pass.end();
|
|
86
|
+
}
|
|
87
|
+
_installDepthGrab({ create: createDepthGrab, record: recordDepthGrab });
|
|
88
|
+
//# sourceMappingURL=transmission-depth-grab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transmission-depth-grab.js","sources":["../../../src/frame-graph/transmission-depth-grab.ts"],"sourcesContent":["import { TU, SS } from \"../engine/gpu-flags.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport { getOrCreateSampler } from \"../resource/gpu-pool.js\";\nimport type { Texture2D } from \"../texture/texture-2d.js\";\nimport { _installDepthGrab, type TransmissionDepthGrabState } from \"./transmission.js\";\n/**\n * Lazy depth-grab implementation for `TransmissionOptions.grabDepth`. This module is dynamic-imported ONLY when a\n * task actually enables `grabDepth` (see `transmission.ts` → task `_preload`), so transmission scenes that do not\n * ask for the opaque-depth snapshot never fetch these shaders or pipelines. It installs itself into `transmission.ts`\n * via a module-level side-effect (`_installDepthGrab`) so the shared transmission chunk holds only a nullable seam.\n */\n\n// Depth grab: copy the depth attachment's NDC depth into an `r32float` texel-for-texel (no filtering — depth must\n// never be interpolated across silhouettes). The MSAA variant resolves sample 0, matching `createDepthResolveTask`.\nconst DEPTH_GRAB_SHADER = `@group(0)@binding(0)var t:texture_depth_2d;struct V{@builtin(position)p:vec4f};@vertex fn vs(@builtin(vertex_index)i:u32)->V{let p=array<vec2f,3>(vec2f(-1,-1),vec2f(3,-1),vec2f(-1,3))[i];return V(vec4f(p,0,1));}@fragment fn fs(@builtin(position)fc:vec4f)->@location(0)f32{return textureLoad(t,vec2<i32>(fc.xy),0);}`;\nconst DEPTH_GRAB_MSAA_SHADER = `@group(0)@binding(0)var t:texture_depth_multisampled_2d;struct V{@builtin(position)p:vec4f};@vertex fn vs(@builtin(vertex_index)i:u32)->V{let p=array<vec2f,3>(vec2f(-1,-1),vec2f(3,-1),vec2f(-1,3))[i];return V(vec4f(p,0,1));}@fragment fn fs(@builtin(position)fc:vec4f)->@location(0)f32{return textureLoad(t,vec2<i32>(fc.xy),0);}`;\n\n// Depth-grab pipeline cache (single-sample + MSAA variants), reset on device change like the colour blits.\nlet depthGrabPipelines: Map<string, GPURenderPipeline> | null = null;\nlet depthGrabShader: GPUShaderModule | null = null;\nlet depthGrabMsaaShader: GPUShaderModule | null = null;\nlet depthGrabBgl: GPUBindGroupLayout | null = null;\nlet depthGrabMsaaBgl: GPUBindGroupLayout | null = null;\nlet depthGrabDevice: GPUDevice | null = null;\n\n/** Lazily build + cache the depth-grab pipeline (single-sample or MSAA sample-0 resolve), reset on device change. */\nfunction getDepthGrabPipeline(engine: EngineContext, multisampled: boolean): GPURenderPipeline {\n const device = engine._device;\n if (device !== depthGrabDevice) {\n depthGrabPipelines?.clear();\n depthGrabPipelines = null;\n depthGrabShader = null;\n depthGrabMsaaShader = null;\n depthGrabBgl = null;\n depthGrabMsaaBgl = null;\n depthGrabDevice = device;\n }\n if (multisampled) {\n depthGrabMsaaShader ??= device.createShaderModule({ code: DEPTH_GRAB_MSAA_SHADER });\n depthGrabMsaaBgl ??= device.createBindGroupLayout({\n entries: [{ binding: 0, visibility: SS.FRAGMENT, texture: { sampleType: \"depth\", multisampled: true } }],\n });\n } else {\n depthGrabShader ??= device.createShaderModule({ code: DEPTH_GRAB_SHADER });\n depthGrabBgl ??= device.createBindGroupLayout({\n entries: [{ binding: 0, visibility: SS.FRAGMENT, texture: { sampleType: \"depth\" } }],\n });\n }\n depthGrabPipelines ??= new Map();\n const key = multisampled ? \"msaa\" : \"1x\";\n let pipeline = depthGrabPipelines.get(key);\n if (!pipeline) {\n const shader = multisampled ? depthGrabMsaaShader! : depthGrabShader!;\n pipeline = device.createRenderPipeline({\n label: \"transmission-depth-grab\",\n layout: device.createPipelineLayout({ bindGroupLayouts: [multisampled ? depthGrabMsaaBgl! : depthGrabBgl!] }),\n vertex: { module: shader, entryPoint: \"vs\" },\n fragment: { module: shader, entryPoint: \"fs\", targets: [{ format: \"r32float\" }] },\n primitive: { topology: \"triangle-list\" },\n });\n depthGrabPipelines.set(key, pipeline);\n }\n return pipeline;\n}\n\n/** Build the depth-grab target (`r32float`, source-sized) + the blit that resolves the task's depth attachment into\n * it. The source view is depth-only so combined depth-stencil formats sample cleanly. */\nfunction createDepthGrab(engine: EngineContext, source: GPUTexture, width: number, height: number, multisampled: boolean): TransmissionDepthGrabState {\n const device = engine._device;\n const texture = device.createTexture({\n label: \"transmission-depth-grab\",\n size: { width, height },\n format: \"r32float\",\n usage: TU.RENDER_ATTACHMENT | TU.TEXTURE_BINDING,\n });\n const view = texture.createView();\n const tex = {\n texture,\n view,\n sampler: getOrCreateSampler(engine, { magFilter: \"nearest\", minFilter: \"nearest\", addressModeU: \"clamp-to-edge\", addressModeV: \"clamp-to-edge\" }),\n width,\n height,\n invertY: false,\n _sampleType: \"float\", // r32float samples as unfilterable float (read with textureLoad)\n } as unknown as Texture2D;\n const pipeline = getDepthGrabPipeline(engine, multisampled);\n const bindGroup = device.createBindGroup({\n layout: multisampled ? depthGrabMsaaBgl! : depthGrabBgl!,\n entries: [{ binding: 0, resource: source.createView({ aspect: \"depth-only\" }) }],\n });\n return { texture: tex, _view: view, _blit: { _pipeline: pipeline, _bindGroup: bindGroup } };\n}\n\n/** Per-frame: record the depth-grab resolve pass into the frame encoder at the transmission mid-pass break. Kept\n * here (not in `transmission.ts`) so its render-pass descriptor bytes only load with the rest of the feature. */\nfunction recordDepthGrab(engine: EngineContext, depth: TransmissionDepthGrabState): void {\n const pass = engine._currentEncoder.beginRenderPass({\n label: \"transmission-depth-grab\",\n colorAttachments: [{ view: depth._view, loadOp: \"clear\", storeOp: \"store\", clearValue: { r: 0, g: 0, b: 0, a: 0 } }],\n });\n pass.setPipeline(depth._blit._pipeline);\n pass.setBindGroup(0, depth._blit._bindGroup);\n pass.draw(3);\n pass.end();\n}\n\n// Module-level side-effect install (see the pbr-primitive-resolver pattern): importing this module wires the\n// depth-grab builder + per-frame recorder into the shared transmission seam. Keeps `transmission.ts` free of these\n// bytes until a task actually enables grabDepth.\n_installDepthGrab({ create: createDepthGrab, record: recordDepthGrab });\n"],"names":[],"mappings":"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"}
|