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}