Skip to content

Commit

Permalink
Add support for ext_private_data (vulkano-rs#2350)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rua authored and hakolao committed Feb 20, 2024
1 parent 9785986 commit 88c2eaf
Show file tree
Hide file tree
Showing 2 changed files with 323 additions and 0 deletions.
47 changes: 47 additions & 0 deletions vulkano/src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ use std::{
};

pub mod physical;
pub mod private_data;
pub(crate) mod properties;
mod queue;

Expand Down Expand Up @@ -198,6 +199,7 @@ impl Device {
enabled_extensions: _,
enabled_features: _,
ref physical_devices,
private_data_slot_request_count: _,
_ne: _,
} = create_info;

Expand Down Expand Up @@ -283,6 +285,7 @@ impl Device {
ref enabled_extensions,
ref enabled_features,
ref physical_devices,
private_data_slot_request_count,
_ne: _,
} = &create_info;

Expand Down Expand Up @@ -361,6 +364,18 @@ impl Device {
create_info_vk.p_next = next as *mut _ as *mut _;
}

let mut private_data_create_info_vk = None;

if private_data_slot_request_count != 0 {
let next = private_data_create_info_vk.insert(ash::vk::DevicePrivateDataCreateInfo {
private_data_slot_request_count,
..Default::default()
});

next.p_next = create_info_vk.p_next;
create_info_vk.p_next = next as *mut _ as *mut _;
}

// VUID-VkDeviceCreateInfo-pNext-00373
if has_khr_get_physical_device_properties2 {
create_info_vk.p_next = features_ffi.head_as_ref() as *const _ as _;
Expand Down Expand Up @@ -401,6 +416,7 @@ impl Device {
enabled_features,
enabled_extensions,
physical_devices,
private_data_slot_request_count: _,
_ne: _,
} = create_info;

Expand Down Expand Up @@ -1208,6 +1224,20 @@ pub struct DeviceCreateInfo {
/// [`khr_device_group`]: crate::device::DeviceExtensions::khr_device_group
pub physical_devices: SmallVec<[Arc<PhysicalDevice>; 2]>,

/// The number of [private data slots] to reserve when creating the device.
///
/// This is purely an optimization, and it is not necessary to do this in order to use private
/// data slots, but it may improve performance.
///
/// If not zero, the physical device API version must be at least 1.3, or `enabled_extensions`
/// must contain [`ext_private_data`].
///
/// The default value is `0`.
///
/// [private data slots]: self::private_data
/// [`ext_private_data`]: DeviceExtensions::ext_private_data
pub private_data_slot_request_count: u32,

pub _ne: crate::NonExhaustive,
}

Expand All @@ -1219,6 +1249,7 @@ impl Default for DeviceCreateInfo {
enabled_extensions: DeviceExtensions::empty(),
enabled_features: Features::empty(),
physical_devices: SmallVec::new(),
private_data_slot_request_count: 0,
_ne: crate::NonExhaustive(()),
}
}
Expand All @@ -1234,6 +1265,7 @@ impl DeviceCreateInfo {
ref enabled_extensions,
ref enabled_features,
ref physical_devices,
private_data_slot_request_count,
_ne: _,
} = self;

Expand Down Expand Up @@ -1525,6 +1557,21 @@ impl DeviceCreateInfo {
}
}

if private_data_slot_request_count != 0
&& !(physical_device.api_version() >= Version::V1_3
|| enabled_extensions.ext_private_data)
{
return Err(Box::new(ValidationError {
context: "private_data_slot_request_count".into(),
problem: "is not zero".into(),
requires_one_of: RequiresOneOf(&[
RequiresAllOf(&[Requires::APIVersion(Version::V1_3)]),
RequiresAllOf(&[Requires::DeviceExtension("ext_private_data")]),
]),
..Default::default()
}));
}

Ok(())
}
}
Expand Down
276 changes: 276 additions & 0 deletions vulkano/src/device/private_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
// Copyright (c) 2023 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Store user-defined data associated with Vulkan objects.
//!
//! A private data slot allows you to associate an arbitrary `u64` value with any device-owned
//! Vulkan object. Each private data slot can store one value per object, but you can use the
//! value to look up a larger amount of data in a collection such as a `HashMap`.
//!
//! The intended usage is to create one private data slot for every subsystem in your program
//! that needs to assign data to objects independently of the others. That way, different parts
//! of a program manage their own private data and don't interfere with each other's data.
//!
//! When creating a device, it is possible to reserve private data slots ahead of time using
//! [`DeviceCreateInfo::private_data_slot_request_count`]. This is not necessary, but it can
//! speed up the use of data slots later.
//!
//! [`DeviceCreateInfo::private_data_slot_request_count`]: super::DeviceCreateInfo::private_data_slot_request_count
use super::{Device, DeviceOwned};
use crate::{
instance::InstanceOwnedDebugWrapper, Requires, RequiresAllOf, RequiresOneOf, Validated,
ValidationError, Version, VulkanError, VulkanObject,
};
use ash::vk::Handle;
use std::{mem::MaybeUninit, ptr, sync::Arc};

/// An object that stores one `u64` value per Vulkan object.
#[derive(Debug)]
pub struct PrivateDataSlot {
device: InstanceOwnedDebugWrapper<Arc<Device>>,
handle: ash::vk::PrivateDataSlot,
}

impl PrivateDataSlot {
/// Creates a new `PrivateDataSlot`.
///
/// The `private_data` feature must be enabled on the device.
#[inline]
pub fn new(
device: Arc<Device>,
create_info: PrivateDataSlotCreateInfo,
) -> Result<Self, Validated<VulkanError>> {
Self::validate_new(&device, &create_info)?;

unsafe { Ok(Self::new_unchecked(device, create_info)?) }
}

fn validate_new(
device: &Device,
create_info: &PrivateDataSlotCreateInfo,
) -> Result<(), Box<ValidationError>> {
if !device.enabled_features().private_data {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
"private_data",
)])]),
vuids: &["VUID-vkCreatePrivateDataSlot-privateData-04564"],
..Default::default()
}));
}

create_info
.validate(device)
.map_err(|err| err.add_context("create_info"))?;

Ok(())
}

#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn new_unchecked(
device: Arc<Device>,
create_info: PrivateDataSlotCreateInfo,
) -> Result<Self, VulkanError> {
let &PrivateDataSlotCreateInfo { _ne: _ } = &create_info;

let create_info_vk = ash::vk::PrivateDataSlotCreateInfo {
flags: ash::vk::PrivateDataSlotCreateFlags::empty(),
..Default::default()
};

let handle = {
let fns = device.fns();
let mut output = MaybeUninit::uninit();

if device.api_version() >= Version::V1_3 {
(fns.v1_3.create_private_data_slot)(
device.handle(),
&create_info_vk,
ptr::null(),
output.as_mut_ptr(),
)
} else {
(fns.ext_private_data.create_private_data_slot_ext)(
device.handle(),
&create_info_vk,
ptr::null(),
output.as_mut_ptr(),
)
}
.result()
.map_err(VulkanError::from)?;

output.assume_init()
};

Ok(Self::from_handle(device, handle, create_info))
}

/// Creates a new `PrivateDataSlot` from a raw object handle.
///
/// # Safety
///
/// - `handle` must be a valid Vulkan object handle created from `device`.
/// - `create_info` must match the info used to create the object.
#[inline]
pub unsafe fn from_handle(
device: Arc<Device>,
handle: ash::vk::PrivateDataSlot,
_create_info: PrivateDataSlotCreateInfo,
) -> Self {
Self {
device: InstanceOwnedDebugWrapper(device),
handle,
}
}

/// Sets the private data that is associated with `object` to `data`.
///
/// If `self` already has data for `object`, that data is replaced with the new value.
#[inline]
pub fn set_private_data<T: VulkanObject + DeviceOwned>(
&self,
object: &T,
data: u64,
) -> Result<(), Validated<VulkanError>> {
self.validate_set_private_data(object)?;

unsafe { Ok(self.set_private_data_unchecked(object, data)?) }
}

fn validate_set_private_data<T: VulkanObject + DeviceOwned>(
&self,
object: &T,
) -> Result<(), Box<ValidationError>> {
assert_eq!(self.device(), object.device());

Ok(())
}

#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn set_private_data_unchecked<T: VulkanObject + DeviceOwned>(
&self,
object: &T,
data: u64,
) -> Result<(), VulkanError> {
let fns = self.device.fns();

if self.device.api_version() >= Version::V1_3 {
(fns.v1_3.set_private_data)(
self.device.handle(),
T::Handle::TYPE,
object.handle().as_raw(),
self.handle,
data,
)
} else {
(fns.ext_private_data.set_private_data_ext)(
self.device.handle(),
T::Handle::TYPE,
object.handle().as_raw(),
self.handle,
data,
)
}
.result()
.map_err(VulkanError::from)
}

/// Returns the private data in `self` that is associated with `object`.
///
/// If no private data was previously set, 0 is returned.
pub fn get_private_data<T: VulkanObject + DeviceOwned>(&self, object: &T) -> u64 {
let fns = self.device.fns();

unsafe {
let mut output = MaybeUninit::uninit();

if self.device.api_version() >= Version::V1_3 {
(fns.v1_3.get_private_data)(
self.device.handle(),
T::Handle::TYPE,
object.handle().as_raw(),
self.handle,
output.as_mut_ptr(),
)
} else {
(fns.ext_private_data.get_private_data_ext)(
self.device.handle(),
T::Handle::TYPE,
object.handle().as_raw(),
self.handle,
output.as_mut_ptr(),
)
}

output.assume_init()
}
}
}

impl Drop for PrivateDataSlot {
#[inline]
fn drop(&mut self) {
unsafe {
let fns = self.device.fns();

if self.device.api_version() >= Version::V1_3 {
(fns.v1_3.destroy_private_data_slot)(
self.device.handle(),
self.handle,
ptr::null(),
);
} else {
(fns.ext_private_data.destroy_private_data_slot_ext)(
self.device.handle(),
self.handle,
ptr::null(),
);
}
}
}
}

unsafe impl VulkanObject for PrivateDataSlot {
type Handle = ash::vk::PrivateDataSlot;

#[inline]
fn handle(&self) -> Self::Handle {
self.handle
}
}

unsafe impl DeviceOwned for PrivateDataSlot {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}

/// Parameters to create a new `PrivateDataSlot`.
#[derive(Clone, Debug)]
pub struct PrivateDataSlotCreateInfo {
pub _ne: crate::NonExhaustive,
}

impl Default for PrivateDataSlotCreateInfo {
#[inline]
fn default() -> Self {
Self {
_ne: crate::NonExhaustive(()),
}
}
}

impl PrivateDataSlotCreateInfo {
pub(crate) fn validate(&self, _device: &Device) -> Result<(), Box<ValidationError>> {
Ok(())
}
}

0 comments on commit 88c2eaf

Please sign in to comment.