refactor(render): move WgpuWrapper into bevy_utils (#19303)
# Objective - A step towards splitting out bevy_camera from bevy_render ## Solution - Move a shim type into bevy_utils to avoid a dependency cycle - Manually expand Deref/DerefMut to avoid having a bevy_derive dependency so early in the dep tree ## Testing - It compiles
This commit is contained in:
parent
7d32dfec18
commit
1732c2253b
@ -65,7 +65,9 @@ bevy_render_macros = { path = "macros", version = "0.16.0-dev" }
|
|||||||
bevy_time = { path = "../bevy_time", version = "0.16.0-dev" }
|
bevy_time = { path = "../bevy_time", version = "0.16.0-dev" }
|
||||||
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
|
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
|
||||||
bevy_window = { path = "../bevy_window", version = "0.16.0-dev" }
|
bevy_window = { path = "../bevy_window", version = "0.16.0-dev" }
|
||||||
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
|
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", features = [
|
||||||
|
"wgpu_wrapper",
|
||||||
|
] }
|
||||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev" }
|
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev" }
|
||||||
bevy_image = { path = "../bevy_image", version = "0.16.0-dev" }
|
bevy_image = { path = "../bevy_image", version = "0.16.0-dev" }
|
||||||
bevy_mesh = { path = "../bevy_mesh", version = "0.16.0-dev" }
|
bevy_mesh = { path = "../bevy_mesh", version = "0.16.0-dev" }
|
||||||
@ -151,9 +153,6 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-featu
|
|||||||
"web",
|
"web",
|
||||||
] }
|
] }
|
||||||
|
|
||||||
[target.'cfg(all(target_arch = "wasm32", target_feature = "atomics"))'.dependencies]
|
|
||||||
send_wrapper = "0.6.0"
|
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
|
@ -15,7 +15,8 @@ use wgpu::{
|
|||||||
PipelineStatisticsTypes, QuerySet, QuerySetDescriptor, QueryType, RenderPass,
|
PipelineStatisticsTypes, QuerySet, QuerySetDescriptor, QueryType, RenderPass,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::renderer::{RenderAdapterInfo, RenderDevice, RenderQueue, WgpuWrapper};
|
use crate::renderer::{RenderAdapterInfo, RenderDevice, RenderQueue};
|
||||||
|
use bevy_utils::WgpuWrapper;
|
||||||
|
|
||||||
use super::RecordDiagnostics;
|
use super::RecordDiagnostics;
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ use crate::{
|
|||||||
mesh::{MeshPlugin, MorphPlugin, RenderMesh},
|
mesh::{MeshPlugin, MorphPlugin, RenderMesh},
|
||||||
render_asset::prepare_assets,
|
render_asset::prepare_assets,
|
||||||
render_resource::{PipelineCache, Shader, ShaderLoader},
|
render_resource::{PipelineCache, Shader, ShaderLoader},
|
||||||
renderer::{render_system, RenderInstance, WgpuWrapper},
|
renderer::{render_system, RenderInstance},
|
||||||
settings::RenderCreation,
|
settings::RenderCreation,
|
||||||
storage::StoragePlugin,
|
storage::StoragePlugin,
|
||||||
view::{ViewPlugin, WindowRenderPlugin},
|
view::{ViewPlugin, WindowRenderPlugin},
|
||||||
@ -112,6 +112,7 @@ use alloc::sync::Arc;
|
|||||||
use bevy_app::{App, AppLabel, Plugin, SubApp};
|
use bevy_app::{App, AppLabel, Plugin, SubApp};
|
||||||
use bevy_asset::{AssetApp, AssetServer};
|
use bevy_asset::{AssetApp, AssetServer};
|
||||||
use bevy_ecs::{prelude::*, schedule::ScheduleLabel};
|
use bevy_ecs::{prelude::*, schedule::ScheduleLabel};
|
||||||
|
use bevy_utils::WgpuWrapper;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use crate::renderer::WgpuWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
define_atomic_id,
|
define_atomic_id,
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
@ -9,6 +8,7 @@ use crate::{
|
|||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
use bevy_ecs::system::{SystemParam, SystemParamItem};
|
use bevy_ecs::system::{SystemParam, SystemParamItem};
|
||||||
pub use bevy_render_macros::AsBindGroup;
|
pub use bevy_render_macros::AsBindGroup;
|
||||||
|
use bevy_utils::WgpuWrapper;
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
use encase::ShaderType;
|
use encase::ShaderType;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::define_atomic_id;
|
use crate::define_atomic_id;
|
||||||
use crate::renderer::WgpuWrapper;
|
use bevy_utils::WgpuWrapper;
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
|
|
||||||
define_atomic_id!(BindGroupLayoutId);
|
define_atomic_id!(BindGroupLayoutId);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::define_atomic_id;
|
use crate::define_atomic_id;
|
||||||
use crate::renderer::WgpuWrapper;
|
use bevy_utils::WgpuWrapper;
|
||||||
use core::ops::{Bound, Deref, RangeBounds};
|
use core::ops::{Bound, Deref, RangeBounds};
|
||||||
|
|
||||||
define_atomic_id!(BufferId);
|
define_atomic_id!(BufferId);
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use super::ShaderDefVal;
|
use super::ShaderDefVal;
|
||||||
use crate::mesh::VertexBufferLayout;
|
use crate::mesh::VertexBufferLayout;
|
||||||
use crate::renderer::WgpuWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
define_atomic_id,
|
define_atomic_id,
|
||||||
render_resource::{BindGroupLayout, Shader},
|
render_resource::{BindGroupLayout, Shader},
|
||||||
};
|
};
|
||||||
use alloc::borrow::Cow;
|
use alloc::borrow::Cow;
|
||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
|
use bevy_utils::WgpuWrapper;
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
ColorTargetState, DepthStencilState, MultisampleState, PrimitiveState, PushConstantRange,
|
ColorTargetState, DepthStencilState, MultisampleState, PrimitiveState, PushConstantRange,
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use crate::renderer::WgpuWrapper;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
render_resource::*,
|
render_resource::*,
|
||||||
renderer::{RenderAdapter, RenderDevice},
|
renderer::{RenderAdapter, RenderDevice},
|
||||||
@ -14,6 +13,7 @@ use bevy_ecs::{
|
|||||||
use bevy_platform::collections::{hash_map::EntryRef, HashMap, HashSet};
|
use bevy_platform::collections::{hash_map::EntryRef, HashMap, HashSet};
|
||||||
use bevy_tasks::Task;
|
use bevy_tasks::Task;
|
||||||
use bevy_utils::default;
|
use bevy_utils::default;
|
||||||
|
use bevy_utils::WgpuWrapper;
|
||||||
use core::{future::Future, hash::Hash, mem, ops::Deref};
|
use core::{future::Future, hash::Hash, mem, ops::Deref};
|
||||||
use naga::valid::Capabilities;
|
use naga::valid::Capabilities;
|
||||||
use std::sync::{Mutex, PoisonError};
|
use std::sync::{Mutex, PoisonError};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::define_atomic_id;
|
use crate::define_atomic_id;
|
||||||
use crate::renderer::WgpuWrapper;
|
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
use bevy_ecs::resource::Resource;
|
use bevy_ecs::resource::Resource;
|
||||||
|
use bevy_utils::WgpuWrapper;
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
|
|
||||||
define_atomic_id!(TextureId);
|
define_atomic_id!(TextureId);
|
||||||
|
@ -4,6 +4,7 @@ mod render_device;
|
|||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
||||||
use bevy_tasks::ComputeTaskPool;
|
use bevy_tasks::ComputeTaskPool;
|
||||||
|
use bevy_utils::WgpuWrapper;
|
||||||
pub use graph_runner::*;
|
pub use graph_runner::*;
|
||||||
pub use render_device::*;
|
pub use render_device::*;
|
||||||
use tracing::{error, info, info_span, warn};
|
use tracing::{error, info, info_span, warn};
|
||||||
@ -120,46 +121,6 @@ pub fn render_system(world: &mut World, state: &mut SystemState<Query<Entity, Wi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper to safely make `wgpu` types Send / Sync on web with atomics enabled.
|
|
||||||
///
|
|
||||||
/// On web with `atomics` enabled the inner value can only be accessed
|
|
||||||
/// or dropped on the `wgpu` thread or else a panic will occur.
|
|
||||||
/// On other platforms the wrapper simply contains the wrapped value.
|
|
||||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
|
||||||
#[derive(Debug, Clone, Deref, DerefMut)]
|
|
||||||
pub struct WgpuWrapper<T>(T);
|
|
||||||
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
|
||||||
#[derive(Debug, Clone, Deref, DerefMut)]
|
|
||||||
pub struct WgpuWrapper<T>(send_wrapper::SendWrapper<T>);
|
|
||||||
|
|
||||||
// SAFETY: SendWrapper is always Send + Sync.
|
|
||||||
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
|
||||||
unsafe impl<T> Send for WgpuWrapper<T> {}
|
|
||||||
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
|
||||||
unsafe impl<T> Sync for WgpuWrapper<T> {}
|
|
||||||
|
|
||||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
|
||||||
impl<T> WgpuWrapper<T> {
|
|
||||||
pub fn new(t: T) -> Self {
|
|
||||||
Self(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_inner(self) -> T {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
|
||||||
impl<T> WgpuWrapper<T> {
|
|
||||||
pub fn new(t: T) -> Self {
|
|
||||||
Self(send_wrapper::SendWrapper::new(t))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_inner(self) -> T {
|
|
||||||
self.0.take()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This queue is used to enqueue tasks for the GPU to execute asynchronously.
|
/// This queue is used to enqueue tasks for the GPU to execute asynchronously.
|
||||||
#[derive(Resource, Clone, Deref, DerefMut)]
|
#[derive(Resource, Clone, Deref, DerefMut)]
|
||||||
pub struct RenderQueue(pub Arc<WgpuWrapper<Queue>>);
|
pub struct RenderQueue(pub Arc<WgpuWrapper<Queue>>);
|
||||||
|
@ -3,8 +3,8 @@ use crate::render_resource::{
|
|||||||
BindGroup, BindGroupLayout, Buffer, ComputePipeline, RawRenderPipelineDescriptor,
|
BindGroup, BindGroupLayout, Buffer, ComputePipeline, RawRenderPipelineDescriptor,
|
||||||
RenderPipeline, Sampler, Texture,
|
RenderPipeline, Sampler, Texture,
|
||||||
};
|
};
|
||||||
use crate::WgpuWrapper;
|
|
||||||
use bevy_ecs::resource::Resource;
|
use bevy_ecs::resource::Resource;
|
||||||
|
use bevy_utils::WgpuWrapper;
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
util::DeviceExt, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor,
|
util::DeviceExt, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor,
|
||||||
BindGroupLayoutEntry, BufferAsyncError, BufferBindingType, MaintainResult,
|
BindGroupLayoutEntry, BufferAsyncError, BufferBindingType, MaintainResult,
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
render_resource::{SurfaceTexture, TextureView},
|
render_resource::{SurfaceTexture, TextureView},
|
||||||
renderer::{RenderAdapter, RenderDevice, RenderInstance},
|
renderer::{RenderAdapter, RenderDevice, RenderInstance},
|
||||||
Extract, ExtractSchedule, Render, RenderApp, RenderSystems, WgpuWrapper,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSystems,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::{entity::EntityHashMap, prelude::*};
|
use bevy_ecs::{entity::EntityHashMap, prelude::*};
|
||||||
use bevy_platform::collections::HashSet;
|
use bevy_platform::collections::HashSet;
|
||||||
use bevy_utils::default;
|
use bevy_utils::default;
|
||||||
|
use bevy_utils::WgpuWrapper;
|
||||||
use bevy_window::{
|
use bevy_window::{
|
||||||
CompositeAlphaMode, PresentMode, PrimaryWindow, RawHandleWrapper, Window, WindowClosing,
|
CompositeAlphaMode, PresentMode, PrimaryWindow, RawHandleWrapper, Window, WindowClosing,
|
||||||
};
|
};
|
||||||
|
@ -11,6 +11,8 @@ keywords = ["bevy"]
|
|||||||
[features]
|
[features]
|
||||||
default = ["parallel"]
|
default = ["parallel"]
|
||||||
|
|
||||||
|
wgpu_wrapper = ["dep:send_wrapper"]
|
||||||
|
|
||||||
# Provides access to the `Parallel` type.
|
# Provides access to the `Parallel` type.
|
||||||
parallel = ["bevy_platform/std", "dep:thread_local"]
|
parallel = ["bevy_platform/std", "dep:thread_local"]
|
||||||
|
|
||||||
@ -19,6 +21,9 @@ bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-fea
|
|||||||
|
|
||||||
thread_local = { version = "1.0", optional = true }
|
thread_local = { version = "1.0", optional = true }
|
||||||
|
|
||||||
|
[target.'cfg(all(target_arch = "wasm32", target_feature = "atomics"))'.dependencies]
|
||||||
|
send_wrapper = { version = "0.6.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
static_assertions = "1.1.0"
|
static_assertions = "1.1.0"
|
||||||
|
|
||||||
|
@ -48,6 +48,8 @@ pub mod prelude {
|
|||||||
|
|
||||||
pub mod synccell;
|
pub mod synccell;
|
||||||
pub mod syncunsafecell;
|
pub mod syncunsafecell;
|
||||||
|
#[cfg(feature = "wgpu_wrapper")]
|
||||||
|
mod wgpu_wrapper;
|
||||||
|
|
||||||
mod default;
|
mod default;
|
||||||
mod once;
|
mod once;
|
||||||
@ -57,6 +59,9 @@ pub use once::OnceFlag;
|
|||||||
|
|
||||||
pub use default::default;
|
pub use default::default;
|
||||||
|
|
||||||
|
#[cfg(feature = "wgpu_wrapper")]
|
||||||
|
pub use wgpu_wrapper::WgpuWrapper;
|
||||||
|
|
||||||
use core::mem::ManuallyDrop;
|
use core::mem::ManuallyDrop;
|
||||||
|
|
||||||
/// A type which calls a function when dropped.
|
/// A type which calls a function when dropped.
|
||||||
|
50
crates/bevy_utils/src/wgpu_wrapper.rs
Normal file
50
crates/bevy_utils/src/wgpu_wrapper.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/// A wrapper to safely make `wgpu` types Send / Sync on web with atomics enabled.
|
||||||
|
///
|
||||||
|
/// On web with `atomics` enabled the inner value can only be accessed
|
||||||
|
/// or dropped on the `wgpu` thread or else a panic will occur.
|
||||||
|
/// On other platforms the wrapper simply contains the wrapped value.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct WgpuWrapper<T>(
|
||||||
|
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))] T,
|
||||||
|
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))] send_wrapper::SendWrapper<T>,
|
||||||
|
);
|
||||||
|
|
||||||
|
// SAFETY: SendWrapper is always Send + Sync.
|
||||||
|
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
||||||
|
#[expect(unsafe_code, reason = "Blanket-impl Send requires unsafe.")]
|
||||||
|
unsafe impl<T> Send for WgpuWrapper<T> {}
|
||||||
|
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
||||||
|
#[expect(unsafe_code, reason = "Blanket-impl Sync requires unsafe.")]
|
||||||
|
unsafe impl<T> Sync for WgpuWrapper<T> {}
|
||||||
|
|
||||||
|
impl<T> WgpuWrapper<T> {
|
||||||
|
/// Constructs a new instance of `WgpuWrapper` which will wrap the specified value.
|
||||||
|
pub fn new(t: T) -> Self {
|
||||||
|
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
||||||
|
return Self(t);
|
||||||
|
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
||||||
|
return Self(send_wrapper::SendWrapper::new(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unwraps the value.
|
||||||
|
pub fn into_inner(self) -> T {
|
||||||
|
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
||||||
|
return self.0;
|
||||||
|
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
||||||
|
return self.0.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> core::ops::Deref for WgpuWrapper<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> core::ops::DerefMut for WgpuWrapper<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user