blob: 67f135eadb39b8eded3cb4be760e67916e22f708 [file] [log] [blame]
// 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_mode` 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::check_errors;
use crate::device::physical::PhysicalDevice;
use crate::instance::Instance;
use crate::swapchain::SupportedSurfaceTransforms;
use crate::OomError;
use crate::VulkanObject;
use std::ffi::CStr;
use std::fmt::Formatter;
use std::sync::Arc;
use std::vec::IntoIter;
use std::{fmt, ptr};
// TODO: extract this to a `display` module and solve the visibility problems
/// ?
// TODO: plane capabilities
// TODO: store properties in the instance?
pub struct DisplayPlane {
instance: Arc<Instance>,
physical_device: usize,
index: u32,
properties: ash::vk::DisplayPlanePropertiesKHR,
supported_displays: Vec<ash::vk::DisplayKHR>,
}
impl DisplayPlane {
/// See the docs of enumerate().
pub fn enumerate_raw(device: PhysicalDevice) -> Result<IntoIter<DisplayPlane>, OomError> {
let fns = device.instance().fns();
assert!(device.instance().enabled_extensions().khr_display); // TODO: return error instead
let num = unsafe {
let mut num: u32 = 0;
check_errors(
fns.khr_display
.get_physical_device_display_plane_properties_khr(
device.internal_object(),
&mut num,
ptr::null_mut(),
),
)?;
num
};
let planes: Vec<ash::vk::DisplayPlanePropertiesKHR> = unsafe {
let mut planes = Vec::with_capacity(num as usize);
let mut num = num;
check_errors(
fns.khr_display
.get_physical_device_display_plane_properties_khr(
device.internal_object(),
&mut num,
planes.as_mut_ptr(),
),
)?;
planes.set_len(num as usize);
planes
};
Ok(planes
.into_iter()
.enumerate()
.map(|(index, prop)| {
let num = unsafe {
let mut num: u32 = 0;
check_errors(fns.khr_display.get_display_plane_supported_displays_khr(
device.internal_object(),
index as u32,
&mut num,
ptr::null_mut(),
))
.unwrap(); // TODO: shouldn't unwrap
num
};
let supported_displays: Vec<ash::vk::DisplayKHR> = unsafe {
let mut displays = Vec::with_capacity(num as usize);
let mut num = num;
check_errors(fns.khr_display.get_display_plane_supported_displays_khr(
device.internal_object(),
index as u32,
&mut num,
displays.as_mut_ptr(),
))
.unwrap(); // TODO: shouldn't unwrap
displays.set_len(num as usize);
displays
};
DisplayPlane {
instance: device.instance().clone(),
physical_device: device.index(),
index: index as u32,
properties: prop,
supported_displays: supported_displays,
}
})
.collect::<Vec<_>>()
.into_iter())
}
/// Enumerates all the display planes that are available on a given physical device.
///
/// # Panic
///
/// - Panics if the device or host ran out of memory.
///
// TODO: move iterator creation here from raw constructor?
#[inline]
pub fn enumerate(device: PhysicalDevice) -> IntoIter<DisplayPlane> {
DisplayPlane::enumerate_raw(device).unwrap()
}
/// Returns the physical device that was used to create this display.
#[inline]
pub fn physical_device(&self) -> PhysicalDevice {
PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
}
/// 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().internal_object() != display.physical_device().internal_object() {
return false;
}
self.supported_displays
.iter()
.find(|&&d| d == display.internal_object())
.is_some()
}
}
/// Represents a monitor connected to a physical device.
// TODO: store properties in the instance?
#[derive(Clone)]
pub struct Display {
instance: Arc<Instance>,
physical_device: usize,
properties: Arc<ash::vk::DisplayPropertiesKHR>, // TODO: Arc because struct isn't clone
}
impl Display {
/// See the docs of enumerate().
pub fn enumerate_raw(device: PhysicalDevice) -> Result<IntoIter<Display>, OomError> {
let fns = device.instance().fns();
assert!(device.instance().enabled_extensions().khr_display); // TODO: return error instead
let num = unsafe {
let mut num = 0;
check_errors(fns.khr_display.get_physical_device_display_properties_khr(
device.internal_object(),
&mut num,
ptr::null_mut(),
))?;
num
};
let displays: Vec<ash::vk::DisplayPropertiesKHR> = unsafe {
let mut displays = Vec::with_capacity(num as usize);
let mut num = num;
check_errors(fns.khr_display.get_physical_device_display_properties_khr(
device.internal_object(),
&mut num,
displays.as_mut_ptr(),
))?;
displays.set_len(num as usize);
displays
};
Ok(displays
.into_iter()
.map(|prop| Display {
instance: device.instance().clone(),
physical_device: device.index(),
properties: Arc::new(prop),
})
.collect::<Vec<_>>()
.into_iter())
}
/// Enumerates all the displays that are available on a given physical device.
///
/// # Panic
///
/// - Panics if the device or host ran out of memory.
///
// TODO: move iterator creation here from raw constructor?
#[inline]
pub fn enumerate(device: PhysicalDevice) -> IntoIter<Display> {
Display::enumerate_raw(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) -> PhysicalDevice {
PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
}
/// Returns the physical dimensions of the display in millimeters.
#[inline]
pub fn physical_dimensions(&self) -> [u32; 2] {
let ref 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 ref r = self.properties.physical_resolution;
[r.width, r.height]
}
/// Returns the transforms supported by this display.
#[inline]
pub fn supported_transforms(&self) -> SupportedSurfaceTransforms {
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>, OomError> {
let fns = self.instance.fns();
let num = unsafe {
let mut num = 0;
check_errors(fns.khr_display.get_display_mode_properties_khr(
self.physical_device().internal_object(),
self.properties.display,
&mut num,
ptr::null_mut(),
))?;
num
};
let modes: Vec<ash::vk::DisplayModePropertiesKHR> = unsafe {
let mut modes = Vec::with_capacity(num as usize);
let mut num = num;
check_errors(fns.khr_display.get_display_mode_properties_khr(
self.physical_device().internal_object(),
self.properties.display,
&mut num,
modes.as_mut_ptr(),
))?;
modes.set_len(num as usize);
modes
};
Ok(modes
.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.
///
/// # Panic
///
/// - 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 Object = ash::vk::DisplayKHR;
#[inline]
fn internal_object(&self) -> ash::vk::DisplayKHR {
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>, OomError> {
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();
check_errors(fns.v1_0.CreateDisplayModeKHR(display.device.internal_object(),
display.display, &infos, ptr::null(),
&mut output))?;
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 ref 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 fmt::Display for DisplayMode {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
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 Object = ash::vk::DisplayModeKHR;
#[inline]
fn internal_object(&self) -> ash::vk::DisplayModeKHR {
self.display_mode
}
}