Skip to content

Commit

Permalink
Merge commit '1b3c2b0fed4821d2a8a7554330310ae7f675373d' into meshlet
Browse files Browse the repository at this point in the history
  • Loading branch information
JMS55 committed Mar 10, 2024
2 parents c768471 + 1b3c2b0 commit be03224
Show file tree
Hide file tree
Showing 13 changed files with 220 additions and 64 deletions.
5 changes: 2 additions & 3 deletions crates/bevy_asset/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use crate::{
io::{embedded::EmbeddedAssetRegistry, AssetSourceBuilder, AssetSourceBuilders, AssetSourceId},
processor::{AssetProcessor, Process},
};
use bevy_app::{App, First, Plugin, PreUpdate};
use bevy_app::{App, Last, Plugin, PreUpdate};
use bevy_ecs::{
reflect::AppTypeRegistry,
schedule::{IntoSystemConfigs, IntoSystemSetConfigs, SystemSet},
Expand Down Expand Up @@ -380,9 +380,8 @@ impl AssetApp for App {
.add_event::<AssetLoadFailedEvent<A>>()
.register_type::<Handle<A>>()
.add_systems(
First,
Last,
Assets::<A>::asset_events
.before(bevy_ecs::event::event_update_system::<AssetEvent<A>>)
.run_if(Assets::<A>::asset_events_condition)
.in_set(AssetEvents),
)
Expand Down
12 changes: 9 additions & 3 deletions crates/bevy_dev_tools/src/ci_testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
use bevy_app::{App, AppExit, Update};
use bevy_ecs::{
entity::Entity,
prelude::Resource,
prelude::{resource_exists, Resource},
query::With,
schedule::IntoSystemConfigs,
system::{Local, Query, Res, ResMut},
};
use bevy_render::view::screenshot::ScreenshotManager;
Expand Down Expand Up @@ -67,8 +68,13 @@ pub(crate) fn setup_app(app: &mut App) -> &mut App {
)));
}

app.insert_resource(config)
.add_systems(Update, (ci_testing_exit_after, ci_testing_screenshot_at));
app.insert_resource(config).add_systems(
Update,
(
ci_testing_exit_after,
ci_testing_screenshot_at.run_if(resource_exists::<ScreenshotManager>),
),
);

app
}
Expand Down
34 changes: 34 additions & 0 deletions crates/bevy_ecs/src/change_detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,15 @@ impl std::fmt::Debug for MutUntyped<'_> {
}
}

impl<'w, T> From<Mut<'w, T>> for MutUntyped<'w> {
fn from(value: Mut<'w, T>) -> Self {
MutUntyped {
value: value.value.into(),
ticks: value.ticks,
}
}
}

#[cfg(test)]
mod tests {
use bevy_ecs_macros::Resource;
Expand Down Expand Up @@ -1254,4 +1263,29 @@ mod tests {

assert!(new.is_changed());
}

#[test]
fn mut_untyped_from_mut() {
let mut component_ticks = ComponentTicks {
added: Tick::new(1),
changed: Tick::new(2),
};
let ticks = TicksMut {
added: &mut component_ticks.added,
changed: &mut component_ticks.changed,
last_run: Tick::new(3),
this_run: Tick::new(4),
};
let mut c = C {};
let mut_typed = Mut {
value: &mut c,
ticks,
};

let into_mut: MutUntyped = mut_typed.into();
assert_eq!(1, into_mut.ticks.added.get());
assert_eq!(2, into_mut.ticks.changed.get());
assert_eq!(3, into_mut.ticks.last_run.get());
assert_eq!(4, into_mut.ticks.this_run.get());
}
}
51 changes: 51 additions & 0 deletions crates/bevy_ecs/src/schedule/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,54 @@ pub(super) fn is_apply_deferred(system: &BoxedSystem) -> bool {
// deref to use `System::type_id` instead of `Any::type_id`
system.as_ref().type_id() == apply_deferred.system_type_id()
}

/// These functions hide the bottom of the callstack from `RUST_BACKTRACE=1` (assuming the default panic handler is used).
/// The full callstack will still be visible with `RUST_BACKTRACE=full`.
/// They are specialized for `System::run` & co instead of being generic over closures because this avoids an
/// extra frame in the backtrace.
///
/// This is reliant on undocumented behavior in Rust's default panic handler, which checks the call stack for symbols
/// containing the string `__rust_begin_short_backtrace` in their mangled name.
mod __rust_begin_short_backtrace {
use std::hint::black_box;

use crate::{
system::{ReadOnlySystem, System},
world::{unsafe_world_cell::UnsafeWorldCell, World},
};

/// # Safety
/// See `System::run_unsafe`.
#[inline(never)]
pub(super) unsafe fn run_unsafe(
system: &mut dyn System<In = (), Out = ()>,
world: UnsafeWorldCell,
) {
system.run_unsafe((), world);
black_box(());
}

/// # Safety
/// See `ReadOnlySystem::run_unsafe`.
#[inline(never)]
pub(super) unsafe fn readonly_run_unsafe<O: 'static>(
system: &mut dyn ReadOnlySystem<In = (), Out = O>,
world: UnsafeWorldCell,
) -> O {
black_box(system.run_unsafe((), world))
}

#[inline(never)]
pub(super) fn run(system: &mut dyn System<In = (), Out = ()>, world: &mut World) {
system.run((), world);
black_box(());
}

#[inline(never)]
pub(super) fn readonly_run<O: 'static>(
system: &mut dyn ReadOnlySystem<In = (), Out = O>,
world: &mut World,
) -> O {
black_box(system.run((), world))
}
}
13 changes: 10 additions & 3 deletions crates/bevy_ecs/src/schedule/executor/multi_threaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ use crate::{

use crate as bevy_ecs;

use super::__rust_begin_short_backtrace;

/// Borrowed data used by the [`MultiThreadedExecutor`].
struct Environment<'env, 'sys> {
executor: &'env MultiThreadedExecutor,
Expand Down Expand Up @@ -618,7 +620,12 @@ impl ExecutorState {
// - The caller ensures that we have permission to
// access the world data used by the system.
// - `update_archetype_component_access` has been called.
unsafe { system.run_unsafe((), context.environment.world_cell) };
unsafe {
__rust_begin_short_backtrace::run_unsafe(
&mut **system,
context.environment.world_cell,
);
};
}));
context.system_completed(system_index, res, system);
};
Expand Down Expand Up @@ -668,7 +675,7 @@ impl ExecutorState {
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
#[cfg(feature = "trace")]
let _span = system_span.enter();
system.run((), world);
__rust_begin_short_backtrace::run(&mut **system, world);
}));
context.system_completed(system_index, res, system);
};
Expand Down Expand Up @@ -780,7 +787,7 @@ unsafe fn evaluate_and_fold_conditions(
.map(|condition| {
// SAFETY: The caller ensures that `world` has permission to
// access any data required by the condition.
unsafe { condition.run_unsafe((), world) }
unsafe { __rust_begin_short_backtrace::readonly_run_unsafe(&mut **condition, world) }
})
.fold(true, |acc, res| acc && res)
}
Expand Down
6 changes: 4 additions & 2 deletions crates/bevy_ecs/src/schedule/executor/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use crate::{
world::World,
};

use super::__rust_begin_short_backtrace;

/// A variant of [`SingleThreadedExecutor`](crate::schedule::SingleThreadedExecutor) that calls
/// [`apply_deferred`](crate::system::System::apply_deferred) immediately after running each system.
#[derive(Default)]
Expand Down Expand Up @@ -93,7 +95,7 @@ impl SystemExecutor for SimpleExecutor {
}

let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
system.run((), world);
__rust_begin_short_backtrace::run(&mut **system, world);
}));
if let Err(payload) = res {
eprintln!("Encountered a panic in system `{}`!", &*system.name());
Expand Down Expand Up @@ -126,7 +128,7 @@ fn evaluate_and_fold_conditions(conditions: &mut [BoxedCondition], world: &mut W
#[allow(clippy::unnecessary_fold)]
conditions
.iter_mut()
.map(|condition| condition.run((), world))
.map(|condition| __rust_begin_short_backtrace::readonly_run(&mut **condition, world))
.fold(true, |acc, res| acc && res)
}

Expand Down
8 changes: 5 additions & 3 deletions crates/bevy_ecs/src/schedule/executor/single_threaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use crate::{
world::World,
};

use super::__rust_begin_short_backtrace;

/// Runs the schedule using a single thread.
///
/// Useful if you're dealing with a single-threaded environment, saving your threads for
Expand Down Expand Up @@ -101,14 +103,14 @@ impl SystemExecutor for SingleThreadedExecutor {

let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
if system.is_exclusive() {
system.run((), world);
__rust_begin_short_backtrace::run(&mut **system, world);
} else {
// Use run_unsafe to avoid immediately applying deferred buffers
let world = world.as_unsafe_world_cell();
system.update_archetype_component_access(world);
// SAFETY: We have exclusive, single-threaded access to the world and
// update_archetype_component_access is being called immediately before this.
unsafe { system.run_unsafe((), world) };
unsafe { __rust_begin_short_backtrace::run_unsafe(&mut **system, world) };
}
}));
if let Err(payload) = res {
Expand Down Expand Up @@ -158,6 +160,6 @@ fn evaluate_and_fold_conditions(conditions: &mut [BoxedCondition], world: &mut W
#[allow(clippy::unnecessary_fold)]
conditions
.iter_mut()
.map(|condition| condition.run((), world))
.map(|condition| __rust_begin_short_backtrace::readonly_run(&mut **condition, world))
.fold(true, |acc, res| acc && res)
}
29 changes: 29 additions & 0 deletions crates/bevy_input/src/button_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,35 @@ use bevy_ecs::schedule::State;
/// * Using [`ButtonInput::clear_just_pressed`] or [`ButtonInput::clear_just_released`] instead.
/// * Calling [`ButtonInput::clear`] or [`ButtonInput::reset`] immediately after the state change.
///
/// ## Performance
///
/// For all operations, the following conventions are used:
/// - **n** is the number of stored inputs.
/// - **m** is the number of input arguments passed to the method.
/// - **\***-suffix denotes an amortized cost.
/// - **~**-suffix denotes an expected cost.
///
/// See Rust's [std::collections doc on performance](https://doc.rust-lang.org/std/collections/index.html#performance) for more details on the conventions used here.
///
/// | **[`ButtonInput`] operations** | **Computational complexity** |
/// |-----------------------------------|------------------------------------|
/// | [`ButtonInput::any_just_pressed`] | *O*(m*n) |
/// | [`ButtonInput::any_just_released`] | *O*(m*n) |
/// | [`ButtonInput::any_pressed`] | *O*(m*n) |
/// | [`ButtonInput::get_just_pressed`] | *O*(n) |
/// | [`ButtonInput::get_just_released`] | *O*(n) |
/// | [`ButtonInput::get_pressed`] | *O*(n) |
/// | [`ButtonInput::just_pressed`] | *O*(1)~ |
/// | [`ButtonInput::just_released`] | *O*(1)~ |
/// | [`ButtonInput::pressed`] | *O*(1)~ |
/// | [`ButtonInput::press`] | *O*(1)~* |
/// | [`ButtonInput::release`] | *O*(1)~* |
/// | [`ButtonInput::release_all`] | *O*(n)~* |
/// | [`ButtonInput::clear_just_pressed`] | *O*(1)~ |
/// | [`ButtonInput::clear_just_released`] | *O*(1)~ |
/// | [`ButtonInput::reset_all`] | *O*(n) |
/// | [`ButtonInput::clear`] | *O*(n) |
///
/// ## Window focus
///
/// `ButtonInput<KeyCode>` is tied to window focus. For example, if the user holds a button
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/render/morph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,6 @@ pub fn no_automatic_morph_batching(
query: Query<Entity, (With<MeshMorphWeights>, Without<NoAutomaticBatching>)>,
) {
for entity in &query {
commands.entity(entity).insert(NoAutomaticBatching);
commands.entity(entity).try_insert(NoAutomaticBatching);
}
}
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/render/skin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,6 @@ pub fn no_automatic_skin_batching(
query: Query<Entity, (With<SkinnedMesh>, Without<NoAutomaticBatching>)>,
) {
for entity in &query {
commands.entity(entity).insert(NoAutomaticBatching);
commands.entity(entity).try_insert(NoAutomaticBatching);
}
}
25 changes: 15 additions & 10 deletions crates/bevy_render/src/pipelined_rendering.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use async_channel::{Receiver, Sender};

use bevy_app::{App, AppLabel, Main, Plugin, SubApp};
use bevy_app::{App, AppExit, AppLabel, Main, Plugin, SubApp};
use bevy_ecs::{
schedule::MainThreadExecutor,
system::Resource,
Expand Down Expand Up @@ -45,10 +45,11 @@ impl RenderAppChannels {
}

/// Receive the `render_app` from the rendering thread.
pub async fn recv(&mut self) -> SubApp {
let render_app = self.render_to_app_receiver.recv().await.unwrap();
/// Return `None` if the render thread has panicked.
pub async fn recv(&mut self) -> Option<SubApp> {
let render_app = self.render_to_app_receiver.recv().await.ok()?;
self.render_app_in_render_thread = false;
render_app
Some(render_app)
}
}

Expand Down Expand Up @@ -180,16 +181,20 @@ fn update_rendering(app_world: &mut World, _sub_app: &mut App) {
world.resource_scope(|world, mut render_channels: Mut<RenderAppChannels>| {
// we use a scope here to run any main thread tasks that the render world still needs to run
// while we wait for the render world to be received.
let mut render_app = ComputeTaskPool::get()
if let Some(mut render_app) = ComputeTaskPool::get()
.scope_with_executor(true, Some(&*main_thread_executor.0), |s| {
s.spawn(async { render_channels.recv().await });
})
.pop()
.unwrap();

render_app.extract(world);

render_channels.send_blocking(render_app);
.unwrap()
{
render_app.extract(world);

render_channels.send_blocking(render_app);
} else {
// Renderer thread panicked
world.send_event(AppExit);
}
});
});
}
13 changes: 10 additions & 3 deletions crates/bevy_ui/src/focus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,16 @@ pub fn ui_focus_system(
// The mouse position relative to the node
// (0., 0.) is the top-left corner, (1., 1.) is the bottom-right corner
// Coordinates are relative to the entire node, not just the visible region.
let relative_cursor_position = camera_cursor_positions
.get(&camera_entity)
.map(|cursor_position| (*cursor_position - node_rect.min) / node_rect.size());
let relative_cursor_position =
camera_cursor_positions
.get(&camera_entity)
.and_then(|cursor_position| {
// ensure node size is non-zero in all dimensions, otherwise relative position will be
// +/-inf. if the node is hidden, the visible rect min/max will also be -inf leading to
// false positives for mouse_over (#12395)
(node_rect.size().cmpgt(Vec2::ZERO).all())
.then_some((*cursor_position - node_rect.min) / node_rect.size())
});

// If the current cursor position is within the bounds of the node's visible area, consider it for
// clicking
Expand Down
Loading

0 comments on commit be03224

Please sign in to comment.