bevy_render/render_resource/bind_group_layout.rs
1use crate::{define_atomic_id, renderer::RenderDevice, renderer::WgpuWrapper};
2use bevy_ecs::system::Res;
3use bevy_platform::sync::OnceLock;
4use core::ops::Deref;
5
6define_atomic_id!(BindGroupLayoutId);
7
8/// Bind group layouts define the interface of resources (e.g. buffers, textures, samplers)
9/// for a shader. The actual resource binding is done via a [`BindGroup`](super::BindGroup).
10///
11/// This is a lightweight thread-safe wrapper around wgpu's own [`BindGroupLayout`](wgpu::BindGroupLayout),
12/// which can be cloned as needed to workaround lifetime management issues. It may be converted
13/// from and dereferences to wgpu's [`BindGroupLayout`](wgpu::BindGroupLayout).
14///
15/// Can be created via [`RenderDevice::create_bind_group_layout`](crate::renderer::RenderDevice::create_bind_group_layout).
16#[derive(Clone, Debug)]
17pub struct BindGroupLayout {
18 id: BindGroupLayoutId,
19 value: WgpuWrapper<wgpu::BindGroupLayout>,
20}
21
22impl PartialEq for BindGroupLayout {
23 fn eq(&self, other: &Self) -> bool {
24 self.id == other.id
25 }
26}
27
28impl Eq for BindGroupLayout {}
29
30impl core::hash::Hash for BindGroupLayout {
31 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
32 self.id.0.hash(state);
33 }
34}
35
36impl BindGroupLayout {
37 /// Returns the [`BindGroupLayoutId`] representing the unique ID of the bind group layout.
38 #[inline]
39 pub fn id(&self) -> BindGroupLayoutId {
40 self.id
41 }
42
43 #[inline]
44 pub fn value(&self) -> &wgpu::BindGroupLayout {
45 &self.value
46 }
47}
48
49impl From<wgpu::BindGroupLayout> for BindGroupLayout {
50 fn from(value: wgpu::BindGroupLayout) -> Self {
51 BindGroupLayout {
52 id: BindGroupLayoutId::new(),
53 value: WgpuWrapper::new(value),
54 }
55 }
56}
57
58impl Deref for BindGroupLayout {
59 type Target = wgpu::BindGroupLayout;
60
61 #[inline]
62 fn deref(&self) -> &Self::Target {
63 &self.value
64 }
65}
66
67static EMPTY_BIND_GROUP_LAYOUT: OnceLock<BindGroupLayout> = OnceLock::new();
68
69pub(crate) fn init_empty_bind_group_layout(render_device: Res<RenderDevice>) {
70 let layout = render_device.create_bind_group_layout(Some("empty_bind_group_layout"), &[]);
71 EMPTY_BIND_GROUP_LAYOUT
72 .set(layout)
73 .expect("init_empty_bind_group_layout was called more than once");
74}
75
76pub fn empty_bind_group_layout() -> BindGroupLayout {
77 EMPTY_BIND_GROUP_LAYOUT
78 .get()
79 .expect("init_empty_bind_group_layout was not called")
80 .clone()
81}