use super::BufferContents;
use crate::buffer::sys::UnsafeBuffer;
use crate::buffer::BufferSlice;
use crate::device::DeviceOwned;
use crate::device::Queue;
use crate::sync::AccessError;
use crate::DeviceSize;
use crate::SafeDeref;
use crate::VulkanObject;
use std::error;
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;
use std::num::NonZeroU64;
use std::ops::Range;
use std::sync::Arc;
pub unsafe trait BufferAccess: DeviceOwned + Send + Sync {
fn inner(&self) -> BufferInner;
fn size(&self) -> DeviceSize;
#[inline]
fn into_buffer_slice(self: &Arc<Self>) -> Arc<BufferSlice<Self::Content, Self>>
where
Self: Sized + TypedBufferAccess,
{
BufferSlice::from_typed_buffer_access(self.clone())
}
#[inline]
fn slice<T>(self: &Arc<Self>, range: Range<DeviceSize>) -> Option<Arc<BufferSlice<[T], Self>>>
where
Self: Sized + TypedBufferAccess<Content = [T]>,
{
BufferSlice::slice(&self.into_buffer_slice(), range)
}
#[inline]
fn index<T>(self: &Arc<Self>, index: DeviceSize) -> Option<Arc<BufferSlice<T, Self>>>
where
Self: Sized + TypedBufferAccess<Content = [T]>,
{
BufferSlice::index(&self.into_buffer_slice(), index)
}
fn conflict_key(&self) -> (u64, u64);
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError>;
unsafe fn increase_gpu_lock(&self);
unsafe fn unlock(&self);
fn raw_device_address(&self) -> Result<NonZeroU64, BufferDeviceAddressError> {
let inner = self.inner();
let device = self.device();
if !device.enabled_features().buffer_device_address {
return Err(BufferDeviceAddressError::FeatureNotEnabled);
}
if !inner.buffer.usage().device_address {
return Err(BufferDeviceAddressError::BufferMissingUsage);
}
unsafe {
let info = ash::vk::BufferDeviceAddressInfo {
buffer: inner.buffer.internal_object(),
..Default::default()
};
let ptr = device
.fns()
.ext_buffer_device_address
.get_buffer_device_address_ext(device.internal_object(), &info);
if ptr == 0 {
panic!("got null ptr from a valid GetBufferDeviceAddressEXT call");
}
Ok(NonZeroU64::new_unchecked(ptr + inner.offset))
}
}
}
pub trait BufferAccessObject {
fn as_buffer_access_object(&self) -> Arc<dyn BufferAccess>;
}
impl BufferAccessObject for Arc<dyn BufferAccess> {
fn as_buffer_access_object(&self) -> Arc<dyn BufferAccess> {
self.clone()
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct BufferInner<'a> {
pub buffer: &'a UnsafeBuffer,
pub offset: DeviceSize,
}
unsafe impl<T> BufferAccess for T
where
T: SafeDeref + Send + Sync,
T::Target: BufferAccess,
{
#[inline]
fn inner(&self) -> BufferInner {
(**self).inner()
}
#[inline]
fn size(&self) -> DeviceSize {
(**self).size()
}
#[inline]
fn conflict_key(&self) -> (u64, u64) {
(**self).conflict_key()
}
#[inline]
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
(**self).try_gpu_lock(exclusive_access, queue)
}
#[inline]
unsafe fn increase_gpu_lock(&self) {
(**self).increase_gpu_lock()
}
#[inline]
unsafe fn unlock(&self) {
(**self).unlock()
}
}
pub unsafe trait TypedBufferAccess: BufferAccess {
type Content: BufferContents + ?Sized;
#[inline]
fn len(&self) -> DeviceSize {
self.size() / Self::Content::size_of_element()
}
}
unsafe impl<T> TypedBufferAccess for T
where
T: SafeDeref + Send + Sync,
T::Target: TypedBufferAccess,
{
type Content = <T::Target as TypedBufferAccess>::Content;
}
impl PartialEq for dyn BufferAccess {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.inner() == other.inner() && self.size() == other.size()
}
}
impl Eq for dyn BufferAccess {}
impl Hash for dyn BufferAccess {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner().hash(state);
self.size().hash(state);
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BufferDeviceAddressError {
BufferMissingUsage,
FeatureNotEnabled,
}
impl error::Error for BufferDeviceAddressError {}
impl fmt::Display for BufferDeviceAddressError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::BufferMissingUsage => write!(
fmt,
"the device address usage flag was not set on this buffer",
),
Self::FeatureNotEnabled => write!(
fmt,
"the buffer_device_address feature was not enabled on the device",
),
}
}
}