use core::PhysicalDevice;
use core::allocator_helper::AllocatorHelper;
use core;
use ext_debug_report;
use khr_android_surface;
use khr_display;
use khr_mir_surface;
use khr_surface;
use khr_wayland_surface;
use khr_win32_surface;
use khr_xcb_surface;
use khr_xlib_surface;
use libloading;
use std::cmp::Ordering;
use std::error;
use std::ffi::CStr;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;
use utils;
use vks;
use {TryDestroyError, TryDestroyErrorKind, VulkanObject};
const VK_GET_INSTANCE_PROC_ADDR: &'static str = "vkGetInstanceProcAddr";
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EarlyInstanceError {
LoadLibraryFailed(String),
SymbolNotFound(String),
VulkanError(core::Error),
}
impl From<vks::VkResult> for EarlyInstanceError {
fn from(res: vks::VkResult) -> Self {
EarlyInstanceError::VulkanError(res.into())
}
}
impl fmt::Display for EarlyInstanceError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
EarlyInstanceError::LoadLibraryFailed(ref l) => write!(f, "Failed to load library {}", l),
EarlyInstanceError::SymbolNotFound(ref s) => write!(f, "Symbol {} not found", s),
EarlyInstanceError::VulkanError(e) => e.fmt(f),
}
}
}
impl error::Error for EarlyInstanceError {
fn description(&self) -> &str {
match *self {
EarlyInstanceError::LoadLibraryFailed(_) => "LoadLibraryFailed",
EarlyInstanceError::SymbolNotFound(_) => "SymbolNotFound",
EarlyInstanceError::VulkanError(ref e) => e.description(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Instance(Arc<Inner>);
impl VulkanObject for Instance {
type NativeVulkanObject = vks::VkInstance;
#[inline]
fn as_native_vulkan_object(&self) -> Self::NativeVulkanObject {
self.handle()
}
fn try_destroy(self) -> Result<(), TryDestroyError<Self>> {
let strong_count = Arc::strong_count(&self.0);
if strong_count == 1 {
Ok(())
}
else {
Err(TryDestroyError::new(self, TryDestroyErrorKind::InUse(Some(strong_count))))
}
}
}
impl Instance {
#[inline]
pub(crate) fn handle(&self) -> vks::VkInstance {
self.0.handle
}
#[inline]
pub(crate) fn loader(&self) -> &vks::InstanceProcAddrLoader {
&self.0.loader
}
pub(crate) fn add_display_mode_allocator(&self, allocator: AllocatorHelper) {
self.0.display_mode_allocators.lock().unwrap().push(allocator);
}
pub fn get_enabled_extensions(&self) -> &core::InstanceExtensions {
&self.0.enabled_extensions
}
pub fn create(create_info: &core::InstanceCreateInfo, allocator: Option<Box<core::Allocator>>) -> Result<Instance, EarlyInstanceError> {
let (library, vk_get_instance_proc_addr) = unsafe {
let library = libloading::Library::new(vks::VULKAN_LIBRARY_NAME)
.map_err(|_| EarlyInstanceError::LoadLibraryFailed(vks::VULKAN_LIBRARY_NAME.to_owned()))?;
let vk_get_instance_proc_addr = {
let vk_get_instance_proc_addr: libloading::Symbol<vks::PFN_vkGetInstanceProcAddr> = library
.get(VK_GET_INSTANCE_PROC_ADDR.as_bytes())
.map_err(|_| EarlyInstanceError::SymbolNotFound(VK_GET_INSTANCE_PROC_ADDR.to_owned()))?;
*vk_get_instance_proc_addr
};
(library, vk_get_instance_proc_addr)
};
let allocator_helper = allocator.map(AllocatorHelper::new);
let allocation_callbacks = allocator_helper.as_ref().map_or(ptr::null(), AllocatorHelper::callbacks);
let mut loader = vks::InstanceProcAddrLoader::from_get_instance_proc_addr(vk_get_instance_proc_addr);
unsafe {
loader.load_core_null_instance();
}
let create_info_wrapper = core::VkInstanceCreateInfoWrapper::new(create_info, true);
let mut instance = ptr::null_mut();
let res = unsafe {
(loader.core_null_instance.vkCreateInstance)(&create_info_wrapper.vks_struct, allocation_callbacks, &mut instance)
};
if res != vks::VK_SUCCESS {
return Err(res.into());
}
unsafe {
loader.load_core(instance);
create_info.enabled_extensions.load_instance(&mut loader, instance);
}
let debug_report_callback = if let Some(ref chain) = create_info.chain {
if let Some(ref debug_report_callback_create_info_ext) = chain.debug_report_callback_create_info_ext {
Some(debug_report_callback_create_info_ext.callback.clone())
}
else {
None
}
}
else {
None
};
Ok(Instance(Arc::new(Inner {
handle: instance,
allocator: allocator_helper,
loader: loader,
library: library,
enabled_extensions: create_info.enabled_extensions.clone(),
debug_report_callback: debug_report_callback,
display_mode_allocators: Mutex::new(Vec::new()),
})))
}
pub fn enumerate_physical_devices(&self) -> Result<Vec<PhysicalDevice>, core::Error> {
let mut num_physical_devices = 0;
let res = unsafe {
(self.loader().core.vkEnumeratePhysicalDevices)(self.handle(), &mut num_physical_devices, ptr::null_mut())
};
if res != vks::VK_SUCCESS {
return Err(res.into());
}
let mut physical_devices = Vec::with_capacity(num_physical_devices as usize);
let res = unsafe {
(self.loader().core.vkEnumeratePhysicalDevices)(self.handle(), &mut num_physical_devices, physical_devices.as_mut_ptr())
};
if res != vks::VK_SUCCESS {
return Err(res.into());
}
unsafe {
physical_devices.set_len(num_physical_devices as usize);
}
let physical_devices: Vec<_> = physical_devices
.iter()
.map(|&d| core::PhysicalDevice::new(d, self.clone()))
.collect();
Ok(physical_devices)
}
pub fn enumerate_instance_layer_properties<B>() -> Result<B, EarlyInstanceError>
where B: FromIterator<core::LayerProperties>
{
unsafe {
let library = libloading::Library::new(vks::VULKAN_LIBRARY_NAME)
.map_err(|_| EarlyInstanceError::LoadLibraryFailed(vks::VULKAN_LIBRARY_NAME.to_owned()))?;
let vk_get_instance_proc_addr: libloading::Symbol<vks::PFN_vkGetInstanceProcAddr> = library
.get(VK_GET_INSTANCE_PROC_ADDR.as_bytes())
.map_err(|_| EarlyInstanceError::SymbolNotFound(VK_GET_INSTANCE_PROC_ADDR.to_owned()))?;
let mut loader = vks::instance_proc_addr_loader::CoreNullInstance::new();
loader.load(*vk_get_instance_proc_addr, ptr::null_mut());
let mut num_layer_properties = 0;
let res = (loader.vkEnumerateInstanceLayerProperties)(&mut num_layer_properties, ptr::null_mut());
if res != vks::VK_SUCCESS {
return Err(res.into());
}
let mut layer_properties = Vec::with_capacity(num_layer_properties as usize);
layer_properties.set_len(num_layer_properties as usize);
let res = (loader.vkEnumerateInstanceLayerProperties)(&mut num_layer_properties, layer_properties.as_mut_ptr());
if res != vks::VK_SUCCESS {
return Err(res.into());
}
Ok(layer_properties.iter().map(From::from).collect())
}
}
pub fn get_instance_extension_properties(layer_name: Option<&str>) -> Result<core::InstanceExtensionsProperties, EarlyInstanceError> {
unsafe {
let library = libloading::Library::new(vks::VULKAN_LIBRARY_NAME)
.map_err(|_| EarlyInstanceError::LoadLibraryFailed(vks::VULKAN_LIBRARY_NAME.to_owned()))?;
let vk_get_instance_proc_addr: libloading::Symbol<vks::PFN_vkGetInstanceProcAddr> = library
.get(VK_GET_INSTANCE_PROC_ADDR.as_bytes())
.map_err(|_| EarlyInstanceError::SymbolNotFound(VK_GET_INSTANCE_PROC_ADDR.to_owned()))?;
let mut loader = vks::instance_proc_addr_loader::CoreNullInstance::new();
loader.load(*vk_get_instance_proc_addr, ptr::null_mut());
let layer_name_cstr = utils::cstr_from_str(layer_name);
let mut num_extension_properties = 0;
let res = (loader.vkEnumerateInstanceExtensionProperties)(layer_name_cstr.1, &mut num_extension_properties, ptr::null_mut());
if res != vks::VK_SUCCESS {
return Err(res.into());
}
let mut extension_properties = Vec::with_capacity(num_extension_properties as usize);
extension_properties.set_len(num_extension_properties as usize);
let res = (loader.vkEnumerateInstanceExtensionProperties)(layer_name_cstr.1, &mut num_extension_properties, extension_properties.as_mut_ptr());
if res != vks::VK_SUCCESS {
return Err(res.into());
}
let mut res = core::InstanceExtensionsProperties::new();
for extension in extension_properties {
let name = CStr::from_ptr(extension.extensionName.as_ptr()).to_str().unwrap();
res.add(name, extension.specVersion);
}
Ok(res)
}
}
pub fn create_debug_report_callback_ext(&self, create_info: &ext_debug_report::DebugReportCallbackCreateInfoExt, allocator: Option<Box<core::Allocator>>) -> Result<ext_debug_report::DebugReportCallbackExt, core::Error> {
let allocator_helper = allocator.map(AllocatorHelper::new);
let allocation_callbacks = allocator_helper.as_ref().map_or(ptr::null(), AllocatorHelper::callbacks);
let create_info_wrapper = ext_debug_report::VkDebugReportCallbackCreateInfoEXTWrapper::new(create_info, true);
let mut debug_report_callback = ptr::null_mut();
let res = unsafe {
(self.loader().ext_debug_report.vkCreateDebugReportCallbackEXT)(self.handle(), &create_info_wrapper.vks_struct, allocation_callbacks, &mut debug_report_callback)
};
if res == vks::VK_SUCCESS {
Ok(ext_debug_report::DebugReportCallbackExt::new(debug_report_callback, self.clone(), allocator_helper, create_info_wrapper.callback_helper))
}
else {
Err(res.into())
}
}
pub fn debug_report_message_ext(&self, flags: ext_debug_report::DebugReportFlagsExt, object_type: ext_debug_report::DebugReportObjectTypeExt, object: u64, location: usize, message_code: i32, layer_prefix: &str, message: &str) {
use std::ffi::CString;
let layer_prefix = CString::new(layer_prefix).unwrap();
let message = CString::new(message).unwrap();
unsafe {
(self.loader().ext_debug_report.vkDebugReportMessageEXT)(self.handle(), flags, object_type.into(), object, location, message_code, layer_prefix.as_ptr(), message.as_ptr());
}
}
pub fn create_display_plane_surface_khr(&self, create_info: &khr_display::DisplaySurfaceCreateInfoKhr, allocator: Option<Box<core::Allocator>>) -> Result<khr_surface::SurfaceKhr, core::Error> {
let allocator_helper = allocator.map(AllocatorHelper::new);
let allocation_callbacks = allocator_helper.as_ref().map_or(ptr::null(), AllocatorHelper::callbacks);
let create_info_wrapper = khr_display::VkDisplaySurfaceCreateInfoKHRWrapper::new(create_info, true);
let mut surface = ptr::null_mut();
let res = unsafe {
(self.loader().khr_display.vkCreateDisplayPlaneSurfaceKHR)(self.handle(), &create_info_wrapper.vks_struct, allocation_callbacks, &mut surface)
};
if res == vks::VK_SUCCESS {
Ok(khr_surface::SurfaceKhr::new(surface, self.clone(), allocator_helper))
}
else {
Err(res.into())
}
}
pub fn create_xlib_surface_khr(&self, create_info: &khr_xlib_surface::XlibSurfaceCreateInfoKhr, allocator: Option<Box<core::Allocator>>) -> Result<khr_surface::SurfaceKhr, core::Error> {
let allocator_helper = allocator.map(AllocatorHelper::new);
let allocation_callbacks = allocator_helper.as_ref().map_or(ptr::null(), AllocatorHelper::callbacks);
let create_info_wrapper = khr_xlib_surface::VkXlibSurfaceCreateInfoKHRWrapper::new(create_info, true);
let mut surface = ptr::null_mut();
let res = unsafe {
(self.loader().khr_xlib_surface.vkCreateXlibSurfaceKHR)(self.handle(), &create_info_wrapper.vks_struct, allocation_callbacks, &mut surface)
};
if res == vks::VK_SUCCESS {
Ok(khr_surface::SurfaceKhr::new(surface, self.clone(), allocator_helper))
}
else {
Err(res.into())
}
}
pub fn create_wayland_surface_khr(&self, create_info: &khr_wayland_surface::WaylandSurfaceCreateInfoKhr, allocator: Option<Box<core::Allocator>>) -> Result<khr_surface::SurfaceKhr, core::Error> {
let allocator_helper = allocator.map(AllocatorHelper::new);
let allocation_callbacks = allocator_helper.as_ref().map_or(ptr::null(), AllocatorHelper::callbacks);
let create_info_wrapper = khr_wayland_surface::VkWaylandSurfaceCreateInfoKHRWrapper::new(create_info, true);
let mut surface = ptr::null_mut();
let res = unsafe {
(self.loader().khr_wayland_surface.vkCreateWaylandSurfaceKHR)(self.handle(), &create_info_wrapper.vks_struct, allocation_callbacks, &mut surface)
};
if res == vks::VK_SUCCESS {
Ok(khr_surface::SurfaceKhr::new(surface, self.clone(), allocator_helper))
}
else {
Err(res.into())
}
}
pub fn create_xcb_surface_khr(&self, create_info: &khr_xcb_surface::XcbSurfaceCreateInfoKhr, allocator: Option<Box<core::Allocator>>) -> Result<khr_surface::SurfaceKhr, core::Error> {
let allocator_helper = allocator.map(AllocatorHelper::new);
let allocation_callbacks = allocator_helper.as_ref().map_or(ptr::null(), AllocatorHelper::callbacks);
let create_info_wrapper = khr_xcb_surface::VkXcbSurfaceCreateInfoKHRWrapper::new(create_info, true);
let mut surface = ptr::null_mut();
let res = unsafe {
(self.loader().khr_xcb_surface.vkCreateXcbSurfaceKHR)(self.handle(), &create_info_wrapper.vks_struct, allocation_callbacks, &mut surface)
};
if res == vks::VK_SUCCESS {
Ok(khr_surface::SurfaceKhr::new(surface, self.clone(), allocator_helper))
}
else {
Err(res.into())
}
}
pub fn create_mir_surface_khr(&self, create_info: &khr_mir_surface::MirSurfaceCreateInfoKhr, allocator: Option<Box<core::Allocator>>) -> Result<khr_surface::SurfaceKhr, core::Error> {
let allocator_helper = allocator.map(AllocatorHelper::new);
let allocation_callbacks = allocator_helper.as_ref().map_or(ptr::null(), AllocatorHelper::callbacks);
let create_info_wrapper = khr_mir_surface::VkMirSurfaceCreateInfoKHRWrapper::new(create_info, true);
let mut surface = ptr::null_mut();
let res = unsafe {
(self.loader().khr_mir_surface.vkCreateMirSurfaceKHR)(self.handle(), &create_info_wrapper.vks_struct, allocation_callbacks, &mut surface)
};
if res == vks::VK_SUCCESS {
Ok(khr_surface::SurfaceKhr::new(surface, self.clone(), allocator_helper))
}
else {
Err(res.into())
}
}
pub fn create_android_surface_khr(&self, create_info: &khr_android_surface::AndroidSurfaceCreateInfoKhr, allocator: Option<Box<core::Allocator>>) -> Result<khr_surface::SurfaceKhr, core::Error> {
let allocator_helper = allocator.map(AllocatorHelper::new);
let allocation_callbacks = allocator_helper.as_ref().map_or(ptr::null(), AllocatorHelper::callbacks);
let create_info_wrapper = khr_android_surface::VkAndroidSurfaceCreateInfoKHRWrapper::new(create_info, true);
let mut surface = ptr::null_mut();
let res = unsafe {
(self.loader().khr_android_surface.vkCreateAndroidSurfaceKHR)(self.handle(), &create_info_wrapper.vks_struct, allocation_callbacks, &mut surface)
};
if res == vks::VK_SUCCESS {
Ok(khr_surface::SurfaceKhr::new(surface, self.clone(), allocator_helper))
}
else {
Err(res.into())
}
}
pub fn create_win32_surface_khr(&self, create_info: &khr_win32_surface::Win32SurfaceCreateInfoKhr, allocator: Option<Box<core::Allocator>>) -> Result<khr_surface::SurfaceKhr, core::Error> {
let allocator_helper = allocator.map(AllocatorHelper::new);
let allocation_callbacks = allocator_helper.as_ref().map_or(ptr::null(), AllocatorHelper::callbacks);
let create_info_wrapper = khr_win32_surface::VkWin32SurfaceCreateInfoKHRWrapper::new(create_info, true);
let mut surface = ptr::null_mut();
let res = unsafe {
(self.loader().khr_win32_surface.vkCreateWin32SurfaceKHR)(self.handle(), &create_info_wrapper.vks_struct, allocation_callbacks, &mut surface)
};
if res == vks::VK_SUCCESS {
Ok(khr_surface::SurfaceKhr::new(surface, self.clone(), allocator_helper))
}
else {
Err(res.into())
}
}
}
#[derive(Debug)]
struct Inner {
handle: vks::VkInstance,
allocator: Option<AllocatorHelper>,
loader: vks::InstanceProcAddrLoader,
library: libloading::Library,
enabled_extensions: core::InstanceExtensions,
debug_report_callback: Option<Arc<ext_debug_report::DebugReportCallbacksExt>>,
display_mode_allocators: Mutex<Vec<AllocatorHelper>>,
}
impl Drop for Inner {
fn drop(&mut self) {
let allocator = match self.allocator {
Some(ref allocator) => allocator.callbacks(),
None => ptr::null(),
};
unsafe {
(self.loader.core.vkDestroyInstance)(self.handle, allocator);
}
}
}
unsafe impl Send for Inner { }
unsafe impl Sync for Inner { }
impl PartialEq for Inner {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.handle == other.handle
}
}
impl Eq for Inner { }
impl PartialOrd for Inner {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.handle.partial_cmp(&other.handle)
}
}
impl Ord for Inner {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.handle.cmp(&other.handle)
}
}
impl Hash for Inner {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.handle.hash(state);
}
}