Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_solari/src/realtime/node.rs
6596 views
1
use super::{
2
prepare::{SolariLightingResources, LIGHT_TILE_BLOCKS, WORLD_CACHE_SIZE},
3
SolariLighting,
4
};
5
use crate::scene::RaytracingSceneBindings;
6
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
7
use bevy_anti_alias::dlss::ViewDlssRayReconstructionTextures;
8
use bevy_asset::{load_embedded_asset, Handle};
9
use bevy_core_pipeline::prepass::{
10
PreviousViewData, PreviousViewUniformOffset, PreviousViewUniforms, ViewPrepassTextures,
11
};
12
use bevy_diagnostic::FrameCount;
13
use bevy_ecs::{
14
query::QueryItem,
15
world::{FromWorld, World},
16
};
17
use bevy_image::ToExtents;
18
use bevy_render::{
19
diagnostic::RecordDiagnostics,
20
render_graph::{NodeRunError, RenderGraphContext, ViewNode},
21
render_resource::{
22
binding_types::{
23
storage_buffer_sized, texture_2d, texture_depth_2d, texture_storage_2d, uniform_buffer,
24
},
25
BindGroupEntries, BindGroupLayout, BindGroupLayoutEntries, CachedComputePipelineId,
26
ComputePassDescriptor, ComputePipelineDescriptor, PipelineCache, PushConstantRange,
27
ShaderStages, StorageTextureAccess, TextureFormat, TextureSampleType,
28
},
29
renderer::{RenderContext, RenderDevice},
30
view::{ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms},
31
};
32
use bevy_shader::{Shader, ShaderDefVal};
33
use bevy_utils::default;
34
35
pub mod graph {
36
use bevy_render::render_graph::RenderLabel;
37
38
#[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)]
39
pub struct SolariLightingNode;
40
}
41
42
pub struct SolariLightingNode {
43
bind_group_layout: BindGroupLayout,
44
bind_group_layout_world_cache_active_cells_dispatch: BindGroupLayout,
45
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
46
bind_group_layout_resolve_dlss_rr_textures: BindGroupLayout,
47
decay_world_cache_pipeline: CachedComputePipelineId,
48
compact_world_cache_single_block_pipeline: CachedComputePipelineId,
49
compact_world_cache_blocks_pipeline: CachedComputePipelineId,
50
compact_world_cache_write_active_cells_pipeline: CachedComputePipelineId,
51
sample_for_world_cache_pipeline: CachedComputePipelineId,
52
blend_new_world_cache_samples_pipeline: CachedComputePipelineId,
53
presample_light_tiles_pipeline: CachedComputePipelineId,
54
di_initial_and_temporal_pipeline: CachedComputePipelineId,
55
di_spatial_and_shade_pipeline: CachedComputePipelineId,
56
gi_initial_and_temporal_pipeline: CachedComputePipelineId,
57
gi_spatial_and_shade_pipeline: CachedComputePipelineId,
58
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
59
resolve_dlss_rr_textures_pipeline: CachedComputePipelineId,
60
}
61
62
impl ViewNode for SolariLightingNode {
63
#[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))]
64
type ViewQuery = (
65
&'static SolariLighting,
66
&'static SolariLightingResources,
67
&'static ViewTarget,
68
&'static ViewPrepassTextures,
69
&'static ViewUniformOffset,
70
&'static PreviousViewUniformOffset,
71
);
72
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
73
type ViewQuery = (
74
&'static SolariLighting,
75
&'static SolariLightingResources,
76
&'static ViewTarget,
77
&'static ViewPrepassTextures,
78
&'static ViewUniformOffset,
79
&'static PreviousViewUniformOffset,
80
Option<&'static ViewDlssRayReconstructionTextures>,
81
);
82
83
fn run(
84
&self,
85
_graph: &mut RenderGraphContext,
86
render_context: &mut RenderContext,
87
#[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))] (
88
solari_lighting,
89
solari_lighting_resources,
90
view_target,
91
view_prepass_textures,
92
view_uniform_offset,
93
previous_view_uniform_offset,
94
): QueryItem<Self::ViewQuery>,
95
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))] (
96
solari_lighting,
97
solari_lighting_resources,
98
view_target,
99
view_prepass_textures,
100
view_uniform_offset,
101
previous_view_uniform_offset,
102
view_dlss_rr_textures,
103
): QueryItem<Self::ViewQuery>,
104
world: &World,
105
) -> Result<(), NodeRunError> {
106
let pipeline_cache = world.resource::<PipelineCache>();
107
let scene_bindings = world.resource::<RaytracingSceneBindings>();
108
let view_uniforms = world.resource::<ViewUniforms>();
109
let previous_view_uniforms = world.resource::<PreviousViewUniforms>();
110
let frame_count = world.resource::<FrameCount>();
111
let (
112
Some(decay_world_cache_pipeline),
113
Some(compact_world_cache_single_block_pipeline),
114
Some(compact_world_cache_blocks_pipeline),
115
Some(compact_world_cache_write_active_cells_pipeline),
116
Some(sample_for_world_cache_pipeline),
117
Some(blend_new_world_cache_samples_pipeline),
118
Some(presample_light_tiles_pipeline),
119
Some(di_initial_and_temporal_pipeline),
120
Some(di_spatial_and_shade_pipeline),
121
Some(gi_initial_and_temporal_pipeline),
122
Some(gi_spatial_and_shade_pipeline),
123
Some(scene_bindings),
124
Some(gbuffer),
125
Some(depth_buffer),
126
Some(motion_vectors),
127
Some(view_uniforms),
128
Some(previous_view_uniforms),
129
) = (
130
pipeline_cache.get_compute_pipeline(self.decay_world_cache_pipeline),
131
pipeline_cache.get_compute_pipeline(self.compact_world_cache_single_block_pipeline),
132
pipeline_cache.get_compute_pipeline(self.compact_world_cache_blocks_pipeline),
133
pipeline_cache
134
.get_compute_pipeline(self.compact_world_cache_write_active_cells_pipeline),
135
pipeline_cache.get_compute_pipeline(self.sample_for_world_cache_pipeline),
136
pipeline_cache.get_compute_pipeline(self.blend_new_world_cache_samples_pipeline),
137
pipeline_cache.get_compute_pipeline(self.presample_light_tiles_pipeline),
138
pipeline_cache.get_compute_pipeline(self.di_initial_and_temporal_pipeline),
139
pipeline_cache.get_compute_pipeline(self.di_spatial_and_shade_pipeline),
140
pipeline_cache.get_compute_pipeline(self.gi_initial_and_temporal_pipeline),
141
pipeline_cache.get_compute_pipeline(self.gi_spatial_and_shade_pipeline),
142
&scene_bindings.bind_group,
143
view_prepass_textures.deferred_view(),
144
view_prepass_textures.depth_view(),
145
view_prepass_textures.motion_vectors_view(),
146
view_uniforms.uniforms.binding(),
147
previous_view_uniforms.uniforms.binding(),
148
)
149
else {
150
return Ok(());
151
};
152
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
153
let Some(resolve_dlss_rr_textures_pipeline) =
154
pipeline_cache.get_compute_pipeline(self.resolve_dlss_rr_textures_pipeline)
155
else {
156
return Ok(());
157
};
158
159
let s = solari_lighting_resources;
160
let bind_group = render_context.render_device().create_bind_group(
161
"solari_lighting_bind_group",
162
&self.bind_group_layout,
163
&BindGroupEntries::sequential((
164
view_target.get_unsampled_color_attachment().view,
165
s.light_tile_samples.as_entire_binding(),
166
s.light_tile_resolved_samples.as_entire_binding(),
167
&s.di_reservoirs_a.1,
168
&s.di_reservoirs_b.1,
169
s.gi_reservoirs_a.as_entire_binding(),
170
s.gi_reservoirs_b.as_entire_binding(),
171
gbuffer,
172
depth_buffer,
173
motion_vectors,
174
&s.previous_gbuffer.1,
175
&s.previous_depth.1,
176
view_uniforms,
177
previous_view_uniforms,
178
s.world_cache_checksums.as_entire_binding(),
179
s.world_cache_life.as_entire_binding(),
180
s.world_cache_radiance.as_entire_binding(),
181
s.world_cache_geometry_data.as_entire_binding(),
182
s.world_cache_active_cells_new_radiance.as_entire_binding(),
183
s.world_cache_a.as_entire_binding(),
184
s.world_cache_b.as_entire_binding(),
185
s.world_cache_active_cell_indices.as_entire_binding(),
186
s.world_cache_active_cells_count.as_entire_binding(),
187
)),
188
);
189
let bind_group_world_cache_active_cells_dispatch =
190
render_context.render_device().create_bind_group(
191
"solari_lighting_bind_group_world_cache_active_cells_dispatch",
192
&self.bind_group_layout_world_cache_active_cells_dispatch,
193
&BindGroupEntries::single(s.world_cache_active_cells_dispatch.as_entire_binding()),
194
);
195
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
196
let bind_group_resolve_dlss_rr_textures = view_dlss_rr_textures.map(|d| {
197
render_context.render_device().create_bind_group(
198
"solari_lighting_bind_group_resolve_dlss_rr_textures",
199
&self.bind_group_layout_resolve_dlss_rr_textures,
200
&BindGroupEntries::sequential((
201
&d.diffuse_albedo.default_view,
202
&d.specular_albedo.default_view,
203
&d.normal_roughness.default_view,
204
&d.specular_motion_vectors.default_view,
205
)),
206
)
207
});
208
209
// Choice of number here is arbitrary
210
let frame_index = frame_count.0.wrapping_mul(5782582);
211
212
let diagnostics = render_context.diagnostic_recorder();
213
let command_encoder = render_context.command_encoder();
214
215
let mut pass = command_encoder.begin_compute_pass(&ComputePassDescriptor {
216
label: Some("solari_lighting"),
217
timestamp_writes: None,
218
});
219
let pass_span = diagnostics.pass_span(&mut pass, "solari_lighting");
220
221
let dx = solari_lighting_resources.view_size.x.div_ceil(8);
222
let dy = solari_lighting_resources.view_size.y.div_ceil(8);
223
224
pass.set_bind_group(0, scene_bindings, &[]);
225
pass.set_bind_group(
226
1,
227
&bind_group,
228
&[
229
view_uniform_offset.offset,
230
previous_view_uniform_offset.offset,
231
],
232
);
233
234
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
235
if let Some(bind_group_resolve_dlss_rr_textures) = bind_group_resolve_dlss_rr_textures {
236
pass.set_bind_group(2, &bind_group_resolve_dlss_rr_textures, &[]);
237
pass.set_pipeline(resolve_dlss_rr_textures_pipeline);
238
pass.dispatch_workgroups(dx, dy, 1);
239
}
240
241
pass.set_bind_group(2, &bind_group_world_cache_active_cells_dispatch, &[]);
242
243
pass.set_pipeline(decay_world_cache_pipeline);
244
pass.dispatch_workgroups((WORLD_CACHE_SIZE / 1024) as u32, 1, 1);
245
246
pass.set_pipeline(compact_world_cache_single_block_pipeline);
247
pass.dispatch_workgroups((WORLD_CACHE_SIZE / 1024) as u32, 1, 1);
248
249
pass.set_pipeline(compact_world_cache_blocks_pipeline);
250
pass.dispatch_workgroups(1, 1, 1);
251
252
pass.set_pipeline(compact_world_cache_write_active_cells_pipeline);
253
pass.dispatch_workgroups((WORLD_CACHE_SIZE / 1024) as u32, 1, 1);
254
255
pass.set_bind_group(2, None, &[]);
256
257
pass.set_pipeline(sample_for_world_cache_pipeline);
258
pass.set_push_constants(
259
0,
260
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
261
);
262
pass.dispatch_workgroups_indirect(
263
&solari_lighting_resources.world_cache_active_cells_dispatch,
264
0,
265
);
266
267
pass.set_pipeline(blend_new_world_cache_samples_pipeline);
268
pass.dispatch_workgroups_indirect(
269
&solari_lighting_resources.world_cache_active_cells_dispatch,
270
0,
271
);
272
273
pass.set_pipeline(presample_light_tiles_pipeline);
274
pass.set_push_constants(
275
0,
276
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
277
);
278
pass.dispatch_workgroups(LIGHT_TILE_BLOCKS as u32, 1, 1);
279
280
pass.set_pipeline(di_initial_and_temporal_pipeline);
281
pass.set_push_constants(
282
0,
283
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
284
);
285
pass.dispatch_workgroups(dx, dy, 1);
286
287
pass.set_pipeline(di_spatial_and_shade_pipeline);
288
pass.set_push_constants(
289
0,
290
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
291
);
292
pass.dispatch_workgroups(dx, dy, 1);
293
294
pass.set_pipeline(gi_initial_and_temporal_pipeline);
295
pass.set_push_constants(
296
0,
297
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
298
);
299
pass.dispatch_workgroups(dx, dy, 1);
300
301
pass.set_pipeline(gi_spatial_and_shade_pipeline);
302
pass.set_push_constants(
303
0,
304
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
305
);
306
pass.dispatch_workgroups(dx, dy, 1);
307
308
pass_span.end(&mut pass);
309
drop(pass);
310
311
// TODO: Remove these copies, and double buffer instead
312
command_encoder.copy_texture_to_texture(
313
view_prepass_textures
314
.deferred
315
.clone()
316
.unwrap()
317
.texture
318
.texture
319
.as_image_copy(),
320
solari_lighting_resources.previous_gbuffer.0.as_image_copy(),
321
solari_lighting_resources.view_size.to_extents(),
322
);
323
command_encoder.copy_texture_to_texture(
324
view_prepass_textures
325
.depth
326
.clone()
327
.unwrap()
328
.texture
329
.texture
330
.as_image_copy(),
331
solari_lighting_resources.previous_depth.0.as_image_copy(),
332
solari_lighting_resources.view_size.to_extents(),
333
);
334
335
Ok(())
336
}
337
}
338
339
impl FromWorld for SolariLightingNode {
340
fn from_world(world: &mut World) -> Self {
341
let render_device = world.resource::<RenderDevice>();
342
let pipeline_cache = world.resource::<PipelineCache>();
343
let scene_bindings = world.resource::<RaytracingSceneBindings>();
344
345
let bind_group_layout = render_device.create_bind_group_layout(
346
"solari_lighting_bind_group_layout",
347
&BindGroupLayoutEntries::sequential(
348
ShaderStages::COMPUTE,
349
(
350
texture_storage_2d(
351
ViewTarget::TEXTURE_FORMAT_HDR,
352
StorageTextureAccess::ReadWrite,
353
),
354
storage_buffer_sized(false, None),
355
storage_buffer_sized(false, None),
356
texture_storage_2d(TextureFormat::Rgba32Uint, StorageTextureAccess::ReadWrite),
357
texture_storage_2d(TextureFormat::Rgba32Uint, StorageTextureAccess::ReadWrite),
358
storage_buffer_sized(false, None),
359
storage_buffer_sized(false, None),
360
texture_2d(TextureSampleType::Uint),
361
texture_depth_2d(),
362
texture_2d(TextureSampleType::Float { filterable: true }),
363
texture_2d(TextureSampleType::Uint),
364
texture_depth_2d(),
365
uniform_buffer::<ViewUniform>(true),
366
uniform_buffer::<PreviousViewData>(true),
367
storage_buffer_sized(false, None),
368
storage_buffer_sized(false, None),
369
storage_buffer_sized(false, None),
370
storage_buffer_sized(false, None),
371
storage_buffer_sized(false, None),
372
storage_buffer_sized(false, None),
373
storage_buffer_sized(false, None),
374
storage_buffer_sized(false, None),
375
storage_buffer_sized(false, None),
376
),
377
),
378
);
379
380
let bind_group_layout_world_cache_active_cells_dispatch = render_device
381
.create_bind_group_layout(
382
"solari_lighting_bind_group_layout_world_cache_active_cells_dispatch",
383
&BindGroupLayoutEntries::single(
384
ShaderStages::COMPUTE,
385
storage_buffer_sized(false, None),
386
),
387
);
388
389
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
390
let bind_group_layout_resolve_dlss_rr_textures = render_device.create_bind_group_layout(
391
"solari_lighting_bind_group_layout_resolve_dlss_rr_textures",
392
&BindGroupLayoutEntries::sequential(
393
ShaderStages::COMPUTE,
394
(
395
texture_storage_2d(TextureFormat::Rgba8Unorm, StorageTextureAccess::WriteOnly),
396
texture_storage_2d(TextureFormat::Rgba8Unorm, StorageTextureAccess::WriteOnly),
397
texture_storage_2d(TextureFormat::Rgba16Float, StorageTextureAccess::WriteOnly),
398
texture_storage_2d(TextureFormat::Rg16Float, StorageTextureAccess::WriteOnly),
399
),
400
),
401
);
402
403
let create_pipeline = |label: &'static str,
404
entry_point: &'static str,
405
shader: Handle<Shader>,
406
extra_bind_group_layout: Option<&BindGroupLayout>,
407
extra_shader_defs: Vec<ShaderDefVal>| {
408
let mut layout = vec![
409
scene_bindings.bind_group_layout.clone(),
410
bind_group_layout.clone(),
411
];
412
if let Some(extra_bind_group_layout) = extra_bind_group_layout {
413
layout.push(extra_bind_group_layout.clone());
414
}
415
416
let mut shader_defs = vec![ShaderDefVal::UInt(
417
"WORLD_CACHE_SIZE".into(),
418
WORLD_CACHE_SIZE as u32,
419
)];
420
shader_defs.extend_from_slice(&extra_shader_defs);
421
422
pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
423
label: Some(label.into()),
424
layout,
425
push_constant_ranges: vec![PushConstantRange {
426
stages: ShaderStages::COMPUTE,
427
range: 0..8,
428
}],
429
shader,
430
shader_defs,
431
entry_point: Some(entry_point.into()),
432
..default()
433
})
434
};
435
436
Self {
437
bind_group_layout: bind_group_layout.clone(),
438
bind_group_layout_world_cache_active_cells_dispatch:
439
bind_group_layout_world_cache_active_cells_dispatch.clone(),
440
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
441
bind_group_layout_resolve_dlss_rr_textures: bind_group_layout_resolve_dlss_rr_textures
442
.clone(),
443
decay_world_cache_pipeline: create_pipeline(
444
"solari_lighting_decay_world_cache_pipeline",
445
"decay_world_cache",
446
load_embedded_asset!(world, "world_cache_compact.wgsl"),
447
Some(&bind_group_layout_world_cache_active_cells_dispatch),
448
vec!["WORLD_CACHE_NON_ATOMIC_LIFE_BUFFER".into()],
449
),
450
compact_world_cache_single_block_pipeline: create_pipeline(
451
"solari_lighting_compact_world_cache_single_block_pipeline",
452
"compact_world_cache_single_block",
453
load_embedded_asset!(world, "world_cache_compact.wgsl"),
454
Some(&bind_group_layout_world_cache_active_cells_dispatch),
455
vec!["WORLD_CACHE_NON_ATOMIC_LIFE_BUFFER".into()],
456
),
457
compact_world_cache_blocks_pipeline: create_pipeline(
458
"solari_lighting_compact_world_cache_blocks_pipeline",
459
"compact_world_cache_blocks",
460
load_embedded_asset!(world, "world_cache_compact.wgsl"),
461
Some(&bind_group_layout_world_cache_active_cells_dispatch),
462
vec![],
463
),
464
compact_world_cache_write_active_cells_pipeline: create_pipeline(
465
"solari_lighting_compact_world_cache_write_active_cells_pipeline",
466
"compact_world_cache_write_active_cells",
467
load_embedded_asset!(world, "world_cache_compact.wgsl"),
468
Some(&bind_group_layout_world_cache_active_cells_dispatch),
469
vec!["WORLD_CACHE_NON_ATOMIC_LIFE_BUFFER".into()],
470
),
471
sample_for_world_cache_pipeline: create_pipeline(
472
"solari_lighting_sample_for_world_cache_pipeline",
473
"sample_radiance",
474
load_embedded_asset!(world, "world_cache_update.wgsl"),
475
None,
476
vec![],
477
),
478
blend_new_world_cache_samples_pipeline: create_pipeline(
479
"solari_lighting_blend_new_world_cache_samples_pipeline",
480
"blend_new_samples",
481
load_embedded_asset!(world, "world_cache_update.wgsl"),
482
None,
483
vec![],
484
),
485
presample_light_tiles_pipeline: create_pipeline(
486
"solari_lighting_presample_light_tiles_pipeline",
487
"presample_light_tiles",
488
load_embedded_asset!(world, "presample_light_tiles.wgsl"),
489
None,
490
vec![],
491
),
492
di_initial_and_temporal_pipeline: create_pipeline(
493
"solari_lighting_di_initial_and_temporal_pipeline",
494
"initial_and_temporal",
495
load_embedded_asset!(world, "restir_di.wgsl"),
496
None,
497
vec![],
498
),
499
di_spatial_and_shade_pipeline: create_pipeline(
500
"solari_lighting_di_spatial_and_shade_pipeline",
501
"spatial_and_shade",
502
load_embedded_asset!(world, "restir_di.wgsl"),
503
None,
504
vec![],
505
),
506
gi_initial_and_temporal_pipeline: create_pipeline(
507
"solari_lighting_gi_initial_and_temporal_pipeline",
508
"initial_and_temporal",
509
load_embedded_asset!(world, "restir_gi.wgsl"),
510
None,
511
vec![],
512
),
513
gi_spatial_and_shade_pipeline: create_pipeline(
514
"solari_lighting_gi_spatial_and_shade_pipeline",
515
"spatial_and_shade",
516
load_embedded_asset!(world, "restir_gi.wgsl"),
517
None,
518
vec![],
519
),
520
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
521
resolve_dlss_rr_textures_pipeline: create_pipeline(
522
"solari_lighting_resolve_dlss_rr_textures_pipeline",
523
"resolve_dlss_rr_textures",
524
load_embedded_asset!(world, "resolve_dlss_rr_textures.wgsl"),
525
Some(&bind_group_layout_resolve_dlss_rr_textures),
526
vec![],
527
),
528
}
529
}
530
}
531
532