Remove render_resource_wrapper (#15441)
# Objective * Remove all uses of render_resource_wrapper. * Make it easier to share a `wgpu::Device` between Bevy and application code. ## Solution Removed the `render_resource_wrapper` macro. To improve the `RenderCreation:: Manual ` API, `ErasedRenderDevice` was replaced by `Arc`. Unfortunately I had to introduce one more usage of `WgpuWrapper` which seems like an unwanted constraint on the caller. ## Testing - Did you test these changes? If so, how? - Ran `cargo test`. - Ran a few examples. - Used `RenderCreation::Manual` in my own project - Exercised `RenderCreation::Automatic` through examples - Are there any parts that need more testing? - No - How can other people (reviewers) test your changes? Is there anything specific they need to know? - Run examples - Use `RenderCreation::Manual` in their own project
This commit is contained in:
parent
f97eba2082
commit
72aaa41603
@ -1,10 +1,12 @@
|
|||||||
|
use crate::renderer::WgpuWrapper;
|
||||||
use crate::{
|
use crate::{
|
||||||
define_atomic_id,
|
define_atomic_id,
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_resource::{resource_macros::*, BindGroupLayout, Buffer, Sampler, TextureView},
|
render_resource::{BindGroupLayout, Buffer, Sampler, TextureView},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::GpuImage,
|
texture::GpuImage,
|
||||||
};
|
};
|
||||||
|
use alloc::sync::Arc;
|
||||||
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 core::ops::Deref;
|
use core::ops::Deref;
|
||||||
@ -13,7 +15,6 @@ use thiserror::Error;
|
|||||||
use wgpu::{BindGroupEntry, BindGroupLayoutEntry, BindingResource};
|
use wgpu::{BindGroupEntry, BindGroupLayoutEntry, BindingResource};
|
||||||
|
|
||||||
define_atomic_id!(BindGroupId);
|
define_atomic_id!(BindGroupId);
|
||||||
render_resource_wrapper!(ErasedBindGroup, wgpu::BindGroup);
|
|
||||||
|
|
||||||
/// Bind groups are responsible for binding render resources (e.g. buffers, textures, samplers)
|
/// Bind groups are responsible for binding render resources (e.g. buffers, textures, samplers)
|
||||||
/// to a [`TrackedRenderPass`](crate::render_phase::TrackedRenderPass).
|
/// to a [`TrackedRenderPass`](crate::render_phase::TrackedRenderPass).
|
||||||
@ -24,7 +25,7 @@ render_resource_wrapper!(ErasedBindGroup, wgpu::BindGroup);
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct BindGroup {
|
pub struct BindGroup {
|
||||||
id: BindGroupId,
|
id: BindGroupId,
|
||||||
value: ErasedBindGroup,
|
value: Arc<WgpuWrapper<wgpu::BindGroup>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BindGroup {
|
impl BindGroup {
|
||||||
@ -39,7 +40,7 @@ impl From<wgpu::BindGroup> for BindGroup {
|
|||||||
fn from(value: wgpu::BindGroup) -> Self {
|
fn from(value: wgpu::BindGroup) -> Self {
|
||||||
BindGroup {
|
BindGroup {
|
||||||
id: BindGroupId::new(),
|
id: BindGroupId::new(),
|
||||||
value: ErasedBindGroup::new(value),
|
value: Arc::new(WgpuWrapper::new(value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
use crate::{define_atomic_id, render_resource::resource_macros::*};
|
use crate::define_atomic_id;
|
||||||
|
use crate::renderer::WgpuWrapper;
|
||||||
|
use alloc::sync::Arc;
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
|
|
||||||
define_atomic_id!(BindGroupLayoutId);
|
define_atomic_id!(BindGroupLayoutId);
|
||||||
render_resource_wrapper!(ErasedBindGroupLayout, wgpu::BindGroupLayout);
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct BindGroupLayout {
|
pub struct BindGroupLayout {
|
||||||
id: BindGroupLayoutId,
|
id: BindGroupLayoutId,
|
||||||
value: ErasedBindGroupLayout,
|
value: Arc<WgpuWrapper<wgpu::BindGroupLayout>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for BindGroupLayout {
|
impl PartialEq for BindGroupLayout {
|
||||||
@ -32,7 +33,7 @@ impl From<wgpu::BindGroupLayout> for BindGroupLayout {
|
|||||||
fn from(value: wgpu::BindGroupLayout) -> Self {
|
fn from(value: wgpu::BindGroupLayout) -> Self {
|
||||||
BindGroupLayout {
|
BindGroupLayout {
|
||||||
id: BindGroupLayoutId::new(),
|
id: BindGroupLayoutId::new(),
|
||||||
value: ErasedBindGroupLayout::new(value),
|
value: Arc::new(WgpuWrapper::new(value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
use crate::{define_atomic_id, render_resource::resource_macros::render_resource_wrapper};
|
use crate::define_atomic_id;
|
||||||
|
use crate::renderer::WgpuWrapper;
|
||||||
|
use alloc::sync::Arc;
|
||||||
use core::ops::{Bound, Deref, RangeBounds};
|
use core::ops::{Bound, Deref, RangeBounds};
|
||||||
|
|
||||||
define_atomic_id!(BufferId);
|
define_atomic_id!(BufferId);
|
||||||
render_resource_wrapper!(ErasedBuffer, wgpu::Buffer);
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Buffer {
|
pub struct Buffer {
|
||||||
id: BufferId,
|
id: BufferId,
|
||||||
value: ErasedBuffer,
|
value: Arc<WgpuWrapper<wgpu::Buffer>>,
|
||||||
size: wgpu::BufferAddress,
|
size: wgpu::BufferAddress,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +49,7 @@ impl From<wgpu::Buffer> for Buffer {
|
|||||||
Buffer {
|
Buffer {
|
||||||
id: BufferId::new(),
|
id: BufferId::new(),
|
||||||
size: value.size(),
|
size: value.size(),
|
||||||
value: ErasedBuffer::new(value),
|
value: Arc::new(WgpuWrapper::new(value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
use super::ShaderDefVal;
|
use super::ShaderDefVal;
|
||||||
|
use crate::renderer::WgpuWrapper;
|
||||||
use crate::{
|
use crate::{
|
||||||
define_atomic_id,
|
define_atomic_id,
|
||||||
render_resource::{resource_macros::render_resource_wrapper, BindGroupLayout, Shader},
|
render_resource::{BindGroupLayout, Shader},
|
||||||
};
|
};
|
||||||
use alloc::borrow::Cow;
|
use alloc::borrow::Cow;
|
||||||
|
use alloc::sync::Arc;
|
||||||
use bevy_asset::Handle;
|
use bevy_asset::Handle;
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
@ -12,7 +14,6 @@ use wgpu::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
define_atomic_id!(RenderPipelineId);
|
define_atomic_id!(RenderPipelineId);
|
||||||
render_resource_wrapper!(ErasedRenderPipeline, wgpu::RenderPipeline);
|
|
||||||
|
|
||||||
/// A [`RenderPipeline`] represents a graphics pipeline and its stages (shaders), bindings and vertex buffers.
|
/// A [`RenderPipeline`] represents a graphics pipeline and its stages (shaders), bindings and vertex buffers.
|
||||||
///
|
///
|
||||||
@ -21,7 +22,7 @@ render_resource_wrapper!(ErasedRenderPipeline, wgpu::RenderPipeline);
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct RenderPipeline {
|
pub struct RenderPipeline {
|
||||||
id: RenderPipelineId,
|
id: RenderPipelineId,
|
||||||
value: ErasedRenderPipeline,
|
value: Arc<WgpuWrapper<wgpu::RenderPipeline>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderPipeline {
|
impl RenderPipeline {
|
||||||
@ -35,7 +36,7 @@ impl From<wgpu::RenderPipeline> for RenderPipeline {
|
|||||||
fn from(value: wgpu::RenderPipeline) -> Self {
|
fn from(value: wgpu::RenderPipeline) -> Self {
|
||||||
RenderPipeline {
|
RenderPipeline {
|
||||||
id: RenderPipelineId::new(),
|
id: RenderPipelineId::new(),
|
||||||
value: ErasedRenderPipeline::new(value),
|
value: Arc::new(WgpuWrapper::new(value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,7 +51,6 @@ impl Deref for RenderPipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
define_atomic_id!(ComputePipelineId);
|
define_atomic_id!(ComputePipelineId);
|
||||||
render_resource_wrapper!(ErasedComputePipeline, wgpu::ComputePipeline);
|
|
||||||
|
|
||||||
/// A [`ComputePipeline`] represents a compute pipeline and its single shader stage.
|
/// A [`ComputePipeline`] represents a compute pipeline and its single shader stage.
|
||||||
///
|
///
|
||||||
@ -59,7 +59,7 @@ render_resource_wrapper!(ErasedComputePipeline, wgpu::ComputePipeline);
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ComputePipeline {
|
pub struct ComputePipeline {
|
||||||
id: ComputePipelineId,
|
id: ComputePipelineId,
|
||||||
value: ErasedComputePipeline,
|
value: Arc<WgpuWrapper<wgpu::ComputePipeline>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComputePipeline {
|
impl ComputePipeline {
|
||||||
@ -74,7 +74,7 @@ impl From<wgpu::ComputePipeline> for ComputePipeline {
|
|||||||
fn from(value: wgpu::ComputePipeline) -> Self {
|
fn from(value: wgpu::ComputePipeline) -> Self {
|
||||||
ComputePipeline {
|
ComputePipeline {
|
||||||
id: ComputePipelineId::new(),
|
id: ComputePipelineId::new(),
|
||||||
value: ErasedComputePipeline::new(value),
|
value: Arc::new(WgpuWrapper::new(value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::renderer::WgpuWrapper;
|
||||||
use crate::{
|
use crate::{
|
||||||
render_resource::*,
|
render_resource::*,
|
||||||
renderer::{RenderAdapter, RenderDevice},
|
renderer::{RenderAdapter, RenderDevice},
|
||||||
@ -27,11 +28,6 @@ use wgpu::{
|
|||||||
VertexBufferLayout as RawVertexBufferLayout,
|
VertexBufferLayout as RawVertexBufferLayout,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::render_resource::resource_macros::*;
|
|
||||||
|
|
||||||
render_resource_wrapper!(ErasedShaderModule, ShaderModule);
|
|
||||||
render_resource_wrapper!(ErasedPipelineLayout, PipelineLayout);
|
|
||||||
|
|
||||||
/// A descriptor for a [`Pipeline`].
|
/// A descriptor for a [`Pipeline`].
|
||||||
///
|
///
|
||||||
/// Used to store an heterogenous collection of render and compute pipeline descriptors together.
|
/// Used to store an heterogenous collection of render and compute pipeline descriptors together.
|
||||||
@ -126,7 +122,7 @@ impl CachedPipelineState {
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ShaderData {
|
struct ShaderData {
|
||||||
pipelines: HashSet<CachedPipelineId>,
|
pipelines: HashSet<CachedPipelineId>,
|
||||||
processed_shaders: HashMap<Box<[ShaderDefVal]>, ErasedShaderModule>,
|
processed_shaders: HashMap<Box<[ShaderDefVal]>, Arc<WgpuWrapper<ShaderModule>>>,
|
||||||
resolved_imports: HashMap<ShaderImport, AssetId<Shader>>,
|
resolved_imports: HashMap<ShaderImport, AssetId<Shader>>,
|
||||||
dependents: HashSet<AssetId<Shader>>,
|
dependents: HashSet<AssetId<Shader>>,
|
||||||
}
|
}
|
||||||
@ -225,7 +221,7 @@ impl ShaderCache {
|
|||||||
pipeline: CachedPipelineId,
|
pipeline: CachedPipelineId,
|
||||||
id: AssetId<Shader>,
|
id: AssetId<Shader>,
|
||||||
shader_defs: &[ShaderDefVal],
|
shader_defs: &[ShaderDefVal],
|
||||||
) -> Result<ErasedShaderModule, PipelineCacheError> {
|
) -> Result<Arc<WgpuWrapper<ShaderModule>>, PipelineCacheError> {
|
||||||
let shader = self
|
let shader = self
|
||||||
.shaders
|
.shaders
|
||||||
.get(&id)
|
.get(&id)
|
||||||
@ -338,7 +334,7 @@ impl ShaderCache {
|
|||||||
return Err(PipelineCacheError::CreateShaderModule(description));
|
return Err(PipelineCacheError::CreateShaderModule(description));
|
||||||
}
|
}
|
||||||
|
|
||||||
entry.insert(ErasedShaderModule::new(shader_module))
|
entry.insert(Arc::new(WgpuWrapper::new(shader_module)))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -410,7 +406,7 @@ impl ShaderCache {
|
|||||||
type LayoutCacheKey = (Vec<BindGroupLayoutId>, Vec<PushConstantRange>);
|
type LayoutCacheKey = (Vec<BindGroupLayoutId>, Vec<PushConstantRange>);
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct LayoutCache {
|
struct LayoutCache {
|
||||||
layouts: HashMap<LayoutCacheKey, ErasedPipelineLayout>,
|
layouts: HashMap<LayoutCacheKey, Arc<WgpuWrapper<PipelineLayout>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutCache {
|
impl LayoutCache {
|
||||||
@ -419,7 +415,7 @@ impl LayoutCache {
|
|||||||
render_device: &RenderDevice,
|
render_device: &RenderDevice,
|
||||||
bind_group_layouts: &[BindGroupLayout],
|
bind_group_layouts: &[BindGroupLayout],
|
||||||
push_constant_ranges: Vec<PushConstantRange>,
|
push_constant_ranges: Vec<PushConstantRange>,
|
||||||
) -> ErasedPipelineLayout {
|
) -> Arc<WgpuWrapper<PipelineLayout>> {
|
||||||
let bind_group_ids = bind_group_layouts.iter().map(BindGroupLayout::id).collect();
|
let bind_group_ids = bind_group_layouts.iter().map(BindGroupLayout::id).collect();
|
||||||
self.layouts
|
self.layouts
|
||||||
.entry((bind_group_ids, push_constant_ranges))
|
.entry((bind_group_ids, push_constant_ranges))
|
||||||
@ -428,13 +424,13 @@ impl LayoutCache {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(BindGroupLayout::value)
|
.map(BindGroupLayout::value)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
ErasedPipelineLayout::new(render_device.create_pipeline_layout(
|
Arc::new(WgpuWrapper::new(render_device.create_pipeline_layout(
|
||||||
&PipelineLayoutDescriptor {
|
&PipelineLayoutDescriptor {
|
||||||
bind_group_layouts: &bind_group_layouts,
|
bind_group_layouts: &bind_group_layouts,
|
||||||
push_constant_ranges,
|
push_constant_ranges,
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
))
|
)))
|
||||||
})
|
})
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
@ -746,7 +742,7 @@ impl PipelineCache {
|
|||||||
multiview: None,
|
multiview: None,
|
||||||
depth_stencil: descriptor.depth_stencil.clone(),
|
depth_stencil: descriptor.depth_stencil.clone(),
|
||||||
label: descriptor.label.as_deref(),
|
label: descriptor.label.as_deref(),
|
||||||
layout: layout.as_deref(),
|
layout: layout.as_ref().map(|layout| -> &PipelineLayout { layout }),
|
||||||
multisample: descriptor.multisample,
|
multisample: descriptor.multisample,
|
||||||
primitive: descriptor.primitive,
|
primitive: descriptor.primitive,
|
||||||
vertex: RawVertexState {
|
vertex: RawVertexState {
|
||||||
@ -814,7 +810,7 @@ impl PipelineCache {
|
|||||||
|
|
||||||
let descriptor = RawComputePipelineDescriptor {
|
let descriptor = RawComputePipelineDescriptor {
|
||||||
label: descriptor.label.as_deref(),
|
label: descriptor.label.as_deref(),
|
||||||
layout: layout.as_deref(),
|
layout: layout.as_ref().map(|layout| -> &PipelineLayout { layout }),
|
||||||
module: &compute_module,
|
module: &compute_module,
|
||||||
entry_point: &descriptor.entry_point,
|
entry_point: &descriptor.entry_point,
|
||||||
// TODO: Expose this somehow
|
// TODO: Expose this somehow
|
||||||
|
@ -1,150 +1,3 @@
|
|||||||
// structs containing wgpu types take a long time to compile. this is particularly bad for generic
|
|
||||||
// structs containing wgpu structs. we avoid that in debug builds (and for cargo check and rust analyzer)
|
|
||||||
// by type-erasing with the `render_resource_wrapper` macro. The resulting type behaves like Arc<$wgpu_type>,
|
|
||||||
// but avoids explicitly storing an Arc<$wgpu_type> member.
|
|
||||||
// analysis from https://github.com/bevyengine/bevy/pull/5950#issuecomment-1243473071 indicates this is
|
|
||||||
// due to `evaluate_obligations`. we should check if this can be removed after a fix lands for
|
|
||||||
// https://github.com/rust-lang/rust/issues/99188 (and after other `evaluate_obligations`-related changes).
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! render_resource_wrapper {
|
|
||||||
($wrapper_type:ident, $wgpu_type:ty) => {
|
|
||||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
|
||||||
#[derive(Debug)]
|
|
||||||
// SAFETY: while self is live, self.0 comes from `into_raw` of an Arc<$wgpu_type> with a strong ref.
|
|
||||||
pub struct $wrapper_type(*const ());
|
|
||||||
|
|
||||||
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct $wrapper_type(send_wrapper::SendWrapper<*const ()>);
|
|
||||||
|
|
||||||
impl $wrapper_type {
|
|
||||||
pub fn new(value: $wgpu_type) -> Self {
|
|
||||||
let arc = alloc::sync::Arc::new(value);
|
|
||||||
let value_ptr = alloc::sync::Arc::into_raw(arc);
|
|
||||||
let unit_ptr = value_ptr.cast::<()>();
|
|
||||||
|
|
||||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
|
||||||
return Self(unit_ptr);
|
|
||||||
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
|
||||||
return Self(send_wrapper::SendWrapper::new(unit_ptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_unwrap(self) -> Option<$wgpu_type> {
|
|
||||||
let value_ptr = self.0.cast::<$wgpu_type>();
|
|
||||||
// SAFETY: pointer refers to a valid Arc, and was created from Arc::into_raw.
|
|
||||||
let arc = unsafe { alloc::sync::Arc::from_raw(value_ptr) };
|
|
||||||
|
|
||||||
// we forget ourselves here since the reconstructed arc will be dropped/decremented within this scope
|
|
||||||
core::mem::forget(self);
|
|
||||||
|
|
||||||
alloc::sync::Arc::try_unwrap(arc).ok()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::ops::Deref for $wrapper_type {
|
|
||||||
type Target = $wgpu_type;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
let value_ptr = self.0.cast::<$wgpu_type>();
|
|
||||||
// SAFETY: the arc lives for 'self, so the ref lives for 'self
|
|
||||||
let value_ref = unsafe { value_ptr.as_ref() };
|
|
||||||
value_ref.unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for $wrapper_type {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let value_ptr = self.0.cast::<$wgpu_type>();
|
|
||||||
// SAFETY: pointer refers to a valid Arc, and was created from Arc::into_raw.
|
|
||||||
// this reconstructed arc is dropped/decremented within this scope.
|
|
||||||
unsafe { alloc::sync::Arc::from_raw(value_ptr) };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
|
||||||
// SAFETY: We manually implement Send and Sync, which is valid for Arc<T> when T: Send + Sync.
|
|
||||||
// We ensure correctness by checking that $wgpu_type does implement Send and Sync.
|
|
||||||
// If in future there is a case where a wrapper is required for a non-send/sync type
|
|
||||||
// we can implement a macro variant that omits these manual Send + Sync impls
|
|
||||||
unsafe impl Send for $wrapper_type {}
|
|
||||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
|
||||||
// SAFETY: As explained above, we ensure correctness by checking that $wgpu_type implements Send and Sync.
|
|
||||||
unsafe impl Sync for $wrapper_type {}
|
|
||||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
|
||||||
const _: () = {
|
|
||||||
trait AssertSendSyncBound: Send + Sync {}
|
|
||||||
impl AssertSendSyncBound for $wgpu_type {}
|
|
||||||
};
|
|
||||||
|
|
||||||
impl Clone for $wrapper_type {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
let value_ptr = self.0.cast::<$wgpu_type>();
|
|
||||||
// SAFETY: pointer refers to a valid Arc, and was created from Arc::into_raw.
|
|
||||||
let arc = unsafe { alloc::sync::Arc::from_raw(value_ptr.cast::<$wgpu_type>()) };
|
|
||||||
let cloned = alloc::sync::Arc::clone(&arc);
|
|
||||||
// we forget the reconstructed Arc to avoid decrementing the ref counter, as self is still live.
|
|
||||||
core::mem::forget(arc);
|
|
||||||
let cloned_value_ptr = alloc::sync::Arc::into_raw(cloned);
|
|
||||||
let cloned_unit_ptr = cloned_value_ptr.cast::<()>();
|
|
||||||
|
|
||||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
|
||||||
return Self(cloned_unit_ptr);
|
|
||||||
|
|
||||||
// Note: this implementation means that this Clone will panic
|
|
||||||
// when called off the wgpu thread.
|
|
||||||
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
|
||||||
return Self(send_wrapper::SendWrapper::new(cloned_unit_ptr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! render_resource_wrapper {
|
|
||||||
($wrapper_type:ident, $wgpu_type:ty) => {
|
|
||||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct $wrapper_type(std::sync::Arc<$wgpu_type>);
|
|
||||||
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct $wrapper_type(std::sync::Arc<send_wrapper::SendWrapper<$wgpu_type>>);
|
|
||||||
|
|
||||||
impl $wrapper_type {
|
|
||||||
pub fn new(value: $wgpu_type) -> Self {
|
|
||||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
|
||||||
return Self(std::sync::Arc::new(value));
|
|
||||||
|
|
||||||
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
|
||||||
return Self(std::sync::Arc::new(send_wrapper::SendWrapper::new(value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_unwrap(self) -> Option<$wgpu_type> {
|
|
||||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
|
||||||
return std::sync::Arc::try_unwrap(self.0).ok();
|
|
||||||
|
|
||||||
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
|
||||||
return std::sync::Arc::try_unwrap(self.0).ok().map(|p| p.take());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::ops::Deref for $wrapper_type {
|
|
||||||
type Target = $wgpu_type;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
self.0.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
|
||||||
const _: () = {
|
|
||||||
trait AssertSendSyncBound: Send + Sync {}
|
|
||||||
impl AssertSendSyncBound for $wgpu_type {}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! define_atomic_id {
|
macro_rules! define_atomic_id {
|
||||||
($atomic_id_type:ident) => {
|
($atomic_id_type:ident) => {
|
||||||
@ -182,5 +35,3 @@ macro_rules! define_atomic_id {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use render_resource_wrapper;
|
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
use crate::define_atomic_id;
|
use crate::define_atomic_id;
|
||||||
|
use crate::renderer::WgpuWrapper;
|
||||||
|
use alloc::sync::Arc;
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
|
|
||||||
use crate::render_resource::resource_macros::*;
|
|
||||||
|
|
||||||
define_atomic_id!(TextureId);
|
define_atomic_id!(TextureId);
|
||||||
render_resource_wrapper!(ErasedTexture, wgpu::Texture);
|
|
||||||
|
|
||||||
/// A GPU-accessible texture.
|
/// A GPU-accessible texture.
|
||||||
///
|
///
|
||||||
@ -13,7 +12,7 @@ render_resource_wrapper!(ErasedTexture, wgpu::Texture);
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Texture {
|
pub struct Texture {
|
||||||
id: TextureId,
|
id: TextureId,
|
||||||
value: ErasedTexture,
|
value: Arc<WgpuWrapper<wgpu::Texture>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Texture {
|
impl Texture {
|
||||||
@ -33,7 +32,7 @@ impl From<wgpu::Texture> for Texture {
|
|||||||
fn from(value: wgpu::Texture) -> Self {
|
fn from(value: wgpu::Texture) -> Self {
|
||||||
Texture {
|
Texture {
|
||||||
id: TextureId::new(),
|
id: TextureId::new(),
|
||||||
value: ErasedTexture::new(value),
|
value: Arc::new(WgpuWrapper::new(value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,23 +47,23 @@ impl Deref for Texture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
define_atomic_id!(TextureViewId);
|
define_atomic_id!(TextureViewId);
|
||||||
render_resource_wrapper!(ErasedTextureView, wgpu::TextureView);
|
|
||||||
render_resource_wrapper!(ErasedSurfaceTexture, wgpu::SurfaceTexture);
|
|
||||||
|
|
||||||
/// Describes a [`Texture`] with its associated metadata required by a pipeline or [`BindGroup`](super::BindGroup).
|
/// Describes a [`Texture`] with its associated metadata required by a pipeline or [`BindGroup`](super::BindGroup).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TextureView {
|
pub struct TextureView {
|
||||||
id: TextureViewId,
|
id: TextureViewId,
|
||||||
value: ErasedTextureView,
|
value: Arc<WgpuWrapper<wgpu::TextureView>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SurfaceTexture {
|
pub struct SurfaceTexture {
|
||||||
value: ErasedSurfaceTexture,
|
value: Arc<WgpuWrapper<wgpu::SurfaceTexture>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SurfaceTexture {
|
impl SurfaceTexture {
|
||||||
pub fn try_unwrap(self) -> Option<wgpu::SurfaceTexture> {
|
pub fn try_unwrap(self) -> Option<wgpu::SurfaceTexture> {
|
||||||
self.value.try_unwrap()
|
Arc::try_unwrap(self.value)
|
||||||
|
.map(WgpuWrapper::into_inner)
|
||||||
|
.ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +79,7 @@ impl From<wgpu::TextureView> for TextureView {
|
|||||||
fn from(value: wgpu::TextureView) -> Self {
|
fn from(value: wgpu::TextureView) -> Self {
|
||||||
TextureView {
|
TextureView {
|
||||||
id: TextureViewId::new(),
|
id: TextureViewId::new(),
|
||||||
value: ErasedTextureView::new(value),
|
value: Arc::new(WgpuWrapper::new(value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,7 +87,7 @@ impl From<wgpu::TextureView> for TextureView {
|
|||||||
impl From<wgpu::SurfaceTexture> for SurfaceTexture {
|
impl From<wgpu::SurfaceTexture> for SurfaceTexture {
|
||||||
fn from(value: wgpu::SurfaceTexture) -> Self {
|
fn from(value: wgpu::SurfaceTexture) -> Self {
|
||||||
SurfaceTexture {
|
SurfaceTexture {
|
||||||
value: ErasedSurfaceTexture::new(value),
|
value: Arc::new(WgpuWrapper::new(value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,7 +111,6 @@ impl Deref for SurfaceTexture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
define_atomic_id!(SamplerId);
|
define_atomic_id!(SamplerId);
|
||||||
render_resource_wrapper!(ErasedSampler, wgpu::Sampler);
|
|
||||||
|
|
||||||
/// A Sampler defines how a pipeline will sample from a [`TextureView`].
|
/// A Sampler defines how a pipeline will sample from a [`TextureView`].
|
||||||
/// They define image filters (including anisotropy) and address (wrapping) modes, among other things.
|
/// They define image filters (including anisotropy) and address (wrapping) modes, among other things.
|
||||||
@ -122,7 +120,7 @@ render_resource_wrapper!(ErasedSampler, wgpu::Sampler);
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Sampler {
|
pub struct Sampler {
|
||||||
id: SamplerId,
|
id: SamplerId,
|
||||||
value: ErasedSampler,
|
value: Arc<WgpuWrapper<wgpu::Sampler>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sampler {
|
impl Sampler {
|
||||||
@ -137,7 +135,7 @@ impl From<wgpu::Sampler> for Sampler {
|
|||||||
fn from(value: wgpu::Sampler) -> Self {
|
fn from(value: wgpu::Sampler) -> Self {
|
||||||
Sampler {
|
Sampler {
|
||||||
id: SamplerId::new(),
|
id: SamplerId::new(),
|
||||||
value: ErasedSampler::new(value),
|
value: Arc::new(WgpuWrapper::new(value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,6 +142,10 @@ impl<T> WgpuWrapper<T> {
|
|||||||
pub fn new(t: T) -> Self {
|
pub fn new(t: T) -> Self {
|
||||||
Self(t)
|
Self(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn into_inner(self) -> T {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
||||||
@ -149,6 +153,10 @@ impl<T> WgpuWrapper<T> {
|
|||||||
pub fn new(t: T) -> Self {
|
pub fn new(t: T) -> Self {
|
||||||
Self(send_wrapper::SendWrapper::new(t))
|
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.
|
||||||
|
@ -1,34 +1,33 @@
|
|||||||
|
use super::RenderQueue;
|
||||||
use crate::render_resource::{
|
use crate::render_resource::{
|
||||||
BindGroup, BindGroupLayout, Buffer, ComputePipeline, RawRenderPipelineDescriptor,
|
BindGroup, BindGroupLayout, Buffer, ComputePipeline, RawRenderPipelineDescriptor,
|
||||||
RenderPipeline, Sampler, Texture,
|
RenderPipeline, Sampler, Texture,
|
||||||
};
|
};
|
||||||
|
use crate::WgpuWrapper;
|
||||||
|
use alloc::sync::Arc;
|
||||||
use bevy_ecs::system::Resource;
|
use bevy_ecs::system::Resource;
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
util::DeviceExt, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor,
|
util::DeviceExt, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor,
|
||||||
BindGroupLayoutEntry, BufferAsyncError, BufferBindingType, MaintainResult,
|
BindGroupLayoutEntry, BufferAsyncError, BufferBindingType, MaintainResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::RenderQueue;
|
|
||||||
|
|
||||||
use crate::{render_resource::resource_macros::*, WgpuWrapper};
|
|
||||||
|
|
||||||
render_resource_wrapper!(ErasedRenderDevice, wgpu::Device);
|
|
||||||
|
|
||||||
/// This GPU device is responsible for the creation of most rendering and compute resources.
|
/// This GPU device is responsible for the creation of most rendering and compute resources.
|
||||||
#[derive(Resource, Clone)]
|
#[derive(Resource, Clone)]
|
||||||
pub struct RenderDevice {
|
pub struct RenderDevice {
|
||||||
device: WgpuWrapper<ErasedRenderDevice>,
|
device: Arc<WgpuWrapper<wgpu::Device>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<wgpu::Device> for RenderDevice {
|
impl From<wgpu::Device> for RenderDevice {
|
||||||
fn from(device: wgpu::Device) -> Self {
|
fn from(device: wgpu::Device) -> Self {
|
||||||
Self {
|
Self::new(Arc::new(WgpuWrapper::new(device)))
|
||||||
device: WgpuWrapper::new(ErasedRenderDevice::new(device)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderDevice {
|
impl RenderDevice {
|
||||||
|
pub fn new(device: Arc<WgpuWrapper<wgpu::Device>>) -> Self {
|
||||||
|
Self { device }
|
||||||
|
}
|
||||||
|
|
||||||
/// List all [`Features`](wgpu::Features) that may be used with this device.
|
/// List all [`Features`](wgpu::Features) that may be used with this device.
|
||||||
///
|
///
|
||||||
/// Functions may panic if you use unsupported features.
|
/// Functions may panic if you use unsupported features.
|
||||||
|
Loading…
Reference in New Issue
Block a user