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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! Buffer usage, creation-info and wrappers.


pub use rendy_core::hal::buffer::*;

use {
    crate::{
        core::{device_owned, Device, DeviceId},
        memory::{Block, Heaps, MappedRange, MemoryBlock, MemoryUsage},
        CreationError,
    },
    relevant::Relevant,
    rendy_core::hal::{device::Device as _, Backend},
};

/// Buffer info.

#[derive(Clone, Copy, Debug)]
pub struct BufferInfo {
    /// Buffer size.

    pub size: u64,

    /// Buffer usage flags.

    pub usage: Usage,
}

/// Generic buffer resource wrapper.

///

/// # Parameters

///

/// `B` - raw image type.

#[derive(Debug)]
pub struct Buffer<B: Backend> {
    device: DeviceId,
    raw: B::Buffer,
    block: MemoryBlock<B>,
    info: BufferInfo,
    relevant: Relevant,
}

device_owned!(Buffer<B>);
/// Alias for the error to create a buffer.

pub type BufferCreationError = CreationError<rendy_core::hal::buffer::CreationError>;

impl<B> Buffer<B>
where
    B: Backend,
{
    /// Create buffer, allocate memory block for it and bind.

    ///

    /// # Safety

    ///

    /// In order to guarantee that `Heap::allocate` will return

    /// memory range owned by this `Device`,

    /// this `Heaps` instance must always be used with this `Device` instance.

    ///

    /// Otherwise usage of hal methods must be always valid.

    pub unsafe fn create(
        device: &Device<B>,
        heaps: &mut Heaps<B>,
        info: BufferInfo,
        memory_usage: impl MemoryUsage,
    ) -> Result<Self, BufferCreationError> {
        log::trace!("{:#?}@{:#?}", info, memory_usage);
        assert_ne!(info.size, 0);

        let mut buf = device
            .create_buffer(info.size, info.usage)
            .map_err(CreationError::Create)?;
        let reqs = device.get_buffer_requirements(&buf);
        let block = heaps
            .allocate(
                device,
                reqs.type_mask as u32,
                memory_usage,
                reqs.size,
                reqs.alignment,
            )
            .map_err(CreationError::Allocate)?;

        device
            .bind_buffer_memory(block.memory(), block.range().start, &mut buf)
            .map_err(CreationError::Bind)?;

        Ok(Buffer {
            device: device.id(),
            raw: buf,
            block,
            info,
            relevant: Relevant,
        })
    }

    /// Dispose of buffer resource.

    /// Deallocate memory block.

    pub unsafe fn dispose(self, device: &Device<B>, heaps: &mut Heaps<B>) {
        self.assert_device_owner(device);
        device.destroy_buffer(self.raw);
        heaps.free(device, self.block);
        self.relevant.dispose();
    }

    /// Get reference to raw buffer resource

    pub fn raw(&self) -> &B::Buffer {
        &self.raw
    }

    /// Get mutable reference to raw buffer resource

    pub unsafe fn raw_mut(&mut self) -> &mut B::Buffer {
        &mut self.raw
    }

    /// Get reference to memory block occupied by buffer.

    pub fn block(&self) -> &MemoryBlock<B> {
        &self.block
    }

    /// Get mutable reference to memory block occupied by buffer.

    pub unsafe fn block_mut(&mut self) -> &mut MemoryBlock<B> {
        &mut self.block
    }

    /// Get buffer info.

    pub fn info(&self) -> &BufferInfo {
        &self.info
    }

    /// Check if this buffer could is bound to CPU visible memory and therefore mappable.

    /// If this function returns `false` `map` will always return `InvalidAccess`.

    ///

    /// [`map`]: #method.map

    /// [`InvalidAccess`]: https://docs.rs/gfx-hal/0.1/rendy_core::hal/mapping/enum.Error.html#InvalidAccess

    pub fn visible(&self) -> bool {
        self.block
            .properties()
            .contains(rendy_core::hal::memory::Properties::CPU_VISIBLE)
    }

    /// Map range of the buffer to the CPU accessible memory.

    pub fn map<'a>(
        &'a mut self,
        device: &Device<B>,
        range: std::ops::Range<u64>,
    ) -> Result<MappedRange<'a, B>, rendy_core::hal::device::MapError> {
        self.block.map(device, range)
    }

    /// Get buffer info.

    pub fn size(&self) -> u64 {
        self.info().size
    }
}