mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 22:34:43 +00:00
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:
parent
3898490bf6
commit
43db3eaf72
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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>,
|
||||
|
@ -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
746
vulkano/src/display.rs
Normal 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,
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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]
|
||||
|
Loading…
Reference in New Issue
Block a user