Refactor the khr_display implementation (#2295)

* Refactor the `khr_display` implementation

* Doc fixes

* Move display out of the swapchain module, as it's usable independently
This commit is contained in:
Rua 2023-08-24 02:51:02 +02:00 committed by GitHub
parent 3898490bf6
commit 43db3eaf72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1523 additions and 542 deletions

View File

@ -44,11 +44,16 @@ where
K: Eq + Hash,
V: Clone,
{
/// Returns the value for the specified `key`, if it exists.
pub(crate) fn get(&self, key: &K) -> Option<V> {
self.inner.read().get(key).cloned()
}
/// Returns the value for the specified `key`. The entry gets written to with the value
/// returned by `f` if it doesn't exist.
pub fn get_or_insert(&self, key: K, f: impl FnOnce(&K) -> V) -> V {
if let Some(value) = self.inner.read().get(&key) {
return value.clone();
pub(crate) fn get_or_insert(&self, key: K, f: impl FnOnce(&K) -> V) -> V {
if let Some(value) = self.get(&key) {
return value;
}
match self.inner.write().entry(key) {
@ -68,8 +73,12 @@ where
/// Returns the value for the specified `key`. The entry gets written to with the value
/// returned by `f` if it doesn't exist. If `f` returns [`Err`], the error is propagated and
/// the entry isn't written to.
pub fn get_or_try_insert<E>(&self, key: K, f: impl FnOnce(&K) -> Result<V, E>) -> Result<V, E> {
if let Some(value) = self.inner.read().get(&key) {
pub(crate) fn get_or_try_insert<E>(
&self,
key: K,
f: impl FnOnce(&K) -> Result<V, E>,
) -> Result<V, E> {
if let Some(value) = self.get(&key) {
return Ok(value.clone());
}
@ -115,16 +124,19 @@ impl<K, V> WeakArcOnceCache<K, V>
where
K: Eq + Hash,
{
/// Returns the value for the specified `key`, if it exists.
pub(crate) fn get(&self, key: &K) -> Option<Arc<V>> {
self.inner
.read()
.get(key)
.and_then(|weak| Weak::upgrade(weak))
}
/// Returns the value for the specified `key`. The entry gets written to with the value
/// returned by `f` if it doesn't exist.
#[allow(dead_code)]
pub fn get_or_insert(&self, key: K, f: impl FnOnce(&K) -> Arc<V>) -> Arc<V> {
if let Some(arc) = self
.inner
.read()
.get(&key)
.and_then(|weak| Weak::upgrade(weak))
{
pub(crate) fn get_or_insert(&self, key: K, f: impl FnOnce(&K) -> Arc<V>) -> Arc<V> {
if let Some(arc) = self.get(&key) {
return arc;
}
@ -152,17 +164,12 @@ where
/// Returns the value for the specified `key`. The entry gets written to with the value
/// returned by `f` if it doesn't exist. If `f` returns [`Err`], the error is propagated and
/// the entry isn't written to.
pub fn get_or_try_insert<E>(
pub(crate) fn get_or_try_insert<E>(
&self,
key: K,
f: impl FnOnce(&K) -> Result<Arc<V>, E>,
) -> Result<Arc<V>, E> {
if let Some(arc) = self
.inner
.read()
.get(&key)
.and_then(|weak| Weak::upgrade(weak))
{
if let Some(arc) = self.get(&key) {
return Ok(arc);
}

View File

@ -267,7 +267,7 @@ where
///
/// [`query_pool.ty().result_len()`]: crate::query::QueryType::result_len
/// [`QueryResultFlags::WITH_AVAILABILITY`]: crate::query::QueryResultFlags::WITH_AVAILABILITY
/// [`get_results`]: crate::query::QueriesRange::get_results
/// [`get_results`]: crate::query::QueryPool::get_results
pub fn copy_query_pool_results<T>(
&mut self,
query_pool: Arc<QueryPool>,

View File

@ -10,8 +10,9 @@
use super::QueueFamilyProperties;
use crate::{
buffer::{ExternalBufferInfo, ExternalBufferProperties},
cache::OnceCache,
cache::{OnceCache, WeakArcOnceCache},
device::{properties::Properties, DeviceExtensions, Features, FeaturesFfi, PropertiesFfi},
display::{Display, DisplayPlaneProperties, DisplayPlanePropertiesRaw, DisplayProperties},
format::{DrmFormatModifierProperties, Format, FormatProperties},
image::{
ImageDrmFormatModifierInfo, ImageFormatInfo, ImageFormatProperties, ImageUsage,
@ -33,8 +34,10 @@ use crate::{
ValidationError, Version, VulkanError, VulkanObject,
};
use bytemuck::cast_slice;
use parking_lot::RwLock;
use std::{
fmt::{Debug, Display, Error as FmtError, Formatter},
ffi::CStr,
fmt::{Debug, Error as FmtError, Formatter},
mem::MaybeUninit,
num::NonZeroU64,
ptr,
@ -77,6 +80,8 @@ pub struct PhysicalDevice {
queue_family_properties: Vec<QueueFamilyProperties>,
// Data queried by the user at runtime, cached for faster lookups.
display_properties: WeakArcOnceCache<ash::vk::DisplayKHR, Display>,
display_plane_properties: RwLock<Vec<DisplayPlanePropertiesRaw>>,
external_buffer_properties: OnceCache<ExternalBufferInfo, ExternalBufferProperties>,
external_fence_properties: OnceCache<ExternalFenceInfo, ExternalFenceProperties>,
external_semaphore_properties: OnceCache<ExternalSemaphoreInfo, ExternalSemaphoreProperties>,
@ -133,6 +138,7 @@ impl PhysicalDevice {
handle,
instance: DebugWrapper(instance),
id: Self::next_id(),
api_version,
supported_extensions,
supported_features,
@ -140,6 +146,9 @@ impl PhysicalDevice {
extension_properties,
memory_properties,
queue_family_properties,
display_properties: WeakArcOnceCache::new(),
display_plane_properties: RwLock::new(Vec::new()),
external_buffer_properties: OnceCache::new(),
external_fence_properties: OnceCache::new(),
external_semaphore_properties: OnceCache::new(),
@ -483,6 +492,445 @@ impl PhysicalDevice {
) != 0
}
/// Returns the properties of displays attached to the physical device.
#[inline]
pub fn display_properties<'a>(
self: &'a Arc<Self>,
) -> Result<Vec<Arc<Display>>, Validated<VulkanError>> {
self.validate_display_properties()?;
unsafe { Ok(self.display_properties_unchecked()?) }
}
fn validate_display_properties(&self) -> Result<(), Box<ValidationError>> {
if !self.instance.enabled_extensions().khr_display {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"khr_display",
)])]),
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn display_properties_unchecked<'a>(
self: &'a Arc<Self>,
) -> Result<Vec<Arc<Display>>, VulkanError> {
let fns = self.instance.fns();
if self
.instance
.enabled_extensions()
.khr_get_display_properties2
{
let properties_vk = unsafe {
loop {
let mut count = 0;
(fns.khr_get_display_properties2
.get_physical_device_display_properties2_khr)(
self.handle,
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)?;
let mut properties =
vec![ash::vk::DisplayProperties2KHR::default(); count as usize];
let result = (fns
.khr_get_display_properties2
.get_physical_device_display_properties2_khr)(
self.handle,
&mut count,
properties.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
properties.set_len(count as usize);
break properties;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
}
};
Ok(properties_vk
.into_iter()
.map(|properties_vk| {
let properties_vk = &properties_vk.display_properties;
self.display_properties
.get_or_insert(properties_vk.display, |&handle| {
let properties = DisplayProperties {
name: properties_vk.display_name.as_ref().map(|name| {
CStr::from_ptr(name)
.to_str()
.expect("non UTF-8 characters in display name")
.to_owned()
}),
physical_dimensions: [
properties_vk.physical_dimensions.width,
properties_vk.physical_dimensions.height,
],
physical_resolution: [
properties_vk.physical_resolution.width,
properties_vk.physical_resolution.height,
],
supported_transforms: properties_vk.supported_transforms.into(),
plane_reorder_possible: properties_vk.plane_reorder_possible
!= ash::vk::FALSE,
persistent_content: properties_vk.persistent_content
!= ash::vk::FALSE,
};
Display::from_handle(self.clone(), handle, properties)
})
})
.collect())
} else {
let properties_vk = unsafe {
loop {
let mut count = 0;
(fns.khr_display.get_physical_device_display_properties_khr)(
self.handle,
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)?;
let mut properties = Vec::with_capacity(count as usize);
let result = (fns.khr_display.get_physical_device_display_properties_khr)(
self.handle,
&mut count,
properties.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
properties.set_len(count as usize);
break properties;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
}
};
Ok(properties_vk
.into_iter()
.map(|properties_vk| {
self.display_properties
.get_or_insert(properties_vk.display, |&handle| {
let properties = DisplayProperties {
name: properties_vk.display_name.as_ref().map(|name| {
CStr::from_ptr(name)
.to_str()
.expect("non UTF-8 characters in display name")
.to_owned()
}),
physical_dimensions: [
properties_vk.physical_dimensions.width,
properties_vk.physical_dimensions.height,
],
physical_resolution: [
properties_vk.physical_resolution.width,
properties_vk.physical_resolution.height,
],
supported_transforms: properties_vk.supported_transforms.into(),
plane_reorder_possible: properties_vk.plane_reorder_possible
!= ash::vk::FALSE,
persistent_content: properties_vk.persistent_content
!= ash::vk::FALSE,
};
Display::from_handle(self.clone(), handle, properties)
})
})
.collect())
}
}
/// Returns the properties of the display planes of the physical device.
#[inline]
pub fn display_plane_properties(
self: &Arc<Self>,
) -> Result<Vec<DisplayPlaneProperties>, Validated<VulkanError>> {
self.validate_display_plane_properties()?;
unsafe { Ok(self.display_plane_properties_unchecked()?) }
}
fn validate_display_plane_properties(&self) -> Result<(), Box<ValidationError>> {
if !self.instance.enabled_extensions().khr_display {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"khr_display",
)])]),
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn display_plane_properties_unchecked(
self: &Arc<Self>,
) -> Result<Vec<DisplayPlaneProperties>, VulkanError> {
self.get_display_plane_properties_raw()?
.iter()
.map(|properties_raw| -> Result<_, VulkanError> {
let &DisplayPlanePropertiesRaw {
current_display,
current_stack_index,
} = properties_raw;
let current_display = current_display
.map(|display_handle| {
self.display_properties
.get(&display_handle)
.map(Ok)
.unwrap_or_else(|| -> Result<_, VulkanError> {
self.display_properties_unchecked()?;
Ok(self.display_properties.get(&display_handle).unwrap())
})
})
.transpose()?;
Ok(DisplayPlaneProperties {
current_display,
current_stack_index,
})
})
.collect()
}
pub(crate) unsafe fn display_plane_properties_raw(
&self,
) -> Result<Vec<DisplayPlanePropertiesRaw>, VulkanError> {
{
let read = self.display_plane_properties.read();
if !read.is_empty() {
return Ok(read.clone());
}
}
self.get_display_plane_properties_raw()
}
unsafe fn get_display_plane_properties_raw(
&self,
) -> Result<Vec<DisplayPlanePropertiesRaw>, VulkanError> {
let fns = self.instance.fns();
let properties_raw: Vec<_> = if self
.instance
.enabled_extensions()
.khr_get_display_properties2
{
let properties_vk = unsafe {
loop {
let mut count = 0;
(fns.khr_get_display_properties2
.get_physical_device_display_plane_properties2_khr)(
self.handle,
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)?;
let mut properties =
vec![ash::vk::DisplayPlaneProperties2KHR::default(); count as usize];
let result = (fns
.khr_get_display_properties2
.get_physical_device_display_plane_properties2_khr)(
self.handle,
&mut count,
properties.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
properties.set_len(count as usize);
break properties;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
}
};
properties_vk
.into_iter()
.map(|properties_vk| {
let properties_vk = &properties_vk.display_plane_properties;
DisplayPlanePropertiesRaw {
current_display: Some(properties_vk.current_display)
.filter(|&x| x != ash::vk::DisplayKHR::null()),
current_stack_index: properties_vk.current_stack_index,
}
})
.collect()
} else {
let properties_vk = unsafe {
loop {
let mut count = 0;
(fns.khr_display
.get_physical_device_display_plane_properties_khr)(
self.handle,
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)?;
let mut properties = Vec::with_capacity(count as usize);
let result = (fns
.khr_display
.get_physical_device_display_plane_properties_khr)(
self.handle,
&mut count,
properties.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
properties.set_len(count as usize);
break properties;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
}
};
properties_vk
.into_iter()
.map(|properties_vk| DisplayPlanePropertiesRaw {
current_display: Some(properties_vk.current_display)
.filter(|&x| x != ash::vk::DisplayKHR::null()),
current_stack_index: properties_vk.current_stack_index,
})
.collect()
};
*self.display_plane_properties.write() = properties_raw.clone();
Ok(properties_raw)
}
/// Returns the displays that are supported for the given plane index.
///
/// The index must be less than the number of elements returned by
/// [`display_plane_properties`](Self::display_plane_properties).
#[inline]
pub fn display_plane_supported_displays(
self: &Arc<Self>,
plane_index: u32,
) -> Result<Vec<Arc<Display>>, Validated<VulkanError>> {
self.validate_display_plane_supported_displays(plane_index)?;
unsafe { Ok(self.display_plane_supported_displays_unchecked(plane_index)?) }
}
fn validate_display_plane_supported_displays(
&self,
plane_index: u32,
) -> Result<(), Box<ValidationError>> {
if !self.instance.enabled_extensions().khr_display {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"khr_display",
)])]),
..Default::default()
}));
}
let display_plane_properties_raw = unsafe {
self.display_plane_properties_raw().map_err(|_err| {
Box::new(ValidationError {
problem: "`PhysicalDevice::display_plane_properties` \
returned an error"
.into(),
..Default::default()
})
})?
};
if plane_index as usize >= display_plane_properties_raw.len() {
return Err(Box::new(ValidationError {
problem: "`plane_index` is not less than the number of display planes on the \
physical device"
.into(),
vuids: &["VUID-vkGetDisplayPlaneSupportedDisplaysKHR-planeIndex-01249"],
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn display_plane_supported_displays_unchecked(
self: &Arc<Self>,
plane_index: u32,
) -> Result<Vec<Arc<Display>>, VulkanError> {
let fns = self.instance.fns();
let displays_vk = unsafe {
loop {
let mut count = 0;
(fns.khr_display.get_display_plane_supported_displays_khr)(
self.handle,
plane_index,
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)?;
let mut displays = Vec::with_capacity(count as usize);
let result = (fns.khr_display.get_display_plane_supported_displays_khr)(
self.handle,
plane_index,
&mut count,
displays.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
displays.set_len(count as usize);
break displays;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
}
};
let displays: Vec<_> = displays_vk
.into_iter()
.map(|display_vk| -> Result<_, VulkanError> {
Ok(
if let Some(display) = self.display_properties.get(&display_vk) {
display
} else {
self.display_properties_unchecked()?;
self.display_properties.get(&display_vk).unwrap()
},
)
})
.collect::<Result<_, _>>()?;
Ok(displays)
}
/// Retrieves the external memory properties supported for buffers with a given configuration.
///
/// Instance API version must be at least 1.1, or the [`khr_external_memory_capabilities`]
@ -2653,6 +3101,8 @@ impl Debug for PhysicalDevice {
memory_properties,
queue_family_properties,
display_properties: _,
display_plane_properties: _,
external_buffer_properties: _,
external_fence_properties: _,
external_semaphore_properties: _,
@ -2774,7 +3224,7 @@ impl Debug for ConformanceVersion {
}
}
impl Display for ConformanceVersion {
impl std::fmt::Display for ConformanceVersion {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
Debug::fmt(self, f)

746
vulkano/src/display.rs Normal file
View File

@ -0,0 +1,746 @@
// Copyright (c) 2016 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.
//! Control and use of display devices (e.g. monitors).
//!
//! A `Display` represents a display device, which is usually a monitor but can also be something
//! else that can display graphical content. You do not create `Display` objects yourself, but
//! you get them from the physical device instead. To get a list of all available displays on the
//! system, you can call [`PhysicalDevice::display_properties`].
//!
//! A *display plane* is a single layer within a display device or graphics stack that a surface
//! can be created from. Depending on the setup used by the system, there may be one fixed
//! display plane for each display, multiple display planes for each display, or even
//! a pool of display planes that multiple displays can make use of.
//!
//! # Creating surfaces that render directly to a display
//!
//! - Choose the `Display` that you want to render to.
//! - Get display plane properties with [`PhysicalDevice::display_plane_properties`],
//! and choose a display plane index that is supported with the chosen display.
//! - Choose a `DisplayMode`, which is the combination of a display, a resolution and a refresh
//! rate. You can enumerate the modes available on a display with
//! [`Display::display_mode_properties`], or create your own mode.
//! A display can show multiple planes in a stacking fashion.
//! - Create a `Surface` object with `Surface::from_display_plane`,
//! and pass the chosen `DisplayMode` and display plane index.
use crate::{
cache::{OnceCache, WeakArcOnceCache},
device::physical::PhysicalDevice,
instance::{Instance, InstanceOwned, InstanceOwnedDebugWrapper},
macros::vulkan_bitflags_enum,
swapchain::SurfaceTransforms,
Validated, ValidationError, VulkanError, VulkanObject,
};
use std::{
hash::{Hash, Hasher},
mem::MaybeUninit,
ptr,
sync::Arc,
};
/// A display device connected to a physical device.
#[derive(Debug)]
pub struct Display {
physical_device: InstanceOwnedDebugWrapper<Arc<PhysicalDevice>>,
handle: ash::vk::DisplayKHR,
name: Option<String>,
physical_dimensions: [u32; 2],
physical_resolution: [u32; 2],
supported_transforms: SurfaceTransforms,
plane_reorder_possible: bool,
persistent_content: bool,
display_modes: WeakArcOnceCache<ash::vk::DisplayModeKHR, DisplayMode>,
}
impl Display {
/// Creates a new `Display` from a raw object handle.
///
/// # Safety
///
/// - `properties` must match the properties retrieved from `physical_device`.
#[inline]
pub fn from_handle(
physical_device: Arc<PhysicalDevice>,
handle: ash::vk::DisplayKHR,
properties: DisplayProperties,
) -> Arc<Self> {
let DisplayProperties {
name,
physical_dimensions,
physical_resolution,
supported_transforms,
plane_reorder_possible,
persistent_content,
} = properties;
Arc::new(Self {
physical_device: InstanceOwnedDebugWrapper(physical_device),
handle,
name,
physical_dimensions,
physical_resolution,
supported_transforms,
plane_reorder_possible,
persistent_content,
display_modes: WeakArcOnceCache::new(),
})
}
/// Returns the physical device that this display belongs to.
#[inline]
pub fn physical_device(&self) -> &Arc<PhysicalDevice> {
&self.physical_device
}
/// Returns the name of the display.
#[inline]
pub fn name(&self) -> Option<&str> {
self.name.as_deref()
}
/// Returns the physical dimensions of the display, in millimeters.
#[inline]
pub fn physical_dimensions(&self) -> [u32; 2] {
self.physical_dimensions
}
/// Returns the physical, or preferred, resolution of the display.
#[inline]
pub fn physical_resolution(&self) -> [u32; 2] {
self.physical_resolution
}
/// Returns the transforms that are supported by the display.
#[inline]
pub fn supported_transforms(&self) -> SurfaceTransforms {
self.supported_transforms
}
/// Returns whether planes on this display can have their z-order changed.
#[inline]
pub fn plane_reorder_possible(&self) -> bool {
self.plane_reorder_possible
}
/// Returns whether the content of the display is buffered internally, and therefore persistent.
#[inline]
pub fn persistent_content(&self) -> bool {
self.persistent_content
}
/// Returns the display modes that this display supports by default.
pub fn display_mode_properties(self: &Arc<Self>) -> Result<Vec<Arc<DisplayMode>>, VulkanError> {
let fns = self.physical_device.instance().fns();
if self
.instance()
.enabled_extensions()
.khr_get_display_properties2
{
let properties_vk = unsafe {
loop {
let mut count = 0;
(fns.khr_get_display_properties2
.get_display_mode_properties2_khr)(
self.physical_device.handle(),
self.handle,
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)?;
let mut properties =
vec![ash::vk::DisplayModeProperties2KHR::default(); count as usize];
let result = (fns
.khr_get_display_properties2
.get_display_mode_properties2_khr)(
self.physical_device.handle(),
self.handle,
&mut count,
properties.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
properties.set_len(count as usize);
break properties;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
}
};
Ok(properties_vk
.into_iter()
.map(|properties_vk| {
let properties_vk = &properties_vk.display_mode_properties;
self.display_modes
.get_or_insert(properties_vk.display_mode, |&handle| {
DisplayMode::from_handle(
self.clone(),
handle,
DisplayModeCreateInfo {
visible_region: [
properties_vk.parameters.visible_region.width,
properties_vk.parameters.visible_region.height,
],
refresh_rate: properties_vk.parameters.refresh_rate,
_ne: crate::NonExhaustive(()),
},
)
})
})
.collect())
} else {
let properties_vk = unsafe {
loop {
let mut count = 0;
(fns.khr_display.get_display_mode_properties_khr)(
self.physical_device.handle(),
self.handle,
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)?;
let mut properties = Vec::with_capacity(count as usize);
let result = (fns.khr_display.get_display_mode_properties_khr)(
self.physical_device.handle(),
self.handle,
&mut count,
properties.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
properties.set_len(count as usize);
break properties;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
}
};
Ok(properties_vk
.into_iter()
.map(|properties_vk| {
self.display_modes
.get_or_insert(properties_vk.display_mode, |&handle| {
DisplayMode::from_handle(
self.clone(),
handle,
DisplayModeCreateInfo {
visible_region: [
properties_vk.parameters.visible_region.width,
properties_vk.parameters.visible_region.height,
],
refresh_rate: properties_vk.parameters.refresh_rate,
_ne: crate::NonExhaustive(()),
},
)
})
})
.collect())
}
}
}
unsafe impl VulkanObject for Display {
type Handle = ash::vk::DisplayKHR;
#[inline]
fn handle(&self) -> Self::Handle {
self.handle
}
}
unsafe impl InstanceOwned for Display {
#[inline]
fn instance(&self) -> &Arc<Instance> {
self.physical_device.instance()
}
}
impl PartialEq for Display {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.physical_device == other.physical_device && self.handle == other.handle
}
}
impl Eq for Display {}
impl Hash for Display {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.physical_device.hash(state);
self.handle.hash(state);
}
}
/// The properties of a display.
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct DisplayProperties {
/// The name of the display.
pub name: Option<String>,
/// The physical dimensions of the display, in millimeters.
pub physical_dimensions: [u32; 2],
/// The physical, or preferred, resolution of the display.
pub physical_resolution: [u32; 2],
/// The transforms that are supported by the display.
pub supported_transforms: SurfaceTransforms,
/// Whether planes on this display can have their z-order changed.
pub plane_reorder_possible: bool,
/// Whether the content of the display is buffered internally, and therefore persistent.
pub persistent_content: bool,
}
/// Represents a mode on a specific display.
///
/// A display mode describes a supported display resolution and refresh rate.
#[derive(Debug)]
pub struct DisplayMode {
display: InstanceOwnedDebugWrapper<Arc<Display>>,
handle: ash::vk::DisplayModeKHR,
visible_region: [u32; 2],
refresh_rate: u32,
display_plane_capabilities: OnceCache<u32, DisplayPlaneCapabilities>,
}
impl DisplayMode {
/// Creates a custom display mode.
#[inline]
pub fn new(
display: Arc<Display>,
create_info: DisplayModeCreateInfo,
) -> Result<Arc<Self>, Validated<VulkanError>> {
Self::validate_new(&display, &create_info)?;
unsafe { Ok(Self::new_unchecked(display, create_info)?) }
}
fn validate_new(
display: &Display,
create_info: &DisplayModeCreateInfo,
) -> Result<(), Box<ValidationError>> {
// VUID-vkCreateDisplayModeKHR-pCreateInfo-parameter
create_info
.validate(&display.physical_device)
.map_err(|err| err.add_context("create_info"))?;
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn new_unchecked(
display: Arc<Display>,
create_info: DisplayModeCreateInfo,
) -> Result<Arc<Self>, VulkanError> {
let &DisplayModeCreateInfo {
visible_region,
refresh_rate,
_ne: _,
} = &create_info;
let physical_device = display.physical_device.clone();
let create_info_vk = ash::vk::DisplayModeCreateInfoKHR {
flags: ash::vk::DisplayModeCreateFlagsKHR::empty(),
parameters: ash::vk::DisplayModeParametersKHR {
visible_region: ash::vk::Extent2D {
width: visible_region[0],
height: visible_region[1],
},
refresh_rate,
},
..Default::default()
};
let handle = {
let fns = physical_device.instance().fns();
let mut output = MaybeUninit::uninit();
(fns.khr_display.create_display_mode_khr)(
physical_device.handle(),
display.handle,
&create_info_vk,
ptr::null(),
output.as_mut_ptr(),
)
.result()
.map_err(VulkanError::from)?;
output.assume_init()
};
Ok(display.display_modes.get_or_insert(handle, |&handle| {
Self::from_handle(display.clone(), handle, create_info)
}))
}
/// Creates a new `DisplayMode` from a raw object handle.
///
/// # Safety
///
/// - `handle` must be a valid Vulkan object handle created from `display`.
/// - `create_info` must match the info used to create the object, or retrieved from `display`.
#[inline]
pub fn from_handle(
display: Arc<Display>,
handle: ash::vk::DisplayModeKHR,
create_info: DisplayModeCreateInfo,
) -> Arc<Self> {
let DisplayModeCreateInfo {
visible_region,
refresh_rate,
_ne: _,
} = create_info;
Arc::new(Self {
display: InstanceOwnedDebugWrapper(display),
handle,
visible_region,
refresh_rate,
display_plane_capabilities: OnceCache::new(),
})
}
/// Returns the display that this display mode belongs to.
#[inline]
pub fn display(&self) -> &Arc<Display> {
&self.display
}
/// Returns the extent of the visible region.
#[inline]
pub fn visible_region(&self) -> [u32; 2] {
self.visible_region
}
/// Returns the refresh rate in millihertz (i.e. `60_000` is 60 times per second).
#[inline]
pub fn refresh_rate(&self) -> u32 {
self.refresh_rate
}
/// Returns the capabilities of a display plane, when used with this display mode.
#[inline]
pub fn display_plane_capabilities(
&self,
plane_index: u32,
) -> Result<DisplayPlaneCapabilities, Validated<VulkanError>> {
self.validate_display_plane_capabilities(plane_index)?;
unsafe { Ok(self.display_plane_capabilities_unchecked(plane_index)?) }
}
fn validate_display_plane_capabilities(
&self,
plane_index: u32,
) -> Result<(), Box<ValidationError>> {
let display_plane_properties_raw = unsafe {
self.display
.physical_device
.display_plane_properties_raw()
.map_err(|_err| {
Box::new(ValidationError {
problem: "`PhysicalDevice::display_plane_properties` \
returned an error"
.into(),
..Default::default()
})
})?
};
if plane_index as usize >= display_plane_properties_raw.len() {
return Err(Box::new(ValidationError {
problem: "`plane_index` is not less than the number of display planes on the \
physical device"
.into(),
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn display_plane_capabilities_unchecked(
&self,
plane_index: u32,
) -> Result<DisplayPlaneCapabilities, VulkanError> {
self.display_plane_capabilities
.get_or_try_insert(plane_index, |&plane_index| unsafe {
let fns = self.display.physical_device.instance().fns();
let mut capabilities_vk = ash::vk::DisplayPlaneCapabilities2KHR::default();
if self
.instance()
.enabled_extensions()
.khr_get_display_properties2
{
let info_vk = ash::vk::DisplayPlaneInfo2KHR {
mode: self.handle,
plane_index,
..Default::default()
};
(fns.khr_get_display_properties2
.get_display_plane_capabilities2_khr)(
self.display.physical_device.handle(),
&info_vk,
&mut capabilities_vk,
)
.result()
.map_err(VulkanError::from)?;
} else {
(fns.khr_display.get_display_plane_capabilities_khr)(
self.display.physical_device.handle(),
self.handle,
plane_index,
&mut capabilities_vk.capabilities,
)
.result()
.map_err(VulkanError::from)?;
}
Ok(DisplayPlaneCapabilities {
supported_alpha: capabilities_vk.capabilities.supported_alpha.into(),
min_src_position: [
capabilities_vk.capabilities.min_src_position.x as u32,
capabilities_vk.capabilities.min_src_position.y as u32,
],
max_src_position: [
capabilities_vk.capabilities.max_src_position.x as u32,
capabilities_vk.capabilities.max_src_position.y as u32,
],
min_src_extent: [
capabilities_vk.capabilities.min_src_extent.width,
capabilities_vk.capabilities.min_src_extent.height,
],
max_src_extent: [
capabilities_vk.capabilities.max_src_extent.width,
capabilities_vk.capabilities.max_src_extent.height,
],
min_dst_position: [
capabilities_vk.capabilities.min_dst_position.x as u32,
capabilities_vk.capabilities.min_dst_position.y as u32,
],
max_dst_position: [
capabilities_vk.capabilities.max_dst_position.x,
capabilities_vk.capabilities.max_dst_position.y,
],
min_dst_extent: [
capabilities_vk.capabilities.min_dst_extent.width,
capabilities_vk.capabilities.min_dst_extent.height,
],
max_dst_extent: [
capabilities_vk.capabilities.max_dst_extent.width,
capabilities_vk.capabilities.max_dst_extent.height,
],
})
})
}
}
unsafe impl VulkanObject for DisplayMode {
type Handle = ash::vk::DisplayModeKHR;
#[inline]
fn handle(&self) -> Self::Handle {
self.handle
}
}
unsafe impl InstanceOwned for DisplayMode {
#[inline]
fn instance(&self) -> &Arc<Instance> {
self.display.instance()
}
}
impl PartialEq for DisplayMode {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.display == other.display && self.handle == other.handle
}
}
impl Eq for DisplayMode {}
impl Hash for DisplayMode {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.display.hash(state);
self.handle.hash(state);
}
}
/// Parameters to create a new `DisplayMode`.
#[derive(Clone, Debug)]
pub struct DisplayModeCreateInfo {
/// The extent of the visible region. Neither coordinate may be zero.
///
/// The default value is `[0; 2]`, which must be overridden.
pub visible_region: [u32; 2],
/// The refresh rate in millihertz (i.e. `60_000` is 60 times per second).
/// This must not be zero.
///
/// The default value is 0, which must be overridden.
pub refresh_rate: u32,
pub _ne: crate::NonExhaustive,
}
impl Default for DisplayModeCreateInfo {
#[inline]
fn default() -> Self {
Self {
visible_region: [0; 2],
refresh_rate: 0,
_ne: crate::NonExhaustive(()),
}
}
}
impl DisplayModeCreateInfo {
pub(crate) fn validate(
&self,
_physical_device: &PhysicalDevice,
) -> Result<(), Box<ValidationError>> {
let &Self {
visible_region,
refresh_rate,
_ne: _,
} = self;
if visible_region[0] == 0 {
return Err(Box::new(ValidationError {
context: "visible_region[0]".into(),
problem: "is zero".into(),
vuids: &["VUID-VkDisplayModeParametersKHR-width-01990"],
..Default::default()
}));
}
if visible_region[1] == 0 {
return Err(Box::new(ValidationError {
context: "visible_region[1]".into(),
problem: "is zero".into(),
vuids: &["VUID-VkDisplayModeParametersKHR-height-01991"],
..Default::default()
}));
}
if refresh_rate == 0 {
return Err(Box::new(ValidationError {
context: "refresh_rate".into(),
problem: "is zero".into(),
vuids: &["VUID-VkDisplayModeParametersKHR-refreshRate-01992"],
..Default::default()
}));
}
Ok(())
}
}
/// The properties of a display plane.
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct DisplayPlaneProperties {
/// The display that the display plane is currently associated with.
pub current_display: Option<Arc<Display>>,
/// The current z-order of the plane. This will always be less than the total number of planes.
pub current_stack_index: u32,
}
#[derive(Clone, Debug)]
pub(crate) struct DisplayPlanePropertiesRaw {
pub(crate) current_display: Option<ash::vk::DisplayKHR>,
pub(crate) current_stack_index: u32,
}
/// The capabilities of a display plane.
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct DisplayPlaneCapabilities {
/// The supported alpha blending modes.
pub supported_alpha: DisplayPlaneAlphaFlags,
/// The minimum supported source rectangle offset.
pub min_src_position: [u32; 2],
/// The maximum supported source rectangle offset.
pub max_src_position: [u32; 2],
/// The minimum supported source rectangle size.
pub min_src_extent: [u32; 2],
/// The maximum supported source rectangle size.
pub max_src_extent: [u32; 2],
/// The minimum supported destination rectangle offset.
pub min_dst_position: [u32; 2],
/// The maximum supported destination rectangle offset.
pub max_dst_position: [i32; 2],
/// The minimum supported destination rectangle size.
pub min_dst_extent: [u32; 2],
/// The maximum supported destination rectangle size.
pub max_dst_extent: [u32; 2],
}
vulkan_bitflags_enum! {
#[non_exhaustive]
/// A set of [`DisplayPlaneAlpha`] values.
DisplayPlaneAlphaFlags,
/// The alpha blending mode to use for a display mode.
DisplayPlaneAlpha,
= DisplayPlaneAlphaFlagsKHR(u32);
/// The source image is treated as opaque.
OPAQUE, Opaque = OPAQUE,
/// Use a single global alpha value that will be used for all pixels in the source image.
GLOBAL, Global = GLOBAL,
/// Use the alpha component of each pixel in the source image.
PER_PIXEL, PerPixel = PER_PIXEL,
/// Use the alpha component of each pixel in the source image,
/// but treat the other components as having already been multiplied by the alpha component.
PER_PIXEL_PREMULTIPLIED, PerPixelPremultiplied = PER_PIXEL_PREMULTIPLIED,
}

View File

@ -1207,7 +1207,7 @@ where
/// Same as [`DebugWrapper`], but also prints the instance handle for disambiguation.
///
/// [`DebugWrapper`]: crate:: DebugWrapper
#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Hash)]
#[repr(transparent)]
pub(crate) struct InstanceOwnedDebugWrapper<T>(pub(crate) T);

View File

@ -177,6 +177,7 @@ pub mod command_buffer;
pub mod deferred;
pub mod descriptor_set;
pub mod device;
pub mod display;
pub mod format;
mod version;
#[macro_use]

View File

@ -1,449 +0,0 @@
// Copyright (c) 2016 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.
//! Allows you to create surfaces that fill a whole display, outside of the windowing system.
//!
//! **As far as the author knows, no existing device supports these features. Therefore the code
//! here is mostly a draft and needs rework in both the API and the implementation.**
//!
//! The purpose of the objects in this module is to let you create a `Surface` object that
//! represents a location on the screen. This is done in four steps:
//!
//! - Choose a `Display` where the surface will be located. A `Display` represents a display
//! display, usually a monitor. The available displays can be enumerated with
//! `Display::enumerate`.
//! - Choose a `DisplayMode`, which is the combination of a display, a resolution and a refresh
//! rate. You can enumerate the modes available on a display with `Display::display_modes`, or
//! attempt to create your own mode with `TODO`.
//! - Choose a `DisplayPlane`. A display can show multiple planes in a stacking fashion.
//! - Create a `Surface` object with `Surface::from_display_plane` and pass the chosen `DisplayMode`
//! and `DisplayPlane`.
#![allow(dead_code)] // TODO: this module isn't finished
#![allow(unused_variables)] // TODO: this module isn't finished
use crate::{
device::physical::PhysicalDevice, swapchain::SurfaceTransforms, VulkanError, VulkanObject,
};
use std::{
ffi::CStr,
fmt::{Display as FmtDisplay, Error as FmtError, Formatter},
ptr,
sync::Arc,
vec::IntoIter,
};
// TODO: extract this to a `display` module and solve the visibility problems
/// ?
// TODO: plane capabilities
// TODO: store properties in the instance?
pub struct DisplayPlane {
physical_device: Arc<PhysicalDevice>,
index: u32,
properties: ash::vk::DisplayPlanePropertiesKHR,
supported_displays: Vec<ash::vk::DisplayKHR>,
}
impl DisplayPlane {
/// See the docs of enumerate().
pub fn enumerate_raw(
physical_device: Arc<PhysicalDevice>,
) -> Result<IntoIter<DisplayPlane>, VulkanError> {
let fns = physical_device.instance().fns();
assert!(physical_device.instance().enabled_extensions().khr_display); // TODO: return error instead
let display_plane_properties = unsafe {
loop {
let mut count = 0;
(fns.khr_display
.get_physical_device_display_plane_properties_khr)(
physical_device.handle(),
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)?;
let mut properties = Vec::with_capacity(count as usize);
let result = (fns
.khr_display
.get_physical_device_display_plane_properties_khr)(
physical_device.handle(),
&mut count,
properties.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
properties.set_len(count as usize);
break properties;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
}
};
Ok(display_plane_properties
.into_iter()
.enumerate()
.map(|(index, prop)| {
let supported_displays = unsafe {
loop {
let mut count = 0;
(fns.khr_display.get_display_plane_supported_displays_khr)(
physical_device.handle(),
index as u32,
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)
.unwrap(); // TODO: shouldn't unwrap
let mut displays = Vec::with_capacity(count as usize);
let result = (fns.khr_display.get_display_plane_supported_displays_khr)(
physical_device.handle(),
index as u32,
&mut count,
displays.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
displays.set_len(count as usize);
break displays;
}
ash::vk::Result::INCOMPLETE => (),
err => todo!(), // TODO: shouldn't panic
}
}
};
DisplayPlane {
physical_device: physical_device.clone(),
index: index as u32,
properties: prop,
supported_displays,
}
})
.collect::<Vec<_>>()
.into_iter())
}
/// Enumerates all the display planes that are available on a given physical device.
///
/// # Panics
///
/// - Panics if the device or host ran out of memory.
// TODO: move iterator creation here from raw constructor?
#[inline]
pub fn enumerate(physical_device: Arc<PhysicalDevice>) -> IntoIter<DisplayPlane> {
DisplayPlane::enumerate_raw(physical_device).unwrap()
}
/// Returns the physical device that was used to create this display.
#[inline]
pub fn physical_device(&self) -> &Arc<PhysicalDevice> {
&self.physical_device
}
/// Returns the index of the plane.
#[inline]
pub fn index(&self) -> u32 {
self.index
}
/// Returns true if this plane supports the given display.
#[inline]
pub fn supports(&self, display: &Display) -> bool {
// making sure that the physical device is the same
if self.physical_device().handle() != display.physical_device().handle() {
return false;
}
self.supported_displays
.iter()
.any(|&d| d == display.handle())
}
}
/// Represents a monitor connected to a physical device.
// TODO: store properties in the instance?
#[derive(Clone)]
pub struct Display {
physical_device: Arc<PhysicalDevice>,
properties: Arc<ash::vk::DisplayPropertiesKHR>, // TODO: Arc because struct isn't clone
}
impl Display {
/// See the docs of enumerate().
pub fn enumerate_raw(
physical_device: Arc<PhysicalDevice>,
) -> Result<IntoIter<Display>, VulkanError> {
let fns = physical_device.instance().fns();
assert!(physical_device.instance().enabled_extensions().khr_display); // TODO: return error instead
let display_properties = unsafe {
loop {
let mut count = 0;
(fns.khr_display.get_physical_device_display_properties_khr)(
physical_device.handle(),
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)?;
let mut properties = Vec::with_capacity(count as usize);
let result = (fns.khr_display.get_physical_device_display_properties_khr)(
physical_device.handle(),
&mut count,
properties.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
properties.set_len(count as usize);
break properties;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
}
};
Ok(display_properties
.into_iter()
.map(|prop| Display {
physical_device: physical_device.clone(),
properties: Arc::new(prop),
})
.collect::<Vec<_>>()
.into_iter())
}
/// Enumerates all the displays that are available on a given physical device.
///
/// # Panics
///
/// - Panics if the device or host ran out of memory.
// TODO: move iterator creation here from raw constructor?
#[inline]
pub fn enumerate(physical_device: Arc<PhysicalDevice>) -> IntoIter<Display> {
Display::enumerate_raw(physical_device).unwrap()
}
/// Returns the name of the display.
#[inline]
pub fn name(&self) -> &str {
unsafe {
CStr::from_ptr(self.properties.display_name)
.to_str()
.expect("non UTF-8 characters in display name")
}
}
/// Returns the physical device that was used to create this display.
#[inline]
pub fn physical_device(&self) -> &Arc<PhysicalDevice> {
&self.physical_device
}
/// Returns the physical dimensions of the display in millimeters.
#[inline]
pub fn physical_dimensions(&self) -> [u32; 2] {
let r = &self.properties.physical_dimensions;
[r.width, r.height]
}
/// Returns the physical, native, or preferred resolution of the display.
///
/// > **Note**: The display is usually still capable of displaying other resolutions. This is
/// > only the "best" resolution.
#[inline]
pub fn physical_resolution(&self) -> [u32; 2] {
let r = &self.properties.physical_resolution;
[r.width, r.height]
}
/// Returns the transforms supported by this display.
#[inline]
pub fn supported_transforms(&self) -> SurfaceTransforms {
self.properties.supported_transforms.into()
}
/// Returns true if TODO.
#[inline]
pub fn plane_reorder_possible(&self) -> bool {
self.properties.plane_reorder_possible != 0
}
/// Returns true if TODO.
#[inline]
pub fn persistent_content(&self) -> bool {
self.properties.persistent_content != 0
}
/// See the docs of display_modes().
pub fn display_modes_raw(&self) -> Result<IntoIter<DisplayMode>, VulkanError> {
let fns = self.physical_device.instance().fns();
let mode_properties = unsafe {
loop {
let mut count = 0;
(fns.khr_display.get_display_mode_properties_khr)(
self.physical_device().handle(),
self.properties.display,
&mut count,
ptr::null_mut(),
)
.result()
.map_err(VulkanError::from)?;
let mut properties = Vec::with_capacity(count as usize);
let result = (fns.khr_display.get_display_mode_properties_khr)(
self.physical_device().handle(),
self.properties.display,
&mut count,
properties.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
properties.set_len(count as usize);
break properties;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(VulkanError::from(err)),
}
}
};
Ok(mode_properties
.into_iter()
.map(|mode| DisplayMode {
display: self.clone(),
display_mode: mode.display_mode,
parameters: mode.parameters,
})
.collect::<Vec<_>>()
.into_iter())
}
/// Returns a list of all modes available on this display.
///
/// # Panics
///
/// - Panics if the device or host ran out of memory.
// TODO: move iterator creation here from display_modes_raw?
#[inline]
pub fn display_modes(&self) -> IntoIter<DisplayMode> {
self.display_modes_raw().unwrap()
}
}
unsafe impl VulkanObject for Display {
type Handle = ash::vk::DisplayKHR;
#[inline]
fn handle(&self) -> Self::Handle {
self.properties.display
}
}
/// Represents a mode on a specific display.
///
/// A display mode describes a supported display resolution and refresh rate.
pub struct DisplayMode {
display: Display,
display_mode: ash::vk::DisplayModeKHR,
parameters: ash::vk::DisplayModeParametersKHR,
}
impl DisplayMode {
/*pub fn new(display: &Display) -> Result<Arc<DisplayMode>, VulkanError> {
let fns = instance.fns();
assert!(device.instance().enabled_extensions().khr_display); // TODO: return error instead
let parameters = ash::vk::DisplayModeParametersKHR {
visibleRegion: ash::vk::Extent2D { width: , height: },
refreshRate: ,
};
let display_mode = {
let infos = ash::vk::DisplayModeCreateInfoKHR {
flags: ash::vk::DisplayModeCreateFlags::empty(),
parameters: parameters,
..Default::default()
};
let mut output = mem::uninitialized();
(fns.v1_0.CreateDisplayModeKHR)(display.device.handle(),
display.display, &infos, ptr::null(),
&mut output).result().map_err(VulkanError::from)?;
output
};
Ok(Arc::new(DisplayMode {
instance: display.device.instance().clone(),
display_mode: display_mode,
parameters: ,
}))
}*/
/// Returns the display corresponding to this mode.
#[inline]
pub fn display(&self) -> &Display {
&self.display
}
/// Returns the dimensions of the region that is visible on the monitor.
#[inline]
pub fn visible_region(&self) -> [u32; 2] {
let d = &self.parameters.visible_region;
[d.width, d.height]
}
/// Returns the refresh rate of this mode.
///
/// The returned value is multiplied by 1000. As such the value is in terms of millihertz (mHz).
/// For example, a 60Hz display mode would have a refresh rate of 60,000 mHz.
#[inline]
pub fn refresh_rate(&self) -> u32 {
self.parameters.refresh_rate
}
}
impl FmtDisplay for DisplayMode {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
let visible_region = self.visible_region();
write!(
f,
"{}×{}px @ {}.{:03} Hz",
visible_region[0],
visible_region[1],
self.refresh_rate() / 1000,
self.refresh_rate() % 1000
)
}
}
unsafe impl VulkanObject for DisplayMode {
type Handle = ash::vk::DisplayModeKHR;
#[inline]
fn handle(&self) -> Self::Handle {
self.display_mode
}
}

View File

@ -98,11 +98,6 @@
//! };
//! ```
//!
//! ## Creating a surface from a monitor
//!
//! Currently no system provides the `VK_KHR_display` extension that contains this feature.
//! This feature is still a work-in-progress in vulkano and will reside in the `display` module.
//!
//! # Swapchains
//!
//! A surface represents a location on the screen and can be created from an instance. Once you
@ -328,7 +323,6 @@ pub use self::{acquire_present::*, surface::*};
pub use surface::IOSMetalLayer;
mod acquire_present;
pub mod display;
mod surface;
use crate::{
@ -2223,8 +2217,8 @@ vulkan_enum! {
Disallowed = DISALLOWED,
/// Indicates the application will manage full-screen exclusive mode by using the
/// [`Swapchain::acquire_full_screen_exclusive()`] and
/// [`Swapchain::release_full_screen_exclusive()`] functions.
/// [`Swapchain::acquire_full_screen_exclusive_mode`] and
/// [`Swapchain::release_full_screen_exclusive_mode`] functions.
ApplicationControlled = APPLICATION_CONTROLLED,
}

View File

@ -11,11 +11,11 @@ use super::{FullScreenExclusive, PresentGravityFlags, PresentScalingFlags, Win32
use crate::{
cache::OnceCache,
device::physical::PhysicalDevice,
display::{DisplayMode, DisplayPlaneAlpha},
format::Format,
image::ImageUsage,
instance::{Instance, InstanceExtensions, InstanceOwned},
macros::{impl_id_counter, vulkan_bitflags_enum, vulkan_enum},
swapchain::display::{DisplayMode, DisplayPlane},
DebugWrapper, Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, VulkanError,
VulkanObject,
};
@ -220,32 +220,27 @@ impl Surface {
)))
}
/// Creates a `Surface` from a `DisplayPlane`.
///
/// # Panics
///
/// - Panics if `display_mode` and `plane` don't belong to the same physical device.
/// - Panics if `plane` doesn't support the display of `display_mode`.
/// Creates a `Surface` from a `DisplayMode` and display plane.
#[inline]
pub fn from_display_plane(
display_mode: &DisplayMode,
plane: &DisplayPlane,
display_mode: Arc<DisplayMode>,
create_info: DisplaySurfaceCreateInfo,
) -> Result<Arc<Self>, Validated<VulkanError>> {
Self::validate_from_display_plane(display_mode, plane)?;
Self::validate_from_display_plane(&display_mode, &create_info)?;
unsafe { Ok(Self::from_display_plane_unchecked(display_mode, plane)?) }
unsafe {
Ok(Self::from_display_plane_unchecked(
display_mode,
create_info,
)?)
}
}
fn validate_from_display_plane(
display_mode: &DisplayMode,
plane: &DisplayPlane,
create_info: &DisplaySurfaceCreateInfo,
) -> Result<(), Box<ValidationError>> {
if !display_mode
.display()
.physical_device()
.instance()
.enabled_extensions()
.khr_display
{
if !display_mode.instance().enabled_extensions().khr_display {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"khr_display",
@ -254,44 +249,143 @@ impl Surface {
}));
}
assert_eq!(
display_mode.display().physical_device(),
plane.physical_device()
);
assert!(plane.supports(display_mode.display()));
// VUID-vkCreateDisplayPlaneSurfaceKHR-pCreateInfo-parameter
create_info
.validate(display_mode.display().physical_device())
.map_err(|err| err.add_context("create_info"))?;
let &DisplaySurfaceCreateInfo {
plane_index,
plane_stack_index,
transform,
alpha_mode,
global_alpha: _,
image_extent: _,
_ne: _,
} = create_info;
let display_plane_properties_raw = unsafe {
display_mode
.display()
.physical_device()
.display_plane_properties_raw()
.map_err(|_err| {
Box::new(ValidationError {
problem: "`PhysicalDevice::display_plane_properties` \
returned an error"
.into(),
..Default::default()
})
})?
};
if display_mode.display().plane_reorder_possible() {
if plane_stack_index as usize >= display_plane_properties_raw.len() {
return Err(Box::new(ValidationError {
problem: "`plane_stack_index` is not less than the number of display planes \
on the physical device"
.into(),
vuids: &["VUID-VkDisplaySurfaceCreateInfoKHR-planeReorderPossible-01253"],
..Default::default()
}));
}
} else {
if plane_stack_index
!= display_plane_properties_raw[plane_index as usize].current_stack_index
{
return Err(Box::new(ValidationError {
problem: "`display_mode.display().plane_reorder_possible()` is `false`, and \
`plane_stack_index` does not equal the `current_stack_index` value of the \
display plane properties"
.into(),
vuids: &["VUID-VkDisplaySurfaceCreateInfoKHR-planeReorderPossible-01253"],
..Default::default()
}));
}
}
let display_plane_capabilities = unsafe {
display_mode
.display_plane_capabilities_unchecked(plane_index)
.map_err(|_err| {
Box::new(ValidationError {
problem: "`DisplayMode::display_plane_capabilities` \
returned an error"
.into(),
..Default::default()
})
})?
};
if !display_plane_capabilities
.supported_alpha
.contains_enum(alpha_mode)
{
return Err(Box::new(ValidationError {
problem: "the `supported_alpha` value of the display plane capabilities of \
`display_mode` for the provided plane index does not contain \
`create_info.alpha_mode`"
.into(),
vuids: &["VUID-VkDisplaySurfaceCreateInfoKHR-alphaMode-01255"],
..Default::default()
}));
}
if !display_mode
.display()
.supported_transforms()
.contains_enum(transform)
{
return Err(Box::new(ValidationError {
problem: "`display_mode.display().supported_transforms()` does not contain \
`create_info.transform`"
.into(),
vuids: &["VUID-VkDisplaySurfaceCreateInfoKHR-transform-06740"],
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn from_display_plane_unchecked(
display_mode: &DisplayMode,
plane: &DisplayPlane,
display_mode: Arc<DisplayMode>,
create_info: DisplaySurfaceCreateInfo,
) -> Result<Arc<Self>, VulkanError> {
let instance = display_mode.display().physical_device().instance();
let &DisplaySurfaceCreateInfo {
plane_index,
plane_stack_index,
transform,
alpha_mode,
global_alpha,
image_extent,
_ne: _,
} = &create_info;
let create_info = ash::vk::DisplaySurfaceCreateInfoKHR {
let create_info_vk = ash::vk::DisplaySurfaceCreateInfoKHR {
flags: ash::vk::DisplaySurfaceCreateFlagsKHR::empty(),
display_mode: display_mode.handle(),
plane_index: plane.index(),
plane_stack_index: 0, // FIXME: plane.properties.currentStackIndex,
transform: ash::vk::SurfaceTransformFlagsKHR::IDENTITY, // TODO: let user choose
global_alpha: 0.0, // TODO: let user choose
alpha_mode: ash::vk::DisplayPlaneAlphaFlagsKHR::OPAQUE, // TODO: let user choose
plane_index,
plane_stack_index,
transform: transform.into(),
alpha_mode: alpha_mode.into(),
global_alpha,
image_extent: ash::vk::Extent2D {
// TODO: let user choose
width: display_mode.visible_region()[0],
height: display_mode.visible_region()[1],
width: image_extent[0],
height: image_extent[1],
},
..Default::default()
};
let instance = display_mode.instance();
let handle = {
let fns = instance.fns();
let mut output = MaybeUninit::uninit();
(fns.khr_display.create_display_plane_surface_khr)(
instance.handle(),
&create_info,
&create_info_vk,
ptr::null(),
output.as_mut_ptr(),
)
@ -1345,30 +1439,6 @@ impl Surface {
}
}
impl Debug for Surface {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
let Self {
handle,
instance,
id,
api,
object,
surface_formats: _,
surface_present_modes: _,
surface_support: _,
} = self;
f.debug_struct("Surface")
.field("handle", handle)
.field("instance", instance)
.field("id", id)
.field("api", api)
.field("object", object)
.finish_non_exhaustive()
}
}
impl Drop for Surface {
#[inline]
fn drop(&mut self) {
@ -1395,6 +1465,30 @@ unsafe impl InstanceOwned for Surface {
}
}
impl Debug for Surface {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
let Self {
handle,
instance,
id,
api,
object,
surface_formats: _,
surface_present_modes: _,
surface_support: _,
} = self;
f.debug_struct("Surface")
.field("handle", handle)
.field("instance", instance)
.field("id", id)
.field("api", api)
.field("object", object)
.finish_non_exhaustive()
}
}
impl_id_counter!(Surface);
/// Get sublayer from iOS main view (ui_view). The sublayer is created as `CAMetalLayer`.
@ -1444,6 +1538,144 @@ unsafe fn get_metal_layer_macos(ns_view: *mut std::ffi::c_void) -> *mut Object {
}
}
/// Parameters to create a surface from a display mode and plane.
#[derive(Clone, Debug)]
pub struct DisplaySurfaceCreateInfo {
/// The index of the display plane in which the surface will appear.
///
/// The default value is 0.
pub plane_index: u32,
/// The z-order of the plane.
///
/// The default value is 0.
pub plane_stack_index: u32,
/// The transformation to apply to images when presented.
///
/// The default value is [`SurfaceTransform::Identity`].
pub transform: SurfaceTransform,
/// How to do alpha blending on the surface when presenting new content.
///
/// The default value is [`DisplayPlaneAlpha::Opaque`].
pub alpha_mode: DisplayPlaneAlpha,
/// If `alpha_mode` is `DisplayPlaneAlpha::Global`, specifies the global alpha value to use for
/// all blending.
///
/// The default value is 1.0.
pub global_alpha: f32,
/// The size of the presentable images that will be used.
///
/// The default value is `[0; 2]`, which must be overridden.
pub image_extent: [u32; 2],
pub _ne: crate::NonExhaustive,
}
impl Default for DisplaySurfaceCreateInfo {
#[inline]
fn default() -> Self {
Self {
plane_index: 0,
plane_stack_index: 0,
transform: SurfaceTransform::Identity,
alpha_mode: DisplayPlaneAlpha::Opaque,
global_alpha: 1.0,
image_extent: [0; 2],
_ne: crate::NonExhaustive(()),
}
}
}
impl DisplaySurfaceCreateInfo {
pub(crate) fn validate(
&self,
physical_device: &PhysicalDevice,
) -> Result<(), Box<ValidationError>> {
let &Self {
plane_index,
plane_stack_index: _,
transform,
alpha_mode,
global_alpha,
image_extent,
_ne: _,
} = self;
let properties = physical_device.properties();
transform
.validate_physical_device(physical_device)
.map_err(|err| {
err.add_context("transform")
.set_vuids(&["VUID-VkDisplaySurfaceCreateInfoKHR-transform-parameter"])
})?;
alpha_mode
.validate_physical_device(physical_device)
.map_err(|err| {
err.add_context("alpha_mode")
.set_vuids(&["VUID-VkDisplaySurfaceCreateInfoKHR-alphaMode-parameter"])
})?;
let display_plane_properties_raw = unsafe {
physical_device
.display_plane_properties_raw()
.map_err(|_err| {
Box::new(ValidationError {
problem: "`PhysicalDevice::display_plane_properties` \
returned an error"
.into(),
..Default::default()
})
})?
};
if plane_index as usize >= display_plane_properties_raw.len() {
return Err(Box::new(ValidationError {
problem: "`plane_index` is not less than the number of display planes on the \
physical device"
.into(),
vuids: &["VUID-VkDisplaySurfaceCreateInfoKHR-planeIndex-01252"],
..Default::default()
}));
}
if alpha_mode == DisplayPlaneAlpha::Global && !(0.0..=1.0).contains(&global_alpha) {
return Err(Box::new(ValidationError {
problem: "`alpha_mode` is `DisplayPlaneAlpha::Global`, but \
`global_alpha` is not between 0 and 1 inclusive"
.into(),
vuids: &["VUID-VkDisplaySurfaceCreateInfoKHR-alphaMode-01254"],
..Default::default()
}));
}
if image_extent[0] > properties.max_image_dimension2_d {
return Err(Box::new(ValidationError {
context: "image_extent[0]".into(),
problem: "is greater than the `max_image_dimension2_d` device limit".into(),
vuids: &["VUID-VkDisplaySurfaceCreateInfoKHR-width-01256"],
..Default::default()
}));
}
if image_extent[1] > properties.max_image_dimension2_d {
return Err(Box::new(ValidationError {
context: "image_extent[1]".into(),
problem: "is greater than the `max_image_dimension2_d` device limit".into(),
vuids: &["VUID-VkDisplaySurfaceCreateInfoKHR-width-01256"],
..Default::default()
}));
}
Ok(())
}
}
/// The windowing API that was used to construct a surface.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]