Create new NonSendMarker
(#18301)
# Objective Create new `NonSendMarker` that does not depend on `NonSend`. Required, in order to accomplish #17682. In that issue, we are trying to replace `!Send` resources with `thread_local!` in order to unblock the resources-as-components effort. However, when we remove all the `!Send` resources from a system, that allows the system to run on a thread other than the main thread, which is against the design of the system. So this marker gives us the control to require a system to run on the main thread without depending on `!Send` resources. ## Solution Create a new `NonSendMarker` to replace the existing one that does not depend on `NonSend`. ## Testing Other than running tests, I ran a few examples: - `window_resizing` - `wireframe` - `volumetric_fog` (looks so cool) - `rotation` - `button` There is a Mac/iOS-specific change and I do not have a Mac or iOS device to test it. I am doubtful that it would cause any problems for 2 reasons: 1. The change is the same as the non-wasm change which I did test 2. The Pixel Eagle tests run Mac tests But it wouldn't hurt if someone wanted to spin up an example that utilizes the `bevy_render` crate, which is where the Mac/iSO change was. ## Migration Guide If `NonSendMarker` is being used from `bevy_app::prelude::*`, replace it with `bevy_ecs::system::NonSendMarker` or use it from `bevy_ecs::prelude::*`. In addition to that, `NonSendMarker` does not need to be wrapped like so: ```rust fn my_system(_non_send_marker: Option<NonSend<NonSendMarker>>) { ... } ``` Instead, it can be used without any wrappers: ```rust fn my_system(_non_send_marker: NonSendMarker) { ... } ``` --------- Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
This commit is contained in:
parent
694db96ab8
commit
8d9f948684
@ -58,6 +58,6 @@ pub mod prelude {
|
|||||||
RunFixedMainLoopSystem, SpawnScene, Startup, Update,
|
RunFixedMainLoopSystem, SpawnScene, Startup, Update,
|
||||||
},
|
},
|
||||||
sub_app::SubApp,
|
sub_app::SubApp,
|
||||||
NonSendMarker, Plugin, PluginGroup, TaskPoolOptions, TaskPoolPlugin,
|
Plugin, PluginGroup, TaskPoolOptions, TaskPoolPlugin,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -3,18 +3,19 @@ use crate::{App, Plugin};
|
|||||||
use alloc::string::ToString;
|
use alloc::string::ToString;
|
||||||
use bevy_platform_support::sync::Arc;
|
use bevy_platform_support::sync::Arc;
|
||||||
use bevy_tasks::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool, TaskPoolBuilder};
|
use bevy_tasks::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool, TaskPoolBuilder};
|
||||||
use core::{fmt::Debug, marker::PhantomData};
|
use core::fmt::Debug;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(not(all(target_arch = "wasm32", feature = "web")))] {
|
if #[cfg(not(all(target_arch = "wasm32", feature = "web")))] {
|
||||||
use {crate::Last, bevy_ecs::prelude::NonSend, bevy_tasks::tick_global_task_pools_on_main_thread};
|
use {crate::Last, bevy_tasks::tick_global_task_pools_on_main_thread};
|
||||||
|
use bevy_ecs::system::NonSendMarker;
|
||||||
|
|
||||||
/// A system used to check and advanced our task pools.
|
/// A system used to check and advanced our task pools.
|
||||||
///
|
///
|
||||||
/// Calls [`tick_global_task_pools_on_main_thread`],
|
/// Calls [`tick_global_task_pools_on_main_thread`],
|
||||||
/// and uses [`NonSendMarker`] to ensure that this system runs on the main thread
|
/// and uses [`NonSendMarker`] to ensure that this system runs on the main thread
|
||||||
fn tick_global_task_pools(_main_thread_marker: Option<NonSend<NonSendMarker>>) {
|
fn tick_global_task_pools(_main_thread_marker: NonSendMarker) {
|
||||||
tick_global_task_pools_on_main_thread();
|
tick_global_task_pools_on_main_thread();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,8 +37,6 @@ impl Plugin for TaskPoolPlugin {
|
|||||||
_app.add_systems(Last, tick_global_task_pools);
|
_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 ()>);
|
|
||||||
|
|
||||||
/// Defines a simple way to determine how many threads to use given the number of remaining cores
|
/// Defines a simple way to determine how many threads to use given the number of remaining cores
|
||||||
/// and number of total cores
|
/// and number of total cores
|
||||||
|
@ -91,8 +91,8 @@ pub mod prelude {
|
|||||||
spawn::{Spawn, SpawnRelated},
|
spawn::{Spawn, SpawnRelated},
|
||||||
system::{
|
system::{
|
||||||
Command, Commands, Deferred, EntityCommand, EntityCommands, In, InMut, InRef,
|
Command, Commands, Deferred, EntityCommand, EntityCommands, In, InMut, InRef,
|
||||||
IntoSystem, Local, NonSend, NonSendMut, ParamSet, Populated, Query, ReadOnlySystem,
|
IntoSystem, Local, NonSend, NonSendMarker, NonSendMut, ParamSet, Populated, Query,
|
||||||
Res, ResMut, Single, System, SystemIn, SystemInput, SystemParamBuilder,
|
ReadOnlySystem, Res, ResMut, Single, System, SystemIn, SystemInput, SystemParamBuilder,
|
||||||
SystemParamFunction, WithParamWarnPolicy,
|
SystemParamFunction, WithParamWarnPolicy,
|
||||||
},
|
},
|
||||||
world::{
|
world::{
|
||||||
|
@ -1420,6 +1420,33 @@ unsafe impl<T: SystemBuffer> SystemParam for Deferred<'_, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A dummy type that is [`!Send`](Send), to force systems to run on the main thread.
|
||||||
|
pub struct NonSendMarker;
|
||||||
|
|
||||||
|
// SAFETY: No world access.
|
||||||
|
unsafe impl SystemParam for NonSendMarker {
|
||||||
|
type State = ();
|
||||||
|
type Item<'w, 's> = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn init_state(_world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
|
||||||
|
system_meta.set_non_send();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn get_param<'world, 'state>(
|
||||||
|
_state: &'state mut Self::State,
|
||||||
|
_system_meta: &SystemMeta,
|
||||||
|
_world: UnsafeWorldCell<'world>,
|
||||||
|
_change_tick: Tick,
|
||||||
|
) -> Self::Item<'world, 'state> {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: Does not read any world state
|
||||||
|
unsafe impl ReadOnlySystemParam for NonSendMarker {}
|
||||||
|
|
||||||
/// Shared borrow of a non-[`Send`] resource.
|
/// Shared borrow of a non-[`Send`] resource.
|
||||||
///
|
///
|
||||||
/// Only `Send` resources may be accessed with the [`Res`] [`SystemParam`]. In case that the
|
/// Only `Send` resources may be accessed with the [`Res`] [`SystemParam`]. In case that the
|
||||||
|
@ -304,9 +304,7 @@ const DEFAULT_DESIRED_MAXIMUM_FRAME_LATENCY: u32 = 2;
|
|||||||
pub fn create_surfaces(
|
pub fn create_surfaces(
|
||||||
// By accessing a NonSend resource, we tell the scheduler to put this system on the main thread,
|
// By accessing a NonSend resource, we tell the scheduler to put this system on the main thread,
|
||||||
// which is necessary for some OS's
|
// which is necessary for some OS's
|
||||||
#[cfg(any(target_os = "macos", target_os = "ios"))] _marker: Option<
|
#[cfg(any(target_os = "macos", target_os = "ios"))] _marker: NonSendMarker,
|
||||||
NonSend<bevy_app::NonSendMarker>,
|
|
||||||
>,
|
|
||||||
windows: Res<ExtractedWindows>,
|
windows: Res<ExtractedWindows>,
|
||||||
mut window_surfaces: ResMut<WindowSurfaces>,
|
mut window_surfaces: ResMut<WindowSurfaces>,
|
||||||
render_instance: Res<RenderInstance>,
|
render_instance: Res<RenderInstance>,
|
||||||
|
Loading…
Reference in New Issue
Block a user