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