use fnv::FnvHasher;
use smallvec::SmallVec;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::error;
use std::fmt;
use std::hash::BuildHasherDefault;
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::MutexGuard;
use std::sync::Weak;
use std::ffi::CStr;
use command_buffer::pool::StandardCommandPool;
use descriptor::descriptor_set::StdDescriptorPool;
use instance::Instance;
use instance::PhysicalDevice;
use instance::QueueFamily;
use memory::pool::StdMemoryPool;
use Error;
use OomError;
use SynchronizedVulkanObject;
use VulkanObject;
use VulkanHandle;
use check_errors;
use vk;
pub use self::extensions::DeviceExtensions;
pub use self::extensions::RawDeviceExtensions;
pub use ::features::Features;
mod extensions;
pub struct Device {
instance: Arc<Instance>,
physical_device: usize,
device: vk::Device,
vk: vk::DevicePointers,
standard_pool: Mutex<Weak<StdMemoryPool>>,
standard_descriptor_pool: Mutex<Weak<StdDescriptorPool>>,
standard_command_pools:
Mutex<HashMap<u32, Weak<StandardCommandPool>, BuildHasherDefault<FnvHasher>>>,
features: Features,
extensions: DeviceExtensions,
active_queue_families: SmallVec<[u32; 8]>,
allocation_count: Mutex<u32>,
fence_pool: Mutex<Vec<vk::Fence>>,
semaphore_pool: Mutex<Vec<vk::Semaphore>>,
event_pool: Mutex<Vec<vk::Event>>,
}
unsafe impl Send for Device {
}
unsafe impl Sync for Device {
}
impl Device {
pub fn new<'a, I, Ext>(phys: PhysicalDevice, requested_features: &Features, extensions: Ext,
queue_families: I)
-> Result<(Arc<Device>, QueuesIter), DeviceCreationError>
where I: IntoIterator<Item = (QueueFamily<'a>, f32)>,
Ext: Into<RawDeviceExtensions>
{
let queue_families = queue_families.into_iter();
if !phys.supported_features().superset_of(&requested_features) {
return Err(DeviceCreationError::FeatureNotPresent);
}
let vk_i = phys.instance().pointers();
let mut output_queues: SmallVec<[(u32, u32); 8]> = SmallVec::new();
let layers_ptr = phys.instance()
.loaded_layers()
.map(|layer| layer.as_ptr())
.collect::<SmallVec<[_; 16]>>();
let extensions = extensions.into();
let extensions_list = extensions
.iter()
.map(|extension| extension.as_ptr())
.collect::<SmallVec<[_; 16]>>();
let device = unsafe {
let mut queues: Vec<(u32, Vec<f32>)> = Vec::with_capacity(phys.queue_families().len());
for (queue_family, priority) in queue_families {
assert_eq!(queue_family.physical_device().internal_object(),
phys.internal_object());
if priority < 0.0 || priority > 1.0 {
return Err(DeviceCreationError::PriorityOutOfRange);
}
if let Some(q) = queues.iter_mut().find(|q| q.0 == queue_family.id()) {
output_queues.push((queue_family.id(), q.1.len() as u32));
q.1.push(priority);
if q.1.len() > queue_family.queues_count() {
return Err(DeviceCreationError::TooManyQueuesForFamily);
}
continue;
}
queues.push((queue_family.id(), vec![priority]));
output_queues.push((queue_family.id(), 0));
}
let queues = queues
.iter()
.map(|&(queue_id, ref priorities)| {
vk::DeviceQueueCreateInfo {
sType: vk::STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
pNext: ptr::null(),
flags: 0,
queueFamilyIndex: queue_id,
queueCount: priorities.len() as u32,
pQueuePriorities: priorities.as_ptr(),
}
})
.collect::<SmallVec<[_; 16]>>();
let features = {
let mut features = requested_features.clone().into_vulkan_features();
features.robustBufferAccess = vk::TRUE;
features
};
let infos = vk::DeviceCreateInfo {
sType: vk::STRUCTURE_TYPE_DEVICE_CREATE_INFO,
pNext: ptr::null(),
flags: 0,
queueCreateInfoCount: queues.len() as u32,
pQueueCreateInfos: queues.as_ptr(),
enabledLayerCount: layers_ptr.len() as u32,
ppEnabledLayerNames: layers_ptr.as_ptr(),
enabledExtensionCount: extensions_list.len() as u32,
ppEnabledExtensionNames: extensions_list.as_ptr(),
pEnabledFeatures: &features,
};
let mut output = MaybeUninit::uninit();
check_errors(vk_i.CreateDevice(phys.internal_object(),
&infos,
ptr::null(),
output.as_mut_ptr()))?;
output.assume_init()
};
let vk = vk::DevicePointers::load(|name| unsafe {
vk_i.GetDeviceProcAddr(device, name.as_ptr()) as
*const _
});
let mut active_queue_families: SmallVec<[u32; 8]> = SmallVec::new();
for (queue_family, _) in output_queues.iter() {
if let None = active_queue_families.iter().find(|&&qf| qf == *queue_family) {
active_queue_families.push(*queue_family);
}
}
let device =
Arc::new(Device {
instance: phys.instance().clone(),
physical_device: phys.index(),
device: device,
vk: vk,
standard_pool: Mutex::new(Weak::new()),
standard_descriptor_pool: Mutex::new(Weak::new()),
standard_command_pools: Mutex::new(Default::default()),
features: Features {
robust_buffer_access: true,
..requested_features.clone()
},
extensions: (&extensions).into(),
active_queue_families,
allocation_count: Mutex::new(0),
fence_pool: Mutex::new(Vec::new()),
semaphore_pool: Mutex::new(Vec::new()),
event_pool: Mutex::new(Vec::new()),
});
let output_queues = QueuesIter {
next_queue: 0,
device: device.clone(),
families_and_ids: output_queues,
};
Ok((device, output_queues))
}
#[inline]
pub(crate) fn pointers(&self) -> &vk::DevicePointers {
&self.vk
}
pub unsafe fn wait(&self) -> Result<(), OomError> {
check_errors(self.vk.DeviceWaitIdle(self.device))?;
Ok(())
}
#[inline]
pub fn instance(&self) -> &Arc<Instance> {
&self.instance
}
#[inline]
pub fn physical_device(&self) -> PhysicalDevice {
PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
}
#[inline]
pub fn active_queue_families<'a>(&'a self)
-> Box<dyn ExactSizeIterator<Item = QueueFamily<'a>> + 'a> {
let physical_device = self.physical_device();
Box::new(self.active_queue_families
.iter()
.map(move |&id| physical_device.queue_family_by_id(id).unwrap()))
}
#[inline]
pub fn enabled_features(&self) -> &Features {
&self.features
}
#[inline]
pub fn loaded_extensions(&self) -> &DeviceExtensions {
&self.extensions
}
pub fn standard_pool(me: &Arc<Self>) -> Arc<StdMemoryPool> {
let mut pool = me.standard_pool.lock().unwrap();
if let Some(p) = pool.upgrade() {
return p;
}
let new_pool = StdMemoryPool::new(me.clone());
*pool = Arc::downgrade(&new_pool);
new_pool
}
pub fn standard_descriptor_pool(me: &Arc<Self>) -> Arc<StdDescriptorPool> {
let mut pool = me.standard_descriptor_pool.lock().unwrap();
if let Some(p) = pool.upgrade() {
return p;
}
let new_pool = Arc::new(StdDescriptorPool::new(me.clone()));
*pool = Arc::downgrade(&new_pool);
new_pool
}
pub fn standard_command_pool(me: &Arc<Self>, queue: QueueFamily) -> Arc<StandardCommandPool> {
let mut standard_command_pools = me.standard_command_pools.lock().unwrap();
match standard_command_pools.entry(queue.id()) {
Entry::Occupied(mut entry) => {
if let Some(pool) = entry.get().upgrade() {
return pool;
}
let new_pool = Arc::new(StandardCommandPool::new(me.clone(), queue));
*entry.get_mut() = Arc::downgrade(&new_pool);
new_pool
},
Entry::Vacant(entry) => {
let new_pool = Arc::new(StandardCommandPool::new(me.clone(), queue));
entry.insert(Arc::downgrade(&new_pool));
new_pool
},
}
}
pub(crate) fn allocation_count(&self) -> &Mutex<u32> {
&self.allocation_count
}
pub(crate) fn fence_pool(&self) -> &Mutex<Vec<vk::Fence>> {
&self.fence_pool
}
pub(crate) fn semaphore_pool(&self) -> &Mutex<Vec<vk::Semaphore>> {
&self.semaphore_pool
}
pub(crate) fn event_pool(&self) -> &Mutex<Vec<vk::Event>> {
&self.event_pool
}
pub fn set_object_name<T: VulkanObject + DeviceOwned>(&self, object: &T, name: &CStr) -> Result<(), OomError> {
assert!(object.device().internal_object() == self.internal_object());
unsafe { self.set_object_name_raw(T::TYPE, object.internal_object().value(), name) }
}
pub unsafe fn set_object_name_raw(&self, ty: vk::ObjectType, object: u64, name: &CStr) -> Result<(), OomError> {
let info = vk::DebugUtilsObjectNameInfoEXT {
sType: vk::STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
pNext: ptr::null(),
objectType: ty,
objectHandle: object,
pObjectName: name.as_ptr(),
};
check_errors(self.vk.SetDebugUtilsObjectNameEXT(self.device, &info))?;
Ok(())
}
}
impl fmt::Debug for Device {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Vulkan device {:?}>", self.device)
}
}
unsafe impl VulkanObject for Device {
type Object = vk::Device;
const TYPE: vk::ObjectType = vk::OBJECT_TYPE_DEVICE;
#[inline]
fn internal_object(&self) -> vk::Device {
self.device
}
}
impl Drop for Device {
#[inline]
fn drop(&mut self) {
unsafe {
for &raw_fence in self.fence_pool.lock().unwrap().iter() {
self.vk.DestroyFence(self.device, raw_fence, ptr::null());
}
for &raw_sem in self.semaphore_pool.lock().unwrap().iter() {
self.vk.DestroySemaphore(self.device, raw_sem, ptr::null());
}
for &raw_event in self.event_pool.lock().unwrap().iter() {
self.vk.DestroyEvent(self.device, raw_event, ptr::null());
}
self.vk.DestroyDevice(self.device, ptr::null());
}
}
}
pub unsafe trait DeviceOwned {
fn device(&self) -> &Arc<Device>;
}
unsafe impl<T> DeviceOwned for T
where T: Deref,
T::Target: DeviceOwned
{
#[inline]
fn device(&self) -> &Arc<Device> {
(**self).device()
}
}
pub struct QueuesIter {
next_queue: usize,
device: Arc<Device>,
families_and_ids: SmallVec<[(u32, u32); 8]>,
}
unsafe impl DeviceOwned for QueuesIter {
fn device(&self) -> &Arc<Device> {
&self.device
}
}
impl Iterator for QueuesIter {
type Item = Arc<Queue>;
fn next(&mut self) -> Option<Arc<Queue>> {
unsafe {
let &(family, id) = match self.families_and_ids.get(self.next_queue) {
Some(a) => a,
None => return None,
};
self.next_queue += 1;
let mut output = MaybeUninit::uninit();
self.device
.vk
.GetDeviceQueue(self.device.device, family, id, output.as_mut_ptr());
Some(Arc::new(Queue {
queue: Mutex::new(output.assume_init()),
device: self.device.clone(),
family: family,
id: id,
}))
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.families_and_ids.len().saturating_sub(self.next_queue);
(len, Some(len))
}
}
impl ExactSizeIterator for QueuesIter {
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DeviceCreationError {
InitializationFailed,
TooManyObjects,
DeviceLost,
FeatureNotPresent,
ExtensionNotPresent,
TooManyQueuesForFamily,
PriorityOutOfRange,
OutOfHostMemory,
OutOfDeviceMemory,
}
impl error::Error for DeviceCreationError {
#[inline]
fn description(&self) -> &str {
match *self {
DeviceCreationError::InitializationFailed => {
"failed to create the device for an implementation-specific reason"
},
DeviceCreationError::OutOfHostMemory => "no memory available on the host",
DeviceCreationError::OutOfDeviceMemory => {
"no memory available on the graphical device"
},
DeviceCreationError::DeviceLost => {
"failed to connect to the device"
},
DeviceCreationError::TooManyQueuesForFamily => {
"tried to create too many queues for a given family"
},
DeviceCreationError::FeatureNotPresent => {
"some of the requested features are unsupported by the physical device"
},
DeviceCreationError::PriorityOutOfRange => {
"the priority of one of the queues is out of the [0.0; 1.0] range"
},
DeviceCreationError::ExtensionNotPresent => {
"some of the requested device extensions are not supported by the physical device"
},
DeviceCreationError::TooManyObjects => {
"you have reached the limit to the number of devices that can be created from the
same physical device"
},
}
}
}
impl fmt::Display for DeviceCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
impl From<Error> for DeviceCreationError {
#[inline]
fn from(err: Error) -> DeviceCreationError {
match err {
Error::InitializationFailed => DeviceCreationError::InitializationFailed,
Error::OutOfHostMemory => DeviceCreationError::OutOfHostMemory,
Error::OutOfDeviceMemory => DeviceCreationError::OutOfDeviceMemory,
Error::DeviceLost => DeviceCreationError::DeviceLost,
Error::ExtensionNotPresent => DeviceCreationError::ExtensionNotPresent,
Error::FeatureNotPresent => DeviceCreationError::FeatureNotPresent,
Error::TooManyObjects => DeviceCreationError::TooManyObjects,
_ => panic!("Unexpected error value: {}", err as i32),
}
}
}
#[derive(Debug)]
pub struct Queue {
queue: Mutex<vk::Queue>,
device: Arc<Device>,
family: u32,
id: u32,
}
impl Queue {
#[inline]
pub fn device(&self) -> &Arc<Device> {
&self.device
}
#[inline]
pub fn is_same(&self, other: &Queue) -> bool {
self.id == other.id && self.family == other.family &&
self.device.internal_object() == other.device.internal_object()
}
#[inline]
pub fn family(&self) -> QueueFamily {
self.device
.physical_device()
.queue_family_by_id(self.family)
.unwrap()
}
#[inline]
pub fn id_within_family(&self) -> u32 {
self.id
}
#[inline]
pub fn wait(&self) -> Result<(), OomError> {
unsafe {
let vk = self.device.pointers();
let queue = self.queue.lock().unwrap();
check_errors(vk.QueueWaitIdle(*queue))?;
Ok(())
}
}
}
unsafe impl DeviceOwned for Queue {
fn device(&self) -> &Arc<Device> {
&self.device
}
}
unsafe impl SynchronizedVulkanObject for Queue {
type Object = vk::Queue;
#[inline]
fn internal_object_guard(&self) -> MutexGuard<vk::Queue> {
self.queue.lock().unwrap()
}
}
#[cfg(test)]
mod tests {
use device::Device;
use device::DeviceCreationError;
use device::DeviceExtensions;
use features::Features;
use instance;
use std::sync::Arc;
#[test]
fn one_ref() {
let (mut device, _) = gfx_dev_and_queue!();
assert!(Arc::get_mut(&mut device).is_some());
}
#[test]
fn too_many_queues() {
let instance = instance!();
let physical = match instance::PhysicalDevice::enumerate(&instance).next() {
Some(p) => p,
None => return,
};
let family = physical.queue_families().next().unwrap();
let queues = (0 .. family.queues_count() + 1).map(|_| (family, 1.0));
match Device::new(physical,
&Features::none(),
&DeviceExtensions::none(),
queues) {
Err(DeviceCreationError::TooManyQueuesForFamily) => return,
_ => panic!(),
};
}
#[test]
fn unsupposed_features() {
let instance = instance!();
let physical = match instance::PhysicalDevice::enumerate(&instance).next() {
Some(p) => p,
None => return,
};
let family = physical.queue_families().next().unwrap();
let features = Features::all();
if physical.supported_features().superset_of(&features) {
return;
}
match Device::new(physical,
&features,
&DeviceExtensions::none(),
Some((family, 1.0))) {
Err(DeviceCreationError::FeatureNotPresent) => return,
_ => panic!(),
};
}
#[test]
fn priority_out_of_range() {
let instance = instance!();
let physical = match instance::PhysicalDevice::enumerate(&instance).next() {
Some(p) => p,
None => return,
};
let family = physical.queue_families().next().unwrap();
match Device::new(physical,
&Features::none(),
&DeviceExtensions::none(),
Some((family, 1.4))) {
Err(DeviceCreationError::PriorityOutOfRange) => (),
_ => panic!(),
};
match Device::new(physical,
&Features::none(),
&DeviceExtensions::none(),
Some((family, -0.2))) {
Err(DeviceCreationError::PriorityOutOfRange) => (),
_ => panic!(),
};
}
}