🔒 Repository is read-only – file editing is disabled.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
//! Types to initialize and use Vulkan.
//!
//! This module provides some thin abstractions over [`ash`](https://crates.io/crates/ash) for initializing
//! Vulkan.
//!
//! This module does not provide abstractions for logical devices, rendering or memory allocation. These
//! should instead be provided in higher level abstractions.
//!
//! Smithay requires at least Vulkan 1.1[^version].
//!
//! # [`Instance`]
//!
//! To use Vulkan, you would first instantiate an [`Instance`]. An instance is effectively the Vulkan library
//! and provides some information about the environment. This includes the list of supported
//! [instance extensions](Instance::enumerate_extensions) and the list of available physical devices.
//!
//! An instance is constructed using an [`Instance::new`] or [`Instance::with_extensions`].
//!
//! ## Layers
//!
//! The validation layers will be enabled if debug assertions are enabled and the validation layers are
//! available on your system.
//!
//! ## Instance extensions
//!
//! Instances may be created with some enabled extensions. Note that any features gated by an extension are
//! only available if the extension (and it's dependencies) are enabled (you will get a validation error if
//! you ignore that).
//!
//! Some features such as window system integration are only available if their features are enabled.
//! Available instance extensions may be obtained using [`Instance::enumerate_extensions`].
//!
//! # [`PhysicalDevice`]
//!
//! Once you have an instance, you may want to find a suitable device to use. A [`PhysicalDevice`] describes a
//! Vulkan implementation that may correspond to a real or virtual device.
//!
//! To get all the available devices, use [`PhysicalDevice::enumerate`].
//!
//! Physical devices are also describe the logical devices that can be created. A physical device can describe
//! a variety of properties that may be used for device selection, including but not limited to:
//! - [Device name](PhysicalDevice::name)
//! - [Supported Vulkan API version](PhysicalDevice::api_version)
//! - [Type](PhysicalDevice::ty) of the device
//! - [Driver information](PhysicalDevice::driver)
//! - [Extensions](PhysicalDevice::device_extensions)
//! - [Features](PhysicalDevice::features) and [limits](PhysicalDevice::limits)
//!
//! Physical devices implement [`Eq`][^device_eq], meaning two physical devices can be tested for equality.
//!
//! ## Device extensions
//!
//! Depending on the device extension (see the Vulkan specification), a device extension may indicate some
//! physical device data is available or indicate some device feature is supported. Any features that are
//! added using a device extension must be enabled in order to be used.
//!
//! [^version]: Internally Vulkan 1.1 is required because several extensions that were made part of core are
//! used quite extensively in some of the extensions our abstractions use. The vast majority of systems using
//! Vulkan also support at least Vulkan 1.1. If you need Vulkan 1.0 support, please open an issue and we can
//! discuss Vulkan 1.0 support.
//!
//! [^device_eq]: Two physical devices are only equal if both physical devices are created from the same
//! instance and have the same physical device handle.
#![warn(missing_debug_implementations)]
#![forbid(unsafe_op_in_unsafe_fn)]
use std::{
env::{self, VarError},
ffi::{CStr, CString},
sync::{Arc, LazyLock},
};
use ash::{
ext,
prelude::VkResult,
vk::{self, PhysicalDeviceDriverProperties, PhysicalDeviceDrmPropertiesEXT},
Entry,
};
use libc::c_void;
use scopeguard::ScopeGuard;
use tracing::{error, info, info_span, instrument, trace, warn};
use crate::backend::vulkan::inner::DebugState;
use self::{inner::InstanceInner, version::Version};
#[cfg(feature = "backend_drm")]
use super::drm::DrmNode;
mod inner;
mod phd;
pub mod version;
static LIBRARY: LazyLock<Result<Entry, LoadError>> =
LazyLock::new(|| unsafe { Entry::load().map_err(|_| LoadError) });
/// Error loading the Vulkan library
#[derive(Debug, thiserror::Error)]
#[error("Failed to load the Vulkan library")]
pub struct LoadError;
/// An error that may occur when creating an [`Instance`].
#[derive(Debug, thiserror::Error)]
pub enum InstanceError {
/// The instance was created using Vulkan 1.0.
#[error("Smithay requires at least Vulkan 1.1")]
UnsupportedVersion,
/// Failed to load the Vulkan library.
#[error(transparent)]
Load(#[from] LoadError),
/// Vulkan API error.
#[error(transparent)]
Vk(#[from] vk::Result),
}
/// Error returned when a physical device property is not supported
#[derive(Debug, thiserror::Error)]
pub enum UnsupportedProperty {
/// Some required extensions are not available.
#[error("The following extensions are not available {0:?}")]
Extensions(&'static [&'static CStr]),
}
/// App info to be passed to the Vulkan implementation.
#[derive(Debug)]
pub struct AppInfo {
/// Name of the app.
pub name: String,
/// Version of the app.
pub version: Version,
}
/// A Vulkan instance.
///
/// An instance is the object which tracks an application's Vulkan state. An instance allows an application to
/// get a list of physical devices.
///
/// In the Vulkan it is common to have objects which may not outlive the parent instance. A great way to
/// ensure compliance when using child objects is to [`Clone`] the instance and keep a handle with the child
/// object. This will ensure the child object does not outlive the instance.
///
/// An instance is [`Send`] and [`Sync`] which allows meaning multiple threads to access the Vulkan state.
/// Note that this **does not** mean the entire Vulkan API is thread safe, you will need to read the
/// specification to determine what parts of the Vulkan API require external synchronization.
///
/// # Instance extensions
///
/// In order to use features exposed through instance extensions (such as window system integration), you must
/// enable the extensions corresponding to the feature.
///
/// By default, [`Instance`] will automatically try to enable the following instance extensions if available:
/// * `VK_EXT_debug_utils`
///
/// No users should assume the instance extensions that are automatically enabled are available.
#[derive(Debug, Clone)]
pub struct Instance(Arc<InstanceInner>);
impl Instance {
/// Creates a new [`Instance`].
pub fn new(max_version: Version, app_info: Option<AppInfo>) -> Result<Instance, InstanceError> {
unsafe { Self::with_extensions(max_version, app_info, &[]) }
}
/// Creates a new [`Instance`] with some additionally specified extensions.
///
/// # Safety
///
/// * All valid usage requirements specified by [`vkCreateInstance`](https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkCreateInstance.html)
/// must be satisfied.
/// * Any enabled extensions must also have the dependency extensions enabled
/// (see `VUID-vkCreateInstance-ppEnabledExtensionNames-01388`).
pub unsafe fn with_extensions(
max_version: Version,
app_info: Option<AppInfo>,
extensions: &[&'static CStr],
) -> Result<Instance, InstanceError> {
assert!(
max_version >= Version::VERSION_1_1,
"Smithay requires at least Vulkan 1.1"
);
let requested_max_version = get_env_or_max_version(max_version);
let span = info_span!("backend_vulkan", version = tracing::field::Empty);
let _guard = span.enter();
// Determine the maximum instance version that is possible.
let max_version = {
unsafe {
LIBRARY
.as_ref()
.or(Err(LoadError))?
.try_enumerate_instance_version()
}
// Any allocation errors must be the result of the loader or layers
.or(Err(LoadError))?
.map(Version::from_raw)
// Vulkan 1.0 does not have `vkEnumerateInstanceVersion`.
.unwrap_or(Version::VERSION_1_0)
};
if max_version == Version::VERSION_1_0 {
error!("Vulkan does not support version 1.1");
return Err(InstanceError::UnsupportedVersion);
}
// Pick the lower of the requested max version and max possible version
let api_version = Version::from_raw(u32::min(max_version.to_raw(), requested_max_version.to_raw()));
span.record("version", tracing::field::display(api_version));
let available_layers = Self::enumerate_layers()?.collect::<Vec<_>>();
let available_extensions = Self::enumerate_extensions()?.collect::<Vec<_>>();
let mut layers = Vec::new();
// Enable debug layers if present and debug assertions are enabled.
if cfg!(debug_assertions) {
const VALIDATION: &CStr = c"VK_LAYER_KHRONOS_validation";
if available_layers
.iter()
.any(|layer| layer.as_c_str() == VALIDATION)
{
layers.push(VALIDATION);
} else {
warn!("Validation layers not available. These can be installed through your package manager",);
}
}
let mut enabled_extensions = Vec::<&'static CStr>::new();
enabled_extensions.extend(extensions);
// Enable debug utils if available.
let has_debug_utils = available_extensions
.iter()
.any(|name| name.as_c_str() == ext::debug_utils::NAME);
if has_debug_utils {
enabled_extensions.push(ext::debug_utils::NAME);
}
// Both of these are safe because both vecs contain static CStrs.
let extension_pointers = enabled_extensions
.iter()
.map(|name| name.as_ptr())
.collect::<Vec<_>>();
let layer_pointers = layers.iter().map(|name| name.as_ptr()).collect::<Vec<_>>();
let app_version = app_info.as_ref().map(|info| info.version.to_raw());
let app_name =
app_info.map(|info| CString::new(info.name).expect("app name contains null terminator"));
let mut app_info = vk::ApplicationInfo::default()
.api_version(api_version.to_raw())
// SAFETY: null terminated with no interior null bytes.
.engine_name(c"Smithay")
.engine_version(Version::SMITHAY.to_raw());
if let Some(app_version) = app_version {
app_info = app_info.application_version(app_version);
}
if let Some(app_name) = &app_name {
app_info = app_info.application_name(app_name);
}
let library = LIBRARY.as_ref().map_err(|_| LoadError)?;
let create_info = vk::InstanceCreateInfo::default()
.application_info(&app_info)
.enabled_layer_names(&layer_pointers)
.enabled_extension_names(&extension_pointers);
// Place the instance in a scopeguard in case creating the debug messenger fails.
let instance = scopeguard::guard(
unsafe { library.create_instance(&create_info, None) }?,
|instance| unsafe {
instance.destroy_instance(None);
},
);
// Setup the debug utils
let debug_state = if has_debug_utils {
let span = info_span!("backend_vulkan_debug");
let debug_utils = ext::debug_utils::Instance::new(library, &instance);
// Place the pointer to the span in a scopeguard to prevent a memory leak in case creating the
// debug messenger fails.
let span_ptr = scopeguard::guard(Box::into_raw(Box::new(span)), |ptr| unsafe {
let _ = Box::from_raw(ptr);
});
let create_info = vk::DebugUtilsMessengerCreateInfoEXT::default()
.message_severity(
vk::DebugUtilsMessageSeverityFlagsEXT::WARNING
| vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE
| vk::DebugUtilsMessageSeverityFlagsEXT::INFO
| vk::DebugUtilsMessageSeverityFlagsEXT::ERROR,
)
.message_type(
vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
| vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE
| vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION,
)
.pfn_user_callback(Some(vulkan_debug_utils_callback))
.user_data(*span_ptr as *mut _);
let debug_messenger = unsafe { debug_utils.create_debug_utils_messenger(&create_info, None) }?;
// Disarm the destructor for the logger pointer since the instance is now responsible for
// destroying the logger.
let span_ptr = ScopeGuard::into_inner(span_ptr);
Some(DebugState {
debug_utils,
debug_messenger,
span_ptr,
})
} else {
None
};
// Creating the debug messenger was successful, disarm the scopeguard and let InstanceInner manage
// destroying the instance.
let instance = ScopeGuard::into_inner(instance);
drop(_guard);
let inner = InstanceInner {
instance,
version: api_version,
debug_state,
span,
enabled_extensions,
};
info!("Created new instance");
info!("Enabled instance extensions: {:?}", inner.enabled_extensions);
#[allow(clippy::arc_with_non_send_sync)]
Ok(Instance(Arc::new(inner)))
}
/// Returns an iterator which contains the available instance extensions on the system.
pub fn enumerate_extensions() -> Result<impl Iterator<Item = CString>, LoadError> {
let library = LIBRARY.as_ref().or(Err(LoadError))?;
let extensions = unsafe { library.enumerate_instance_extension_properties(None) }
.or(Err(LoadError))?
.into_iter()
.map(|properties| {
// SAFETY: Vulkan guarantees the string is null terminated.
unsafe { CStr::from_ptr(&properties.extension_name as *const _) }.to_owned()
})
.collect::<Vec<_>>()
.into_iter();
Ok(extensions)
}
/// Returns the enabled instance extensions.
pub fn enabled_extensions(&self) -> impl Iterator<Item = &CStr> {
self.0.enabled_extensions.iter().copied()
}
/// Returns true if the specified instance extension is enabled.
///
/// This function may be used to ensure safe access to features provided by instance extensions.
pub fn is_extension_enabled(&self, extension: &CStr) -> bool {
self.enabled_extensions().any(|name| name == extension)
}
/// Returns the version of Vulkan supported by this instance.
///
/// This corresponds to the version specified when building the instance.
pub fn api_version(&self) -> Version {
self.0.version
}
/// Returns a reference to the underlying [`ash::Instance`].
///
/// Any objects created using the handle must be destroyed before the final instance is dropped per the
/// valid usage requirements (`VUID-vkDestroyInstance-instance-00629`).
pub fn handle(&self) -> &ash::Instance {
&self.0.instance
}
}
/// A Vulkan physical device.
///
/// A physical device refers to a Vulkan implementation. A physical device has no associated resources and may
/// be used to create a logical device.
#[derive(Debug, Clone)]
pub struct PhysicalDevice {
phd: vk::PhysicalDevice,
info: PhdInfo,
extensions: Vec<CString>,
instance: Instance,
span: tracing::Span,
}
impl PhysicalDevice {
/// Enumerates over all physical devices available on the system, returning an iterator of [`PhysicalDevice`]
pub fn enumerate(instance: &Instance) -> VkResult<impl Iterator<Item = PhysicalDevice>> {
let _span = instance.0.span.enter();
// Must clone instance or else the returned iterator has a lifetime over `&Instance`
let instance = instance.clone();
let devices = unsafe { instance.handle().enumerate_physical_devices() }?;
let devices = devices
.into_iter()
// TODO: Warn if any physical devices have an error when getting device properties.
.flat_map(move |phd| unsafe { PhysicalDevice::from_phd(&instance, phd) })
.flatten();
Ok(devices)
}
/// Returns the name of the device.
pub fn name(&self) -> &str {
&self.info.name
}
/// Returns the version of Vulkan supported by this device.
///
/// Unlike the `api_version` property, which is the version reported by the device directly, this function
/// returns the version the device can actually support, based on the instance’s, `api_version`.
///
/// The Vulkan specification provides more information about the version requirements: <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#fundamentals-validusage-versions>
pub fn api_version(&self) -> Version {
self.info.api_version
}
/// Returns the device type.
///
/// This may be used during device selection to choose a higher performance GPU.
pub fn ty(&self) -> vk::PhysicalDeviceType {
self.info.properties.device_type
}
/// Returns the Vulkan 1.0 physical device features.
pub fn features(&self) -> vk::PhysicalDeviceFeatures {
self.info.features
}
/// Returns the physical device properties.
///
/// Some properties such as the device name can be obtained using other functions defined on
/// [`PhysicalDevice`].
pub fn properties(&self) -> vk::PhysicalDeviceProperties {
self.info.properties
}
/// Returns the device's descriptor set properties.
///
/// This also describes the maximum memory allocation size.
pub fn properties_maintenance_3(&self) -> vk::PhysicalDeviceMaintenance3Properties<'_> {
self.info.maintenance_3
}
/// Information about universally unique identifiers (UUIDs) that identify this device.
pub fn id_properties(&self) -> vk::PhysicalDeviceIDProperties<'_> {
self.info.id
}
/// Returns the physical device limits.
pub fn limits(&self) -> vk::PhysicalDeviceLimits {
self.info.properties.limits
}
/// Information about the Vulkan driver.
///
/// This may return [`None`] for a few reasons:
/// * The Vulkan implementation is not at least 1.2
/// * If the Vulkan implementation is not at least Vulkan 1.2, the `VK_KHR_driver_properties` device
/// extension is not available.
pub fn driver(&self) -> Option<&DriverInfo> {
self.info.driver.as_ref()
}
/// Returns the major and minor numbers of the primary node which corresponds to this physical device's DRM
/// device.
#[cfg(feature = "backend_drm")]
#[instrument(level = "debug", parent = &self.span, skip(self))]
pub fn primary_node(&self) -> Result<Option<DrmNode>, UnsupportedProperty> {
let properties_drm = self.info.get_drm_properties()?;
let node = Some(properties_drm)
.filter(|props| props.has_primary == vk::TRUE)
.and_then(|props| {
DrmNode::from_dev_id(libc::makedev(props.primary_major as _, props.primary_minor as _)).ok()
});
Ok(node)
}
/// Returns the major and minor numbers of the render node which corresponds to this physical device's DRM
/// device.
///
/// Note that not every device has a render node. If there is no render node (this function returns [`None`])
/// then try to use the primary node.
#[cfg(feature = "backend_drm")]
#[instrument(level = "debug", parent = &self.span, skip(self))]
pub fn render_node(&self) -> Result<Option<DrmNode>, UnsupportedProperty> {
let properties_drm = self.info.get_drm_properties()?;
let node = Some(properties_drm)
.filter(|props| props.has_render == vk::TRUE)
.and_then(|props| {
DrmNode::from_dev_id(libc::makedev(props.render_major as _, props.render_minor as _)).ok()
});
Ok(node)
}
/// Get physical device properties.
///
/// This function is equivalent to calling [`vkGetPhysicalDeviceProperties2`].
///
/// # Safety
///
/// - All valid usage requirements for [`vkGetPhysicalDeviceProperties2`] apply. Read the specification
/// for more information.
///
/// [`vkGetPhysicalDeviceProperties2`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetPhysicalDeviceProperties2.html
pub unsafe fn get_properties(&self, props: &mut vk::PhysicalDeviceProperties2<'_>) {
let instance = self.instance().handle();
// SAFETY: The caller has garunteed all valid usage requirements for vkGetPhysicalDeviceProperties2
// are satisfied.
unsafe { instance.get_physical_device_properties2(self.handle(), props) }
}
/// Get physical device format properties.
///
/// This function is equivalent to calling [`vkGetPhysicalDeviceFormatProperties2`].
///
/// # Safety
///
/// - All valid usage requirements for [`vkGetPhysicalDeviceFormatProperties2`] apply. Read the specification
/// for more information.
///
/// [`vkGetPhysicalDeviceFormatProperties2`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkGetPhysicalDeviceFormatProperties2.html
pub unsafe fn get_format_properties(&self, format: vk::Format, props: &mut vk::FormatProperties2<'_>) {
let instance = self.instance().handle();
// SAFETY: The caller has garunteed all valid usage requirements for vkGetPhysicalDeviceFormatProperties2
// are satisfied.
unsafe { instance.get_physical_device_format_properties2(self.handle(), format, props) }
}
/// Returns properties for each supported DRM modifier for the specified format.
///
/// Returns [`Err`] if the `VK_EXT_image_drm_format_modifier` extension is not supported.
#[instrument(level = "debug", parent = &self.span, skip(self))]
pub fn get_format_modifier_properties(
&self,
format: vk::Format,
) -> Result<Vec<vk::DrmFormatModifierPropertiesEXT>, UnsupportedProperty> {
if !self.has_device_extension(ext::image_drm_format_modifier::NAME) {
const EXTENSIONS: &[&CStr] = &[ext::image_drm_format_modifier::NAME];
return Err(UnsupportedProperty::Extensions(EXTENSIONS));
}
// First get the number of modifiers the driver supports.
let count = unsafe {
let mut list = vk::DrmFormatModifierPropertiesListEXT::default();
let mut format_properties2 = vk::FormatProperties2::default().push_next(&mut list);
self.get_format_properties(format, &mut format_properties2);
list.drm_format_modifier_count as usize
};
// Allocate the vector to receive the modifiers in.
let mut data = Vec::with_capacity(count);
unsafe {
let mut list = vk::DrmFormatModifierPropertiesListEXT {
// We cannot use the builder here because the Vec is currently empty, so we need to tell Vulkan
// where to write out the modifier properties and tell it how large the Vec is.
p_drm_format_modifier_properties: data.as_mut_ptr(),
drm_format_modifier_count: count as u32,
..Default::default()
};
let mut format_properties2 = vk::FormatProperties2::default().push_next(&mut list);
self.get_format_properties(format, &mut format_properties2);
// SAFETY: Vulkan just initialized the elements of the vector.
data.set_len(list.drm_format_modifier_count as usize);
}
Ok(data)
}
/// Returns the device extensions supported by the physical device.
pub fn device_extensions(&self) -> impl Iterator<Item = &CStr> {
self.extensions.iter().map(CString::as_c_str)
}
/// Returns `true` if this device supports the specified device extension.
pub fn has_device_extension(&self, extension: &CStr) -> bool {
self.device_extensions().any(|name| name == extension)
}
/// Returns a handle to the underlying [`vk::PhysicalDevice`].
///
/// The handle refers to a specific physical device advertised by the instance. This handle is only valid
/// for the lifetime of the instance.
pub fn handle(&self) -> vk::PhysicalDevice {
self.phd
}
/// The instance which provided this physical device.
pub fn instance(&self) -> &Instance {
&self.instance
}
}
impl PartialEq for PhysicalDevice {
#[inline]
fn eq(&self, other: &Self) -> bool {
// Both the physical device handle and instance handle must be the same
self.phd == other.phd && self.instance().handle().handle() == other.instance().handle().handle()
}
}
// SAFETY: The internal pointers in the PhysicalDevice*Properties are always null and only copies of the
// PhysicalDevice*Properties types are returned.
unsafe impl Send for PhysicalDevice {}
unsafe impl Sync for PhysicalDevice {}
/// Information about the driver providing a [`PhysicalDevice`].
#[derive(Debug, Clone)]
pub struct DriverInfo {
/// ID which identifies the driver.
pub id: vk::DriverId,
/// The name of the driver.
pub name: String,
/// Information describing the driver.
///
/// This may include information such as the driver version.
pub info: String,
/// The Vulkan conformance test this driver is conformant against.
pub conformance: vk::ConformanceVersion,
}
#[derive(Debug, Clone, Default)]
struct PhdInfo {
api_version: Version,
name: String,
properties: vk::PhysicalDeviceProperties,
features: vk::PhysicalDeviceFeatures,
maintenance_3: vk::PhysicalDeviceMaintenance3Properties<'static>,
id: vk::PhysicalDeviceIDProperties<'static>,
properties_driver: Option<PhysicalDeviceDriverProperties<'static>>,
/// Information about the DRM device which corresponds to this physical device.
#[cfg_attr(not(feature = "backend_drm"), allow(dead_code))]
properties_drm: Option<PhysicalDeviceDrmPropertiesEXT<'static>>,
driver: Option<DriverInfo>,
}
fn get_env_or_max_version(max_version: Version) -> Version {
// Consider max version overrides from env
match env::var("SMITHAY_VK_VERSION") {
Ok(version) => {
let overriden_version = match &version[..] {
"1.0" => {
warn!("Smithay does not support Vulkan 1.0, ignoring SMITHAY_VK_VERSION");
return max_version;
}
"1.1" => Some(Version::VERSION_1_1),
"1.2" => Some(Version::VERSION_1_2),
"1.3" => Some(Version::VERSION_1_3),
_ => None,
};
// The env var can only lower the maximum version, not raise it.
if let Some(overridden_version) = overriden_version {
if overridden_version > max_version {
warn!(
"Ignoring SMITHAY_VK_VERSION since the requested max version is higher than the maximum of {}.{}",
max_version.major,
max_version.minor
);
max_version
} else {
overridden_version
}
} else {
warn!("SMITHAY_VK_VERSION was set to an unknown Vulkan version");
max_version
}
}
Err(VarError::NotUnicode(_)) => {
warn!("Value of SMITHAY_VK_VERSION is not valid Unicode, ignoring.");
max_version
}
Err(VarError::NotPresent) => max_version,
}
}
unsafe extern "system" fn vulkan_debug_utils_callback(
message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
message_type: vk::DebugUtilsMessageTypeFlagsEXT,
p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT<'_>,
span: *mut c_void,
) -> vk::Bool32 {
let _ = std::panic::catch_unwind(|| {
// Get the span from the user data pointer we gave to Vulkan.
//
// The span is allocated on the heap using a box, but we do not want to drop the span,
// so read from the pointer.
let _guard = unsafe { (span as *mut tracing::Span).as_ref() }.unwrap().enter();
// VUID-VkDebugUtilsMessengerCallbackDataEXT-pMessage-parameter: Message must be valid UTF-8 with a null
// terminator.
let message = unsafe { CStr::from_ptr((*p_callback_data).p_message) }.to_string_lossy();
// Message type is in full uppercase since we print the bitflag debug representation.
let ty = format!("{:?}", message_type).to_lowercase();
match message_severity {
vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE => {
trace!(ty, "{}", message)
}
vk::DebugUtilsMessageSeverityFlagsEXT::INFO => info!(ty, "{}", message),
vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => warn!(ty, "{}", message),
vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => error!(ty, "{}", message),
_ => (),
}
});
// Must always return false.
vk::FALSE
}
#[cfg(test)]
mod tests {
use super::{Instance, PhysicalDevice};
fn is_send_sync<T: Send + Sync>() {}
/// Test that both [`Instance`] and [`PhysicalDevice`] are Send and Sync.
#[test]
fn send_sync() {
is_send_sync::<Instance>();
is_send_sync::<PhysicalDevice>();
}
}