mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 14:24:18 +00:00
Improve DeviceLayout
convenience (#2599)
This commit is contained in:
parent
4f87b525e7
commit
a52e327184
@ -30,7 +30,6 @@
|
||||
use glam::f32::Mat4;
|
||||
use rand::Rng;
|
||||
use std::{
|
||||
alloc::Layout,
|
||||
error::Error,
|
||||
slice,
|
||||
sync::{
|
||||
@ -293,7 +292,7 @@ impl App {
|
||||
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||
..Default::default()
|
||||
},
|
||||
DeviceLayout::from_layout(Layout::for_value(&vertices)).unwrap(),
|
||||
DeviceLayout::for_value(vertices.as_slice()).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@ -311,7 +310,7 @@ impl App {
|
||||
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||
..Default::default()
|
||||
},
|
||||
DeviceLayout::from_layout(Layout::new::<vs::Data>()).unwrap(),
|
||||
DeviceLayout::new_sized::<vs::Data>(),
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{App, RenderContext};
|
||||
use std::{alloc::Layout, slice, sync::Arc};
|
||||
use std::{slice, sync::Arc};
|
||||
use vulkano::{
|
||||
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage},
|
||||
command_buffer::RenderPassBeginInfo,
|
||||
@ -122,7 +122,7 @@ impl SceneTask {
|
||||
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||
..Default::default()
|
||||
},
|
||||
DeviceLayout::from_layout(Layout::for_value(&vertices)).unwrap(),
|
||||
DeviceLayout::for_value(vertices.as_slice()).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -13,7 +13,7 @@ use crate::{
|
||||
},
|
||||
DeviceAlignment,
|
||||
},
|
||||
DeviceSize, NonZeroDeviceSize, Validated,
|
||||
DeviceSize, Validated,
|
||||
};
|
||||
use crossbeam_queue::ArrayQueue;
|
||||
use std::{
|
||||
@ -241,7 +241,6 @@ where
|
||||
where
|
||||
T: BufferContents + ?Sized,
|
||||
{
|
||||
let len = NonZeroDeviceSize::new(len).expect("empty slices are not valid buffer contents");
|
||||
let layout = T::LAYOUT.layout_for_len(len).unwrap();
|
||||
|
||||
unsafe { &mut *self.state.get() }
|
||||
|
@ -83,8 +83,8 @@ use crate::{
|
||||
},
|
||||
range_map::RangeMap,
|
||||
sync::{future::AccessError, AccessConflict, CurrentAccess, Sharing},
|
||||
DeviceSize, NonNullDeviceAddress, NonZeroDeviceSize, Requires, RequiresAllOf, RequiresOneOf,
|
||||
Validated, ValidationError, Version, VulkanError, VulkanObject,
|
||||
DeviceSize, NonNullDeviceAddress, Requires, RequiresAllOf, RequiresOneOf, Validated,
|
||||
ValidationError, Version, VulkanError, VulkanObject,
|
||||
};
|
||||
use parking_lot::{Mutex, MutexGuard};
|
||||
use smallvec::SmallVec;
|
||||
@ -352,7 +352,6 @@ impl Buffer {
|
||||
where
|
||||
T: BufferContents + ?Sized,
|
||||
{
|
||||
let len = NonZeroDeviceSize::new(len).expect("empty slices are not valid buffer contents");
|
||||
let layout = T::LAYOUT.layout_for_len(len).unwrap();
|
||||
let buffer = Subbuffer::new(Buffer::new(
|
||||
allocator,
|
||||
|
@ -944,10 +944,10 @@ impl BufferContentsLayout {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the [`DeviceLayout`] for the data for the given `len`, or returns [`None`] on
|
||||
/// arithmetic overflow or if the total size would exceed [`DeviceLayout::MAX_SIZE`].
|
||||
/// Returns the [`DeviceLayout`] for the data for the given `len`, or returns [`None`] if `len`
|
||||
/// is zero or if the total size would exceed [`DeviceLayout::MAX_SIZE`].
|
||||
#[inline]
|
||||
pub const fn layout_for_len(&self, len: NonZeroDeviceSize) -> Option<DeviceLayout> {
|
||||
pub const fn layout_for_len(&self, len: DeviceSize) -> Option<DeviceLayout> {
|
||||
match &self.0 {
|
||||
BufferContentsLayoutInner::Sized(sized) => Some(*sized),
|
||||
BufferContentsLayoutInner::Unsized {
|
||||
@ -977,7 +977,7 @@ impl BufferContentsLayout {
|
||||
"types with alignments above 64 are not valid buffer contents",
|
||||
);
|
||||
|
||||
if let Ok(sized) = DeviceLayout::from_layout(sized) {
|
||||
if let Some(sized) = DeviceLayout::from_layout(sized) {
|
||||
Self(BufferContentsLayoutInner::Sized(sized))
|
||||
} else {
|
||||
unreachable!()
|
||||
@ -994,7 +994,7 @@ impl BufferContentsLayout {
|
||||
"types with alignments above 64 are not valid buffer contents",
|
||||
);
|
||||
|
||||
if let Ok(element_layout) = DeviceLayout::from_layout(element_layout) {
|
||||
if let Some(element_layout) = DeviceLayout::from_layout(element_layout) {
|
||||
Self(BufferContentsLayoutInner::Unsized {
|
||||
head_layout: None,
|
||||
element_layout,
|
||||
@ -1021,11 +1021,11 @@ impl BufferContentsLayout {
|
||||
|
||||
while i < field_layouts.len() {
|
||||
head_layout = match DeviceLayout::from_layout(field_layouts[i]) {
|
||||
Ok(field_layout) => Some(match head_layout {
|
||||
Some(field_layout) => Some(match head_layout {
|
||||
Some(layout) => extend(layout, field_layout),
|
||||
None => field_layout,
|
||||
}),
|
||||
Err(_) => unreachable!(),
|
||||
None => unreachable!(),
|
||||
};
|
||||
|
||||
i += 1;
|
||||
@ -1133,7 +1133,7 @@ impl BufferContentsLayout {
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) const fn unwrap_sized(self) -> DeviceLayout {
|
||||
pub(crate) const fn unwrap_sized(self) -> DeviceLayout {
|
||||
match self.0 {
|
||||
BufferContentsLayoutInner::Sized(sized) => sized,
|
||||
BufferContentsLayoutInner::Unsized { .. } => {
|
||||
|
@ -4,7 +4,7 @@ use std::{
|
||||
error::Error,
|
||||
fmt::{Debug, Display, Formatter, Result as FmtResult},
|
||||
hash::{Hash, Hasher},
|
||||
mem::{self, align_of, size_of},
|
||||
mem,
|
||||
};
|
||||
|
||||
/// Vulkan analog of std's [`Alignment`], stored as a [`DeviceSize`] that is guaranteed to be a
|
||||
@ -15,8 +15,10 @@ use std::{
|
||||
#[repr(transparent)]
|
||||
pub struct DeviceAlignment(AlignmentEnum);
|
||||
|
||||
const _: () = assert!(size_of::<DeviceAlignment>() == size_of::<DeviceSize>());
|
||||
const _: () = assert!(align_of::<DeviceAlignment>() == align_of::<DeviceSize>());
|
||||
const _: () = assert!(mem::size_of::<DeviceAlignment>() == mem::size_of::<DeviceSize>());
|
||||
const _: () = assert!(mem::align_of::<DeviceAlignment>() == mem::align_of::<DeviceSize>());
|
||||
|
||||
const _: () = assert!(mem::size_of::<DeviceSize>() >= mem::size_of::<usize>());
|
||||
|
||||
impl DeviceAlignment {
|
||||
/// The smallest possible alignment, 1.
|
||||
@ -28,17 +30,15 @@ impl DeviceAlignment {
|
||||
/// Returns the alignment for a type.
|
||||
#[inline]
|
||||
pub const fn of<T>() -> Self {
|
||||
#[cfg(any(
|
||||
target_pointer_width = "64",
|
||||
target_pointer_width = "32",
|
||||
target_pointer_width = "16",
|
||||
))]
|
||||
{
|
||||
const _: () = assert!(size_of::<DeviceSize>() >= size_of::<usize>());
|
||||
// SAFETY: rustc guarantees that the alignment of types is a power of two.
|
||||
unsafe { DeviceAlignment::new_unchecked(mem::align_of::<T>() as DeviceSize) }
|
||||
}
|
||||
|
||||
// SAFETY: rustc guarantees that the alignment of types is a power of two.
|
||||
unsafe { DeviceAlignment::new_unchecked(align_of::<T>() as DeviceSize) }
|
||||
}
|
||||
/// Returns the alignment for a value.
|
||||
#[inline]
|
||||
pub fn of_val<T: ?Sized>(value: &T) -> Self {
|
||||
// SAFETY: rustc guarantees that the alignment of types is a power of two.
|
||||
unsafe { DeviceAlignment::new_unchecked(mem::align_of_val(value) as DeviceSize) }
|
||||
}
|
||||
|
||||
/// Tries to create a `DeviceAlignment` from a [`DeviceSize`], returning [`None`] if it's not a
|
||||
|
@ -1,11 +1,13 @@
|
||||
use super::align_up;
|
||||
use crate::{macros::try_opt, memory::DeviceAlignment, DeviceSize, NonZeroDeviceSize};
|
||||
use crate::{
|
||||
buffer::BufferContents, macros::try_opt, memory::DeviceAlignment, DeviceSize, NonZeroDeviceSize,
|
||||
};
|
||||
use std::{
|
||||
alloc::Layout,
|
||||
error::Error,
|
||||
fmt::{Debug, Display, Formatter, Result as FmtResult},
|
||||
hash::Hash,
|
||||
mem::size_of,
|
||||
mem,
|
||||
};
|
||||
|
||||
/// Vulkan analog of std's [`Layout`], represented using [`DeviceSize`]s.
|
||||
@ -17,6 +19,9 @@ pub struct DeviceLayout {
|
||||
alignment: DeviceAlignment,
|
||||
}
|
||||
|
||||
const _: () = assert!(mem::size_of::<DeviceSize>() >= mem::size_of::<usize>());
|
||||
const _: () = assert!(DeviceLayout::MAX_SIZE >= isize::MAX as DeviceSize);
|
||||
|
||||
impl DeviceLayout {
|
||||
/// The maximum size of a memory block after its layout's size has been rounded up to the
|
||||
/// nearest multiple of its layout's alignment.
|
||||
@ -26,59 +31,43 @@ impl DeviceLayout {
|
||||
/// undefined behavior*.
|
||||
pub const MAX_SIZE: DeviceSize = DeviceAlignment::MAX.as_devicesize() - 1;
|
||||
|
||||
/// Creates a new `DeviceLayout` from a [`Layout`], or returns an error if the `Layout` has
|
||||
/// Creates a new `DeviceLayout` from a [`Layout`], or returns [`None`] if the `Layout` has
|
||||
/// zero size.
|
||||
#[inline]
|
||||
pub const fn from_layout(layout: Layout) -> Result<Self, TryFromLayoutError> {
|
||||
pub const fn from_layout(layout: Layout) -> Option<DeviceLayout> {
|
||||
let (size, alignment) = Self::size_alignment_from_layout(&layout);
|
||||
|
||||
#[cfg(any(
|
||||
target_pointer_width = "64",
|
||||
target_pointer_width = "32",
|
||||
target_pointer_width = "16",
|
||||
))]
|
||||
{
|
||||
const _: () = assert!(size_of::<DeviceSize>() >= size_of::<usize>());
|
||||
const _: () = assert!(DeviceLayout::MAX_SIZE >= isize::MAX as DeviceSize);
|
||||
|
||||
if let Some(size) = NonZeroDeviceSize::new(size) {
|
||||
// SAFETY: Under the precondition that `usize` can't overflow `DeviceSize`, which
|
||||
// we checked above, `Layout`'s overflow-invariant is the same if not stricter than
|
||||
// that of `DeviceLayout`.
|
||||
Ok(unsafe { DeviceLayout::new_unchecked(size, alignment) })
|
||||
} else {
|
||||
Err(TryFromLayoutError)
|
||||
}
|
||||
if let Some(size) = NonZeroDeviceSize::new(size) {
|
||||
// SAFETY: Under the precondition that `usize` can't overflow `DeviceSize`, which we
|
||||
// checked above, `Layout`'s overflow-invariant is the same if not stricter than that
|
||||
// of `DeviceLayout`.
|
||||
Some(unsafe { DeviceLayout::new_unchecked(size, alignment) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the `DeviceLayout` into a [`Layout`], or returns an error if the `DeviceLayout`
|
||||
/// Converts the `DeviceLayout` into a [`Layout`], or returns [`None`] if the `DeviceLayout`
|
||||
/// doesn't meet the invariants of `Layout`.
|
||||
#[inline]
|
||||
pub const fn into_layout(self) -> Result<Layout, TryFromDeviceLayoutError> {
|
||||
pub const fn into_layout(self) -> Option<Layout> {
|
||||
let (size, alignment) = (self.size(), self.alignment().as_devicesize());
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
{
|
||||
const _: () = assert!(size_of::<DeviceSize>() <= size_of::<usize>());
|
||||
const _: () = assert!(DeviceLayout::MAX_SIZE as usize <= isize::MAX as usize);
|
||||
|
||||
// SAFETY: Under the precondition that `DeviceSize` can't overflow `usize`, which we
|
||||
// checked above, `DeviceLayout`'s overflow-invariant is the same if not stricter that
|
||||
// of `Layout`.
|
||||
Ok(unsafe { Layout::from_size_align_unchecked(size as usize, alignment as usize) })
|
||||
Some(unsafe { Layout::from_size_align_unchecked(size as usize, alignment as usize) })
|
||||
}
|
||||
#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))]
|
||||
{
|
||||
const _: () = assert!(size_of::<DeviceSize>() > size_of::<usize>());
|
||||
const _: () = assert!(DeviceLayout::MAX_SIZE > isize::MAX as DeviceSize);
|
||||
|
||||
if size > usize::MAX as DeviceSize || alignment > usize::MAX as DeviceSize {
|
||||
Err(TryFromDeviceLayoutError)
|
||||
None
|
||||
} else if let Ok(layout) = Layout::from_size_align(size as usize, alignment as usize) {
|
||||
Ok(layout)
|
||||
Some(layout)
|
||||
} else {
|
||||
Err(TryFromDeviceLayoutError)
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,6 +105,24 @@ impl DeviceLayout {
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new `DeviceLayout` for a sized `T`.
|
||||
#[inline]
|
||||
pub const fn new_sized<T: BufferContents>() -> DeviceLayout {
|
||||
T::LAYOUT.unwrap_sized()
|
||||
}
|
||||
|
||||
/// Creates a new `DeviceLayout` for an unsized `T` with an unsized tail of `len` elements.
|
||||
///
|
||||
/// Returns [`None`] if `len` is zero or if the total size would exceed
|
||||
/// [`DeviceLayout::MAX_SIZE`], unless the `T` is actually sized, in which case this behaves
|
||||
/// identically to [`new_sized`] and `len` is ignored.
|
||||
///
|
||||
/// [`new_sized`]: Self::new_sized
|
||||
#[inline]
|
||||
pub const fn new_unsized<T: BufferContents + ?Sized>(len: DeviceSize) -> Option<DeviceLayout> {
|
||||
T::LAYOUT.layout_for_len(len)
|
||||
}
|
||||
|
||||
/// Creates a new `DeviceLayout` from the given `size` and `alignment`.
|
||||
///
|
||||
/// Returns [`None`] if `size` would exceed [`DeviceLayout::MAX_SIZE`] when rounded up to the
|
||||
@ -151,6 +158,14 @@ impl DeviceLayout {
|
||||
DeviceLayout { size, alignment }
|
||||
}
|
||||
|
||||
/// Creates a new `DeviceLayout` for the given `value`.
|
||||
///
|
||||
/// Returns [`None`] if the value is zero-sized.
|
||||
#[inline]
|
||||
pub fn for_value<T: BufferContents + ?Sized>(value: &T) -> Option<DeviceLayout> {
|
||||
DeviceLayout::from_layout(Layout::for_value(value))
|
||||
}
|
||||
|
||||
/// Returns the minimum size in bytes for a memory block of this layout.
|
||||
#[inline]
|
||||
pub const fn size(&self) -> DeviceSize {
|
||||
@ -202,10 +217,11 @@ impl DeviceLayout {
|
||||
/// with padding at the end of each to ensure correct alignment of all instances.
|
||||
///
|
||||
/// Returns a tuple consisting of the new layout and the stride, in bytes, of `self`, or
|
||||
/// returns [`None`] on arithmetic overflow or when the total size would exceed
|
||||
/// returns [`None`] if `n` is zero or when the total size would exceed
|
||||
/// [`DeviceLayout::MAX_SIZE`].
|
||||
#[inline]
|
||||
pub const fn repeat(&self, n: NonZeroDeviceSize) -> Option<(Self, DeviceSize)> {
|
||||
pub const fn repeat(&self, n: DeviceSize) -> Option<(Self, DeviceSize)> {
|
||||
let n = try_opt!(NonZeroDeviceSize::new(n));
|
||||
let stride = self.padded_size();
|
||||
let size = try_opt!(stride.checked_mul(n));
|
||||
let layout = try_opt!(DeviceLayout::new(size, self.alignment));
|
||||
@ -275,23 +291,13 @@ impl DeviceLayout {
|
||||
|
||||
#[inline(always)]
|
||||
const fn size_alignment_from_layout(layout: &Layout) -> (DeviceSize, DeviceAlignment) {
|
||||
#[cfg(any(
|
||||
target_pointer_width = "64",
|
||||
target_pointer_width = "32",
|
||||
target_pointer_width = "16",
|
||||
))]
|
||||
{
|
||||
const _: () = assert!(size_of::<DeviceSize>() >= size_of::<usize>());
|
||||
const _: () = assert!(DeviceLayout::MAX_SIZE >= isize::MAX as DeviceSize);
|
||||
// We checked that `usize` can't overflow `DeviceSize` above, so this can't truncate.
|
||||
let (size, alignment) = (layout.size() as DeviceSize, layout.align() as DeviceSize);
|
||||
|
||||
// We checked that `usize` can't overflow `DeviceSize`, so this can't truncate.
|
||||
let (size, alignment) = (layout.size() as DeviceSize, layout.align() as DeviceSize);
|
||||
// SAFETY: `Layout`'s alignment-invariant guarantees that it is a power of two.
|
||||
let alignment = unsafe { DeviceAlignment::new_unchecked(alignment) };
|
||||
|
||||
// SAFETY: `Layout`'s alignment-invariant guarantees that it is a power of two.
|
||||
let alignment = unsafe { DeviceAlignment::new_unchecked(alignment) };
|
||||
|
||||
(size, alignment)
|
||||
}
|
||||
(size, alignment)
|
||||
}
|
||||
}
|
||||
|
||||
@ -300,7 +306,7 @@ impl TryFrom<Layout> for DeviceLayout {
|
||||
|
||||
#[inline]
|
||||
fn try_from(layout: Layout) -> Result<Self, Self::Error> {
|
||||
DeviceLayout::from_layout(layout)
|
||||
DeviceLayout::from_layout(layout).ok_or(TryFromLayoutError)
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,7 +315,7 @@ impl TryFrom<DeviceLayout> for Layout {
|
||||
|
||||
#[inline]
|
||||
fn try_from(device_layout: DeviceLayout) -> Result<Self, Self::Error> {
|
||||
DeviceLayout::into_layout(device_layout)
|
||||
DeviceLayout::into_layout(device_layout).ok_or(TryFromDeviceLayoutError)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user