use super::features::DeviceFeatures;
use super::flags::PipelineStage;
use super::physical::PhysicalDevice;
use super::sync::{Fence, Semaphore};
use super::{Error, Result, check};
use crate::raw::VulkanLibrary;
use crate::raw::bindings::*;
use std::ffi::{CString, c_char, c_void};
use std::sync::Arc;
#[derive(Clone, Copy)]
pub struct WaitSemaphore<'a> {
pub semaphore: &'a Semaphore,
pub value: u64,
pub dst_stage_mask: PipelineStage,
pub device_index: u32,
}
#[derive(Clone, Copy)]
pub struct SignalSemaphore<'a> {
pub semaphore: &'a Semaphore,
pub value: u64,
pub device_index: u32,
}
#[derive(Debug, Clone)]
pub struct QueueCreateInfo {
pub queue_family_index: u32,
pub queue_priorities: Vec<f32>,
}
impl QueueCreateInfo {
pub fn single(queue_family_index: u32) -> Self {
Self {
queue_family_index,
queue_priorities: vec![1.0],
}
}
}
impl WaitSemaphore<'_> {
pub fn binary(semaphore: &Semaphore, dst_stage: PipelineStage) -> WaitSemaphore<'_> {
WaitSemaphore {
semaphore,
value: 0,
dst_stage_mask: dst_stage,
device_index: 0,
}
}
pub fn timeline(
semaphore: &Semaphore,
value: u64,
dst_stage: PipelineStage,
) -> WaitSemaphore<'_> {
WaitSemaphore {
semaphore,
value,
dst_stage_mask: dst_stage,
device_index: 0,
}
}
}
impl SignalSemaphore<'_> {
pub fn binary(semaphore: &Semaphore) -> SignalSemaphore<'_> {
SignalSemaphore {
semaphore,
value: 0,
device_index: 0,
}
}
pub fn timeline(semaphore: &Semaphore, value: u64) -> SignalSemaphore<'_> {
SignalSemaphore {
semaphore,
value,
device_index: 0,
}
}
}
#[derive(Debug, Clone)]
pub struct DeviceCreateInfo<'a> {
pub queue_create_infos: &'a [QueueCreateInfo],
pub enabled_extensions: &'a [&'a str],
pub enabled_features: Option<&'a DeviceFeatures>,
}
#[allow(clippy::derivable_impls)]
impl<'a> Default for DeviceCreateInfo<'a> {
fn default() -> Self {
Self {
queue_create_infos: &[],
enabled_extensions: &[],
enabled_features: None,
}
}
}
pub(crate) struct DeviceInner {
pub(crate) handle: VkDevice,
pub(crate) dispatch: VkDeviceDispatchTable,
#[allow(dead_code)]
pub(crate) instance: Arc<super::instance::InstanceInner>,
pub(crate) physical_devices: Vec<VkPhysicalDevice>,
}
unsafe impl Send for DeviceInner {}
unsafe impl Sync for DeviceInner {}
impl Drop for DeviceInner {
fn drop(&mut self) {
if let Some(destroy) = self.dispatch.vkDestroyDevice {
unsafe { destroy(self.handle, std::ptr::null()) };
}
}
}
#[derive(Clone)]
pub struct Device {
pub(crate) inner: Arc<DeviceInner>,
}
impl Device {
pub(crate) fn new_group(
group: &super::physical::PhysicalDeviceGroup,
info: DeviceCreateInfo<'_>,
) -> Result<Self> {
let physical = group
.physical_devices
.first()
.ok_or(Error::Vk(VkResult::ERROR_INITIALIZATION_FAILED))?;
let raw_handles: Vec<VkPhysicalDevice> =
group.physical_devices.iter().map(|p| p.handle).collect();
Self::new_inner(physical, info, raw_handles)
}
pub(crate) fn new(physical: &PhysicalDevice, info: DeviceCreateInfo<'_>) -> Result<Self> {
Self::new_inner(physical, info, vec![physical.handle])
}
fn new_inner(
physical: &PhysicalDevice,
info: DeviceCreateInfo<'_>,
raw_physical_handles: Vec<VkPhysicalDevice>,
) -> Result<Self> {
let create = physical
.instance
.dispatch
.vkCreateDevice
.ok_or(Error::MissingFunction("vkCreateDevice"))?;
let mut raw_infos: Vec<VkDeviceQueueCreateInfo> =
Vec::with_capacity(info.queue_create_infos.len());
for qci in info.queue_create_infos {
raw_infos.push(VkDeviceQueueCreateInfo {
sType: VkStructureType::STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
pNext: std::ptr::null(),
flags: 0,
queueFamilyIndex: qci.queue_family_index,
queueCount: qci.queue_priorities.len() as u32,
pQueuePriorities: qci.queue_priorities.as_ptr(),
});
}
let ext_cstrings: Vec<CString> = info
.enabled_extensions
.iter()
.map(|s| CString::new(*s))
.collect::<std::result::Result<_, _>>()?;
let ext_ptrs: Vec<*mut c_char> = ext_cstrings
.iter()
.map(|s| s.as_ptr() as *mut c_char)
.collect();
let chain_owned: Option<(
VkPhysicalDeviceFeatures2,
VkPhysicalDeviceVulkan11Features,
VkPhysicalDeviceVulkan12Features,
VkPhysicalDeviceVulkan13Features,
)>;
let p_next: *const c_void;
let p_enabled_features: *const VkPhysicalDeviceFeatures;
if let Some(f) = info.enabled_features {
let mut v13 = f.features13;
v13.pNext = std::ptr::null_mut();
let mut v12 = f.features12;
v12.pNext = (&v13 as *const _ as *mut c_void).cast();
let mut v11 = f.features11;
v11.pNext = std::ptr::null_mut();
let mut features2 = VkPhysicalDeviceFeatures2 {
sType: VkStructureType::STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
pNext: std::ptr::null_mut(),
features: f.features10,
};
features2.pNext = std::ptr::null_mut();
chain_owned = Some((features2, v11, v12, v13));
let chain_ref = chain_owned.as_ref().unwrap();
unsafe {
let f2_ptr = &chain_ref.0 as *const _ as *mut VkPhysicalDeviceFeatures2;
let v11_ptr = &chain_ref.1 as *const _ as *mut VkPhysicalDeviceVulkan11Features;
let v12_ptr = &chain_ref.2 as *const _ as *mut VkPhysicalDeviceVulkan12Features;
let v13_ptr = &chain_ref.3 as *const _ as *mut VkPhysicalDeviceVulkan13Features;
(*f2_ptr).pNext = v11_ptr.cast();
(*v11_ptr).pNext = v12_ptr.cast();
(*v12_ptr).pNext = v13_ptr.cast();
(*v13_ptr).pNext = std::ptr::null_mut();
}
p_next = &chain_ref.0 as *const _ as *const c_void;
p_enabled_features = std::ptr::null();
} else {
chain_owned = None;
p_next = std::ptr::null();
p_enabled_features = std::ptr::null();
}
let group_info_owned: Option<VkDeviceGroupDeviceCreateInfo>;
let final_p_next: *const c_void = if raw_physical_handles.len() > 1 {
let mut g = VkDeviceGroupDeviceCreateInfo {
sType: VkStructureType::STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO,
pNext: p_next, physicalDeviceCount: raw_physical_handles.len() as u32,
pPhysicalDevices: raw_physical_handles.as_ptr(),
};
group_info_owned = Some(g);
let g_ref = group_info_owned.as_ref().unwrap();
g = *g_ref;
let _ = g;
group_info_owned.as_ref().unwrap() as *const _ as *const c_void
} else {
group_info_owned = None;
p_next
};
let create_info = VkDeviceCreateInfo {
sType: VkStructureType::STRUCTURE_TYPE_DEVICE_CREATE_INFO,
pNext: final_p_next,
queueCreateInfoCount: raw_infos.len() as u32,
pQueueCreateInfos: raw_infos.as_ptr(),
enabledExtensionCount: ext_ptrs.len() as u32,
ppEnabledExtensionNames: if ext_ptrs.is_empty() {
std::ptr::null()
} else {
ext_ptrs.as_ptr()
},
pEnabledFeatures: p_enabled_features,
..Default::default()
};
let mut handle: VkDevice = std::ptr::null_mut();
check(unsafe { create(physical.handle, &create_info, std::ptr::null(), &mut handle) })?;
let _ = chain_owned;
let _ = group_info_owned;
let library: &VulkanLibrary = &physical.instance.library;
let dispatch = unsafe { library.load_device(physical.instance.handle, handle) };
Ok(Self {
inner: Arc::new(DeviceInner {
handle,
dispatch,
instance: Arc::clone(&physical.instance),
physical_devices: raw_physical_handles,
}),
})
}
pub fn physical_device_count(&self) -> u32 {
self.inner.physical_devices.len() as u32
}
pub fn physical_device_handles(&self) -> &[VkPhysicalDevice] {
&self.inner.physical_devices
}
pub fn default_device_mask(&self) -> u32 {
let n = self.inner.physical_devices.len() as u32;
if n >= 32 {
0xFFFF_FFFF
} else {
(1u32 << n) - 1
}
}
pub fn dispatch(&self) -> &VkDeviceDispatchTable {
&self.inner.dispatch
}
pub fn raw(&self) -> VkDevice {
self.inner.handle
}
pub fn get_queue(&self, queue_family_index: u32, queue_index: u32) -> Queue {
let get = self
.inner
.dispatch
.vkGetDeviceQueue
.expect("vkGetDeviceQueue is required by Vulkan 1.0");
let mut queue: VkQueue = std::ptr::null_mut();
unsafe {
get(
self.inner.handle,
queue_family_index,
queue_index,
&mut queue,
)
};
Queue {
handle: queue,
device: Arc::clone(&self.inner),
}
}
pub fn wait_idle(&self) -> Result<()> {
let wait = self
.inner
.dispatch
.vkDeviceWaitIdle
.ok_or(Error::MissingFunction("vkDeviceWaitIdle"))?;
check(unsafe { wait(self.inner.handle) })
}
}
#[derive(Clone)]
pub struct Queue {
pub(crate) handle: VkQueue,
pub(crate) device: Arc<DeviceInner>,
}
impl Queue {
pub fn raw(&self) -> VkQueue {
self.handle
}
pub fn submit(
&self,
command_buffers: &[&super::CommandBuffer],
signal_fence: Option<&super::Fence>,
) -> Result<()> {
self.submit_with_sync(command_buffers, &[], &[], signal_fence)
}
pub fn submit_with_sync(
&self,
command_buffers: &[&super::CommandBuffer],
wait_semaphores: &[WaitSemaphore<'_>],
signal_semaphores: &[SignalSemaphore<'_>],
signal_fence: Option<&super::Fence>,
) -> Result<()> {
self.submit_with_groups(
command_buffers,
None,
wait_semaphores,
signal_semaphores,
signal_fence,
)
}
pub fn submit_with_groups(
&self,
command_buffers: &[&super::CommandBuffer],
command_buffer_device_masks: Option<&[u32]>,
wait_semaphores: &[WaitSemaphore<'_>],
signal_semaphores: &[SignalSemaphore<'_>],
signal_fence: Option<&super::Fence>,
) -> Result<()> {
let submit = self
.device
.dispatch
.vkQueueSubmit
.ok_or(Error::MissingFunction("vkQueueSubmit"))?;
if let Some(masks) = command_buffer_device_masks
&& masks.len() != command_buffers.len()
{
return Err(Error::InvalidArgument(
"submit_with_groups: command_buffer_device_masks length must \
match command_buffers length",
));
}
let raw_cmds: Vec<VkCommandBuffer> = command_buffers.iter().map(|c| c.raw()).collect();
let raw_wait: Vec<VkSemaphore> =
wait_semaphores.iter().map(|w| w.semaphore.raw()).collect();
let raw_wait_stages: Vec<u32> = wait_semaphores.iter().map(|w| w.dst_stage_mask.0).collect();
let raw_wait_values: Vec<u64> = wait_semaphores.iter().map(|w| w.value).collect();
let raw_wait_device_indices: Vec<u32> =
wait_semaphores.iter().map(|w| w.device_index).collect();
let raw_signal: Vec<VkSemaphore> = signal_semaphores
.iter()
.map(|s| s.semaphore.raw())
.collect();
let raw_signal_values: Vec<u64> = signal_semaphores.iter().map(|s| s.value).collect();
let raw_signal_device_indices: Vec<u32> = signal_semaphores
.iter()
.map(|s| s.device_index)
.collect();
let timeline_info = VkTimelineSemaphoreSubmitInfo {
sType: VkStructureType::STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
pNext: std::ptr::null(),
waitSemaphoreValueCount: raw_wait_values.len() as u32,
pWaitSemaphoreValues: if raw_wait_values.is_empty() {
std::ptr::null()
} else {
raw_wait_values.as_ptr()
},
signalSemaphoreValueCount: raw_signal_values.len() as u32,
pSignalSemaphoreValues: if raw_signal_values.is_empty() {
std::ptr::null()
} else {
raw_signal_values.as_ptr()
},
};
let mut p_next: *const std::ffi::c_void =
if self.device.dispatch.vkGetSemaphoreCounterValue.is_some() {
&timeline_info as *const _ as *const _
} else {
std::ptr::null()
};
let needs_group_chain = command_buffer_device_masks.is_some()
|| raw_wait_device_indices.iter().any(|&i| i != 0)
|| raw_signal_device_indices.iter().any(|&i| i != 0);
let cb_masks_owned: Vec<u32> = if needs_group_chain {
match command_buffer_device_masks {
Some(masks) => masks.to_vec(),
None => {
let default_mask = (1u32 << self.device.physical_devices.len() as u32)
.wrapping_sub(1);
vec![default_mask; raw_cmds.len()]
}
}
} else {
Vec::new()
};
let group_info = VkDeviceGroupSubmitInfo {
sType: VkStructureType::STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO,
pNext: p_next,
waitSemaphoreCount: raw_wait_device_indices.len() as u32,
pWaitSemaphoreDeviceIndices: if raw_wait_device_indices.is_empty() {
std::ptr::null()
} else {
raw_wait_device_indices.as_ptr()
},
commandBufferCount: cb_masks_owned.len() as u32,
pCommandBufferDeviceMasks: if cb_masks_owned.is_empty() {
std::ptr::null()
} else {
cb_masks_owned.as_ptr()
},
signalSemaphoreCount: raw_signal_device_indices.len() as u32,
pSignalSemaphoreDeviceIndices: if raw_signal_device_indices.is_empty() {
std::ptr::null()
} else {
raw_signal_device_indices.as_ptr()
},
};
if needs_group_chain {
p_next = &group_info as *const _ as *const _;
}
let submit_info = VkSubmitInfo {
sType: VkStructureType::STRUCTURE_TYPE_SUBMIT_INFO,
pNext: p_next,
waitSemaphoreCount: raw_wait.len() as u32,
pWaitSemaphores: if raw_wait.is_empty() {
std::ptr::null()
} else {
raw_wait.as_ptr()
},
pWaitDstStageMask: if raw_wait_stages.is_empty() {
std::ptr::null()
} else {
raw_wait_stages.as_ptr()
},
commandBufferCount: raw_cmds.len() as u32,
pCommandBuffers: raw_cmds.as_ptr(),
signalSemaphoreCount: raw_signal.len() as u32,
pSignalSemaphores: if raw_signal.is_empty() {
std::ptr::null()
} else {
raw_signal.as_ptr()
},
};
let fence_handle = signal_fence.map_or(0u64, super::Fence::raw);
check(unsafe { submit(self.handle, 1, &submit_info, fence_handle) })
}
pub fn wait_idle(&self) -> Result<()> {
let wait = self
.device
.dispatch
.vkQueueWaitIdle
.ok_or(Error::MissingFunction("vkQueueWaitIdle"))?;
check(unsafe { wait(self.handle) })
}
pub fn one_shot<F>(&self, device: &Device, queue_family_index: u32, record: F) -> Result<()>
where
F: FnOnce(&mut super::CommandBufferRecording<'_>) -> Result<()>,
{
let pool = super::CommandPool::new(device, queue_family_index)?;
let mut cmd = pool.allocate_primary()?;
{
let mut rec = cmd.begin()?;
record(&mut rec)?;
rec.end()?;
}
let fence = Fence::new(device)?;
self.submit(&[&cmd], Some(&fence))?;
fence.wait(u64::MAX)?;
Ok(())
}
}