use super::{sys::Buffer, BufferContents, BufferSlice, BufferUsage};
use crate::{device::DeviceOwned, DeviceSize, RequiresOneOf, SafeDeref, Version, VulkanObject};
use std::{
error::Error,
fmt::{Debug, Display, Error as FmtError, Formatter},
hash::{Hash, Hasher},
num::NonZeroU64,
ops::Range,
sync::Arc,
};
pub unsafe trait BufferAccess: DeviceOwned + Send + Sync {
fn inner(&self) -> BufferInner<'_>;
fn size(&self) -> DeviceSize;
#[inline]
fn usage(&self) -> &BufferUsage {
self.inner().buffer.usage()
}
#[inline]
fn into_buffer_slice(self: &Arc<Self>) -> Arc<BufferSlice<Self::Content, Self>>
where
Self: Sized + TypedBufferAccess,
{
BufferSlice::from_typed_buffer_access(self.clone())
}
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)
}
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 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::RequirementNotMet {
required_for: "`raw_device_address`",
requires_one_of: RequiresOneOf {
features: &["buffer_device_address"],
..Default::default()
},
});
}
if !inner.buffer.usage().shader_device_address {
return Err(BufferDeviceAddressError::BufferMissingUsage);
}
unsafe {
let info = ash::vk::BufferDeviceAddressInfo {
buffer: inner.buffer.handle(),
..Default::default()
};
let fns = device.fns();
let f = if device.api_version() >= Version::V1_2 {
fns.v1_2.get_buffer_device_address
} else if device.enabled_extensions().khr_buffer_device_address {
fns.khr_buffer_device_address.get_buffer_device_address_khr
} else {
fns.ext_buffer_device_address.get_buffer_device_address_ext
};
let ptr = f(device.handle(), &info);
if ptr == 0 {
panic!("got null ptr from a valid GetBufferDeviceAddress 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> {
#[inline]
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 Arc<Buffer>,
pub offset: DeviceSize,
}
unsafe impl<T> BufferAccess for T
where
T: SafeDeref + Send + Sync,
T::Target: BufferAccess,
{
fn inner(&self) -> BufferInner<'_> {
(**self).inner()
}
fn size(&self) -> DeviceSize {
(**self).size()
}
}
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 Debug for dyn BufferAccess {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
f.debug_struct("dyn BufferAccess")
.field("inner", &self.inner())
.finish()
}
}
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 {
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 {
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
BufferMissingUsage,
}
impl Error for BufferDeviceAddressError {}
impl Display for BufferDeviceAddressError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::BufferMissingUsage => write!(
f,
"the device address usage flag was not set on this buffer",
),
}
}
}