Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions crates/bevy_solari/src/realtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ impl Plugin for SolariLightingPlugin {
fn build(&self, app: &mut App) {
load_shader_library!(app, "gbuffer_utils.wgsl");
load_shader_library!(app, "realtime_bindings.wgsl");
load_shader_library!(app, "resolution_utils.wgsl");
load_shader_library!(app, "presample_light_tiles.wgsl");
embedded_asset!(app, "restir_di.wgsl");
embedded_asset!(app, "restir_gi.wgsl");
Expand Down Expand Up @@ -93,6 +94,12 @@ impl Plugin for SolariLightingPlugin {
DepthPrepassDoubleBuffer
)]
pub struct SolariLighting {
/// Set to true to greatly improve performance at the cost of quality.
///
/// May force [`bevy_camera::ClearColor`] to black if not already.
pub quarter_resolution_direct_lighting: bool,
/// Set to true to greatly improve performance at the cost of quality.
pub quarter_resolution_indirect_lighting: bool,
/// Set to true to delete the saved temporal history (past frames).
///
/// Useful for preventing ghosting when the history is no longer
Expand All @@ -106,6 +113,8 @@ pub struct SolariLighting {
impl Default for SolariLighting {
fn default() -> Self {
Self {
quarter_resolution_direct_lighting: false,
quarter_resolution_indirect_lighting: false,
reset: true, // No temporal history on the first frame
}
}
Expand Down
90 changes: 48 additions & 42 deletions crates/bevy_solari/src/realtime/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ pub fn solari_lighting(
#[cfg(not(all(feature = "dlss", not(feature = "force_disable_dlss"))))]
let specular_gi_pipeline = pipelines.specular_gi_pipeline;
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
let specular_gi_pipeline = if view_dlss_rr_textures.is_some() {
let specular_gi_pipeline = if view_dlss_rr_textures.is_some()
&& !solari_lighting.quarter_resolution_indirect_lighting
{
pipelines.specular_gi_with_psr_pipeline
} else {
pipelines.specular_gi_pipeline
Expand Down Expand Up @@ -177,7 +179,7 @@ pub fn solari_lighting(
return;
};

let view_target_attachment = view_target.get_unsampled_color_attachment();
let mut view_target_attachment = view_target.get_unsampled_color_attachment();

let s = solari_lighting_resources;
let bind_group = render_device.create_bind_group(
Expand Down Expand Up @@ -234,14 +236,28 @@ pub fn solari_lighting(

// Choice of number here is arbitrary
let frame_index = frame_count.0.wrapping_mul(5782582);
let immediates = [
frame_index,
solari_lighting.reset as u32,
solari_lighting.quarter_resolution_direct_lighting as u32,
solari_lighting.quarter_resolution_indirect_lighting as u32,
];
let immediates = bytemuck::cast_slice(&immediates);

let diagnostics = ctx.diagnostic_recorder();
let diagnostics = diagnostics.as_deref();

let command_encoder = ctx.command_encoder();

// Clear the view target if we're the first node to write to it
if matches!(view_target_attachment.ops.load, LoadOp::Clear(_)) {
if let LoadOp::Clear(ref mut clear_color) = view_target_attachment.ops.load {
if solari_lighting.quarter_resolution_direct_lighting {
clear_color.r = 0.0;
clear_color.g = 0.0;
clear_color.b = 0.0;
clear_color.a = 1.0;
}

command_encoder.begin_render_pass(&RenderPassDescriptor {
label: Some("solari_lighting_clear"),
color_attachments: &[Some(view_target_attachment)],
Expand All @@ -259,6 +275,18 @@ pub fn solari_lighting(

let dx = solari_lighting_resources.view_size.x.div_ceil(8);
let dy = solari_lighting_resources.view_size.y.div_ceil(8);
let mut di_dx = dx;
let mut di_dy = dy;
if solari_lighting.quarter_resolution_direct_lighting {
di_dx = di_dx.div_ceil(2);
di_dy = di_dy.div_ceil(2);
}
let mut gi_dx = dx;
let mut gi_dy = dy;
if solari_lighting.quarter_resolution_indirect_lighting {
gi_dx = gi_dx.div_ceil(2);
gi_dy = gi_dy.div_ceil(2);
}

pass.set_bind_group(0, scene_bind_group, &[]);
pass.set_bind_group(
Expand All @@ -279,10 +307,7 @@ pub fn solari_lighting(

let d = diagnostics.time_span(&mut pass, "solari_lighting/presample_light_tiles");
pass.set_pipeline(presample_light_tiles_pipeline);
pass.set_immediates(
0,
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
);
pass.set_immediates(0, immediates);
pass.dispatch_workgroups(LIGHT_TILE_BLOCKS as u32, 1, 1);
d.end(&mut pass);

Expand All @@ -305,20 +330,14 @@ pub fn solari_lighting(
pass.set_bind_group(2, None, &[]);

pass.set_pipeline(sample_di_for_world_cache_pipeline);
pass.set_immediates(
0,
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
);
pass.set_immediates(0, immediates);
pass.dispatch_workgroups_indirect(
&solari_lighting_resources.world_cache_active_cells_dispatch,
0,
);

pass.set_pipeline(sample_gi_for_world_cache_pipeline);
pass.set_immediates(
0,
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
);
pass.set_immediates(0, immediates);
pass.dispatch_workgroups_indirect(
&solari_lighting_resources.world_cache_active_cells_dispatch,
0,
Expand All @@ -335,50 +354,37 @@ pub fn solari_lighting(
let d = diagnostics.time_span(&mut pass, "solari_lighting/direct_lighting");

pass.set_pipeline(di_initial_and_temporal_pipeline);
pass.set_immediates(
0,
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
);
pass.dispatch_workgroups(dx, dy, 1);
pass.set_immediates(0, immediates);
pass.dispatch_workgroups(di_dx, di_dy, 1);

pass.set_pipeline(di_spatial_and_shade_pipeline);
pass.set_immediates(
0,
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
);
pass.dispatch_workgroups(dx, dy, 1);
pass.set_immediates(0, immediates);
pass.dispatch_workgroups(di_dx, di_dy, 1);

d.end(&mut pass);

let d = diagnostics.time_span(&mut pass, "solari_lighting/diffuse_indirect_lighting");

pass.set_pipeline(gi_initial_and_temporal_pipeline);
pass.set_immediates(
0,
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
);
pass.dispatch_workgroups(dx, dy, 1);
pass.set_immediates(0, immediates);
pass.dispatch_workgroups(gi_dx, gi_dy, 1);

pass.set_pipeline(gi_spatial_and_shade_pipeline);
pass.set_immediates(
0,
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
);
pass.dispatch_workgroups(dx, dy, 1);
pass.set_immediates(0, immediates);
pass.dispatch_workgroups(gi_dx, gi_dy, 1);

d.end(&mut pass);

let d = diagnostics.time_span(&mut pass, "solari_lighting/specular_indirect_lighting");
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
if let Some(bind_group_resolve_dlss_rr_textures) = &bind_group_resolve_dlss_rr_textures {
if let Some(bind_group_resolve_dlss_rr_textures) = &bind_group_resolve_dlss_rr_textures
&& !solari_lighting.quarter_resolution_indirect_lighting
{
pass.set_bind_group(2, bind_group_resolve_dlss_rr_textures, &[]);
}
pass.set_pipeline(specular_gi_pipeline);
pass.set_immediates(
0,
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
);
pass.dispatch_workgroups(dx, dy, 1);
pass.set_immediates(0, immediates);
pass.dispatch_workgroups(gi_dx, gi_dy, 1);
d.end(&mut pass);

drop(pass);
Expand Down Expand Up @@ -471,7 +477,7 @@ pub fn init_solari_lighting_pipelines(
pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
label: Some(label.into()),
layout,
immediate_size: 8,
immediate_size: 16,
shader,
shader_defs,
entry_point: Some(entry_point.into()),
Expand Down
76 changes: 52 additions & 24 deletions crates/bevy_solari/src/realtime/prepare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use bevy_ecs::query::Has;
use bevy_ecs::{
component::Component,
entity::Entity,
query::With,
system::{Commands, Query, Res},
};
use bevy_image::ToExtents;
Expand Down Expand Up @@ -61,37 +60,42 @@ pub struct SolariLightingResources {
pub world_cache_active_cells_count: Buffer,
pub world_cache_active_cells_dispatch: Buffer,
pub view_size: UVec2,
pub quarter_resolution_direct_lighting: bool,
pub quarter_resolution_indirect_lighting: bool,
}

pub fn prepare_solari_lighting_resources(
#[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))] query: Query<
(
Entity,
&ExtractedCamera,
Option<&SolariLightingResources>,
Option<&MainPassResolutionOverride>,
),
With<SolariLighting>,
>,
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))] query: Query<
(
Entity,
&ExtractedCamera,
Option<&SolariLightingResources>,
Option<&MainPassResolutionOverride>,
Has<Dlss<DlssRayReconstructionFeature>>,
),
With<SolariLighting>,
>,
#[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))] query: Query<(
Entity,
&SolariLighting,
&ExtractedCamera,
Option<&SolariLightingResources>,
Option<&MainPassResolutionOverride>,
)>,
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))] query: Query<(
Entity,
&SolariLighting,
&ExtractedCamera,
Option<&SolariLightingResources>,
Option<&MainPassResolutionOverride>,
Has<Dlss<DlssRayReconstructionFeature>>,
)>,
render_device: Res<RenderDevice>,
mut commands: Commands,
) {
for query_item in &query {
#[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))]
let (entity, camera, solari_lighting_resources, resolution_override) = query_item;
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
let (entity, camera, solari_lighting_resources, resolution_override, has_dlss_rr) =
let (entity, solari_lighting, camera, solari_lighting_resources, resolution_override) =
query_item;
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
let (
entity,
solari_lighting,
camera,
solari_lighting_resources,
resolution_override,
has_dlss_rr,
) = query_item;

let Some(mut view_size) = camera.physical_viewport_size else {
continue;
Expand All @@ -100,7 +104,17 @@ pub fn prepare_solari_lighting_resources(
view_size = *resolution_override;
}

if solari_lighting_resources.map(|r| r.view_size) == Some(view_size) {
if solari_lighting_resources.map(|r| {
(
r.view_size,
r.quarter_resolution_direct_lighting,
r.quarter_resolution_indirect_lighting,
)
}) == Some((
view_size,
solari_lighting.quarter_resolution_direct_lighting,
solari_lighting.quarter_resolution_indirect_lighting,
)) {
continue;
}

Expand All @@ -121,6 +135,11 @@ pub fn prepare_solari_lighting_resources(
});

let di_reservoirs = |name| {
let mut view_size = view_size;
if solari_lighting.quarter_resolution_direct_lighting {
view_size.x = view_size.x.div_ceil(2);
view_size.y = view_size.y.div_ceil(2);
}
render_device
.create_texture(&TextureDescriptor {
label: Some(name),
Expand All @@ -138,6 +157,12 @@ pub fn prepare_solari_lighting_resources(
let di_reservoirs_b = di_reservoirs("solari_lighting_di_reservoirs_b");

let gi_reservoirs = |name| {
let mut view_size = view_size;
if solari_lighting.quarter_resolution_indirect_lighting {
view_size.x = view_size.x.div_ceil(2);
view_size.y = view_size.y.div_ceil(2);
}

render_device.create_buffer(&BufferDescriptor {
label: Some(name),
size: (view_size.x * view_size.y) as u64 * GI_RESERVOIR_STRUCT_SIZE,
Expand Down Expand Up @@ -244,6 +269,9 @@ pub fn prepare_solari_lighting_resources(
world_cache_active_cells_count,
world_cache_active_cells_dispatch,
view_size,
quarter_resolution_direct_lighting: solari_lighting.quarter_resolution_direct_lighting,
quarter_resolution_indirect_lighting: solari_lighting
.quarter_resolution_indirect_lighting,
});

#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
Expand Down
3 changes: 1 addition & 2 deletions crates/bevy_solari/src/realtime/presample_light_tiles.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ enable wgpu_ray_query;

#import bevy_pbr::rgb9e5::{vec3_to_rgb9e5_, rgb9e5_to_vec3_}
#import bevy_pbr::utils::{octahedral_encode, octahedral_decode}
#import bevy_render::view::View
#import bevy_solari::sampling::{generate_random_light_sample, LightSample, ResolvedLightSample}
#import bevy_solari::sampling::{generate_random_light_sample, ResolvedLightSample}
#import bevy_solari::realtime_bindings::{light_tile_samples, light_tile_resolved_samples, view, constants, ResolvedLightSamplePacked}

@compute @workgroup_size(1024, 1, 1)
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_solari/src/realtime/realtime_bindings.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ enable wgpu_ray_query;
@group(2) @binding(3) var specular_motion_vectors: texture_storage_2d<rg16float, write>;
#endif

struct PushConstants { frame_index: u32, reset: u32 }
struct PushConstants { frame_index: u32, reset: u32, quarter_resolution_direct_lighting: u32, quarter_resolution_indirect_lighting: u32 }
var<immediate> constants: PushConstants;

// Don't adjust the size of this struct without also adjusting `prepare::RESOLVED_LIGHT_SAMPLE_STRUCT_SIZE`.
Expand Down
Loading
Loading