• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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