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_transform = { path = "../bevy_transform", 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_image = { path = "../bevy_image", 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",
|
||||
] }
|
||||
|
||||
[target.'cfg(all(target_arch = "wasm32", target_feature = "atomics"))'.dependencies]
|
||||
send_wrapper = "0.6.0"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
|
@ -15,7 +15,8 @@ use wgpu::{
|
||||
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;
|
||||
|
||||
|
@ -103,7 +103,7 @@ use crate::{
|
||||
mesh::{MeshPlugin, MorphPlugin, RenderMesh},
|
||||
render_asset::prepare_assets,
|
||||
render_resource::{PipelineCache, Shader, ShaderLoader},
|
||||
renderer::{render_system, RenderInstance, WgpuWrapper},
|
||||
renderer::{render_system, RenderInstance},
|
||||
settings::RenderCreation,
|
||||
storage::StoragePlugin,
|
||||
view::{ViewPlugin, WindowRenderPlugin},
|
||||
@ -112,6 +112,7 @@ use alloc::sync::Arc;
|
||||
use bevy_app::{App, AppLabel, Plugin, SubApp};
|
||||
use bevy_asset::{AssetApp, AssetServer};
|
||||
use bevy_ecs::{prelude::*, schedule::ScheduleLabel};
|
||||
use bevy_utils::WgpuWrapper;
|
||||
use bitflags::bitflags;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use std::sync::Mutex;
|
||||
|
@ -1,4 +1,3 @@
|
||||
use crate::renderer::WgpuWrapper;
|
||||
use crate::{
|
||||
define_atomic_id,
|
||||
render_asset::RenderAssets,
|
||||
@ -9,6 +8,7 @@ use crate::{
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::system::{SystemParam, SystemParamItem};
|
||||
pub use bevy_render_macros::AsBindGroup;
|
||||
use bevy_utils::WgpuWrapper;
|
||||
use core::ops::Deref;
|
||||
use encase::ShaderType;
|
||||
use thiserror::Error;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::define_atomic_id;
|
||||
use crate::renderer::WgpuWrapper;
|
||||
use bevy_utils::WgpuWrapper;
|
||||
use core::ops::Deref;
|
||||
|
||||
define_atomic_id!(BindGroupLayoutId);
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::define_atomic_id;
|
||||
use crate::renderer::WgpuWrapper;
|
||||
use bevy_utils::WgpuWrapper;
|
||||
use core::ops::{Bound, Deref, RangeBounds};
|
||||
|
||||
define_atomic_id!(BufferId);
|
||||
|
@ -1,12 +1,12 @@
|
||||
use super::ShaderDefVal;
|
||||
use crate::mesh::VertexBufferLayout;
|
||||
use crate::renderer::WgpuWrapper;
|
||||
use crate::{
|
||||
define_atomic_id,
|
||||
render_resource::{BindGroupLayout, Shader},
|
||||
};
|
||||
use alloc::borrow::Cow;
|
||||
use bevy_asset::Handle;
|
||||
use bevy_utils::WgpuWrapper;
|
||||
use core::ops::Deref;
|
||||
use wgpu::{
|
||||
ColorTargetState, DepthStencilState, MultisampleState, PrimitiveState, PushConstantRange,
|
||||
|
@ -1,4 +1,3 @@
|
||||
use crate::renderer::WgpuWrapper;
|
||||
use crate::{
|
||||
render_resource::*,
|
||||
renderer::{RenderAdapter, RenderDevice},
|
||||
@ -14,6 +13,7 @@ use bevy_ecs::{
|
||||
use bevy_platform::collections::{hash_map::EntryRef, HashMap, HashSet};
|
||||
use bevy_tasks::Task;
|
||||
use bevy_utils::default;
|
||||
use bevy_utils::WgpuWrapper;
|
||||
use core::{future::Future, hash::Hash, mem, ops::Deref};
|
||||
use naga::valid::Capabilities;
|
||||
use std::sync::{Mutex, PoisonError};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::define_atomic_id;
|
||||
use crate::renderer::WgpuWrapper;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::resource::Resource;
|
||||
use bevy_utils::WgpuWrapper;
|
||||
use core::ops::Deref;
|
||||
|
||||
define_atomic_id!(TextureId);
|
||||
|
@ -4,6 +4,7 @@ mod render_device;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
||||
use bevy_tasks::ComputeTaskPool;
|
||||
use bevy_utils::WgpuWrapper;
|
||||
pub use graph_runner::*;
|
||||
pub use render_device::*;
|
||||
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.
|
||||
#[derive(Resource, Clone, Deref, DerefMut)]
|
||||
pub struct RenderQueue(pub Arc<WgpuWrapper<Queue>>);
|
||||
|
@ -3,8 +3,8 @@ use crate::render_resource::{
|
||||
BindGroup, BindGroupLayout, Buffer, ComputePipeline, RawRenderPipelineDescriptor,
|
||||
RenderPipeline, Sampler, Texture,
|
||||
};
|
||||
use crate::WgpuWrapper;
|
||||
use bevy_ecs::resource::Resource;
|
||||
use bevy_utils::WgpuWrapper;
|
||||
use wgpu::{
|
||||
util::DeviceExt, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor,
|
||||
BindGroupLayoutEntry, BufferAsyncError, BufferBindingType, MaintainResult,
|
||||
|
@ -1,12 +1,13 @@
|
||||
use crate::{
|
||||
render_resource::{SurfaceTexture, TextureView},
|
||||
renderer::{RenderAdapter, RenderDevice, RenderInstance},
|
||||
Extract, ExtractSchedule, Render, RenderApp, RenderSystems, WgpuWrapper,
|
||||
Extract, ExtractSchedule, Render, RenderApp, RenderSystems,
|
||||
};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_ecs::{entity::EntityHashMap, prelude::*};
|
||||
use bevy_platform::collections::HashSet;
|
||||
use bevy_utils::default;
|
||||
use bevy_utils::WgpuWrapper;
|
||||
use bevy_window::{
|
||||
CompositeAlphaMode, PresentMode, PrimaryWindow, RawHandleWrapper, Window, WindowClosing,
|
||||
};
|
||||
|
@ -11,6 +11,8 @@ keywords = ["bevy"]
|
||||
[features]
|
||||
default = ["parallel"]
|
||||
|
||||
wgpu_wrapper = ["dep:send_wrapper"]
|
||||
|
||||
# Provides access to the `Parallel` type.
|
||||
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 }
|
||||
|
||||
[target.'cfg(all(target_arch = "wasm32", target_feature = "atomics"))'.dependencies]
|
||||
send_wrapper = { version = "0.6.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
static_assertions = "1.1.0"
|
||||
|
||||
|
@ -48,6 +48,8 @@ pub mod prelude {
|
||||
|
||||
pub mod synccell;
|
||||
pub mod syncunsafecell;
|
||||
#[cfg(feature = "wgpu_wrapper")]
|
||||
mod wgpu_wrapper;
|
||||
|
||||
mod default;
|
||||
mod once;
|
||||
@ -57,6 +59,9 @@ pub use once::OnceFlag;
|
||||
|
||||
pub use default::default;
|
||||
|
||||
#[cfg(feature = "wgpu_wrapper")]
|
||||
pub use wgpu_wrapper::WgpuWrapper;
|
||||
|
||||
use core::mem::ManuallyDrop;
|
||||
|
||||
/// 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