Remove bevy_core
(#16897)
# Objective - Fixes #16892 ## Solution - Removed `TypeRegistryPlugin` (`Name` is now automatically registered with a default `App`) - Moved `TaskPoolPlugin` to `bevy_app` - Moved `FrameCountPlugin` to `bevy_diagnostic` - Deleted now-empty `bevy_core` ## Testing - CI ## Migration Guide - `TypeRegistryPlugin` no longer exists. If you can't use a default `App` but still need `Name` registered, do so manually with `app.register_type::<Name>()`. - References to `TaskPoolPlugin` and associated types will need to import it from `bevy_app` instead of `bevy_core` - References to `FrameCountPlugin` and associated types will need to import it from `bevy_diagnostic` instead of `bevy_core` ## Notes This strategy was agreed upon by Cart and several other members in [Discord](https://discord.com/channels/691052431525675048/692572690833473578/1319137218312278077).
This commit is contained in:
parent
d4b07a5114
commit
21786632c3
@ -7,7 +7,7 @@
|
||||
entities: {
|
||||
4294967296: (
|
||||
components: {
|
||||
"bevy_core::name::Name": (
|
||||
"bevy_ecs::name::Name": (
|
||||
hash: 17588334858059901562,
|
||||
name: "joe",
|
||||
),
|
||||
|
@ -13,7 +13,6 @@ keywords = ["bevy"]
|
||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev" }
|
||||
bevy_asset = { path = "../bevy_asset", version = "0.15.0-dev" }
|
||||
bevy_color = { path = "../bevy_color", version = "0.15.0-dev" }
|
||||
bevy_core = { path = "../bevy_core", version = "0.15.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }
|
||||
bevy_log = { path = "../bevy_log", version = "0.15.0-dev" }
|
||||
bevy_math = { path = "../bevy_math", version = "0.15.0-dev" }
|
||||
|
@ -55,11 +55,20 @@ std = [
|
||||
|
||||
## `critical-section` provides the building blocks for synchronization primitives
|
||||
## on all platforms, including `no_std`.
|
||||
critical-section = ["bevy_tasks?/critical-section", "bevy_ecs/critical-section"]
|
||||
critical-section = [
|
||||
"portable-atomic?/critical-section",
|
||||
"bevy_tasks?/critical-section",
|
||||
"bevy_ecs/critical-section",
|
||||
]
|
||||
|
||||
## `portable-atomic` provides additional platform support for atomic types and
|
||||
## operations, even on targets without native support.
|
||||
portable-atomic = ["bevy_tasks?/portable-atomic", "bevy_ecs/portable-atomic"]
|
||||
portable-atomic = [
|
||||
"dep:portable-atomic",
|
||||
"dep:portable-atomic-util",
|
||||
"bevy_tasks?/portable-atomic",
|
||||
"bevy_ecs/portable-atomic",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
# bevy
|
||||
@ -77,6 +86,12 @@ thiserror = { version = "2", default-features = false }
|
||||
variadics_please = "1.1"
|
||||
tracing = { version = "0.1", default-features = false, optional = true }
|
||||
log = { version = "0.4", default-features = false }
|
||||
portable-atomic = { version = "1", default-features = false, features = [
|
||||
"fallback",
|
||||
], optional = true }
|
||||
portable-atomic-util = { version = "0.2.4", features = [
|
||||
"alloc",
|
||||
], optional = true }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
ctrlc = { version = "3.4.4", optional = true }
|
||||
@ -86,6 +101,9 @@ wasm-bindgen = { version = "0.2" }
|
||||
web-sys = { version = "0.3", features = ["Window"] }
|
||||
console_error_panic_hook = "0.1.6"
|
||||
|
||||
[dev-dependencies]
|
||||
crossbeam-channel = "0.5.0"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
|
@ -103,7 +103,10 @@ impl Default for App {
|
||||
app.sub_apps.main.update_schedule = Some(Main.intern());
|
||||
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
app.init_resource::<AppTypeRegistry>();
|
||||
{
|
||||
app.init_resource::<AppTypeRegistry>();
|
||||
app.register_type::<Name>();
|
||||
}
|
||||
|
||||
#[cfg(feature = "reflect_functions")]
|
||||
app.init_resource::<AppFunctionRegistry>();
|
||||
|
@ -24,6 +24,8 @@ mod plugin;
|
||||
mod plugin_group;
|
||||
mod schedule_runner;
|
||||
mod sub_app;
|
||||
#[cfg(feature = "bevy_tasks")]
|
||||
mod task_pool_plugin;
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
|
||||
mod terminal_ctrl_c_handler;
|
||||
|
||||
@ -34,6 +36,8 @@ pub use plugin::*;
|
||||
pub use plugin_group::*;
|
||||
pub use schedule_runner::*;
|
||||
pub use sub_app::*;
|
||||
#[cfg(feature = "bevy_tasks")]
|
||||
pub use task_pool_plugin::*;
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
|
||||
pub use terminal_ctrl_c_handler::*;
|
||||
|
||||
@ -52,4 +56,8 @@ pub mod prelude {
|
||||
sub_app::SubApp,
|
||||
Plugin, PluginGroup,
|
||||
};
|
||||
|
||||
#[cfg(feature = "bevy_tasks")]
|
||||
#[doc(hidden)]
|
||||
pub use crate::{NonSendMarker, TaskPoolOptions, TaskPoolPlugin};
|
||||
}
|
||||
|
@ -1,8 +1,55 @@
|
||||
use bevy_tasks::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool, TaskPoolBuilder};
|
||||
use bevy_utils::tracing::trace;
|
||||
#![cfg_attr(
|
||||
feature = "portable-atomic",
|
||||
expect(
|
||||
clippy::redundant_closure,
|
||||
reason = "portable_atomic_util::Arc has subtly different implicit behavior"
|
||||
)
|
||||
)]
|
||||
|
||||
use crate::{App, Last, Plugin};
|
||||
|
||||
use alloc::string::ToString;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_tasks::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool, TaskPoolBuilder};
|
||||
use core::{fmt::Debug, marker::PhantomData};
|
||||
use log::trace;
|
||||
|
||||
#[cfg(feature = "portable-atomic")]
|
||||
use portable_atomic_util::Arc;
|
||||
|
||||
#[cfg(not(feature = "portable-atomic"))]
|
||||
use alloc::sync::Arc;
|
||||
use core::fmt::Debug;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use bevy_tasks::tick_global_task_pools_on_main_thread;
|
||||
|
||||
/// Setup of default task pools: [`AsyncComputeTaskPool`], [`ComputeTaskPool`], [`IoTaskPool`].
|
||||
#[derive(Default)]
|
||||
pub struct TaskPoolPlugin {
|
||||
/// Options for the [`TaskPool`](bevy_tasks::TaskPool) created at application start.
|
||||
pub task_pool_options: TaskPoolOptions,
|
||||
}
|
||||
|
||||
impl Plugin for TaskPoolPlugin {
|
||||
fn build(&self, _app: &mut App) {
|
||||
// Setup the default bevy task pools
|
||||
self.task_pool_options.create_default_pools();
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
_app.add_systems(Last, tick_global_task_pools);
|
||||
}
|
||||
}
|
||||
/// A dummy type that is [`!Send`](Send), to force systems to run on the main thread.
|
||||
pub struct NonSendMarker(PhantomData<*mut ()>);
|
||||
|
||||
/// A system used to check and advanced our task pools.
|
||||
///
|
||||
/// Calls [`tick_global_task_pools_on_main_thread`],
|
||||
/// and uses [`NonSendMarker`] to ensure that this system runs on the main thread
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn tick_global_task_pools(_main_thread_marker: Option<NonSend<NonSendMarker>>) {
|
||||
tick_global_task_pools_on_main_thread();
|
||||
}
|
||||
|
||||
/// Defines a simple way to determine how many threads to use given the number of remaining cores
|
||||
/// and number of total cores
|
||||
@ -37,7 +84,14 @@ impl TaskPoolThreadAssignmentPolicy {
|
||||
/// Determine the number of threads to use for this task pool
|
||||
fn get_number_of_threads(&self, remaining_threads: usize, total_threads: usize) -> usize {
|
||||
assert!(self.percent >= 0.0);
|
||||
let mut desired = (total_threads as f32 * self.percent).round() as usize;
|
||||
let proportion = total_threads as f32 * self.percent;
|
||||
let mut desired = proportion as usize;
|
||||
|
||||
// Equivalent to round() for positive floats without libm requirement for
|
||||
// no_std compatibility
|
||||
if proportion - desired as f32 >= 0.5 {
|
||||
desired += 1;
|
||||
}
|
||||
|
||||
// Limit ourselves to the number of cores available
|
||||
desired = desired.min(remaining_threads);
|
||||
@ -50,7 +104,7 @@ impl TaskPoolThreadAssignmentPolicy {
|
||||
}
|
||||
|
||||
/// Helper for configuring and creating the default task pools. For end-users who want full control,
|
||||
/// set up [`TaskPoolPlugin`](super::TaskPoolPlugin)
|
||||
/// set up [`TaskPoolPlugin`]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TaskPoolOptions {
|
||||
/// If the number of physical cores is less than `min_total_threads`, force using
|
||||
@ -208,3 +262,42 @@ impl TaskPoolOptions {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use bevy_tasks::prelude::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool};
|
||||
|
||||
#[test]
|
||||
fn runs_spawn_local_tasks() {
|
||||
let mut app = App::new();
|
||||
app.add_plugins(TaskPoolPlugin::default());
|
||||
|
||||
let (async_tx, async_rx) = crossbeam_channel::unbounded();
|
||||
AsyncComputeTaskPool::get()
|
||||
.spawn_local(async move {
|
||||
async_tx.send(()).unwrap();
|
||||
})
|
||||
.detach();
|
||||
|
||||
let (compute_tx, compute_rx) = crossbeam_channel::unbounded();
|
||||
ComputeTaskPool::get()
|
||||
.spawn_local(async move {
|
||||
compute_tx.send(()).unwrap();
|
||||
})
|
||||
.detach();
|
||||
|
||||
let (io_tx, io_rx) = crossbeam_channel::unbounded();
|
||||
IoTaskPool::get()
|
||||
.spawn_local(async move {
|
||||
io_tx.send(()).unwrap();
|
||||
})
|
||||
.detach();
|
||||
|
||||
app.run();
|
||||
|
||||
async_rx.try_recv().unwrap();
|
||||
compute_rx.try_recv().unwrap();
|
||||
io_rx.try_recv().unwrap();
|
||||
}
|
||||
}
|
@ -65,7 +65,6 @@ js-sys = "0.3"
|
||||
notify-debouncer-full = { version = "0.4.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
bevy_core = { path = "../bevy_core", version = "0.15.0-dev" }
|
||||
bevy_log = { path = "../bevy_log", version = "0.15.0-dev" }
|
||||
|
||||
[lints]
|
||||
|
@ -296,8 +296,7 @@ mod tests {
|
||||
use core::num::NonZero;
|
||||
|
||||
use crate::{AssetApp, Assets};
|
||||
use bevy_app::{App, AppExit, Last, Startup, Update};
|
||||
use bevy_core::TaskPoolPlugin;
|
||||
use bevy_app::{App, AppExit, Last, Startup, TaskPoolPlugin, Update};
|
||||
use bevy_ecs::schedule::IntoSystemConfigs;
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
|
@ -633,8 +633,7 @@ mod tests {
|
||||
AssetPlugin, AssetServer, Assets,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use bevy_app::{App, Update};
|
||||
use bevy_core::TaskPoolPlugin;
|
||||
use bevy_app::{App, TaskPoolPlugin, Update};
|
||||
use bevy_ecs::{
|
||||
event::EventCursor,
|
||||
prelude::*,
|
||||
|
@ -1,42 +0,0 @@
|
||||
[package]
|
||||
name = "bevy_core"
|
||||
version = "0.15.0-dev"
|
||||
edition = "2021"
|
||||
description = "Provides core functionality for Bevy Engine"
|
||||
homepage = "https://bevyengine.org"
|
||||
repository = "https://github.com/bevyengine/bevy"
|
||||
license = "MIT OR Apache-2.0"
|
||||
keywords = ["bevy"]
|
||||
|
||||
[dependencies]
|
||||
# bevy
|
||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev", default-features = false }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev", default-features = false }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [
|
||||
"bevy",
|
||||
], optional = true }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.15.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
|
||||
|
||||
# other
|
||||
serde = { version = "1.0", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["bevy_reflect"]
|
||||
bevy_reflect = [
|
||||
"dep:bevy_reflect",
|
||||
"bevy_app/bevy_reflect",
|
||||
"bevy_ecs/bevy_reflect",
|
||||
]
|
||||
serialize = ["dep:serde"]
|
||||
|
||||
[dev-dependencies]
|
||||
crossbeam-channel = "0.5.0"
|
||||
serde_test = "1.0"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["-Zunstable-options", "--generate-link-to-definition"]
|
||||
all-features = true
|
@ -1,7 +0,0 @@
|
||||
# Bevy Core
|
||||
|
||||
[](https://github.com/bevyengine/bevy#license)
|
||||
[](https://crates.io/crates/bevy_core)
|
||||
[](https://crates.io/crates/bevy_core)
|
||||
[](https://docs.rs/bevy_core/latest/bevy_core/)
|
||||
[](https://discord.gg/bevy)
|
@ -1,157 +0,0 @@
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![forbid(unsafe_code)]
|
||||
#![doc(
|
||||
html_logo_url = "https://bevyengine.org/assets/icon.png",
|
||||
html_favicon_url = "https://bevyengine.org/assets/icon.png"
|
||||
)]
|
||||
|
||||
//! This crate provides core functionality for Bevy Engine.
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
mod serde;
|
||||
mod task_pool_options;
|
||||
|
||||
use bevy_ecs::system::Resource;
|
||||
pub use task_pool_options::*;
|
||||
|
||||
/// The core prelude.
|
||||
///
|
||||
/// This includes the most common types in this crate, re-exported for your convenience.
|
||||
pub mod prelude {
|
||||
#[doc(hidden)]
|
||||
pub use crate::{FrameCountPlugin, TaskPoolOptions, TaskPoolPlugin, TypeRegistrationPlugin};
|
||||
}
|
||||
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_ecs::prelude::*;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use bevy_tasks::tick_global_task_pools_on_main_thread;
|
||||
|
||||
/// Registration of default types to the [`TypeRegistry`](bevy_reflect::TypeRegistry) resource.
|
||||
#[derive(Default)]
|
||||
pub struct TypeRegistrationPlugin;
|
||||
|
||||
impl Plugin for TypeRegistrationPlugin {
|
||||
#[cfg_attr(not(feature = "bevy_reflect"), allow(unused_variables))]
|
||||
fn build(&self, app: &mut App) {
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
app.register_type::<Name>();
|
||||
}
|
||||
}
|
||||
|
||||
/// Setup of default task pools: [`AsyncComputeTaskPool`](bevy_tasks::AsyncComputeTaskPool),
|
||||
/// [`ComputeTaskPool`](bevy_tasks::ComputeTaskPool), [`IoTaskPool`](bevy_tasks::IoTaskPool).
|
||||
#[derive(Default)]
|
||||
pub struct TaskPoolPlugin {
|
||||
/// Options for the [`TaskPool`](bevy_tasks::TaskPool) created at application start.
|
||||
pub task_pool_options: TaskPoolOptions,
|
||||
}
|
||||
|
||||
impl Plugin for TaskPoolPlugin {
|
||||
fn build(&self, _app: &mut App) {
|
||||
// Setup the default bevy task pools
|
||||
self.task_pool_options.create_default_pools();
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
_app.add_systems(Last, tick_global_task_pools);
|
||||
}
|
||||
}
|
||||
/// A dummy type that is [`!Send`](Send), to force systems to run on the main thread.
|
||||
pub struct NonSendMarker(PhantomData<*mut ()>);
|
||||
|
||||
/// A system used to check and advanced our task pools.
|
||||
///
|
||||
/// Calls [`tick_global_task_pools_on_main_thread`],
|
||||
/// and uses [`NonSendMarker`] to ensure that this system runs on the main thread
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn tick_global_task_pools(_main_thread_marker: Option<NonSend<NonSendMarker>>) {
|
||||
tick_global_task_pools_on_main_thread();
|
||||
}
|
||||
|
||||
/// Maintains a count of frames rendered since the start of the application.
|
||||
///
|
||||
/// [`FrameCount`] is incremented during [`Last`], providing predictable
|
||||
/// behavior: it will be 0 during the first update, 1 during the next, and so forth.
|
||||
///
|
||||
/// # Overflows
|
||||
///
|
||||
/// [`FrameCount`] will wrap to 0 after exceeding [`u32::MAX`]. Within reasonable
|
||||
/// assumptions, one may exploit wrapping arithmetic to determine the number of frames
|
||||
/// that have elapsed between two observations – see [`u32::wrapping_sub()`].
|
||||
#[derive(Debug, Default, Resource, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct FrameCount(pub u32);
|
||||
|
||||
/// Adds frame counting functionality to Apps.
|
||||
#[derive(Default)]
|
||||
pub struct FrameCountPlugin;
|
||||
|
||||
impl Plugin for FrameCountPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.init_resource::<FrameCount>();
|
||||
app.add_systems(Last, update_frame_count);
|
||||
}
|
||||
}
|
||||
|
||||
/// A system used to increment [`FrameCount`] with wrapping addition.
|
||||
///
|
||||
/// See [`FrameCount`] for more details.
|
||||
pub fn update_frame_count(mut frame_count: ResMut<FrameCount>) {
|
||||
frame_count.0 = frame_count.0.wrapping_add(1);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use bevy_tasks::prelude::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool};
|
||||
|
||||
#[test]
|
||||
fn runs_spawn_local_tasks() {
|
||||
let mut app = App::new();
|
||||
app.add_plugins((TaskPoolPlugin::default(), TypeRegistrationPlugin));
|
||||
|
||||
let (async_tx, async_rx) = crossbeam_channel::unbounded();
|
||||
AsyncComputeTaskPool::get()
|
||||
.spawn_local(async move {
|
||||
async_tx.send(()).unwrap();
|
||||
})
|
||||
.detach();
|
||||
|
||||
let (compute_tx, compute_rx) = crossbeam_channel::unbounded();
|
||||
ComputeTaskPool::get()
|
||||
.spawn_local(async move {
|
||||
compute_tx.send(()).unwrap();
|
||||
})
|
||||
.detach();
|
||||
|
||||
let (io_tx, io_rx) = crossbeam_channel::unbounded();
|
||||
IoTaskPool::get()
|
||||
.spawn_local(async move {
|
||||
io_tx.send(()).unwrap();
|
||||
})
|
||||
.detach();
|
||||
|
||||
app.run();
|
||||
|
||||
async_rx.try_recv().unwrap();
|
||||
compute_rx.try_recv().unwrap();
|
||||
io_rx.try_recv().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frame_counter_update() {
|
||||
let mut app = App::new();
|
||||
app.add_plugins((
|
||||
TaskPoolPlugin::default(),
|
||||
TypeRegistrationPlugin,
|
||||
FrameCountPlugin,
|
||||
));
|
||||
app.update();
|
||||
|
||||
let frame_count = app.world().resource::<FrameCount>();
|
||||
assert_eq!(1, frame_count.0);
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
use core::{
|
||||
any,
|
||||
fmt::{self, Formatter},
|
||||
};
|
||||
|
||||
use serde::{
|
||||
de::{Error, Visitor},
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
};
|
||||
|
||||
use super::FrameCount;
|
||||
|
||||
// Manually implementing serialize/deserialize allows us to use a more compact representation as simple integers
|
||||
impl Serialize for FrameCount {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
serializer.serialize_u32(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for FrameCount {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
deserializer.deserialize_u32(FrameVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct FrameVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for FrameVisitor {
|
||||
type Value = FrameCount;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||
formatter.write_str(any::type_name::<FrameCount>())
|
||||
}
|
||||
|
||||
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(FrameCount(v))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use serde_test::{assert_tokens, Token};
|
||||
|
||||
#[test]
|
||||
fn test_serde_frame_count() {
|
||||
let frame_count = FrameCount(100);
|
||||
assert_tokens(&frame_count, &[Token::U32(100)]);
|
||||
}
|
||||
}
|
@ -24,9 +24,9 @@ smaa_luts = ["bevy_render/ktx2", "bevy_image/ktx2", "bevy_image/zstd"]
|
||||
# bevy
|
||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev" }
|
||||
bevy_asset = { path = "../bevy_asset", version = "0.15.0-dev" }
|
||||
bevy_core = { path = "../bevy_core", version = "0.15.0-dev" }
|
||||
bevy_color = { path = "../bevy_color", version = "0.15.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }
|
||||
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.15.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
|
||||
bevy_image = { path = "../bevy_image", version = "0.15.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev" }
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_asset::{load_internal_asset, Handle};
|
||||
use bevy_core::FrameCount;
|
||||
use bevy_diagnostic::FrameCount;
|
||||
use bevy_ecs::{
|
||||
prelude::{require, Bundle, Component, Entity, ReflectComponent},
|
||||
query::{QueryItem, With},
|
||||
|
@ -12,17 +12,18 @@ keywords = ["bevy"]
|
||||
# Disables diagnostics that are unsupported when Bevy is dynamically linked
|
||||
dynamic_linking = []
|
||||
sysinfo_plugin = ["sysinfo"]
|
||||
serialize = ["dep:serde"]
|
||||
|
||||
[dependencies]
|
||||
# bevy
|
||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev" }
|
||||
bevy_core = { path = "../bevy_core", version = "0.15.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
|
||||
bevy_time = { path = "../bevy_time", version = "0.15.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.15.0-dev" }
|
||||
|
||||
const-fnv1a-hash = "1.1.0"
|
||||
serde = { version = "1.0", optional = true }
|
||||
|
||||
# macOS
|
||||
[target.'cfg(all(target_os="macos"))'.dependencies]
|
||||
@ -38,6 +39,9 @@ sysinfo = { version = "0.33.0", optional = true, default-features = false, featu
|
||||
"system",
|
||||
] }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_test = "1.0"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
|
101
crates/bevy_diagnostic/src/frame_count_diagnostics_plugin.rs
Normal file
101
crates/bevy_diagnostic/src/frame_count_diagnostics_plugin.rs
Normal file
@ -0,0 +1,101 @@
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_ecs::prelude::*;
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
use serde::{
|
||||
de::{Error, Visitor},
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
};
|
||||
|
||||
/// Maintains a count of frames rendered since the start of the application.
|
||||
///
|
||||
/// [`FrameCount`] is incremented during [`Last`], providing predictable
|
||||
/// behavior: it will be 0 during the first update, 1 during the next, and so forth.
|
||||
///
|
||||
/// # Overflows
|
||||
///
|
||||
/// [`FrameCount`] will wrap to 0 after exceeding [`u32::MAX`]. Within reasonable
|
||||
/// assumptions, one may exploit wrapping arithmetic to determine the number of frames
|
||||
/// that have elapsed between two observations – see [`u32::wrapping_sub()`].
|
||||
#[derive(Debug, Default, Resource, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct FrameCount(pub u32);
|
||||
|
||||
/// Adds frame counting functionality to Apps.
|
||||
#[derive(Default)]
|
||||
pub struct FrameCountPlugin;
|
||||
|
||||
impl Plugin for FrameCountPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.init_resource::<FrameCount>();
|
||||
app.add_systems(Last, update_frame_count);
|
||||
}
|
||||
}
|
||||
|
||||
/// A system used to increment [`FrameCount`] with wrapping addition.
|
||||
///
|
||||
/// See [`FrameCount`] for more details.
|
||||
pub fn update_frame_count(mut frame_count: ResMut<FrameCount>) {
|
||||
frame_count.0 = frame_count.0.wrapping_add(1);
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
// Manually implementing serialize/deserialize allows us to use a more compact representation as simple integers
|
||||
impl Serialize for FrameCount {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
serializer.serialize_u32(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
impl<'de> Deserialize<'de> for FrameCount {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
deserializer.deserialize_u32(FrameVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
struct FrameVisitor;
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
impl<'de> Visitor<'de> for FrameVisitor {
|
||||
type Value = FrameCount;
|
||||
|
||||
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
formatter.write_str(core::any::type_name::<FrameCount>())
|
||||
}
|
||||
|
||||
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(FrameCount(v))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn frame_counter_update() {
|
||||
let mut app = App::new();
|
||||
app.add_plugins(FrameCountPlugin);
|
||||
app.update();
|
||||
|
||||
let frame_count = app.world().resource::<FrameCount>();
|
||||
assert_eq!(1, frame_count.0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "serialize"))]
|
||||
mod serde_tests {
|
||||
use super::*;
|
||||
|
||||
use serde_test::{assert_tokens, Token};
|
||||
|
||||
#[test]
|
||||
fn test_serde_frame_count() {
|
||||
let frame_count = FrameCount(100);
|
||||
assert_tokens(&frame_count, &[Token::U32(100)]);
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
use crate::{Diagnostic, DiagnosticPath, Diagnostics, RegisterDiagnostic};
|
||||
use crate::{Diagnostic, DiagnosticPath, Diagnostics, FrameCount, RegisterDiagnostic};
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_core::FrameCount;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_time::{Real, Time};
|
||||
|
||||
|
@ -14,6 +14,7 @@ extern crate alloc;
|
||||
|
||||
mod diagnostic;
|
||||
mod entity_count_diagnostics_plugin;
|
||||
mod frame_count_diagnostics_plugin;
|
||||
mod frame_time_diagnostics_plugin;
|
||||
mod log_diagnostics_plugin;
|
||||
#[cfg(feature = "sysinfo_plugin")]
|
||||
@ -22,6 +23,7 @@ mod system_information_diagnostics_plugin;
|
||||
pub use diagnostic::*;
|
||||
|
||||
pub use entity_count_diagnostics_plugin::EntityCountDiagnosticsPlugin;
|
||||
pub use frame_count_diagnostics_plugin::{update_frame_count, FrameCount, FrameCountPlugin};
|
||||
pub use frame_time_diagnostics_plugin::FrameTimeDiagnosticsPlugin;
|
||||
pub use log_diagnostics_plugin::LogDiagnosticsPlugin;
|
||||
#[cfg(feature = "sysinfo_plugin")]
|
||||
|
@ -2,7 +2,6 @@ use alloc::{
|
||||
boxed::Box,
|
||||
collections::{btree_map, btree_set},
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use core::{
|
||||
@ -14,6 +13,12 @@ use core::{
|
||||
|
||||
use super::Entity;
|
||||
|
||||
#[cfg(feature = "portable-atomic")]
|
||||
use portable_atomic_util::Arc;
|
||||
|
||||
#[cfg(not(feature = "portable-atomic"))]
|
||||
use alloc::sync::Arc;
|
||||
|
||||
/// A trait for entity borrows.
|
||||
///
|
||||
/// This trait can be thought of as `Borrow<Entity>`, but yielding `Entity` directly.
|
||||
|
@ -45,7 +45,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
||||
reflect(Deserialize, Serialize)
|
||||
)]
|
||||
pub struct Name {
|
||||
hash: u64, // Won't be serialized (see: `bevy_core::serde` module)
|
||||
hash: u64, // Won't be serialized
|
||||
name: Cow<'static, str>,
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,19 @@
|
||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
use core::any::Any;
|
||||
use std::sync::{Mutex, MutexGuard};
|
||||
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use bevy_tasks::{ComputeTaskPool, Scope, TaskPool, ThreadExecutor};
|
||||
use bevy_utils::{default, syncunsafecell::SyncUnsafeCell};
|
||||
use core::panic::AssertUnwindSafe;
|
||||
use concurrent_queue::ConcurrentQueue;
|
||||
use core::{any::Any, panic::AssertUnwindSafe};
|
||||
use fixedbitset::FixedBitSet;
|
||||
use std::sync::{Mutex, MutexGuard};
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
use tracing::{info_span, Span};
|
||||
|
||||
use concurrent_queue::ConcurrentQueue;
|
||||
use fixedbitset::FixedBitSet;
|
||||
#[cfg(feature = "portable-atomic")]
|
||||
use portable_atomic_util::Arc;
|
||||
|
||||
#[cfg(not(feature = "portable-atomic"))]
|
||||
use alloc::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
archetype::ArchetypeComponentId,
|
||||
|
@ -22,7 +22,6 @@ bevy_animation = { path = "../bevy_animation", version = "0.15.0-dev", optional
|
||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev" }
|
||||
bevy_asset = { path = "../bevy_asset", version = "0.15.0-dev" }
|
||||
bevy_color = { path = "../bevy_color", version = "0.15.0-dev" }
|
||||
bevy_core = { path = "../bevy_core", version = "0.15.0-dev" }
|
||||
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.15.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
|
||||
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.15.0-dev" }
|
||||
|
@ -2260,7 +2260,7 @@ mod test {
|
||||
use std::path::Path;
|
||||
|
||||
use crate::{Gltf, GltfAssetLabel, GltfNode, GltfSkin};
|
||||
use bevy_app::App;
|
||||
use bevy_app::{App, TaskPoolPlugin};
|
||||
use bevy_asset::{
|
||||
io::{
|
||||
memory::{Dir, MemoryAssetReader},
|
||||
@ -2268,7 +2268,6 @@ mod test {
|
||||
},
|
||||
AssetApp, AssetPlugin, AssetServer, Assets, Handle, LoadState,
|
||||
};
|
||||
use bevy_core::TaskPoolPlugin;
|
||||
use bevy_ecs::{system::Resource, world::World};
|
||||
use bevy_log::LogPlugin;
|
||||
use bevy_render::mesh::{skinning::SkinnedMeshInverseBindposes, MeshPlugin};
|
||||
|
@ -11,13 +11,12 @@ keywords = ["bevy"]
|
||||
[features]
|
||||
default = ["bevy_app"]
|
||||
trace = []
|
||||
bevy_app = ["reflect", "dep:bevy_app", "bevy_core"]
|
||||
bevy_app = ["reflect", "dep:bevy_app"]
|
||||
reflect = ["bevy_ecs/bevy_reflect", "bevy_reflect"]
|
||||
|
||||
[dependencies]
|
||||
# bevy
|
||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev", optional = true }
|
||||
bevy_core = { path = "../bevy_core", version = "0.15.0-dev", optional = true }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev", default-features = false }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [
|
||||
"bevy",
|
||||
|
@ -21,7 +21,6 @@ serialize = ["serde", "smol_str/serde"]
|
||||
[dependencies]
|
||||
# bevy
|
||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev", default-features = false }
|
||||
bevy_core = { path = "../bevy_core", version = "0.15.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev", default-features = false, features = [
|
||||
"serialize",
|
||||
] }
|
||||
|
@ -88,7 +88,6 @@ shader_format_spirv = ["bevy_render/shader_format_spirv"]
|
||||
|
||||
serialize = [
|
||||
"bevy_color?/serialize",
|
||||
"bevy_core/serialize",
|
||||
"bevy_ecs/serialize",
|
||||
"bevy_input/serialize",
|
||||
"bevy_math/serialize",
|
||||
@ -264,7 +263,6 @@ ghost_nodes = ["bevy_ui/ghost_nodes"]
|
||||
# bevy
|
||||
bevy_a11y = { path = "../bevy_a11y", version = "0.15.0-dev", optional = true }
|
||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev" }
|
||||
bevy_core = { path = "../bevy_core", version = "0.15.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }
|
||||
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.15.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
|
||||
|
@ -5,9 +5,8 @@ plugin_group! {
|
||||
pub struct DefaultPlugins {
|
||||
bevy_app:::PanicHandlerPlugin,
|
||||
bevy_log:::LogPlugin,
|
||||
bevy_core:::TaskPoolPlugin,
|
||||
bevy_core:::TypeRegistrationPlugin,
|
||||
bevy_core:::FrameCountPlugin,
|
||||
bevy_app:::TaskPoolPlugin,
|
||||
bevy_diagnostic:::FrameCountPlugin,
|
||||
bevy_time:::TimePlugin,
|
||||
bevy_transform:::TransformPlugin,
|
||||
bevy_hierarchy:::HierarchyPlugin,
|
||||
@ -107,9 +106,8 @@ impl Plugin for IgnoreAmbiguitiesPlugin {
|
||||
plugin_group! {
|
||||
/// This plugin group will add the minimal plugins for a *Bevy* application:
|
||||
pub struct MinimalPlugins {
|
||||
bevy_core:::TaskPoolPlugin,
|
||||
bevy_core:::TypeRegistrationPlugin,
|
||||
bevy_core:::FrameCountPlugin,
|
||||
bevy_app:::TaskPoolPlugin,
|
||||
bevy_diagnostic:::FrameCountPlugin,
|
||||
bevy_time:::TimePlugin,
|
||||
bevy_app:::ScheduleRunnerPlugin,
|
||||
#[cfg(feature = "bevy_ci_testing")]
|
||||
|
@ -24,7 +24,6 @@ pub use bevy_asset as asset;
|
||||
pub use bevy_audio as audio;
|
||||
#[cfg(feature = "bevy_color")]
|
||||
pub use bevy_color as color;
|
||||
pub use bevy_core as core;
|
||||
#[cfg(feature = "bevy_core_pipeline")]
|
||||
pub use bevy_core_pipeline as core_pipeline;
|
||||
#[cfg(feature = "bevy_dev_tools")]
|
||||
|
@ -1,8 +1,8 @@
|
||||
#[doc(hidden)]
|
||||
pub use crate::{
|
||||
app::prelude::*, core::prelude::*, ecs::prelude::*, hierarchy::prelude::*, input::prelude::*,
|
||||
log::prelude::*, math::prelude::*, reflect::prelude::*, time::prelude::*,
|
||||
transform::prelude::*, utils::prelude::*, DefaultPlugins, MinimalPlugins,
|
||||
app::prelude::*, ecs::prelude::*, hierarchy::prelude::*, input::prelude::*, log::prelude::*,
|
||||
math::prelude::*, reflect::prelude::*, time::prelude::*, transform::prelude::*,
|
||||
utils::prelude::*, DefaultPlugins, MinimalPlugins,
|
||||
};
|
||||
|
||||
#[doc(hidden)]
|
||||
|
@ -40,7 +40,6 @@ bevy_color = { path = "../bevy_color", version = "0.15.0-dev", features = [
|
||||
"serialize",
|
||||
"wgpu-types",
|
||||
] }
|
||||
bevy_core = { path = "../bevy_core", version = "0.15.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }
|
||||
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.15.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
|
||||
|
@ -7,7 +7,7 @@ use crate::{
|
||||
};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_asset::{load_internal_asset, Handle};
|
||||
use bevy_core::FrameCount;
|
||||
use bevy_diagnostic::FrameCount;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_reflect::prelude::*;
|
||||
use bevy_time::Time;
|
||||
|
@ -308,7 +308,7 @@ pub fn create_surfaces(
|
||||
// By accessing a NonSend resource, we tell the scheduler to put this system on the main thread,
|
||||
// which is necessary for some OS's
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))] _marker: Option<
|
||||
NonSend<bevy_core::NonSendMarker>,
|
||||
NonSend<bevy_app::NonSendMarker>,
|
||||
>,
|
||||
windows: Res<ExtractedWindows>,
|
||||
mut window_surfaces: ResMut<WindowSurfaces>,
|
||||
|
@ -1,4 +1,3 @@
|
||||
use alloc::sync::Arc;
|
||||
use core::{future::Future, marker::PhantomData, mem, panic::AssertUnwindSafe};
|
||||
use std::thread::{self, JoinHandle};
|
||||
|
||||
@ -6,6 +5,12 @@ use crate::executor::FallibleTask;
|
||||
use concurrent_queue::ConcurrentQueue;
|
||||
use futures_lite::FutureExt;
|
||||
|
||||
#[cfg(feature = "portable-atomic")]
|
||||
use {alloc::boxed::Box, portable_atomic_util::Arc};
|
||||
|
||||
#[cfg(not(feature = "portable-atomic"))]
|
||||
use alloc::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
block_on,
|
||||
thread_executor::{ThreadExecutor, ThreadExecutorTicker},
|
||||
@ -70,7 +75,17 @@ impl TaskPoolBuilder {
|
||||
/// This is called on the thread itself and has access to all thread-local storage.
|
||||
/// This will block running async tasks on the thread until the callback completes.
|
||||
pub fn on_thread_spawn(mut self, f: impl Fn() + Send + Sync + 'static) -> Self {
|
||||
self.on_thread_spawn = Some(Arc::new(f));
|
||||
#[cfg(feature = "portable-atomic")]
|
||||
let arc = {
|
||||
let boxed = Box::new(f);
|
||||
let boxed: Box<dyn Fn() + Send + Sync + 'static> = boxed;
|
||||
Arc::from(boxed)
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "portable-atomic"))]
|
||||
let arc = Arc::new(f);
|
||||
|
||||
self.on_thread_spawn = Some(arc);
|
||||
self
|
||||
}
|
||||
|
||||
@ -79,7 +94,17 @@ impl TaskPoolBuilder {
|
||||
/// This is called on the thread itself and has access to all thread-local storage.
|
||||
/// This will block thread termination until the callback completes.
|
||||
pub fn on_thread_destroy(mut self, f: impl Fn() + Send + Sync + 'static) -> Self {
|
||||
self.on_thread_destroy = Some(Arc::new(f));
|
||||
#[cfg(feature = "portable-atomic")]
|
||||
let arc = {
|
||||
let boxed = Box::new(f);
|
||||
let boxed: Box<dyn Fn() + Send + Sync + 'static> = boxed;
|
||||
Arc::from(boxed)
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "portable-atomic"))]
|
||||
let arc = Arc::new(f);
|
||||
|
||||
self.on_thread_destroy = Some(arc);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ taskpool! {
|
||||
(IO_TASK_POOL, IoTaskPool)
|
||||
}
|
||||
|
||||
/// A function used by `bevy_core` to tick the global tasks pools on the main thread.
|
||||
/// A function used by `bevy_app` to tick the global tasks pools on the main thread.
|
||||
/// This will run a maximum of 100 local tasks per executor per call to this function.
|
||||
///
|
||||
/// # Warning
|
||||
|
@ -19,7 +19,7 @@
|
||||
//!
|
||||
//! Let's look at an example of each.
|
||||
|
||||
use bevy::{core::FrameCount, ecs::event::EventCursor, prelude::*};
|
||||
use bevy::{diagnostic::FrameCount, ecs::event::EventCursor, prelude::*};
|
||||
|
||||
fn main() {
|
||||
let mut app = App::new();
|
||||
|
@ -4,8 +4,7 @@
|
||||
#[cfg(feature = "custom_cursor")]
|
||||
use bevy::winit::cursor::CustomCursor;
|
||||
use bevy::{
|
||||
core::FrameCount,
|
||||
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||
diagnostic::{FrameCount, FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||
prelude::*,
|
||||
window::{CursorGrabMode, PresentMode, SystemCursorIcon, WindowLevel, WindowTheme},
|
||||
winit::cursor::CursorIcon,
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! A test to confirm that `bevy` allows minimizing the window
|
||||
//! This is run in CI to ensure that this doesn't regress again.
|
||||
use bevy::{core::FrameCount, prelude::*};
|
||||
use bevy::{diagnostic::FrameCount, prelude::*};
|
||||
|
||||
fn main() {
|
||||
// TODO: Combine this with `resizing` once multiple_windows is simpler than
|
||||
|
@ -19,7 +19,6 @@ crates=(
|
||||
bevy_asset/macros
|
||||
bevy_asset
|
||||
bevy_audio
|
||||
bevy_core
|
||||
bevy_diagnostic
|
||||
bevy_hierarchy
|
||||
bevy_transform
|
||||
|
Loading…
Reference in New Issue
Block a user