mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-22 14:56:42 +00:00
Allow sparse flags when creating an UnsafeBuffer
This commit is contained in:
parent
2d0d3526e5
commit
8ac0cc8a7d
@ -30,6 +30,8 @@ use std::sync::Weak;
|
||||
use std::time::Duration;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use buffer::sys::BufferCreationError;
|
||||
use buffer::sys::SparseLevel;
|
||||
use buffer::sys::UnsafeBuffer;
|
||||
use buffer::sys::Usage;
|
||||
use buffer::traits::AccessRange;
|
||||
@ -122,7 +124,12 @@ impl<T: ?Sized> CpuAccessibleBuffer<T> {
|
||||
Sharing::Exclusive
|
||||
};
|
||||
|
||||
try!(UnsafeBuffer::new(device, size, &usage, sharing))
|
||||
match UnsafeBuffer::new(device, size, &usage, sharing, SparseLevel::none()) {
|
||||
Ok(b) => b,
|
||||
Err(BufferCreationError::OomError(err)) => return Err(err),
|
||||
Err(_) => unreachable!() // We don't use sparse binding, therefore the other
|
||||
// errors can't happen
|
||||
}
|
||||
};
|
||||
|
||||
let mem_ty = device.physical_device().memory_types()
|
||||
|
@ -21,6 +21,8 @@ use std::sync::Mutex;
|
||||
use std::sync::Weak;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use buffer::sys::BufferCreationError;
|
||||
use buffer::sys::SparseLevel;
|
||||
use buffer::sys::UnsafeBuffer;
|
||||
use buffer::sys::Usage;
|
||||
use buffer::traits::AccessRange;
|
||||
@ -110,7 +112,12 @@ impl<T: ?Sized> DeviceLocalBuffer<T> {
|
||||
Sharing::Exclusive
|
||||
};
|
||||
|
||||
try!(UnsafeBuffer::new(device, size, &usage, sharing))
|
||||
match UnsafeBuffer::new(device, size, &usage, sharing, SparseLevel::none()) {
|
||||
Ok(b) => b,
|
||||
Err(BufferCreationError::OomError(err)) => return Err(err),
|
||||
Err(_) => unreachable!() // We don't use sparse binding, therefore the other
|
||||
// errors can't happen
|
||||
}
|
||||
};
|
||||
|
||||
let mem_ty = {
|
||||
|
@ -28,6 +28,8 @@ use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::Ordering;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use buffer::sys::BufferCreationError;
|
||||
use buffer::sys::SparseLevel;
|
||||
use buffer::sys::UnsafeBuffer;
|
||||
use buffer::sys::Usage;
|
||||
use buffer::traits::AccessRange;
|
||||
@ -108,7 +110,12 @@ impl<T: ?Sized> ImmutableBuffer<T> {
|
||||
Sharing::Exclusive
|
||||
};
|
||||
|
||||
try!(UnsafeBuffer::new(device, size, &usage, sharing))
|
||||
match UnsafeBuffer::new(device, size, &usage, sharing, SparseLevel::none()) {
|
||||
Ok(b) => b,
|
||||
Err(BufferCreationError::OomError(err)) => return Err(err),
|
||||
Err(_) => unreachable!() // We don't use sparse binding, therefore the other
|
||||
// errors can't happen
|
||||
}
|
||||
};
|
||||
|
||||
let mem_ty = {
|
||||
|
@ -63,6 +63,7 @@ use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use self::device_local::DeviceLocalBuffer;
|
||||
pub use self::sys::BufferCreationError;
|
||||
pub use self::sys::Usage;
|
||||
pub use self::traits::Buffer;
|
||||
pub use self::traits::TypedBuffer;
|
||||
|
@ -7,6 +7,8 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
@ -18,6 +20,7 @@ use memory::MemoryRequirements;
|
||||
use sync::Sharing;
|
||||
|
||||
use check_errors;
|
||||
use Error;
|
||||
use OomError;
|
||||
use VulkanObject;
|
||||
use VulkanPointers;
|
||||
@ -27,6 +30,10 @@ use vk;
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - Doesn't handle synchronization.
|
||||
/// - Doesn't handle memory aliasing problems.
|
||||
/// - Doesn't check that memory was correctly bound and only once.
|
||||
/// - Doesn't enforce type safety.
|
||||
///
|
||||
#[derive(Debug)]
|
||||
pub struct UnsafeBuffer {
|
||||
@ -40,14 +47,36 @@ impl UnsafeBuffer {
|
||||
/// Creates a new buffer of the given size.
|
||||
///
|
||||
/// See the module's documentation for information about safety.
|
||||
pub unsafe fn new<'a, I>(device: &Arc<Device>, size: usize, usage: &Usage, sharing: Sharing<I>)
|
||||
-> Result<(UnsafeBuffer, MemoryRequirements), OomError>
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// Panicks if `sparse.sparse` is false and `sparse.sparse_residency` or
|
||||
/// `sparse.sparse_aliased` is true.
|
||||
///
|
||||
pub unsafe fn new<'a, I>(device: &Arc<Device>, size: usize, usage: &Usage, sharing: Sharing<I>,
|
||||
sparse: SparseLevel)
|
||||
-> Result<(UnsafeBuffer, MemoryRequirements), BufferCreationError>
|
||||
where I: Iterator<Item = u32>
|
||||
{
|
||||
let vk = device.pointers();
|
||||
|
||||
let usage = usage.to_usage_bits();
|
||||
|
||||
// Checking sparse features.
|
||||
assert!(sparse.sparse || !sparse.sparse_residency, "Can't enable sparse residency without \
|
||||
enabling sparse binding as well");
|
||||
assert!(sparse.sparse || !sparse.sparse_aliased, "Can't enable sparse aliasing without \
|
||||
enabling sparse binding as well");
|
||||
if sparse.sparse && !device.enabled_features().sparse_binding {
|
||||
return Err(BufferCreationError::SparseBindingFeatureNotEnabled);
|
||||
}
|
||||
if sparse.sparse_residency && !device.enabled_features().sparse_residency_buffer {
|
||||
return Err(BufferCreationError::SparseResidencyBufferFeatureNotEnabled);
|
||||
}
|
||||
if sparse.sparse_aliased && !device.enabled_features().sparse_residency_aliased {
|
||||
return Err(BufferCreationError::SparseResidencyAliasedFeatureNotEnabled);
|
||||
}
|
||||
|
||||
let buffer = {
|
||||
let (sh_mode, sh_indices) = match sharing {
|
||||
Sharing::Exclusive => (vk::SHARING_MODE_EXCLUSIVE, SmallVec::<[u32; 8]>::new()),
|
||||
@ -57,7 +86,7 @@ impl UnsafeBuffer {
|
||||
let infos = vk::BufferCreateInfo {
|
||||
sType: vk::STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
pNext: ptr::null(),
|
||||
flags: 0, // TODO: sparse resources binding
|
||||
flags: sparse.to_flags(),
|
||||
size: size as u64,
|
||||
usage: usage,
|
||||
sharingMode: sh_mode,
|
||||
@ -186,6 +215,33 @@ impl Drop for UnsafeBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct SparseLevel {
|
||||
pub sparse: bool,
|
||||
pub sparse_residency: bool,
|
||||
pub sparse_aliased: bool,
|
||||
}
|
||||
|
||||
impl SparseLevel {
|
||||
#[inline]
|
||||
pub fn none() -> SparseLevel {
|
||||
SparseLevel {
|
||||
sparse: false,
|
||||
sparse_residency: false,
|
||||
sparse_aliased: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_flags(&self) -> vk::BufferCreateFlagBits {
|
||||
let mut result = 0;
|
||||
if self.sparse { result |= vk::BUFFER_CREATE_SPARSE_BINDING_BIT; }
|
||||
if self.sparse_residency { result |= vk::BUFFER_CREATE_SPARSE_RESIDENCY_BIT; }
|
||||
if self.sparse_aliased { result |= vk::BUFFER_CREATE_SPARSE_ALIASED_BIT; }
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes how a buffer is going to be used. This is **not** an optimization.
|
||||
///
|
||||
/// If you try to use a buffer in a way that you didn't declare, a panic will happen.
|
||||
@ -341,10 +397,76 @@ impl Usage {
|
||||
}
|
||||
}
|
||||
|
||||
/// Error that can happen when creating a buffer.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum BufferCreationError {
|
||||
/// Not enough memory.
|
||||
OomError(OomError),
|
||||
/// Sparse binding was requested but the corresponding feature wasn't enabled.
|
||||
SparseBindingFeatureNotEnabled,
|
||||
/// Sparse residency was requested but the corresponding feature wasn't enabled.
|
||||
SparseResidencyBufferFeatureNotEnabled,
|
||||
/// Sparse aliasing was requested but the corresponding feature wasn't enabled.
|
||||
SparseResidencyAliasedFeatureNotEnabled,
|
||||
}
|
||||
|
||||
impl error::Error for BufferCreationError {
|
||||
#[inline]
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
BufferCreationError::OomError(_) => "not enough memory available",
|
||||
BufferCreationError::SparseBindingFeatureNotEnabled => {
|
||||
"sparse binding was requested but the corresponding feature wasn't enabled"
|
||||
},
|
||||
BufferCreationError::SparseResidencyBufferFeatureNotEnabled => {
|
||||
"sparse residency was requested but the corresponding feature wasn't enabled"
|
||||
},
|
||||
BufferCreationError::SparseResidencyAliasedFeatureNotEnabled => {
|
||||
"sparse aliasing was requested but the corresponding feature wasn't enabled"
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
match *self {
|
||||
BufferCreationError::OomError(ref err) => Some(err),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BufferCreationError {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
write!(fmt, "{}", error::Error::description(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OomError> for BufferCreationError {
|
||||
#[inline]
|
||||
fn from(err: OomError) -> BufferCreationError {
|
||||
BufferCreationError::OomError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for BufferCreationError {
|
||||
#[inline]
|
||||
fn from(err: Error) -> BufferCreationError {
|
||||
match err {
|
||||
err @ Error::OutOfHostMemory => BufferCreationError::OomError(OomError::from(err)),
|
||||
err @ Error::OutOfDeviceMemory => BufferCreationError::OomError(OomError::from(err)),
|
||||
_ => panic!("unexpected error: {:?}", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::iter::Empty;
|
||||
|
||||
use super::BufferCreationError;
|
||||
use super::SparseLevel;
|
||||
use super::UnsafeBuffer;
|
||||
use super::Usage;
|
||||
|
||||
@ -355,11 +477,76 @@ mod tests {
|
||||
fn create() {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
let (buf, reqs) = unsafe {
|
||||
UnsafeBuffer::new(&device, 128, &Usage::all(), Sharing::Exclusive::<Empty<_>>)
|
||||
UnsafeBuffer::new(&device, 128, &Usage::all(), Sharing::Exclusive::<Empty<_>>,
|
||||
SparseLevel::none())
|
||||
}.unwrap();
|
||||
|
||||
assert!(reqs.size >= 128);
|
||||
assert_eq!(buf.size(), 128);
|
||||
assert_eq!(&**buf.device() as *const Device, &*device as *const Device);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic = "Can't enable sparse residency without enabling sparse binding as well"]
|
||||
fn panic_wrong_sparse_residency() {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
let sparse = SparseLevel { sparse: false, sparse_residency: true, sparse_aliased: false };
|
||||
let _ = unsafe {
|
||||
UnsafeBuffer::new(&device, 128, &Usage::all(), Sharing::Exclusive::<Empty<_>>,
|
||||
sparse)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic = "Can't enable sparse aliasing without enabling sparse binding as well"]
|
||||
fn panic_wrong_sparse_aliased() {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
let sparse = SparseLevel { sparse: false, sparse_residency: false, sparse_aliased: true };
|
||||
let _ = unsafe {
|
||||
UnsafeBuffer::new(&device, 128, &Usage::all(), Sharing::Exclusive::<Empty<_>>,
|
||||
sparse)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_feature_sparse_binding() {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
let sparse = SparseLevel { sparse: true, sparse_residency: false, sparse_aliased: false };
|
||||
unsafe {
|
||||
match UnsafeBuffer::new(&device, 128, &Usage::all(), Sharing::Exclusive::<Empty<_>>,
|
||||
sparse)
|
||||
{
|
||||
Err(BufferCreationError::SparseBindingFeatureNotEnabled) => (),
|
||||
_ => panic!()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_feature_sparse_residency() {
|
||||
let (device, _) = gfx_dev_and_queue!(sparse_binding);
|
||||
let sparse = SparseLevel { sparse: true, sparse_residency: true, sparse_aliased: false };
|
||||
unsafe {
|
||||
match UnsafeBuffer::new(&device, 128, &Usage::all(), Sharing::Exclusive::<Empty<_>>,
|
||||
sparse)
|
||||
{
|
||||
Err(BufferCreationError::SparseResidencyBufferFeatureNotEnabled) => (),
|
||||
_ => panic!()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_feature_sparse_aliased() {
|
||||
let (device, _) = gfx_dev_and_queue!(sparse_binding);
|
||||
let sparse = SparseLevel { sparse: true, sparse_residency: false, sparse_aliased: true };
|
||||
unsafe {
|
||||
match UnsafeBuffer::new(&device, 128, &Usage::all(), Sharing::Exclusive::<Empty<_>>,
|
||||
sparse)
|
||||
{
|
||||
Err(BufferCreationError::SparseResidencyAliasedFeatureNotEnabled) => (),
|
||||
_ => panic!()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,11 @@ macro_rules! gfx_dev_and_queue {
|
||||
.. Features::none()
|
||||
};
|
||||
|
||||
// If the physical device doesn't support the requested features, just return.
|
||||
if !physical.supported_features().superset_of(&features) {
|
||||
return;
|
||||
}
|
||||
|
||||
let (device, queues) = match Device::new(&physical, &features,
|
||||
&extensions, None, [(queue, 0.5)].iter().cloned())
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user