Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into opt-out-gpu-culling
Browse files Browse the repository at this point in the history
  • Loading branch information
pcwalton committed Dec 12, 2024
2 parents 02e4450 + a900f68 commit 00dfec3
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 53 deletions.
42 changes: 34 additions & 8 deletions crates/bevy_animation/src/animation_curves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,18 +243,26 @@ where

impl<C: Typed, P, F: Fn(&mut C) -> &mut P + 'static> AnimatedField<C, P, F> {
/// Creates a new instance of [`AnimatedField`]. This operates under the assumption that
/// `C` is a reflect-able struct with named fields, and that `field_name` is a valid field on that struct.
/// `C` is a reflect-able struct, and that `field_name` is a valid field on that struct.
///
/// # Panics
/// If the type of `C` is not a struct with named fields or if the `field_name` does not exist.
/// If the type of `C` is not a struct or if the `field_name` does not exist.
pub fn new_unchecked(field_name: &str, func: F) -> Self {
let TypeInfo::Struct(struct_info) = C::type_info() else {
let field_index;
if let TypeInfo::Struct(struct_info) = C::type_info() {
field_index = struct_info
.index_of(field_name)
.expect("Field name should exist");
} else if let TypeInfo::TupleStruct(struct_info) = C::type_info() {
field_index = field_name
.parse()
.expect("Field name should be a valid tuple index");
if field_index >= struct_info.field_len() {
panic!("Field name should be a valid tuple index");
}
} else {
panic!("Only structs are supported in `AnimatedField::new_unchecked`")
};

let field_index = struct_info
.index_of(field_name)
.expect("Field name should exist");
}

Self {
func,
Expand Down Expand Up @@ -984,3 +992,21 @@ macro_rules! animated_field {
})
};
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_animated_field_tuple_struct_simple_uses() {
#[derive(Clone, Debug, Component, Reflect)]
struct A(f32);
let _ = AnimatedField::new_unchecked("0", |a: &mut A| &mut a.0);

#[derive(Clone, Debug, Component, Reflect)]
struct B(f32, f64, f32);
let _ = AnimatedField::new_unchecked("0", |b: &mut B| &mut b.0);
let _ = AnimatedField::new_unchecked("1", |b: &mut B| &mut b.1);
let _ = AnimatedField::new_unchecked("2", |b: &mut B| &mut b.2);
}
}
13 changes: 12 additions & 1 deletion crates/bevy_audio/src/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ impl Volume {
#[derive(Debug, Clone, Copy, Reflect)]
pub enum PlaybackMode {
/// Play the sound once. Do nothing when it ends.
///
/// Note: It is not possible to reuse an `AudioPlayer` after it has finished playing and
/// the underlying `AudioSink` or `SpatialAudioSink` has been drained.
///
/// To replay a sound, the audio components provided by `AudioPlayer` must be removed and
/// added again.
Once,
/// Repeat the sound forever.
Loop,
Expand Down Expand Up @@ -77,13 +83,18 @@ pub struct PlaybackSettings {

impl Default for PlaybackSettings {
fn default() -> Self {
// TODO: what should the default be: ONCE/DESPAWN/REMOVE?
Self::ONCE
}
}

impl PlaybackSettings {
/// Will play the associated audio source once.
///
/// Note: It is not possible to reuse an `AudioPlayer` after it has finished playing and
/// the underlying `AudioSink` or `SpatialAudioSink` has been drained.
///
/// To replay a sound, the audio components provided by `AudioPlayer` must be removed and
/// added again.
pub const ONCE: PlaybackSettings = PlaybackSettings {
mode: PlaybackMode::Once,
volume: Volume(1.0),
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_core_pipeline/src/core_3d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ impl PhaseItem for AlphaMask3d {

#[inline]
fn draw_function(&self) -> DrawFunctionId {
self.key.draw_function
self.key.batch_set_key.draw_function
}

#[inline]
Expand Down Expand Up @@ -414,7 +414,7 @@ impl BinnedPhaseItem for AlphaMask3d {
impl CachedRenderPipelinePhaseItem for AlphaMask3d {
#[inline]
fn cached_pipeline(&self) -> CachedRenderPipelineId {
self.key.pipeline
self.key.batch_set_key.pipeline
}
}

Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_core_pipeline/src/deferred/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl PhaseItem for Opaque3dDeferred {

#[inline]
fn draw_function(&self) -> DrawFunctionId {
self.key.draw_function
self.key.batch_set_key.draw_function
}

#[inline]
Expand Down Expand Up @@ -89,7 +89,7 @@ impl BinnedPhaseItem for Opaque3dDeferred {
impl CachedRenderPipelinePhaseItem for Opaque3dDeferred {
#[inline]
fn cached_pipeline(&self) -> CachedRenderPipelineId {
self.key.pipeline
self.key.batch_set_key.pipeline
}
}

Expand Down Expand Up @@ -118,7 +118,7 @@ impl PhaseItem for AlphaMask3dDeferred {

#[inline]
fn draw_function(&self) -> DrawFunctionId {
self.key.draw_function
self.key.batch_set_key.draw_function
}

#[inline]
Expand Down Expand Up @@ -163,6 +163,6 @@ impl BinnedPhaseItem for AlphaMask3dDeferred {
impl CachedRenderPipelinePhaseItem for AlphaMask3dDeferred {
#[inline]
fn cached_pipeline(&self) -> CachedRenderPipelineId {
self.key.pipeline
self.key.batch_set_key.pipeline
}
}
32 changes: 23 additions & 9 deletions crates/bevy_core_pipeline/src/prepass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,13 @@ pub struct Opaque3dPrepass {
pub extra_index: PhaseItemExtraIndex,
}

// TODO: Try interning these.
/// The data used to bin each opaque 3D object in the prepass and deferred pass.
/// Information that must be identical in order to place opaque meshes in the
/// same *batch set* in the prepass and deferred pass.
///
/// A batch set is a set of batches that can be multi-drawn together, if
/// multi-draw is in use.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OpaqueNoLightmap3dBinKey {
pub struct OpaqueNoLightmap3dBatchSetKey {
/// The ID of the GPU pipeline.
pub pipeline: CachedRenderPipelineId,

Expand All @@ -163,16 +166,27 @@ pub struct OpaqueNoLightmap3dBinKey {
///
/// In the case of PBR, this is the `MaterialBindGroupIndex`.
pub material_bind_group_index: Option<u32>,
}

// TODO: Try interning these.
/// The data used to bin each opaque 3D object in the prepass and deferred pass.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OpaqueNoLightmap3dBinKey {
/// The key of the *batch set*.
///
/// As batches belong to a batch set, meshes in a batch must obviously be
/// able to be placed in a single batch set.
pub batch_set_key: OpaqueNoLightmap3dBatchSetKey,

/// The ID of the asset.
pub asset_id: UntypedAssetId,
}

impl PhaseItemBinKey for OpaqueNoLightmap3dBinKey {
type BatchSetKey = ();
type BatchSetKey = OpaqueNoLightmap3dBatchSetKey;

fn get_batch_set_key(&self) -> Option<Self::BatchSetKey> {
None
Some(self.batch_set_key.clone())
}
}

Expand All @@ -188,7 +202,7 @@ impl PhaseItem for Opaque3dPrepass {

#[inline]
fn draw_function(&self) -> DrawFunctionId {
self.key.draw_function
self.key.batch_set_key.draw_function
}

#[inline]
Expand Down Expand Up @@ -234,7 +248,7 @@ impl BinnedPhaseItem for Opaque3dPrepass {
impl CachedRenderPipelinePhaseItem for Opaque3dPrepass {
#[inline]
fn cached_pipeline(&self) -> CachedRenderPipelineId {
self.key.pipeline
self.key.batch_set_key.pipeline
}
}

Expand Down Expand Up @@ -262,7 +276,7 @@ impl PhaseItem for AlphaMask3dPrepass {

#[inline]
fn draw_function(&self) -> DrawFunctionId {
self.key.draw_function
self.key.batch_set_key.draw_function
}

#[inline]
Expand Down Expand Up @@ -308,7 +322,7 @@ impl BinnedPhaseItem for AlphaMask3dPrepass {
impl CachedRenderPipelinePhaseItem for AlphaMask3dPrepass {
#[inline]
fn cached_pipeline(&self) -> CachedRenderPipelineId {
self.key.pipeline
self.key.batch_set_key.pipeline
}
}

Expand Down
11 changes: 7 additions & 4 deletions crates/bevy_pbr/src/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use bevy_core_pipeline::{
},
oit::OrderIndependentTransparencySettings,
prepass::{
DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass, OpaqueNoLightmap3dBinKey,
DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass,
OpaqueNoLightmap3dBatchSetKey, OpaqueNoLightmap3dBinKey,
},
tonemapping::{DebandDither, Tonemapping},
};
Expand Down Expand Up @@ -906,10 +907,12 @@ pub fn queue_material_meshes<M: Material>(
});
} else if material.properties.render_method == OpaqueRendererMethod::Forward {
let bin_key = OpaqueNoLightmap3dBinKey {
draw_function: draw_alpha_mask_pbr,
pipeline: pipeline_id,
batch_set_key: OpaqueNoLightmap3dBatchSetKey {
draw_function: draw_alpha_mask_pbr,
pipeline: pipeline_id,
material_bind_group_index: Some(material.binding.group.0),
},
asset_id: mesh_instance.mesh_asset_id.into(),
material_bind_group_index: Some(material.binding.group.0),
};
alpha_mask_phase.add(
bin_key,
Expand Down
32 changes: 20 additions & 12 deletions crates/bevy_pbr/src/prepass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -951,21 +951,25 @@ pub fn queue_prepass_material_meshes<M: Material>(
if deferred {
opaque_deferred_phase.as_mut().unwrap().add(
OpaqueNoLightmap3dBinKey {
draw_function: opaque_draw_deferred,
pipeline: pipeline_id,
batch_set_key: OpaqueNoLightmap3dBatchSetKey {
draw_function: opaque_draw_deferred,
pipeline: pipeline_id,
material_bind_group_index: Some(material.binding.group.0),
},
asset_id: mesh_instance.mesh_asset_id.into(),
material_bind_group_index: Some(material.binding.group.0),
},
(*render_entity, *visible_entity),
BinnedRenderPhaseType::mesh(mesh_instance.should_batch()),
);
} else if let Some(opaque_phase) = opaque_phase.as_mut() {
opaque_phase.add(
OpaqueNoLightmap3dBinKey {
draw_function: opaque_draw_prepass,
pipeline: pipeline_id,
batch_set_key: OpaqueNoLightmap3dBatchSetKey {
draw_function: opaque_draw_prepass,
pipeline: pipeline_id,
material_bind_group_index: Some(material.binding.group.0),
},
asset_id: mesh_instance.mesh_asset_id.into(),
material_bind_group_index: Some(material.binding.group.0),
},
(*render_entity, *visible_entity),
BinnedRenderPhaseType::mesh(mesh_instance.should_batch()),
Expand All @@ -976,10 +980,12 @@ pub fn queue_prepass_material_meshes<M: Material>(
MeshPipelineKey::MAY_DISCARD => {
if deferred {
let bin_key = OpaqueNoLightmap3dBinKey {
pipeline: pipeline_id,
draw_function: alpha_mask_draw_deferred,
batch_set_key: OpaqueNoLightmap3dBatchSetKey {
draw_function: alpha_mask_draw_deferred,
pipeline: pipeline_id,
material_bind_group_index: Some(material.binding.group.0),
},
asset_id: mesh_instance.mesh_asset_id.into(),
material_bind_group_index: Some(material.binding.group.0),
};
alpha_mask_deferred_phase.as_mut().unwrap().add(
bin_key,
Expand All @@ -988,10 +994,12 @@ pub fn queue_prepass_material_meshes<M: Material>(
);
} else if let Some(alpha_mask_phase) = alpha_mask_phase.as_mut() {
let bin_key = OpaqueNoLightmap3dBinKey {
pipeline: pipeline_id,
draw_function: alpha_mask_draw_prepass,
batch_set_key: OpaqueNoLightmap3dBatchSetKey {
draw_function: alpha_mask_draw_prepass,
pipeline: pipeline_id,
material_bind_group_index: Some(material.binding.group.0),
},
asset_id: mesh_instance.mesh_asset_id.into(),
material_bind_group_index: Some(material.binding.group.0),
};
alpha_mask_phase.add(
bin_key,
Expand Down
20 changes: 15 additions & 5 deletions crates/bevy_pbr/src/render/pbr_prepass.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
pbr_functions,
pbr_functions::SampleBias,
prepass_io,
mesh_bindings::mesh,
mesh_view_bindings::view,
}

Expand All @@ -28,6 +29,15 @@ fn fragment(
let is_front = true;
#else // MESHLET_MESH_MATERIAL_PASS

#ifdef BINDLESS
let slot = mesh[in.instance_index].material_bind_group_slot;
let flags = pbr_bindings::material[slot].flags;
let uv_transform = pbr_bindings::material[slot].uv_transform;
#else // BINDLESS
let flags = pbr_bindings::material.flags;
let uv_transform = pbr_bindings::material.uv_transform;
#endif // BINDLESS

// If we're in the crossfade section of a visibility range, conditionally
// discard the fragment according to the visibility pattern.
#ifdef VISIBILITY_RANGE_DITHER
Expand All @@ -45,8 +55,8 @@ fn fragment(

#ifdef NORMAL_PREPASS
// NOTE: Unlit bit not set means == 0 is true, so the true case is if lit
if (material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u {
let double_sided = (material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u;
if (flags & pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u {
let double_sided = (flags & pbr_types::STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u;

let world_normal = pbr_functions::prepare_world_normal(
in.world_normal,
Expand All @@ -62,9 +72,9 @@ fn fragment(

// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
#ifdef STANDARD_MATERIAL_NORMAL_MAP_UV_B
let uv = (material.uv_transform * vec3(in.uv_b, 1.0)).xy;
let uv = (uv_transform * vec3(in.uv_b, 1.0)).xy;
#else
let uv = (material.uv_transform * vec3(in.uv, 1.0)).xy;
let uv = (uv_transform * vec3(in.uv, 1.0)).xy;
#endif

// Fill in the sample bias so we can sample from textures.
Expand Down Expand Up @@ -100,7 +110,7 @@ fn fragment(
let TBN = pbr_functions::calculate_tbn_mikktspace(normal, in.world_tangent);

normal = pbr_functions::apply_normal_mapping(
material.flags,
flags,
TBN,
double_sided,
is_front,
Expand Down
Loading

0 comments on commit 00dfec3

Please sign in to comment.