Add support for the Physical Storage Buffer Access feature. (#1359)

This feature was recently promoted from an extension to the core spec in Vulkan 1.2. It is already supported on many recent drivers: NVidia, Mesa RADV, and AMDVLK.

Other than supporting enabling the feature and the basic buffer address query, I made no attempt to create safe interfaces for its use. Such will come later, after I've experimented with its use in Geobacter.
This commit is contained in:
Richard Diamond 2020-05-15 13:26:06 -05:00 committed by GitHub
parent 68cc93932d
commit 57c545d7ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 560 additions and 153 deletions

View File

@ -56,6 +56,7 @@ pub type SwapchainKHR = u64;
pub type DisplayKHR = u64;
pub type DisplayModeKHR = u64;
pub type DescriptorUpdateTemplateKHR = u64;
pub type DeviceAddress = u64;
pub const LOD_CLAMP_NONE: f32 = 1000.0;
pub const REMAINING_MIP_LEVELS: u32 = 0xffffffff;
@ -195,6 +196,8 @@ pub const STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR: u32 = 1000
pub const STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR: u32 = 1000146003;
pub const STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR: u32 = 1000146004;
pub const STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT: u32 = 1000255000;
pub const STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT: u32 = 1000244000;
pub const STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO: u32 = 1000244001;
pub type SystemAllocationScope = u32;
pub const SYSTEM_ALLOCATION_SCOPE_COMMAND: u32 = 0;
@ -765,6 +768,7 @@ pub const BUFFER_USAGE_STORAGE_BUFFER_BIT: u32 = 0x00000020;
pub const BUFFER_USAGE_INDEX_BUFFER_BIT: u32 = 0x00000040;
pub const BUFFER_USAGE_VERTEX_BUFFER_BIT: u32 = 0x00000080;
pub const BUFFER_USAGE_INDIRECT_BUFFER_BIT: u32 = 0x00000100;
pub const BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT: u32 = 0x00020000;
pub type BufferUsageFlags = Flags;
pub type BufferViewCreateFlags = Flags;
pub type ImageViewCreateFlags = Flags;
@ -1563,6 +1567,13 @@ pub struct ImageCreateInfo {
pub initialLayout: ImageLayout,
}
#[repr(C)]
pub struct BufferDeviceAddressInfo {
pub sType: StructureType,
pub pNext: *const c_void,
pub buffer: Buffer,
}
#[repr(C)]
pub struct SubresourceLayout {
pub offset: DeviceSize,
@ -2547,6 +2558,15 @@ pub struct PhysicalDeviceSparseImageFormatInfo2KHR {
pub tiling: ImageTiling,
}
#[repr(C)]
pub struct PhysicalDeviceBufferAddressFeaturesEXT {
pub sType: StructureType,
pub pNext: *const c_void,
pub bufferDeviceAddress: Bool32,
pub bufferDeviceAddressCaptureReplay: Bool32,
pub bufferDeviceAddressMultiDevice: Bool32,
}
pub type ViSurfaceCreateFlagsNN = Flags;
#[repr(C)]
@ -2958,4 +2978,5 @@ ptrs!(DevicePointers, {
CmdInsertDebugUtilsLabelEXT => (commandBuffer: CommandBuffer, pLabelInfo: *const DebugUtilsLabelEXT) -> Result,
AcquireFullScreenExclusiveModeEXT => (device: Device, swapchain: SwapchainKHR) -> Result,
ReleaseFullScreenExclusiveModeEXT => (device: Device, swapchain: SwapchainKHR) -> Result,
GetBufferDeviceAddressEXT => (device: Device, pInfo: *const BufferDeviceAddressInfo) -> DeviceAddress,
});

View File

@ -69,7 +69,7 @@ impl UnsafeBuffer {
pub unsafe fn new<'a, I>(
device: Arc<Device>,
size: usize,
usage: BufferUsage,
mut usage: BufferUsage,
sharing: Sharing<I>,
sparse: SparseLevel,
) -> Result<(UnsafeBuffer, MemoryRequirements), BufferCreationError>
@ -86,14 +86,6 @@ impl UnsafeBuffer {
size
};
let usage_bits = usage.to_vulkan_bits();
// Checking for empty BufferUsage.
assert!(
usage_bits != 0,
"Can't create buffer with empty BufferUsage"
);
// Checking sparse features.
assert!(
sparse.sparse || !sparse.sparse_residency,
@ -112,6 +104,21 @@ impl UnsafeBuffer {
if sparse.sparse_aliased && !device.enabled_features().sparse_residency_aliased {
return Err(BufferCreationError::SparseResidencyAliasedFeatureNotEnabled);
}
if usage.device_address && !device.enabled_features().buffer_device_address {
usage.device_address = false;
if usage.to_vulkan_bits() == 0 {
// return an error iff device_address was the only requested usage and the
// feature isn't enabled. Otherwise we'll hit that assert below.
return Err(BufferCreationError::DeviceAddressFeatureNotEnabled);
}
}
let usage_bits = usage.to_vulkan_bits();
// Checking for empty BufferUsage.
assert!(
usage_bits != 0,
"Can't create buffer with empty BufferUsage"
);
let buffer = {
let (sh_mode, sh_indices) = match sharing {
@ -324,6 +331,11 @@ impl UnsafeBuffer {
(self.usage & vk::BUFFER_USAGE_INDIRECT_BUFFER_BIT) != 0
}
#[inline]
pub fn usage_device_address(&self) -> bool {
(self.usage & vk::BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) != 0
}
/// Returns a key unique to each `UnsafeBuffer`. Can be used for the `conflicts_key` method.
#[inline]
pub fn key(&self) -> u64 {
@ -416,6 +428,17 @@ impl SparseLevel {
}
}
/// The device address usage flag was not set.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct DeviceAddressUsageNotEnabledError;
impl error::Error for DeviceAddressUsageNotEnabledError { }
impl fmt::Display for DeviceAddressUsageNotEnabledError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("the device address usage flag was not set on this buffer")
}
}
/// Error that can happen when creating a buffer.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BufferCreationError {
@ -427,6 +450,8 @@ pub enum BufferCreationError {
SparseResidencyBufferFeatureNotEnabled,
/// Sparse aliasing was requested but the corresponding feature wasn't enabled.
SparseResidencyAliasedFeatureNotEnabled,
/// Device address was requested but the corresponding feature wasn't enabled.
DeviceAddressFeatureNotEnabled,
}
impl error::Error for BufferCreationError {
@ -453,6 +478,9 @@ impl fmt::Display for BufferCreationError {
BufferCreationError::SparseResidencyAliasedFeatureNotEnabled => {
"sparse aliasing was requested but the corresponding feature wasn't enabled"
}
BufferCreationError::DeviceAddressFeatureNotEnabled => {
"device address was requested but the corresponding feature wasn't enabled"
}
})
}
}

View File

@ -9,9 +9,11 @@
use std::hash::Hash;
use std::hash::Hasher;
use std::num::NonZeroU64;
use std::ops::Range;
use std::ptr;
use buffer::sys::UnsafeBuffer;
use buffer::sys::{UnsafeBuffer, DeviceAddressUsageNotEnabledError};
use buffer::BufferSlice;
use device::DeviceOwned;
use device::Queue;
@ -19,7 +21,7 @@ use image::ImageAccess;
use memory::Content;
use sync::AccessError;
use SafeDeref;
use ::{SafeDeref, VulkanObject, vk};
/// Trait for objects that represent a way for the GPU to have access to a buffer or a slice of a
/// buffer.
@ -142,6 +144,39 @@ pub unsafe trait BufferAccess: DeviceOwned {
///
/// Must only be called once per previous lock.
unsafe fn unlock(&self);
/// Gets the device address for this buffer.
///
/// # Safety
///
/// No lock checking or waiting is performed. This is nevertheless still safe because the
/// returned value isn't directly dereferencable. Unsafe code is required to dereference the
/// value in a shader.
fn raw_device_address(&self) -> Result<NonZeroU64, DeviceAddressUsageNotEnabledError> {
let inner = self.inner();
if !inner.buffer.usage_device_address() {
return Err(DeviceAddressUsageNotEnabledError);
}
let dev = self.device();
unsafe {
let info = vk::BufferDeviceAddressInfo {
sType: vk::STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
pNext: ptr::null(),
buffer: inner.buffer.internal_object(),
};
let ptr = dev.pointers()
.GetBufferDeviceAddressEXT(dev.internal_object(),
&info);
if ptr == 0 {
panic!("got null ptr from a valid GetBufferDeviceAddressEXT call");
}
Ok(NonZeroU64::new_unchecked(ptr + inner.offset as u64))
}
}
}
/// Inner information about a buffer.

View File

@ -27,6 +27,9 @@ pub struct BufferUsage {
pub index_buffer: bool,
pub vertex_buffer: bool,
pub indirect_buffer: bool,
/// Requires the `buffer_device_address` feature. If that feature is not enabled, this will
/// be silently ignored.
pub device_address: bool,
}
impl BufferUsage {
@ -60,6 +63,9 @@ impl BufferUsage {
if self.indirect_buffer {
result |= vk::BUFFER_USAGE_INDIRECT_BUFFER_BIT;
}
if self.device_address {
result |= vk::BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
}
result
}
@ -76,6 +82,7 @@ impl BufferUsage {
index_buffer: false,
vertex_buffer: false,
indirect_buffer: false,
device_address: false,
}
}
@ -92,6 +99,7 @@ impl BufferUsage {
index_buffer: true,
vertex_buffer: true,
indirect_buffer: true,
device_address: true,
}
}
@ -191,6 +199,15 @@ impl BufferUsage {
..BufferUsage::none()
}
}
/// Builds a `BufferUsage` with `device_address` set to true and the rest to false.
#[inline]
pub fn device_address() -> BufferUsage {
BufferUsage {
device_address: true,
..BufferUsage::none()
}
}
}
impl BitOr for BufferUsage {
@ -208,6 +225,7 @@ impl BitOr for BufferUsage {
index_buffer: self.index_buffer || rhs.index_buffer,
vertex_buffer: self.vertex_buffer || rhs.vertex_buffer,
indirect_buffer: self.indirect_buffer || rhs.indirect_buffer,
device_address: self.device_address || rhs.device_address,
}
}
}

View File

@ -221,6 +221,11 @@ impl Device {
.map(|extension| extension.as_ptr())
.collect::<SmallVec<[_; 16]>>();
let mut requested_features = requested_features.clone();
// Always enabled; see below.
requested_features.robust_buffer_access = true;
let requested_features = requested_features;
// device creation
let device = unsafe {
// each element of `queues` is a `(queue_family, priorities)`
@ -281,15 +286,12 @@ impl Device {
//
// Note that if we ever remove this, don't forget to adjust the change in
// `Device`'s construction below.
let features = {
let mut features = requested_features.clone().into_vulkan_features();
features.robustBufferAccess = vk::TRUE;
features
};
let features = requested_features.into_vulkan_features_v2();
let infos = vk::DeviceCreateInfo {
sType: vk::STRUCTURE_TYPE_DEVICE_CREATE_INFO,
pNext: ptr::null(),
pNext: features.base_ptr() as *const _,
flags: 0, // reserved
queueCreateInfoCount: queues.len() as u32,
pQueueCreateInfos: queues.as_ptr(),
@ -297,7 +299,7 @@ impl Device {
ppEnabledLayerNames: layers_ptr.as_ptr(),
enabledExtensionCount: extensions_list.len() as u32,
ppEnabledExtensionNames: extensions_list.as_ptr(),
pEnabledFeatures: &features,
pEnabledFeatures: ptr::null(),
};
let mut output = MaybeUninit::uninit();

View File

@ -7,56 +7,277 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::{mem, ptr};
use std::marker::PhantomPinned;
use std::pin::Pin;
use vk;
macro_rules! features {
($($name:ident => $vk:ident,)+) => (
/// Represents all the features that are available on a physical device or enabled on
/// a logical device.
///
/// Note that the `robust_buffer_access` is guaranteed to be supported by all Vulkan
/// implementations.
///
/// # Example
///
/// ```
/// use vulkano::device::Features;
/// # let physical_device: vulkano::instance::PhysicalDevice = return;
/// let minimal_features = Features {
/// geometry_shader: true,
/// .. Features::none()
/// };
///
/// let optimal_features = vulkano::device::Features {
/// geometry_shader: true,
/// tessellation_shader: true,
/// .. Features::none()
/// };
///
/// if !physical_device.supported_features().superset_of(&minimal_features) {
/// panic!("The physical device is not good enough for this application.");
/// }
///
/// assert!(optimal_features.superset_of(&minimal_features));
/// let features_to_request = optimal_features.intersection(physical_device.supported_features());
/// ```
///
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub struct Features {
$(
pub $name: bool,
)+
}
macro_rules! features_init {
(core { $name:ident => $vk:ident }, $out:expr, $val:expr) => {
$out.$name = $val;
};
(extension {
ty: $ty:ty,
ffi_name: $ffi_name:ident,
sType: $stype:expr,
fields: [
$($name:ident => $vk:ident,)+
],
}, $out:expr, $val:expr) => {
$($out.$name = $val;)+
};
}
macro_rules! features_superset_of {
(core { $name:ident => $vk:ident }, $self:expr, $other:expr) => {
($self.$name == true || $other.$name == false)
};
(extension {
ty: $ty:ty,
ffi_name: $ffi_name:ident,
sType: $stype:expr,
fields: [
$($name:ident => $vk:ident,)+
],
}, $self:expr, $other:expr) => {
$(($self.$name == true || $other.$name == false))&&+
};
}
macro_rules! features_intersection {
(core { $name:ident => $vk:ident }, $out:expr, $self:expr, $other:expr) => {
$out.$name = $self.$name && $other.$name;
};
(extension {
ty: $ty:ty,
ffi_name: $ffi_name:ident,
sType: $stype:expr,
fields: [
$($name:ident => $vk:ident,)+
],
}, $out:expr, $self:expr, $other:expr) => {
$($out.$name = $self.$name && $other.$name;)+
};
}
macro_rules! features_difference {
(core { $name:ident => $vk:ident }, $out:expr, $self:expr, $other:expr) => {
$out.$name = $self.$name && !$other.$name;
};
(extension {
ty: $ty:ty,
ffi_name: $ffi_name:ident,
sType: $stype:expr,
fields: [
$($name:ident => $vk:ident,)+
],
}, $out:expr, $self:expr, $other:expr) => {
$($out.$name = $self.$name && !$other.$name;)+
};
}
macro_rules! from_feature_v1 {
(core { $name:ident => $vk:ident }, $out:expr, $features:expr) => {
$out.$name = $features.$vk != vk::FALSE;
};
(extension {
ty: $ty:ty,
ffi_name: $ffi_name:ident,
sType: $stype:expr,
fields: [
$($name:ident => $vk:ident,)+
],
}, $out:expr, $features:expr) => {
// nothing.
};
}
macro_rules! into_feature_v1 {
(core { $name:ident => $vk:ident }, $out:expr, $self:expr) => {
$out.$vk = if $self.$name { vk::TRUE } else { vk::FALSE };
};
(extension {
ty: $ty:ty,
ffi_name: $ffi_name:ident,
sType: $stype:expr,
fields: [
$($name:ident => $vk:ident,)+
],
}, $out:expr, $self:expr) => {
// nothing.
};
}
macro_rules! from_ext_features_match {
(core { $name:ident => $vk:ident }, $output:expr, $base_ref:expr, $base_ptr:expr) => {
// nothing.
};
(extension {
ty: $ty:ty,
ffi_name: $ffi_name:ident,
sType: $stype:expr,
fields: [
$($name:ident => $vk:ident,)+
],
}, $output:expr, $base_ref:expr, $base_ptr:expr) => {
if $base_ref.sType == $stype {
let ptr = $base_ptr as *const $ty;
let r = ptr.as_ref().unwrap();
$($output.$name = r.$vk != vk::FALSE;)+
}
};
}
macro_rules! into_ext_features_match {
(core { $name:ident => $vk:ident }, $output:expr, $base_ref:expr, $base_ptr:expr) => {
// nothing.
};
(extension {
ty: $ty:ty,
ffi_name: $ffi_name:ident,
sType: $stype:expr,
fields: [
$($name:ident => $vk:ident,)+
],
}, $this:expr, $base_ref:expr, $base_ptr:expr) => {
if $base_ref.sType == $stype {
let ptr = $base_ptr as *mut $ty;
let r = ptr.as_mut().unwrap();
$(r.$vk = if $this.$name { vk::TRUE } else { vk::FALSE };)+
}
};
}
macro_rules! features_ffi_init_pinned {
(core { $name:ident => $vk:ident }, $this:expr, $prev:expr) => {
// nothing.
};
(extension {
ty: $ty:ty,
ffi_name: $ffi_name:ident,
sType: $stype:expr,
fields: [
$($name:ident => $vk:ident,)*
],
}, $this:expr, $prev:expr) => {{
$this.$ffi_name.sType = $stype;
let next = &mut $this.$ffi_name as *mut _ as *mut Base;
(&mut *$prev).pNext = next;
$prev = next;
}};
}
#[allow(non_snake_case)]
#[repr(C)]
pub(crate) struct Base {
sType: vk::StructureType,
pNext: *mut Base,
}
// Can't define this structure with macros :(
/// Represents all the features that are available on a physical device or enabled on
/// a logical device.
///
/// Note that the `robust_buffer_access` is guaranteed to be supported by all Vulkan
/// implementations.
///
/// # Example
///
/// ```
/// use vulkano::device::Features;
/// # let physical_device: vulkano::instance::PhysicalDevice = return;
/// let minimal_features = Features {
/// geometry_shader: true,
/// .. Features::none()
/// };
///
/// let optimal_features = vulkano::device::Features {
/// geometry_shader: true,
/// tessellation_shader: true,
/// .. Features::none()
/// };
///
/// if !physical_device.supported_features().superset_of(&minimal_features) {
/// panic!("The physical device is not good enough for this application.");
/// }
///
/// assert!(optimal_features.superset_of(&minimal_features));
/// let features_to_request = optimal_features.intersection(physical_device.supported_features());
/// ```
///
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
#[allow(missing_docs)]
pub struct Features {
pub robust_buffer_access: bool,
pub full_draw_index_uint32: bool,
pub image_cube_array: bool,
pub independent_blend: bool,
pub geometry_shader: bool,
pub tessellation_shader: bool,
pub sample_rate_shading: bool,
pub dual_src_blend: bool,
pub logic_op: bool,
pub multi_draw_indirect: bool,
pub draw_indirect_first_instance: bool,
pub depth_clamp: bool,
pub depth_bias_clamp: bool,
pub fill_mode_non_solid: bool,
pub depth_bounds: bool,
pub wide_lines: bool,
pub large_points: bool,
pub alpha_to_one: bool,
pub multi_viewport: bool,
pub sampler_anisotropy: bool,
pub texture_compression_etc2: bool,
pub texture_compression_astc_ldr: bool,
pub texture_compression_bc: bool,
pub occlusion_query_precise: bool,
pub pipeline_statistics_query: bool,
pub vertex_pipeline_stores_and_atomics: bool,
pub fragment_stores_and_atomics: bool,
pub shader_tessellation_and_geometry_point_size: bool,
pub shader_image_gather_extended: bool,
pub shader_storage_image_extended_formats: bool,
pub shader_storage_image_multisample: bool,
pub shader_storage_image_read_without_format: bool,
pub shader_storage_image_write_without_format: bool,
pub shader_uniform_buffer_array_dynamic_indexing: bool,
pub shader_sampled_image_array_dynamic_indexing: bool,
pub shader_storage_buffer_array_dynamic_indexing: bool,
pub shader_storage_image_array_dynamic_indexing: bool,
pub shader_clip_distance: bool,
pub shader_cull_distance: bool,
pub shader_f3264: bool,
pub shader_int64: bool,
pub shader_int16: bool,
pub shader_resource_residency: bool,
pub shader_resource_min_lod: bool,
pub sparse_binding: bool,
pub sparse_residency_buffer: bool,
pub sparse_residency_image2d: bool,
pub sparse_residency_image3d: bool,
pub sparse_residency2_samples: bool,
pub sparse_residency4_samples: bool,
pub sparse_residency8_samples: bool,
pub sparse_residency16_samples: bool,
pub sparse_residency_aliased: bool,
pub variable_multisample_rate: bool,
pub inherited_queries: bool,
pub buffer_device_address: bool,
pub buffer_device_address_capture_replay: bool,
pub buffer_device_address_multi_device: bool,
}
pub(crate) struct FeaturesFfi {
_pinned: PhantomPinned,
pub(crate) main: vk::PhysicalDeviceFeatures2KHR,
phys_dev_buf_addr: vk::PhysicalDeviceBufferAddressFeaturesEXT,
}
macro_rules! features {
($($kind:ident $args:tt,)+) => (
impl Features {
/// Builds a `Features` object with all values to false.
pub fn none() -> Features {
Features {
$(
$name: false,
)+
}
let mut out = Features::default();
$(features_init!($kind $args, out, false);)+
out
}
/// Builds a `Features` object with all values to true.
@ -64,11 +285,9 @@ macro_rules! features {
/// > **Note**: This function is used for testing purposes, and is probably useless in
/// > a real code.
pub fn all() -> Features {
Features {
$(
$name: true,
)+
}
let mut out = Features::default();
$(features_init!($kind $args, out, true);)+
out
}
/// Returns true if `self` is a superset of the parameter.
@ -76,7 +295,7 @@ macro_rules! features {
/// That is, for each feature of the parameter that is true, the corresponding value
/// in self is true as well.
pub fn superset_of(&self, other: &Features) -> bool {
$((self.$name == true || other.$name == false))&&+
$(features_superset_of!($kind $args, self, other))&&+
}
/// Builds a `Features` that is the intersection of `self` and another `Features`
@ -84,97 +303,184 @@ macro_rules! features {
///
/// The result's field will be true if it is also true in both `self` and `other`.
pub fn intersection(&self, other: &Features) -> Features {
Features {
$(
$name: self.$name && other.$name,
)+
}
let mut out = Self::none();
$(features_intersection!($kind $args, out, self, other);)+
out
}
/// Builds a `Features` that is the difference of another `Features` object from `self`.
///
/// The result's field will be true if it is true in `self` but not `other`.
pub fn difference(&self, other: &Features) -> Features {
Features {
$(
$name: self.$name && !other.$name,
)+
}
let mut out = Self::none();
$(features_difference!($kind $args, out, self, other);)+
out
}
pub(crate) fn from_vulkan_features(features: vk::PhysicalDeviceFeatures) -> Features {
Features {
$(
$name: features.$vk != 0,
)+
}
let mut out = Self::none();
$(from_feature_v1!($kind $args, out, features);)+
out
}
pub(crate) fn into_vulkan_features(self) -> vk::PhysicalDeviceFeatures {
vk::PhysicalDeviceFeatures {
$(
$vk: if self.$name { vk::TRUE } else { vk::FALSE },
)+
}
let mut out: vk::PhysicalDeviceFeatures = unsafe { mem::zeroed() };
$(into_feature_v1!($kind $args, out, self);)+
out
}
#[inline(always)]
pub(crate) fn into_vulkan_features_v2(&self) -> Pin<Box<FeaturesFfi>> {
let mut features = FeaturesFfi::new();
unsafe {
let mut next = FeaturesFfi::mut_base_ptr(&mut features);
while let Some(next_mut) = next.as_mut() {
match next_mut.sType {
vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR => {
let r = (next as *mut vk::PhysicalDeviceFeatures2KHR).as_mut().unwrap();
$(into_feature_v1!($kind $args, r.features, self);)+
},
_ => {
$(into_ext_features_match!($kind $args, self, next_mut, next);)+
},
}
next = next_mut.pNext as *mut Base;
}
}
features
}
#[inline(always)]
pub(crate) fn from_vulkan_features_v2(features: &vk::PhysicalDeviceFeatures2KHR) -> Self {
let mut output = Self::none();
unsafe {
let mut next: *const Base = features as *const vk::PhysicalDeviceFeatures2KHR as _;
while let Some(next_ref) = next.as_ref() {
match next_ref.sType {
vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR => {
let r = (next as *const vk::PhysicalDeviceFeatures2KHR).as_ref().unwrap();
$(from_feature_v1!($kind $args, output, r.features);)+
},
_ => {
$(from_ext_features_match!($kind $args, output, next_ref, next);)+
},
}
next = next_ref.pNext as *const Base;
}
}
output
}
}
impl FeaturesFfi {
#[inline(always)]
pub(crate) fn new() -> Pin<Box<Self>> {
#![allow(unused_assignments)]
let this = FeaturesFfi {
_pinned: PhantomPinned,
main: vk::PhysicalDeviceFeatures2KHR {
sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR,
pNext: ptr::null(),
features: unsafe { mem::zeroed() },
},
.. unsafe { mem::zeroed() }
};
let mut this = Box::pin(this);
unsafe {
let this = this.as_mut();
let this = this.get_unchecked_mut();
let mut base = &mut this.main as *mut _ as *mut Base;
$(features_ffi_init_pinned!($kind $args, this, base);)*
}
this
}
#[inline(always)]
pub(crate) fn base_ptr(&self) -> *const Base {
&self.main as *const _ as *const Base
}
#[inline(always)]
pub(crate) fn mut_base_ptr(this: &mut Pin<Box<Self>>) -> *mut Base {
unsafe {
let this = this.as_mut();
let this = this.get_unchecked_mut();
&mut this.main as *mut _ as *mut Base
}
}
}
)
}
features! {
robust_buffer_access => robustBufferAccess,
full_draw_index_uint32 => fullDrawIndexUint32,
image_cube_array => imageCubeArray,
independent_blend => independentBlend,
geometry_shader => geometryShader,
tessellation_shader => tessellationShader,
sample_rate_shading => sampleRateShading,
dual_src_blend => dualSrcBlend,
logic_op => logicOp,
multi_draw_indirect => multiDrawIndirect,
draw_indirect_first_instance => drawIndirectFirstInstance,
depth_clamp => depthClamp,
depth_bias_clamp => depthBiasClamp,
fill_mode_non_solid => fillModeNonSolid,
depth_bounds => depthBounds,
wide_lines => wideLines,
large_points => largePoints,
alpha_to_one => alphaToOne,
multi_viewport => multiViewport,
sampler_anisotropy => samplerAnisotropy,
texture_compression_etc2 => textureCompressionETC2,
texture_compression_astc_ldr => textureCompressionASTC_LDR,
texture_compression_bc => textureCompressionBC,
occlusion_query_precise => occlusionQueryPrecise,
pipeline_statistics_query => pipelineStatisticsQuery,
vertex_pipeline_stores_and_atomics => vertexPipelineStoresAndAtomics,
fragment_stores_and_atomics => fragmentStoresAndAtomics,
shader_tessellation_and_geometry_point_size => shaderTessellationAndGeometryPointSize,
shader_image_gather_extended => shaderImageGatherExtended,
shader_storage_image_extended_formats => shaderStorageImageExtendedFormats,
shader_storage_image_multisample => shaderStorageImageMultisample,
shader_storage_image_read_without_format => shaderStorageImageReadWithoutFormat,
shader_storage_image_write_without_format => shaderStorageImageWriteWithoutFormat,
shader_uniform_buffer_array_dynamic_indexing => shaderUniformBufferArrayDynamicIndexing,
shader_sampled_image_array_dynamic_indexing => shaderSampledImageArrayDynamicIndexing,
shader_storage_buffer_array_dynamic_indexing => shaderStorageBufferArrayDynamicIndexing,
shader_storage_image_array_dynamic_indexing => shaderStorageImageArrayDynamicIndexing,
shader_clip_distance => shaderClipDistance,
shader_cull_distance => shaderCullDistance,
shader_f3264 => shaderf3264,
shader_int64 => shaderInt64,
shader_int16 => shaderInt16,
shader_resource_residency => shaderResourceResidency,
shader_resource_min_lod => shaderResourceMinLod,
sparse_binding => sparseBinding,
sparse_residency_buffer => sparseResidencyBuffer,
sparse_residency_image2d => sparseResidencyImage2D,
sparse_residency_image3d => sparseResidencyImage3D,
sparse_residency2_samples => sparseResidency2Samples,
sparse_residency4_samples => sparseResidency4Samples,
sparse_residency8_samples => sparseResidency8Samples,
sparse_residency16_samples => sparseResidency16Samples,
sparse_residency_aliased => sparseResidencyAliased,
variable_multisample_rate => variableMultisampleRate,
inherited_queries => inheritedQueries,
core { robust_buffer_access => robustBufferAccess },
core { full_draw_index_uint32 => fullDrawIndexUint32 },
core { image_cube_array => imageCubeArray },
core { independent_blend => independentBlend },
core { geometry_shader => geometryShader },
core { tessellation_shader => tessellationShader },
core { sample_rate_shading => sampleRateShading },
core { dual_src_blend => dualSrcBlend },
core { logic_op => logicOp },
core { multi_draw_indirect => multiDrawIndirect },
core { draw_indirect_first_instance => drawIndirectFirstInstance },
core { depth_clamp => depthClamp },
core { depth_bias_clamp => depthBiasClamp },
core { fill_mode_non_solid => fillModeNonSolid },
core { depth_bounds => depthBounds },
core { wide_lines => wideLines },
core { large_points => largePoints },
core { alpha_to_one => alphaToOne },
core { multi_viewport => multiViewport },
core { sampler_anisotropy => samplerAnisotropy },
core { texture_compression_etc2 => textureCompressionETC2 },
core { texture_compression_astc_ldr => textureCompressionASTC_LDR },
core { texture_compression_bc => textureCompressionBC },
core { occlusion_query_precise => occlusionQueryPrecise },
core { pipeline_statistics_query => pipelineStatisticsQuery },
core { vertex_pipeline_stores_and_atomics => vertexPipelineStoresAndAtomics },
core { fragment_stores_and_atomics => fragmentStoresAndAtomics },
core { shader_tessellation_and_geometry_point_size => shaderTessellationAndGeometryPointSize },
core { shader_image_gather_extended => shaderImageGatherExtended },
core { shader_storage_image_extended_formats => shaderStorageImageExtendedFormats },
core { shader_storage_image_multisample => shaderStorageImageMultisample },
core { shader_storage_image_read_without_format => shaderStorageImageReadWithoutFormat },
core { shader_storage_image_write_without_format => shaderStorageImageWriteWithoutFormat },
core { shader_uniform_buffer_array_dynamic_indexing => shaderUniformBufferArrayDynamicIndexing },
core { shader_sampled_image_array_dynamic_indexing => shaderSampledImageArrayDynamicIndexing },
core { shader_storage_buffer_array_dynamic_indexing => shaderStorageBufferArrayDynamicIndexing },
core { shader_storage_image_array_dynamic_indexing => shaderStorageImageArrayDynamicIndexing },
core { shader_clip_distance => shaderClipDistance },
core { shader_cull_distance => shaderCullDistance },
core { shader_f3264 => shaderf3264 },
core { shader_int64 => shaderInt64 },
core { shader_int16 => shaderInt16 },
core { shader_resource_residency => shaderResourceResidency },
core { shader_resource_min_lod => shaderResourceMinLod },
core { sparse_binding => sparseBinding },
core { sparse_residency_buffer => sparseResidencyBuffer },
core { sparse_residency_image2d => sparseResidencyImage2D },
core { sparse_residency_image3d => sparseResidencyImage3D },
core { sparse_residency2_samples => sparseResidency2Samples },
core { sparse_residency4_samples => sparseResidency4Samples },
core { sparse_residency8_samples => sparseResidency8Samples },
core { sparse_residency16_samples => sparseResidency16Samples },
core { sparse_residency_aliased => sparseResidencyAliased },
core { variable_multisample_rate => variableMultisampleRate },
core { inherited_queries => inheritedQueries },
extension {
ty: vk::PhysicalDeviceBufferAddressFeaturesEXT,
ffi_name: phys_dev_buf_addr,
sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT,
fields: [
buffer_device_address => bufferDeviceAddress,
buffer_device_address_capture_replay => bufferDeviceAddressCaptureReplay,
buffer_device_address_multi_device => bufferDeviceAddressMultiDevice,
],
},
}

View File

@ -33,7 +33,7 @@ use Error;
use OomError;
use VulkanObject;
use features::Features;
use features::{Features, FeaturesFfi};
use instance::{InstanceExtensions, RawInstanceExtensions};
use version::Version;
@ -444,14 +444,11 @@ impl Instance {
output.memoryProperties
};
let available_features: vk::PhysicalDeviceFeatures = unsafe {
let mut output = vk::PhysicalDeviceFeatures2KHR {
sType: vk::STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR,
pNext: ptr::null_mut(),
features: mem::zeroed(),
};
vk.GetPhysicalDeviceFeatures2KHR(device, &mut output);
output.features
let available_features: Features = unsafe {
let mut output = FeaturesFfi::new();
let ptr = FeaturesFfi::mut_base_ptr(&mut output) as *mut _;
vk.GetPhysicalDeviceFeatures2KHR(device, ptr);
Features::from_vulkan_features_v2(&output.main)
};
output.push(PhysicalDeviceInfos {
@ -460,7 +457,7 @@ impl Instance {
extended_properties,
memory,
queue_families,
available_features: Features::from_vulkan_features(available_features),
available_features,
});
}
output