• 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::sys::{DeviceAddressUsageNotEnabledError, UnsafeBuffer};
11 use crate::buffer::BufferSlice;
12 use crate::device::DeviceOwned;
13 use crate::device::Queue;
14 use crate::memory::Content;
15 use crate::sync::AccessError;
16 use crate::DeviceSize;
17 use crate::{SafeDeref, VulkanObject};
18 use std::hash::Hash;
19 use std::hash::Hasher;
20 use std::num::NonZeroU64;
21 use std::ops::Range;
22 
23 /// Trait for objects that represent a way for the GPU to have access to a buffer or a slice of a
24 /// buffer.
25 ///
26 /// See also `TypedBufferAccess`.
27 pub unsafe trait BufferAccess: DeviceOwned {
28     /// Returns the inner information about this buffer.
inner(&self) -> BufferInner29     fn inner(&self) -> BufferInner;
30 
31     /// Returns the size of the buffer in bytes.
size(&self) -> DeviceSize32     fn size(&self) -> DeviceSize;
33 
34     /// Builds a `BufferSlice` object holding the buffer by reference.
35     #[inline]
as_buffer_slice(&self) -> BufferSlice<Self::Content, &Self> where Self: Sized + TypedBufferAccess,36     fn as_buffer_slice(&self) -> BufferSlice<Self::Content, &Self>
37     where
38         Self: Sized + TypedBufferAccess,
39     {
40         BufferSlice::from_typed_buffer_access(self)
41     }
42 
43     /// Builds a `BufferSlice` object holding part of the buffer by reference.
44     ///
45     /// This method can only be called for buffers whose type is known to be an array.
46     ///
47     /// This method can be used when you want to perform an operation on some part of the buffer
48     /// and not on the whole buffer.
49     ///
50     /// Returns `None` if out of range.
51     #[inline]
slice<T>(&self, range: Range<DeviceSize>) -> Option<BufferSlice<[T], &Self>> where Self: Sized + TypedBufferAccess<Content = [T]>,52     fn slice<T>(&self, range: Range<DeviceSize>) -> Option<BufferSlice<[T], &Self>>
53     where
54         Self: Sized + TypedBufferAccess<Content = [T]>,
55     {
56         BufferSlice::slice(self.as_buffer_slice(), range)
57     }
58 
59     /// Builds a `BufferSlice` object holding the buffer by value.
60     #[inline]
into_buffer_slice(self) -> BufferSlice<Self::Content, Self> where Self: Sized + TypedBufferAccess,61     fn into_buffer_slice(self) -> BufferSlice<Self::Content, Self>
62     where
63         Self: Sized + TypedBufferAccess,
64     {
65         BufferSlice::from_typed_buffer_access(self)
66     }
67 
68     /// Builds a `BufferSlice` object holding part of the buffer by reference.
69     ///
70     /// This method can only be called for buffers whose type is known to be an array.
71     ///
72     /// This method can be used when you want to perform an operation on a specific element of the
73     /// buffer and not on the whole buffer.
74     ///
75     /// Returns `None` if out of range.
76     #[inline]
index<T>(&self, index: DeviceSize) -> Option<BufferSlice<[T], &Self>> where Self: Sized + TypedBufferAccess<Content = [T]>,77     fn index<T>(&self, index: DeviceSize) -> Option<BufferSlice<[T], &Self>>
78     where
79         Self: Sized + TypedBufferAccess<Content = [T]>,
80     {
81         self.slice(index..(index + 1))
82     }
83 
84     /// Returns a key that uniquely identifies the buffer. Two buffers or images that potentially
85     /// overlap in memory must return the same key.
86     ///
87     /// The key is shared amongst all buffers and images, which means that you can make several
88     /// different buffer objects share the same memory, or make some buffer objects share memory
89     /// with images, as long as they return the same key.
90     ///
91     /// Since it is possible to accidentally return the same key for memory ranges that don't
92     /// overlap, the `conflicts_buffer` or `conflicts_image` function should always be called to
93     /// verify whether they actually overlap.
conflict_key(&self) -> (u64, u64)94     fn conflict_key(&self) -> (u64, u64);
95 
96     /// Locks the resource for usage on the GPU. Returns an error if the lock can't be acquired.
97     ///
98     /// This function exists to prevent the user from causing a data race by reading and writing
99     /// to the same resource at the same time.
100     ///
101     /// If you call this function, you should call `unlock()` once the resource is no longer in use
102     /// by the GPU. The implementation is not expected to automatically perform any unlocking and
103     /// can rely on the fact that `unlock()` is going to be called.
try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError>104     fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError>;
105 
106     /// Locks the resource for usage on the GPU. Supposes that the resource is already locked, and
107     /// simply increases the lock by one.
108     ///
109     /// Must only be called after `try_gpu_lock()` succeeded.
110     ///
111     /// If you call this function, you should call `unlock()` once the resource is no longer in use
112     /// by the GPU. The implementation is not expected to automatically perform any unlocking and
113     /// can rely on the fact that `unlock()` is going to be called.
increase_gpu_lock(&self)114     unsafe fn increase_gpu_lock(&self);
115 
116     /// Unlocks the resource previously acquired with `try_gpu_lock` or `increase_gpu_lock`.
117     ///
118     /// # Safety
119     ///
120     /// Must only be called once per previous lock.
unlock(&self)121     unsafe fn unlock(&self);
122 
123     /// Gets the device address for this buffer.
124     ///
125     /// # Safety
126     ///
127     /// No lock checking or waiting is performed. This is nevertheless still safe because the
128     /// returned value isn't directly dereferencable. Unsafe code is required to dereference the
129     /// value in a shader.
raw_device_address(&self) -> Result<NonZeroU64, DeviceAddressUsageNotEnabledError>130     fn raw_device_address(&self) -> Result<NonZeroU64, DeviceAddressUsageNotEnabledError> {
131         let inner = self.inner();
132 
133         if !inner.buffer.usage().device_address {
134             return Err(DeviceAddressUsageNotEnabledError);
135         }
136 
137         let dev = self.device();
138         unsafe {
139             let info = ash::vk::BufferDeviceAddressInfo {
140                 buffer: inner.buffer.internal_object(),
141                 ..Default::default()
142             };
143             let ptr = dev
144                 .fns()
145                 .ext_buffer_device_address
146                 .get_buffer_device_address_ext(dev.internal_object(), &info);
147 
148             if ptr == 0 {
149                 panic!("got null ptr from a valid GetBufferDeviceAddressEXT call");
150             }
151 
152             Ok(NonZeroU64::new_unchecked(ptr + inner.offset))
153         }
154     }
155 }
156 
157 /// Inner information about a buffer.
158 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
159 pub struct BufferInner<'a> {
160     /// The underlying buffer object.
161     pub buffer: &'a UnsafeBuffer,
162     /// The offset in bytes from the start of the underlying buffer object to the start of the
163     /// buffer we're describing.
164     pub offset: DeviceSize,
165 }
166 
167 unsafe impl<T> BufferAccess for T
168 where
169     T: SafeDeref,
170     T::Target: BufferAccess,
171 {
172     #[inline]
inner(&self) -> BufferInner173     fn inner(&self) -> BufferInner {
174         (**self).inner()
175     }
176 
177     #[inline]
size(&self) -> DeviceSize178     fn size(&self) -> DeviceSize {
179         (**self).size()
180     }
181 
182     #[inline]
conflict_key(&self) -> (u64, u64)183     fn conflict_key(&self) -> (u64, u64) {
184         (**self).conflict_key()
185     }
186 
187     #[inline]
try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError>188     fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
189         (**self).try_gpu_lock(exclusive_access, queue)
190     }
191 
192     #[inline]
increase_gpu_lock(&self)193     unsafe fn increase_gpu_lock(&self) {
194         (**self).increase_gpu_lock()
195     }
196 
197     #[inline]
unlock(&self)198     unsafe fn unlock(&self) {
199         (**self).unlock()
200     }
201 }
202 
203 /// Extension trait for `BufferAccess`. Indicates the type of the content of the buffer.
204 pub unsafe trait TypedBufferAccess: BufferAccess {
205     /// The type of the content.
206     type Content: ?Sized;
207 
208     /// Returns the length of the buffer in number of elements.
209     ///
210     /// This method can only be called for buffers whose type is known to be an array.
211     #[inline]
len(&self) -> DeviceSize where Self::Content: Content,212     fn len(&self) -> DeviceSize
213     where
214         Self::Content: Content,
215     {
216         self.size() / <Self::Content as Content>::indiv_size()
217     }
218 }
219 
220 unsafe impl<T> TypedBufferAccess for T
221 where
222     T: SafeDeref,
223     T::Target: TypedBufferAccess,
224 {
225     type Content = <T::Target as TypedBufferAccess>::Content;
226 }
227 
228 impl PartialEq for dyn BufferAccess + Send + Sync {
229     #[inline]
eq(&self, other: &Self) -> bool230     fn eq(&self, other: &Self) -> bool {
231         self.inner() == other.inner() && self.size() == other.size()
232     }
233 }
234 
235 impl Eq for dyn BufferAccess + Send + Sync {}
236 
237 impl Hash for dyn BufferAccess + Send + Sync {
238     #[inline]
hash<H: Hasher>(&self, state: &mut H)239     fn hash<H: Hasher>(&self, state: &mut H) {
240         self.inner().hash(state);
241         self.size().hash(state);
242     }
243 }
244