Skip to content

Commit

Permalink
Make setup of Opaque3dPrepass and AlphaMask3dPrepass phase items cons…
Browse files Browse the repository at this point in the history
…istent with others (#8408)

# Objective

When browsing the bevy source code to try and learn about
`bevy_core_pipeline`, I noticed that the `DrawFunctions` resources,
`sort_phase_system`s and texture preparation for the `Opaque3d` and
`AlphaMask3d` phase items are all set up in `bevy_core_pipeline`, while
the `Opaque3dPrepass` and `AlphaMask3dPrepass` phase items are only
*declared* in `bevy_core_pipeline`, and actually registered properly
with the renderer in `bevy_pbr`.

This means that, if I am trying to make crate that replaces `bevy_pbr`,
I need to make sure I manually fix this unfinished setup the same way
that `bevy_pbr` does. Worse, it means that if I try to use the
`PrepassNode` `bevy_core_pipeline` adds *without* fixing this, the
engine will simply crash because the `DrawFunctions<T>` resources cannot
be accessed.

The only advantage I can think of for bevy doing it this way is an
ambiguous performance save due to the prepass render phases not being
present unless you are using prepass materials with PBR.

## Solution

I have moved the registration of `DrawFunctions<T>`,
`sort_phase_system::<T>`, camera `RenderPhase` extraction, and texture
preparation for prepass's phase items into `bevy_core_pipeline`
alongside the equivalent code that sets up the `Opaque3d`, `AlphaMask3d`
and `Transparent3d` phase items.

Am open to tweaking this to improve the performance impact of prepass
things being around if the app doesn't use them if needed.

I've tested that the `shader_prepass` example still works with this
change.
  • Loading branch information
Sixmorphugus authored Jun 12, 2023
1 parent 584e7d0 commit a78c4d7
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 168 deletions.
166 changes: 165 additions & 1 deletion crates/bevy_core_pipeline/src/core_3d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ use bevy_render::{
use bevy_utils::{FloatOrd, HashMap};

use crate::{
prepass::{node::PrepassNode, DepthPrepass},
prepass::{
node::PrepassNode, AlphaMask3dPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass,
Opaque3dPrepass, ViewPrepassTextures, DEPTH_PREPASS_FORMAT, MOTION_VECTOR_PREPASS_FORMAT,
NORMAL_PREPASS_FORMAT,
},
skybox::SkyboxPlugin,
tonemapping::TonemappingNode,
upscaling::UpscalingNode,
Expand All @@ -77,16 +81,24 @@ impl Plugin for Core3dPlugin {
.init_resource::<DrawFunctions<Opaque3d>>()
.init_resource::<DrawFunctions<AlphaMask3d>>()
.init_resource::<DrawFunctions<Transparent3d>>()
.init_resource::<DrawFunctions<Opaque3dPrepass>>()
.init_resource::<DrawFunctions<AlphaMask3dPrepass>>()
.add_systems(ExtractSchedule, extract_core_3d_camera_phases)
.add_systems(ExtractSchedule, extract_camera_prepass_phase)
.add_systems(
Render,
(
prepare_core_3d_depth_textures
.in_set(RenderSet::Prepare)
.after(bevy_render::view::prepare_windows),
prepare_prepass_textures
.in_set(RenderSet::Prepare)
.after(bevy_render::view::prepare_windows),
sort_phase_system::<Opaque3d>.in_set(RenderSet::PhaseSort),
sort_phase_system::<AlphaMask3d>.in_set(RenderSet::PhaseSort),
sort_phase_system::<Transparent3d>.in_set(RenderSet::PhaseSort),
sort_phase_system::<Opaque3dPrepass>.in_set(RenderSet::PhaseSort),
sort_phase_system::<AlphaMask3dPrepass>.in_set(RenderSet::PhaseSort),
),
);

Expand Down Expand Up @@ -257,6 +269,50 @@ pub fn extract_core_3d_camera_phases(
}
}

// Extract the render phases for the prepass
pub fn extract_camera_prepass_phase(
mut commands: Commands,
cameras_3d: Extract<
Query<
(
Entity,
&Camera,
Option<&DepthPrepass>,
Option<&NormalPrepass>,
Option<&MotionVectorPrepass>,
),
With<Camera3d>,
>,
>,
) {
for (entity, camera, depth_prepass, normal_prepass, motion_vector_prepass) in cameras_3d.iter()
{
if camera.is_active {
let mut entity = commands.get_or_spawn(entity);

if depth_prepass.is_some()
|| normal_prepass.is_some()
|| motion_vector_prepass.is_some()
{
entity.insert((
RenderPhase::<Opaque3dPrepass>::default(),
RenderPhase::<AlphaMask3dPrepass>::default(),
));
}

if depth_prepass.is_some() {
entity.insert(DepthPrepass);
}
if normal_prepass.is_some() {
entity.insert(NormalPrepass);
}
if motion_vector_prepass.is_some() {
entity.insert(MotionVectorPrepass);
}
}
}
}

pub fn prepare_core_3d_depth_textures(
mut commands: Commands,
mut texture_cache: ResMut<TextureCache>,
Expand Down Expand Up @@ -316,3 +372,111 @@ pub fn prepare_core_3d_depth_textures(
});
}
}

// Prepares the textures used by the prepass
pub fn prepare_prepass_textures(
mut commands: Commands,
mut texture_cache: ResMut<TextureCache>,
msaa: Res<Msaa>,
render_device: Res<RenderDevice>,
views_3d: Query<
(
Entity,
&ExtractedCamera,
Option<&DepthPrepass>,
Option<&NormalPrepass>,
Option<&MotionVectorPrepass>,
),
(
With<RenderPhase<Opaque3dPrepass>>,
With<RenderPhase<AlphaMask3dPrepass>>,
),
>,
) {
let mut depth_textures = HashMap::default();
let mut normal_textures = HashMap::default();
let mut motion_vectors_textures = HashMap::default();
for (entity, camera, depth_prepass, normal_prepass, motion_vector_prepass) in &views_3d {
let Some(physical_target_size) = camera.physical_target_size else {
continue;
};

let size = Extent3d {
depth_or_array_layers: 1,
width: physical_target_size.x,
height: physical_target_size.y,
};

let cached_depth_texture = depth_prepass.is_some().then(|| {
depth_textures
.entry(camera.target.clone())
.or_insert_with(|| {
let descriptor = TextureDescriptor {
label: Some("prepass_depth_texture"),
size,
mip_level_count: 1,
sample_count: msaa.samples(),
dimension: TextureDimension::D2,
format: DEPTH_PREPASS_FORMAT,
usage: TextureUsages::COPY_DST
| TextureUsages::RENDER_ATTACHMENT
| TextureUsages::TEXTURE_BINDING,
view_formats: &[],
};
texture_cache.get(&render_device, descriptor)
})
.clone()
});

let cached_normals_texture = normal_prepass.is_some().then(|| {
normal_textures
.entry(camera.target.clone())
.or_insert_with(|| {
texture_cache.get(
&render_device,
TextureDescriptor {
label: Some("prepass_normal_texture"),
size,
mip_level_count: 1,
sample_count: msaa.samples(),
dimension: TextureDimension::D2,
format: NORMAL_PREPASS_FORMAT,
usage: TextureUsages::RENDER_ATTACHMENT
| TextureUsages::TEXTURE_BINDING,
view_formats: &[],
},
)
})
.clone()
});

let cached_motion_vectors_texture = motion_vector_prepass.is_some().then(|| {
motion_vectors_textures
.entry(camera.target.clone())
.or_insert_with(|| {
texture_cache.get(
&render_device,
TextureDescriptor {
label: Some("prepass_motion_vectors_textures"),
size,
mip_level_count: 1,
sample_count: msaa.samples(),
dimension: TextureDimension::D2,
format: MOTION_VECTOR_PREPASS_FORMAT,
usage: TextureUsages::RENDER_ATTACHMENT
| TextureUsages::TEXTURE_BINDING,
view_formats: &[],
},
)
})
.clone()
});

commands.entity(entity).insert(ViewPrepassTextures {
depth: cached_depth_texture,
normal: cached_normals_texture,
motion_vectors: cached_motion_vectors_texture,
size,
});
}
}
Loading

0 comments on commit a78c4d7

Please sign in to comment.