1 // Copyright (c) 2016 The vulkano developers 2 // Licensed under the Apache License, Version 2.0 3 // <LICENSE-APACHE or 4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT 5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, 6 // at your option. All files in the project carrying such 7 // notice may not be copied, modified, or distributed except 8 // according to those terms. 9 10 use crate::buffer::traits::BufferAccess; 11 use crate::buffer::traits::BufferInner; 12 use crate::buffer::traits::TypedBufferAccess; 13 use crate::device::Device; 14 use crate::device::DeviceOwned; 15 use crate::device::Queue; 16 use crate::sync::AccessError; 17 use crate::DeviceSize; 18 use std::hash::Hash; 19 use std::hash::Hasher; 20 use std::marker::PhantomData; 21 use std::mem; 22 use std::mem::MaybeUninit; 23 use std::ops::Range; 24 use std::sync::Arc; 25 26 /// A subpart of a buffer. 27 /// 28 /// This object doesn't correspond to any Vulkan object. It exists for API convenience. 29 /// 30 /// # Example 31 /// 32 /// Creating a slice: 33 /// 34 /// ```ignore // FIXME: unignore 35 /// use vulkano::buffer::BufferSlice; 36 /// # let buffer: std::sync::Arc<vulkano::buffer::DeviceLocalBuffer<[u8]>> = return; 37 /// let _slice = BufferSlice::from(&buffer); 38 /// ``` 39 /// 40 /// Selecting a slice of a buffer that contains `[T]`: 41 /// 42 /// ```ignore // FIXME: unignore 43 /// use vulkano::buffer::BufferSlice; 44 /// # let buffer: std::sync::Arc<vulkano::buffer::DeviceLocalBuffer<[u8]>> = return; 45 /// let _slice = BufferSlice::from(&buffer).slice(12 .. 14).unwrap(); 46 /// ``` 47 /// 48 pub struct BufferSlice<T: ?Sized, B> { 49 marker: PhantomData<T>, 50 resource: B, 51 offset: DeviceSize, 52 size: DeviceSize, 53 } 54 55 // We need to implement `Clone` manually, otherwise the derive adds a `T: Clone` requirement. 56 impl<T: ?Sized, B> Clone for BufferSlice<T, B> 57 where 58 B: Clone, 59 { 60 #[inline] clone(&self) -> Self61 fn clone(&self) -> Self { 62 BufferSlice { 63 marker: PhantomData, 64 resource: self.resource.clone(), 65 offset: self.offset, 66 size: self.size, 67 } 68 } 69 } 70 71 impl<T: ?Sized, B> BufferSlice<T, B> { 72 #[inline] from_typed_buffer_access(r: B) -> BufferSlice<T, B> where B: TypedBufferAccess<Content = T>,73 pub fn from_typed_buffer_access(r: B) -> BufferSlice<T, B> 74 where 75 B: TypedBufferAccess<Content = T>, 76 { 77 let size = r.size(); 78 79 BufferSlice { 80 marker: PhantomData, 81 resource: r, 82 offset: 0, 83 size: size, 84 } 85 } 86 87 /// Returns the buffer that this slice belongs to. buffer(&self) -> &B88 pub fn buffer(&self) -> &B { 89 &self.resource 90 } 91 92 /// Returns the offset of that slice within the buffer. 93 #[inline] offset(&self) -> DeviceSize94 pub fn offset(&self) -> DeviceSize { 95 self.offset 96 } 97 98 /// Returns the size of that slice in bytes. 99 #[inline] size(&self) -> DeviceSize100 pub fn size(&self) -> DeviceSize { 101 self.size 102 } 103 104 /// Builds a slice that contains an element from inside the buffer. 105 /// 106 /// This method builds an object that represents a slice of the buffer. No actual operation 107 /// is performed. 108 /// 109 /// # Example 110 /// 111 /// TODO 112 /// 113 /// # Safety 114 /// 115 /// The object whose reference is passed to the closure is uninitialized. Therefore you 116 /// **must not** access the content of the object. 117 /// 118 /// You **must** return a reference to an element from the parameter. The closure **must not** 119 /// panic. 120 #[inline] slice_custom<F, R: ?Sized>(self, f: F) -> BufferSlice<R, B> where F: for<'r> FnOnce(&'r T) -> &'r R,121 pub unsafe fn slice_custom<F, R: ?Sized>(self, f: F) -> BufferSlice<R, B> 122 where 123 F: for<'r> FnOnce(&'r T) -> &'r R, // TODO: bounds on R 124 { 125 let data: MaybeUninit<&T> = MaybeUninit::zeroed(); 126 let result = f(data.assume_init()); 127 let size = mem::size_of_val(result) as DeviceSize; 128 let result = result as *const R as *const () as DeviceSize; 129 130 assert!(result <= self.size()); 131 assert!(result + size <= self.size()); 132 133 BufferSlice { 134 marker: PhantomData, 135 resource: self.resource, 136 offset: self.offset + result, 137 size, 138 } 139 } 140 141 /// Changes the `T` generic parameter of the `BufferSlice` to the desired type. This can be 142 /// useful when you have a buffer with various types of data and want to create a typed slice 143 /// of a region that contains a single type of data. 144 /// 145 /// # Example 146 /// 147 /// ``` 148 /// # use std::sync::Arc; 149 /// # use vulkano::buffer::BufferSlice; 150 /// # use vulkano::buffer::immutable::ImmutableBuffer; 151 /// # struct VertexImpl; 152 /// let blob_slice: BufferSlice<[u8], Arc<ImmutableBuffer<[u8]>>> = return; 153 /// let vertex_slice: BufferSlice<[VertexImpl], Arc<ImmutableBuffer<[u8]>>> = unsafe { 154 /// blob_slice.reinterpret::<[VertexImpl]>() 155 /// }; 156 /// ``` 157 /// 158 /// # Safety 159 /// 160 /// Correct `offset` and `size` must be ensured before using this `BufferSlice` on the device. 161 /// See `BufferSlice::slice` for adjusting these properties. 162 #[inline] reinterpret<R: ?Sized>(self) -> BufferSlice<R, B>163 pub unsafe fn reinterpret<R: ?Sized>(self) -> BufferSlice<R, B> { 164 BufferSlice { 165 marker: PhantomData, 166 resource: self.resource, 167 offset: self.offset, 168 size: self.size, 169 } 170 } 171 } 172 173 impl<T, B> BufferSlice<[T], B> { 174 /// Returns the number of elements in this slice. 175 #[inline] len(&self) -> DeviceSize176 pub fn len(&self) -> DeviceSize { 177 debug_assert_eq!(self.size() % mem::size_of::<T>() as DeviceSize, 0); 178 self.size() / mem::size_of::<T>() as DeviceSize 179 } 180 181 /// Reduces the slice to just one element of the array. 182 /// 183 /// Returns `None` if out of range. 184 #[inline] index(self, index: DeviceSize) -> Option<BufferSlice<T, B>>185 pub fn index(self, index: DeviceSize) -> Option<BufferSlice<T, B>> { 186 if index >= self.len() { 187 return None; 188 } 189 190 Some(BufferSlice { 191 marker: PhantomData, 192 resource: self.resource, 193 offset: self.offset + index * mem::size_of::<T>() as DeviceSize, 194 size: mem::size_of::<T>() as DeviceSize, 195 }) 196 } 197 198 /// Reduces the slice to just a range of the array. 199 /// 200 /// Returns `None` if out of range. 201 #[inline] slice(self, range: Range<DeviceSize>) -> Option<BufferSlice<[T], B>>202 pub fn slice(self, range: Range<DeviceSize>) -> Option<BufferSlice<[T], B>> { 203 if range.end > self.len() { 204 return None; 205 } 206 207 Some(BufferSlice { 208 marker: PhantomData, 209 resource: self.resource, 210 offset: self.offset + range.start * mem::size_of::<T>() as DeviceSize, 211 size: (range.end - range.start) * mem::size_of::<T>() as DeviceSize, 212 }) 213 } 214 } 215 216 unsafe impl<T: ?Sized, B> BufferAccess for BufferSlice<T, B> 217 where 218 B: BufferAccess, 219 { 220 #[inline] inner(&self) -> BufferInner221 fn inner(&self) -> BufferInner { 222 let inner = self.resource.inner(); 223 BufferInner { 224 buffer: inner.buffer, 225 offset: inner.offset + self.offset, 226 } 227 } 228 229 #[inline] size(&self) -> DeviceSize230 fn size(&self) -> DeviceSize { 231 self.size 232 } 233 234 #[inline] conflict_key(&self) -> (u64, u64)235 fn conflict_key(&self) -> (u64, u64) { 236 self.resource.conflict_key() 237 } 238 239 #[inline] try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError>240 fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> { 241 self.resource.try_gpu_lock(exclusive_access, queue) 242 } 243 244 #[inline] increase_gpu_lock(&self)245 unsafe fn increase_gpu_lock(&self) { 246 self.resource.increase_gpu_lock() 247 } 248 249 #[inline] unlock(&self)250 unsafe fn unlock(&self) { 251 self.resource.unlock() 252 } 253 } 254 255 unsafe impl<T: ?Sized, B> TypedBufferAccess for BufferSlice<T, B> 256 where 257 B: BufferAccess, 258 { 259 type Content = T; 260 } 261 262 unsafe impl<T: ?Sized, B> DeviceOwned for BufferSlice<T, B> 263 where 264 B: DeviceOwned, 265 { 266 #[inline] device(&self) -> &Arc<Device>267 fn device(&self) -> &Arc<Device> { 268 self.resource.device() 269 } 270 } 271 272 impl<T, B> From<BufferSlice<T, B>> for BufferSlice<[T], B> { 273 #[inline] from(r: BufferSlice<T, B>) -> BufferSlice<[T], B>274 fn from(r: BufferSlice<T, B>) -> BufferSlice<[T], B> { 275 BufferSlice { 276 marker: PhantomData, 277 resource: r.resource, 278 offset: r.offset, 279 size: r.size, 280 } 281 } 282 } 283 284 impl<T: ?Sized, B> PartialEq for BufferSlice<T, B> 285 where 286 B: BufferAccess, 287 { 288 #[inline] eq(&self, other: &Self) -> bool289 fn eq(&self, other: &Self) -> bool { 290 self.inner() == other.inner() && self.size() == other.size() 291 } 292 } 293 294 impl<T: ?Sized, B> Eq for BufferSlice<T, B> where B: BufferAccess {} 295 296 impl<T: ?Sized, B> Hash for BufferSlice<T, B> 297 where 298 B: BufferAccess, 299 { 300 #[inline] hash<H: Hasher>(&self, state: &mut H)301 fn hash<H: Hasher>(&self, state: &mut H) { 302 self.inner().hash(state); 303 self.size().hash(state); 304 } 305 } 306 307 /// Takes a `BufferSlice` that points to a struct, and returns a `BufferSlice` that points to 308 /// a specific field of that struct. 309 #[macro_export] 310 macro_rules! buffer_slice_field { 311 ($slice:expr, $field:ident) => { 312 // TODO: add #[allow(unsafe_code)] when that's allowed 313 unsafe { $slice.slice_custom(|s| &s.$field) } 314 }; 315 } 316