@woosh/meep-engine 2.39.37 → 2.39.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +13 -0
- package/core/assert.js +14 -5
- package/core/bvh2/aabb3/AABB3.js +2 -2
- package/core/bvh2/aabb3/aabb3_detailed_volume_intersection.js +3 -2
- package/core/bvh2/aabb3/aabb3_intersects_frustum_array.js +2 -2
- package/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +7 -0
- package/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.js +149 -6
- package/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.spec.js +41 -0
- package/core/bvh2/traversal/ThreeClippingPlaneComputingBVHVisitor.js +2 -2
- package/core/bvh2/traversal/__process_point_if_within_planes.js +2 -2
- package/core/bvh2/traversal/aabb3_detailed_volume_intersection_callback_based.js +3 -0
- package/core/geom/3d/aabb/aabb3_computeDistanceAbovePlane_max.spec.js +8 -0
- package/core/geom/3d/aabb/{aabb3_computeDistanceAbovePlane.js → aabb3_compute_distance_above_plane_max.js} +3 -2
- package/core/geom/3d/aabb/computeAABB3PlaneSide.js +3 -3
- package/core/geom/3d/frustum/frustum3_computeNearestPointToPoint.js +3 -2
- package/core/geom/3d/plane/is_point_within_planes.js +2 -2
- package/core/geom/3d/plane/plane3_projectPoint.js +2 -2
- package/core/geom/3d/plane/plane3_projectPoint.spec.js +54 -0
- package/core/geom/Plane.js +0 -19
- package/core/geom/v3_distance_above_plane.js +20 -0
- package/core/geom/v3_distance_above_plane.spec.js +40 -0
- package/core/math/statistics/halton_sequence.js +26 -0
- package/engine/asset/loaders/ArrayBufferLoader.js +76 -16
- package/engine/ecs/EntityComponentDataset.js +18 -28
- package/engine/graphics/GraphicsEngine.d.ts +2 -2
- package/engine/graphics/GraphicsEngine.js +11 -15
- package/engine/graphics/composit/LayerCompositer.js +1 -0
- package/engine/graphics/ecs/camera/Camera.js +2 -2
- package/engine/graphics/ecs/camera/CameraSystem.js +6 -0
- package/engine/graphics/ecs/light/binding/three/ThreeLightBinding.js +1 -1
- package/engine/graphics/ecs/mesh-v2/aggregate/prototypeSGMesh.js +17 -20
- package/engine/graphics/filter/FlipArrayInPlace.js +11 -6
- package/engine/graphics/geometry/clipping/ClippedGeometry.js +4 -4
- package/engine/graphics/micron/prototypeVirtualGeometry.js +3 -1
- package/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js +2 -0
- package/engine/graphics/render/buffer/simple-fx/taa/TemporalSupersamplingRenderPlugin.js +95 -0
- package/engine/graphics/render/buffer/simple-fx/taa/prototypeTAA.js +61 -0
- package/engine/graphics/render/forward_plus/LightManager.js +4 -4
- package/engine/graphics/render/forward_plus/plugin/ForwardPlusRenderingPlugin.js +6 -7
- package/engine/graphics/render/forward_plus/plugin/MaterialTransformer.js +6 -2
- package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_objects.js +4 -2
- package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +4 -2
- package/engine/graphics/render/frame_graph/GraphNode.js +22 -0
- package/engine/graphics/render/frame_graph/RenderGraph.js +405 -0
- package/engine/graphics/render/frame_graph/RenderGraphBuilder.js +77 -0
- package/engine/graphics/render/frame_graph/RenderPass.js +30 -12
- package/engine/graphics/render/frame_graph/RenderPassNode.js +103 -0
- package/engine/graphics/render/frame_graph/RenderPassResources.js +54 -4
- package/engine/graphics/render/frame_graph/ResourceEntry.js +77 -0
- package/engine/graphics/render/frame_graph/ResourceNode.js +23 -0
- package/engine/graphics/render/frame_graph/TextureDescriptor.js +38 -4
- package/engine/graphics/render/frame_graph/sample/deferred/GBufferDrawPass.js +11 -5
- package/engine/graphics/render/frame_graph/sample/deferred/LightingPass.js +24 -0
- package/engine/graphics/render/frame_graph/sample/deferred/run.js +31 -0
- package/engine/graphics/render/frame_graph/sample/meep-v1/ColorDepthPass.js +38 -0
- package/engine/graphics/render/frame_graph/sample/meep-v1/OutlinePass.js +9 -0
- package/engine/graphics/render/frame_graph/sample/meep-v1/SSAOPass.js +5 -0
- package/engine/graphics/render/frame_graph/sample/meep-v1/render.js +7 -0
- package/engine/graphics/render/frame_graph/webgl/WebGLRenderContext.js +5 -0
- package/engine/graphics/render/layers/RenderLayerUtils.js +5 -3
- package/engine/graphics/render/view/CameraView.js +38 -0
- package/engine/knowledge/database/DATABASE_SERIALIZATION_IGNORE_PROPERTY.js +1 -0
- package/engine/knowledge/database/StaticKnowledgeDataTable.js +5 -4
- package/package.json +1 -1
- package/core/geom/Plane.spec.js +0 -12
- package/engine/graphics/render/frame_graph/FrameGraphBuilder.js +0 -36
- package/engine/graphics/render/frame_graph/Resource.js +0 -21
- package/engine/graphics/render/frame_graph/ResourceReference.js +0 -14
- package/engine/graphics/render/frame_graph/UsageModeType.js +0 -5
- package/engine/graphics/render/frame_graph/sample/deferred/PresentPass.js +0 -17
|
@@ -20,15 +20,13 @@ export class ForwardPlusRenderingPlugin extends EnginePlugin {
|
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
*
|
|
23
|
-
* @param {
|
|
24
|
-
* @param {Camera} camera
|
|
25
|
-
* @param {Scene} scene
|
|
23
|
+
* @param {CameraView} view
|
|
26
24
|
* @private
|
|
27
25
|
*/
|
|
28
|
-
__prepare_for_render(
|
|
29
|
-
this.__material_transformer.updateCamera(
|
|
26
|
+
__prepare_for_render(view) {
|
|
27
|
+
this.__material_transformer.updateCamera(view);
|
|
30
28
|
|
|
31
|
-
this.__light_manager.buildTiles(camera);
|
|
29
|
+
this.__light_manager.buildTiles(view.camera);
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
updateResolution() {
|
|
@@ -49,7 +47,8 @@ export class ForwardPlusRenderingPlugin extends EnginePlugin {
|
|
|
49
47
|
graphics.viewport.size.onChanged.add(this.updateResolution, this);
|
|
50
48
|
graphics.pixelRatio.onChanged.add(this.updateResolution, this);
|
|
51
49
|
|
|
52
|
-
|
|
50
|
+
|
|
51
|
+
graphics.main_view.on.preRender.add(this.__prepare_for_render, this);
|
|
53
52
|
|
|
54
53
|
this.updateResolution();
|
|
55
54
|
|
|
@@ -62,9 +62,13 @@ export class MaterialTransformer extends AbstractMaterialTransformer {
|
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
*
|
|
67
|
+
* @param {CameraView} c
|
|
68
|
+
*/
|
|
65
69
|
updateCamera(c) {
|
|
66
|
-
this.__common_uniforms.fp_f_camera_far.value = c.far;
|
|
67
|
-
this.__common_uniforms.fp_f_camera_near.value = c.near;
|
|
70
|
+
this.__common_uniforms.fp_f_camera_far.value = c.camera.far;
|
|
71
|
+
this.__common_uniforms.fp_f_camera_near.value = c.camera.near;
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
transform(source) {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
aabb3_computeDistanceAbovePlane_max
|
|
3
|
+
} from "../../../../../core/geom/3d/aabb/aabb3_compute_distance_above_plane_max.js";
|
|
2
4
|
import { point_light_inside_volume } from "./point_light_inside_volume.js";
|
|
3
5
|
import { spot_light_inside_volume } from "./spot_light_inside_volume.js";
|
|
4
6
|
|
|
@@ -50,7 +52,7 @@ export function query_bvh_frustum_from_objects(
|
|
|
50
52
|
const plane_normal_z = planes[plane_address + 2];
|
|
51
53
|
const plane_constant = planes[plane_address + 3];
|
|
52
54
|
|
|
53
|
-
const distanceAbovePlane =
|
|
55
|
+
const distanceAbovePlane = aabb3_computeDistanceAbovePlane_max(
|
|
54
56
|
plane_normal_x, plane_normal_y, plane_normal_z, plane_constant,
|
|
55
57
|
n.x0, n.y0, n.z0,
|
|
56
58
|
n.x1, n.y1, n.z1
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
aabb3_computeDistanceAbovePlane_max
|
|
3
|
+
} from "../../../../../core/geom/3d/aabb/aabb3_compute_distance_above_plane_max.js";
|
|
2
4
|
import { point_light_inside_volume } from "./point_light_inside_volume.js";
|
|
3
5
|
import { BVH_BINARY_NODE_SIZE, BVH_LEAF_NODE_SIZE } from "../../../../../core/bvh2/binary/2/BinaryUint32BVH.js";
|
|
4
6
|
|
|
@@ -69,7 +71,7 @@ export function query_bvh_frustum_from_texture(
|
|
|
69
71
|
const plane_normal_z = planes[plane_address + 2];
|
|
70
72
|
const plane_constant = planes[plane_address + 3];
|
|
71
73
|
|
|
72
|
-
const distanceAbovePlane =
|
|
74
|
+
const distanceAbovePlane = aabb3_computeDistanceAbovePlane_max(
|
|
73
75
|
plane_normal_x, plane_normal_y, plane_normal_z, plane_constant,
|
|
74
76
|
n_x0, n_y0, n_z0,
|
|
75
77
|
n_x1, n_y1, n_z1
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import { RenderGraphBuilder } from "./RenderGraphBuilder.js";
|
|
2
|
+
import { RenderPassNode } from "./RenderPassNode.js";
|
|
3
|
+
import { ResourceNode } from "./ResourceNode.js";
|
|
4
|
+
import { assert } from "../../../../core/assert.js";
|
|
5
|
+
import LineBuilder from "../../../../core/codegen/LineBuilder.js";
|
|
6
|
+
import { RenderPassResources } from "./RenderPassResources.js";
|
|
7
|
+
import { ResourceEntry } from "./ResourceEntry.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Based on the Frostbite's GDC paper "FrameGraph: Extensible Rendering Architecture in Frostbite" by Yuriy O'Donnell
|
|
11
|
+
* @see https://github.com/skaarj1989/FrameGraph
|
|
12
|
+
*/
|
|
13
|
+
export class RenderGraph {
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @type {RenderPass[]}
|
|
17
|
+
* @private
|
|
18
|
+
*/
|
|
19
|
+
__passes = [];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* @type {RenderPassNode[]}
|
|
24
|
+
* @private
|
|
25
|
+
*/
|
|
26
|
+
__pass_nodes = [];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @type {ResourceNode[]}
|
|
31
|
+
* @private
|
|
32
|
+
*/
|
|
33
|
+
__resource_nodes = [];
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
*
|
|
37
|
+
* @type {ResourceEntry[]}
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
__resource_registry = [];
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
*
|
|
44
|
+
* @param {number} id Resource Node ID
|
|
45
|
+
* @returns {ResourceEntry}
|
|
46
|
+
*/
|
|
47
|
+
getResourceEntry(id) {
|
|
48
|
+
const node = this.getResourceNode(id);
|
|
49
|
+
|
|
50
|
+
return this.__resource_registry[node.resource_id];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
*
|
|
55
|
+
* @param {number} id
|
|
56
|
+
* @returns {ResourceNode}
|
|
57
|
+
*/
|
|
58
|
+
getResourceNode(id) {
|
|
59
|
+
assert.isNonNegativeInteger(id, 'id');
|
|
60
|
+
|
|
61
|
+
const nodes = this.__resource_nodes;
|
|
62
|
+
const node_count = nodes.length;
|
|
63
|
+
for (let i = 0; i < node_count; i++) {
|
|
64
|
+
const node = nodes[i];
|
|
65
|
+
if (node.id === id) {
|
|
66
|
+
return node;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
throw new Error(`Resource Node ${id} not found`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @template T
|
|
75
|
+
* @param {number} id resource ID
|
|
76
|
+
* @returns {T}
|
|
77
|
+
*/
|
|
78
|
+
getDescriptor(id) {
|
|
79
|
+
return this.getResourceEntry(id).resource_descriptor;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @template T
|
|
84
|
+
* @param {string} name
|
|
85
|
+
* @param {T} descriptor
|
|
86
|
+
*/
|
|
87
|
+
create_resource(name, descriptor) {
|
|
88
|
+
const resource = this._createResourceEntry(descriptor);
|
|
89
|
+
|
|
90
|
+
return this._createResourceNode(name, resource.resource_id).id;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @template T
|
|
95
|
+
* @param {T} descriptor
|
|
96
|
+
* @return {ResourceEntry}
|
|
97
|
+
* @private
|
|
98
|
+
*/
|
|
99
|
+
_createResourceEntry(descriptor) {
|
|
100
|
+
|
|
101
|
+
const entry = new ResourceEntry();
|
|
102
|
+
|
|
103
|
+
entry.resource_id = this.__resource_registry.length;
|
|
104
|
+
entry.resource_descriptor = descriptor;
|
|
105
|
+
|
|
106
|
+
this.__resource_registry.push(entry);
|
|
107
|
+
|
|
108
|
+
return entry;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
*
|
|
113
|
+
* @param {string} name
|
|
114
|
+
* @param {number} resource_id
|
|
115
|
+
* @return {ResourceNode}
|
|
116
|
+
* @private
|
|
117
|
+
*/
|
|
118
|
+
_createResourceNode(name, resource_id) {
|
|
119
|
+
assert.isNonNegativeInteger(resource_id, 'resource_id');
|
|
120
|
+
|
|
121
|
+
const n = new ResourceNode();
|
|
122
|
+
|
|
123
|
+
const id = this.__resource_nodes.length;
|
|
124
|
+
|
|
125
|
+
n.id = id;
|
|
126
|
+
n.name = name;
|
|
127
|
+
n.resource_id = resource_id;
|
|
128
|
+
|
|
129
|
+
this.__resource_nodes[id] = n;
|
|
130
|
+
|
|
131
|
+
return n;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
*
|
|
136
|
+
* @param {number} res
|
|
137
|
+
* @returns {number}
|
|
138
|
+
*/
|
|
139
|
+
clone_resource(res) {
|
|
140
|
+
const node = this.getResourceNode(res);
|
|
141
|
+
|
|
142
|
+
const entry = this.__resource_registry[node.resource_id];
|
|
143
|
+
|
|
144
|
+
entry.resource_version++;
|
|
145
|
+
|
|
146
|
+
const clone_node = new ResourceNode();
|
|
147
|
+
clone_node.id = this.__resource_nodes.length;
|
|
148
|
+
clone_node.name = node.name;
|
|
149
|
+
clone_node.resource_id = node.resource_id;
|
|
150
|
+
clone_node.version = entry.resource_version;
|
|
151
|
+
|
|
152
|
+
this.__resource_nodes.push(clone_node);
|
|
153
|
+
|
|
154
|
+
return clone_node.id;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @template T
|
|
159
|
+
* @param {string} name
|
|
160
|
+
* @param {TextureDescriptor} description
|
|
161
|
+
* @param {T} resource
|
|
162
|
+
* @returns {number}
|
|
163
|
+
*/
|
|
164
|
+
import_resource(name, description, resource) {
|
|
165
|
+
const record = this._createResourceEntry(description);
|
|
166
|
+
|
|
167
|
+
record.resource = resource;
|
|
168
|
+
|
|
169
|
+
record.imported = true;
|
|
170
|
+
|
|
171
|
+
return this._createResourceNode(name, record.resource_id).id;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @returns {boolean}
|
|
176
|
+
* @param id
|
|
177
|
+
*/
|
|
178
|
+
is_valid_resource(id) {
|
|
179
|
+
const node = this.getResourceNode(id);
|
|
180
|
+
const record = this.getResourceEntry(id);
|
|
181
|
+
|
|
182
|
+
return node.version === record.resource_version;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* @template T
|
|
187
|
+
* @param {RenderPass} pass
|
|
188
|
+
* @returns {T} resources/handles returned by {@link RenderPass#setup}
|
|
189
|
+
*/
|
|
190
|
+
add(pass) {
|
|
191
|
+
|
|
192
|
+
const pass_nodes = this.__pass_nodes;
|
|
193
|
+
|
|
194
|
+
const builder = new RenderGraphBuilder();
|
|
195
|
+
const node = new RenderPassNode();
|
|
196
|
+
|
|
197
|
+
node.id = pass_nodes.length;
|
|
198
|
+
node.name = pass.name;
|
|
199
|
+
node.pass = pass;
|
|
200
|
+
|
|
201
|
+
pass_nodes.push(node);
|
|
202
|
+
|
|
203
|
+
builder.init(this, node);
|
|
204
|
+
|
|
205
|
+
const result = pass.setup(builder, pass.inputs);
|
|
206
|
+
|
|
207
|
+
this.__passes.push(pass);
|
|
208
|
+
|
|
209
|
+
node.data = result;
|
|
210
|
+
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
compile() {
|
|
215
|
+
const pass_nodes = this.__pass_nodes;
|
|
216
|
+
|
|
217
|
+
// wire resources of passes
|
|
218
|
+
const pass_node_count = pass_nodes.length;
|
|
219
|
+
const resource_nodes = this.__resource_nodes;
|
|
220
|
+
|
|
221
|
+
for (let i = 0; i < pass_node_count; i++) {
|
|
222
|
+
const pass = pass_nodes[i];
|
|
223
|
+
|
|
224
|
+
// mask pass as having number of references equal to number of resources it writes to
|
|
225
|
+
pass.ref_count = pass.resource_writes.length;
|
|
226
|
+
|
|
227
|
+
for (const id of pass.resource_reads) {
|
|
228
|
+
const read_node = resource_nodes[id];
|
|
229
|
+
|
|
230
|
+
read_node.ref_count++;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
for (const id of pass.resource_writes) {
|
|
234
|
+
const written_node = resource_nodes[id];
|
|
235
|
+
|
|
236
|
+
written_node.producer = pass;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// perform culling
|
|
241
|
+
/**
|
|
242
|
+
*
|
|
243
|
+
* @type {ResourceNode[]}
|
|
244
|
+
*/
|
|
245
|
+
const unreferenced_resources = [];
|
|
246
|
+
|
|
247
|
+
for (const node of resource_nodes) {
|
|
248
|
+
if (node.ref_count === 0) {
|
|
249
|
+
unreferenced_resources.push(node);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
while (unreferenced_resources.length > 0) {
|
|
254
|
+
const unreferenced_resource = unreferenced_resources.pop();
|
|
255
|
+
|
|
256
|
+
const producer = unreferenced_resource.producer;
|
|
257
|
+
|
|
258
|
+
if (producer === null || producer.has_side_effects) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
assert.greaterThanOrEqual(producer.ref_count, 1, 'must have at least one reference'); // Why?
|
|
263
|
+
|
|
264
|
+
// disconnect unreferenced resource from producer
|
|
265
|
+
producer.ref_count--;
|
|
266
|
+
|
|
267
|
+
if (producer.ref_count === 0) {
|
|
268
|
+
|
|
269
|
+
// producer is no longer referenced
|
|
270
|
+
|
|
271
|
+
for (const id of producer.resource_reads) {
|
|
272
|
+
const node = resource_nodes[id];
|
|
273
|
+
|
|
274
|
+
// disconnect producer from all its reads (upstream)
|
|
275
|
+
node.ref_count--;
|
|
276
|
+
|
|
277
|
+
if (node.ref_count === 0) {
|
|
278
|
+
// resource is no longer referenced
|
|
279
|
+
unreferenced_resources.push(node);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// calculate lifetimes
|
|
286
|
+
for (const pass of pass_nodes) {
|
|
287
|
+
if (pass.ref_count === 0) {
|
|
288
|
+
// unused pass
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
for (const id of pass.resource_creates) {
|
|
293
|
+
this.getResourceEntry(id).producer = pass;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
for (const id of pass.resource_writes) {
|
|
297
|
+
this.getResourceEntry(id).last = pass;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
for (const id of pass.resource_reads) {
|
|
301
|
+
this.getResourceEntry(id).last = pass;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
*
|
|
308
|
+
* @param {IRenderContext} context
|
|
309
|
+
*/
|
|
310
|
+
execute(context) {
|
|
311
|
+
const pass_nodes = this.__pass_nodes;
|
|
312
|
+
const pass_node_count = pass_nodes.length;
|
|
313
|
+
for (let i = 0; i < pass_node_count; i++) {
|
|
314
|
+
const node = pass_nodes[i];
|
|
315
|
+
|
|
316
|
+
if (!node.can_execute()) {
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
for (const id of node.resource_creates) {
|
|
321
|
+
// allocate resource
|
|
322
|
+
this.getResourceEntry(id).create();
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const resources = new RenderPassResources();
|
|
326
|
+
resources.init(this, node);
|
|
327
|
+
|
|
328
|
+
// execute pass
|
|
329
|
+
node.pass.execute(node.data, resources, context);
|
|
330
|
+
|
|
331
|
+
for (const entry of this.__resource_registry) {
|
|
332
|
+
if (entry.last === node && entry.isTransient()) {
|
|
333
|
+
// this was the last user of the resource and the resource is transient (no external usage)
|
|
334
|
+
entry.destroy();
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
exportToDot() {
|
|
342
|
+
const out = new LineBuilder();
|
|
343
|
+
|
|
344
|
+
out.add("digraph FrameGraph {");
|
|
345
|
+
out.indent();
|
|
346
|
+
out.add("graph [style=invis, rankdir=\"TB\" ordering=out, splines=spline]");
|
|
347
|
+
out.add("node [shape=record, fontname=\"helvetica\", fontsize=10, margin=\"0.2,0.03\"]");
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
// -- Define pass nodes
|
|
351
|
+
|
|
352
|
+
out.add("");
|
|
353
|
+
out.add("# Pass Nodes");
|
|
354
|
+
for (const node of this.__pass_nodes) {
|
|
355
|
+
out.add(`P${node.id} [label=<{ {<B>${node.name}</B>} | {${(node.has_side_effects ? "★ " : "")} Refs: ${node.ref_count}<BR/> Index: ${node.id}} }> style=\"rounded,filled\", fillcolor=${(node.ref_count > 0 || node.has_side_effects) ? "orange" : "lightgray"}]`);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// -- Define resource nodes
|
|
359
|
+
|
|
360
|
+
out.add("");
|
|
361
|
+
out.add("# Resource Nodes");
|
|
362
|
+
for (const node of this.__resource_nodes) {
|
|
363
|
+
const entry = this.__resource_registry[node.resource_id];
|
|
364
|
+
out.add(`R${entry.resource_id}_${node.version} [label=<{ {<B>${node.name}</B>${node.version > 0 ? `<FONT>v${node.version}</FONT>` : ""}<BR/>${entry.toString()}} | {Index: ${entry.resource_id}<BR/> Refs : ${node.ref_count} } }> style=filled, fillcolor=${entry.isImported() ? "lightsteelblue" : "skyblue"}]`);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// -- Each pass node points to resource that it writes
|
|
368
|
+
|
|
369
|
+
out.add("");
|
|
370
|
+
out.add("# Resource Writes");
|
|
371
|
+
for (const node of this.__pass_nodes) {
|
|
372
|
+
out.add(`P${node.id} -> {`);
|
|
373
|
+
out.indent();
|
|
374
|
+
for (const id of node.resource_writes) {
|
|
375
|
+
const written = this.__resource_nodes[id];
|
|
376
|
+
out.add(`R${written.resource_id}_${written.version} `);
|
|
377
|
+
}
|
|
378
|
+
out.dedent();
|
|
379
|
+
out.add("} [color=orangered]");
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// -- Each resource node points to pass where it's consumed
|
|
383
|
+
|
|
384
|
+
out.add("");
|
|
385
|
+
out.add("# Resource Reads");
|
|
386
|
+
|
|
387
|
+
for (const node of this.__resource_nodes) {
|
|
388
|
+
out.add(`R${node.resource_id}_${node.version} -> {`);
|
|
389
|
+
out.indent();
|
|
390
|
+
// find all readers of this resource node
|
|
391
|
+
for (const pass of this.__pass_nodes) {
|
|
392
|
+
for (const id of pass.resource_reads)
|
|
393
|
+
if (id === node.id) {
|
|
394
|
+
out.add(`P${pass.id} `);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
out.dedent();
|
|
398
|
+
out.add("} [color=olivedrab3]");
|
|
399
|
+
}
|
|
400
|
+
out.dedent();
|
|
401
|
+
out.add("}");
|
|
402
|
+
// -- Clusters:
|
|
403
|
+
return out.build();
|
|
404
|
+
}
|
|
405
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
|
|
3
|
+
export class RenderGraphBuilder {
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @type {RenderGraph}
|
|
7
|
+
* @private
|
|
8
|
+
*/
|
|
9
|
+
__graph = null;
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* @type {RenderPassNode}
|
|
13
|
+
* @private
|
|
14
|
+
*/
|
|
15
|
+
__node = null;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
*
|
|
19
|
+
* @param {RenderGraph} graph
|
|
20
|
+
* @param {RenderPassNode} node
|
|
21
|
+
*/
|
|
22
|
+
init(graph, node) {
|
|
23
|
+
this.__graph = graph;
|
|
24
|
+
this.__node = node;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
*
|
|
29
|
+
* @param {string} name
|
|
30
|
+
* @param {TextureDescriptor} descriptor
|
|
31
|
+
* @returns {number} resource ID
|
|
32
|
+
*/
|
|
33
|
+
create(name, descriptor) {
|
|
34
|
+
const node = this.__graph.create_resource(name, descriptor);
|
|
35
|
+
|
|
36
|
+
// remember resource
|
|
37
|
+
this.__node.resource_creates.push(node);
|
|
38
|
+
|
|
39
|
+
return node;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
*
|
|
44
|
+
* @param {number} resource
|
|
45
|
+
* @returns {number}
|
|
46
|
+
*/
|
|
47
|
+
read(resource) {
|
|
48
|
+
assert.isNonNegativeInteger(resource, 'resource');
|
|
49
|
+
|
|
50
|
+
return this.__node.read(resource);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
*
|
|
55
|
+
* @param {number} resource
|
|
56
|
+
* @returns {number}
|
|
57
|
+
*/
|
|
58
|
+
write(resource) {
|
|
59
|
+
const graph = this.__graph;
|
|
60
|
+
const node = this.__node;
|
|
61
|
+
|
|
62
|
+
if (graph.getResourceEntry(resource).isImported()) {
|
|
63
|
+
// comes from outside the graph, and we write to it. That's a side effect
|
|
64
|
+
node.has_side_effects = true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (node.creates(resource)) {
|
|
68
|
+
return node.write(resource);
|
|
69
|
+
} else {
|
|
70
|
+
// writing to a resource produces a renamed handle
|
|
71
|
+
node.read(resource);
|
|
72
|
+
|
|
73
|
+
return node.write(graph.clone_resource(resource));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -1,32 +1,50 @@
|
|
|
1
1
|
const DEFAULT_FLAGS = 0;
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @template DATA
|
|
5
|
+
*/
|
|
3
6
|
export class RenderPass {
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Used for debug and visualisation
|
|
10
|
+
* @type {string}
|
|
11
|
+
*/
|
|
12
|
+
name = "Render Pass";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @type {number|RenderPassFlags}
|
|
17
|
+
*/
|
|
18
|
+
flags = DEFAULT_FLAGS;
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Arbitrary dictionary of data
|
|
23
|
+
* @type {Object<number>}
|
|
24
|
+
*/
|
|
25
|
+
inputs = {};
|
|
26
|
+
|
|
27
|
+
constructor(inputs = {}) {
|
|
28
|
+
this.inputs = inputs;
|
|
12
29
|
}
|
|
13
30
|
|
|
31
|
+
|
|
14
32
|
/**
|
|
15
33
|
*
|
|
16
|
-
* @param {
|
|
17
|
-
* @param {Object<
|
|
18
|
-
* @returns {Object<
|
|
34
|
+
* @param {RenderGraphBuilder} builder
|
|
35
|
+
* @param {Object<number>} inputs
|
|
36
|
+
* @returns {Object<number>}
|
|
19
37
|
*/
|
|
20
38
|
setup(builder, inputs) {
|
|
21
39
|
throw new Error('Not Implemented');
|
|
22
40
|
}
|
|
23
41
|
|
|
24
42
|
/**
|
|
25
|
-
*
|
|
43
|
+
* @param {DATA} data
|
|
26
44
|
* @param {RenderPassResources} resources
|
|
27
45
|
* @param {IRenderContext} render_context
|
|
28
46
|
*/
|
|
29
|
-
execute(resources, render_context) {
|
|
47
|
+
execute(data, resources, render_context) {
|
|
30
48
|
throw new Error('Not Implemented');
|
|
31
49
|
}
|
|
32
50
|
}
|