1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
use super::{BufferId, RenderResourceBinding, SamplerId, TextureId};
use bevy_utils::AHasher;
use std::{
    hash::{Hash, Hasher},
    ops::Range,
    sync::Arc,
};

#[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)]
pub struct BindGroupId(pub u64);

#[derive(Eq, PartialEq, Debug)]
pub struct IndexedBindGroupEntry {
    pub index: u32,
    pub entry: RenderResourceBinding,
}

#[derive(Clone, Eq, PartialEq, Debug)]
pub struct BindGroup {
    pub id: BindGroupId,
    pub indexed_bindings: Arc<Vec<IndexedBindGroupEntry>>,
    pub dynamic_uniform_indices: Option<Arc<Vec<u32>>>,
}

impl BindGroup {
    pub fn build() -> BindGroupBuilder {
        BindGroupBuilder::default()
    }
}

#[derive(Default)]
pub struct BindGroupBuilder {
    pub indexed_bindings: Vec<IndexedBindGroupEntry>,
    pub dynamic_uniform_indices: Vec<u32>,
    pub hasher: AHasher,
}

impl BindGroupBuilder {
    pub fn add_binding(mut self, index: u32, binding: RenderResourceBinding) -> Self {
        if let RenderResourceBinding::Buffer {
            dynamic_index: Some(dynamic_index),
            ..
        } = binding
        {
            self.dynamic_uniform_indices.push(dynamic_index);
        }

        binding.hash(&mut self.hasher);
        self.indexed_bindings.push(IndexedBindGroupEntry {
            index,
            entry: binding,
        });
        self
    }

    pub fn add_texture(self, index: u32, texture: TextureId) -> Self {
        self.add_binding(index, RenderResourceBinding::Texture(texture))
    }

    pub fn add_sampler(self, index: u32, sampler: SamplerId) -> Self {
        self.add_binding(index, RenderResourceBinding::Sampler(sampler))
    }

    pub fn add_buffer(self, index: u32, buffer: BufferId, range: Range<u64>) -> Self {
        self.add_binding(
            index,
            RenderResourceBinding::Buffer {
                buffer,
                range,
                dynamic_index: None,
            },
        )
    }

    pub fn add_dynamic_buffer(
        self,
        index: u32,
        buffer: BufferId,
        range: Range<u64>,
        dynamic_index: u32,
    ) -> Self {
        self.add_binding(
            index,
            RenderResourceBinding::Buffer {
                buffer,
                range,
                dynamic_index: Some(dynamic_index),
            },
        )
    }

    pub fn finish(mut self) -> BindGroup {
        // this sort ensures that RenderResourceSets are insertion-order independent
        self.indexed_bindings.sort_by_key(|i| i.index);
        BindGroup {
            id: BindGroupId(self.hasher.finish()),
            indexed_bindings: Arc::new(self.indexed_bindings),
            dynamic_uniform_indices: if self.dynamic_uniform_indices.is_empty() {
                None
            } else {
                Some(Arc::new(self.dynamic_uniform_indices))
            },
        }
    }
}