1 // Copyright (c) 2016 The vulkano developers 2 // Licensed under the Apache License, Version 2.0 3 // <LICENSE-APACHE or 4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT 5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, 6 // at your option. All files in the project carrying such 7 // notice may not be copied, modified, or distributed except 8 // according to those terms. 9 10 //! Allows you to create surfaces that fill a whole display, outside of the windowing system. 11 //! 12 //! **As far as the author knows, no existing device supports these features. Therefore the code 13 //! here is mostly a draft and needs rework in both the API and the implementation.** 14 //! 15 //! The purpose of the objects in this module is to let you create a `Surface` object that 16 //! represents a location on the screen. This is done in four steps: 17 //! 18 //! - Choose a `Display` where the surface will be located. A `Display` represents a display 19 //! display, usually a monitor. The available displays can be enumerated with 20 //! `Display::enumerate`. 21 //! - Choose a `DisplayMode`, which is the combination of a display, a resolution and a refresh 22 //! rate. You can enumerate the modes available on a display with `Display::display_modes`, or 23 //! attempt to create your own mode with `TODO`. 24 //! - Choose a `DisplayPlane`. A display can show multiple planes in a stacking fashion. 25 //! - Create a `Surface` object with `Surface::from_display_mode` and pass the chosen `DisplayMode` 26 //! and `DisplayPlane`. 27 28 #![allow(dead_code)] // TODO: this module isn't finished 29 #![allow(unused_variables)] // TODO: this module isn't finished 30 31 use crate::check_errors; 32 use crate::device::physical::PhysicalDevice; 33 use crate::instance::Instance; 34 use crate::swapchain::SupportedSurfaceTransforms; 35 use crate::OomError; 36 use crate::VulkanObject; 37 use std::ffi::CStr; 38 use std::fmt::Formatter; 39 use std::sync::Arc; 40 use std::vec::IntoIter; 41 use std::{fmt, ptr}; 42 43 // TODO: extract this to a `display` module and solve the visibility problems 44 45 /// ? 46 // TODO: plane capabilities 47 // TODO: store properties in the instance? 48 pub struct DisplayPlane { 49 instance: Arc<Instance>, 50 physical_device: usize, 51 index: u32, 52 properties: ash::vk::DisplayPlanePropertiesKHR, 53 supported_displays: Vec<ash::vk::DisplayKHR>, 54 } 55 56 impl DisplayPlane { 57 /// See the docs of enumerate(). enumerate_raw(device: PhysicalDevice) -> Result<IntoIter<DisplayPlane>, OomError>58 pub fn enumerate_raw(device: PhysicalDevice) -> Result<IntoIter<DisplayPlane>, OomError> { 59 let fns = device.instance().fns(); 60 61 assert!(device.instance().enabled_extensions().khr_display); // TODO: return error instead 62 63 let num = unsafe { 64 let mut num: u32 = 0; 65 check_errors( 66 fns.khr_display 67 .get_physical_device_display_plane_properties_khr( 68 device.internal_object(), 69 &mut num, 70 ptr::null_mut(), 71 ), 72 )?; 73 num 74 }; 75 76 let planes: Vec<ash::vk::DisplayPlanePropertiesKHR> = unsafe { 77 let mut planes = Vec::with_capacity(num as usize); 78 let mut num = num; 79 check_errors( 80 fns.khr_display 81 .get_physical_device_display_plane_properties_khr( 82 device.internal_object(), 83 &mut num, 84 planes.as_mut_ptr(), 85 ), 86 )?; 87 planes.set_len(num as usize); 88 planes 89 }; 90 91 Ok(planes 92 .into_iter() 93 .enumerate() 94 .map(|(index, prop)| { 95 let num = unsafe { 96 let mut num: u32 = 0; 97 check_errors(fns.khr_display.get_display_plane_supported_displays_khr( 98 device.internal_object(), 99 index as u32, 100 &mut num, 101 ptr::null_mut(), 102 )) 103 .unwrap(); // TODO: shouldn't unwrap 104 num 105 }; 106 107 let supported_displays: Vec<ash::vk::DisplayKHR> = unsafe { 108 let mut displays = Vec::with_capacity(num as usize); 109 let mut num = num; 110 check_errors(fns.khr_display.get_display_plane_supported_displays_khr( 111 device.internal_object(), 112 index as u32, 113 &mut num, 114 displays.as_mut_ptr(), 115 )) 116 .unwrap(); // TODO: shouldn't unwrap 117 displays.set_len(num as usize); 118 displays 119 }; 120 121 DisplayPlane { 122 instance: device.instance().clone(), 123 physical_device: device.index(), 124 index: index as u32, 125 properties: prop, 126 supported_displays: supported_displays, 127 } 128 }) 129 .collect::<Vec<_>>() 130 .into_iter()) 131 } 132 133 /// Enumerates all the display planes that are available on a given physical device. 134 /// 135 /// # Panic 136 /// 137 /// - Panics if the device or host ran out of memory. 138 /// 139 // TODO: move iterator creation here from raw constructor? 140 #[inline] enumerate(device: PhysicalDevice) -> IntoIter<DisplayPlane>141 pub fn enumerate(device: PhysicalDevice) -> IntoIter<DisplayPlane> { 142 DisplayPlane::enumerate_raw(device).unwrap() 143 } 144 145 /// Returns the physical device that was used to create this display. 146 #[inline] physical_device(&self) -> PhysicalDevice147 pub fn physical_device(&self) -> PhysicalDevice { 148 PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap() 149 } 150 151 /// Returns the index of the plane. 152 #[inline] index(&self) -> u32153 pub fn index(&self) -> u32 { 154 self.index 155 } 156 157 /// Returns true if this plane supports the given display. 158 #[inline] supports(&self, display: &Display) -> bool159 pub fn supports(&self, display: &Display) -> bool { 160 // making sure that the physical device is the same 161 if self.physical_device().internal_object() != display.physical_device().internal_object() { 162 return false; 163 } 164 165 self.supported_displays 166 .iter() 167 .find(|&&d| d == display.internal_object()) 168 .is_some() 169 } 170 } 171 172 /// Represents a monitor connected to a physical device. 173 // TODO: store properties in the instance? 174 #[derive(Clone)] 175 pub struct Display { 176 instance: Arc<Instance>, 177 physical_device: usize, 178 properties: Arc<ash::vk::DisplayPropertiesKHR>, // TODO: Arc because struct isn't clone 179 } 180 181 impl Display { 182 /// See the docs of enumerate(). enumerate_raw(device: PhysicalDevice) -> Result<IntoIter<Display>, OomError>183 pub fn enumerate_raw(device: PhysicalDevice) -> Result<IntoIter<Display>, OomError> { 184 let fns = device.instance().fns(); 185 assert!(device.instance().enabled_extensions().khr_display); // TODO: return error instead 186 187 let num = unsafe { 188 let mut num = 0; 189 check_errors(fns.khr_display.get_physical_device_display_properties_khr( 190 device.internal_object(), 191 &mut num, 192 ptr::null_mut(), 193 ))?; 194 num 195 }; 196 197 let displays: Vec<ash::vk::DisplayPropertiesKHR> = unsafe { 198 let mut displays = Vec::with_capacity(num as usize); 199 let mut num = num; 200 check_errors(fns.khr_display.get_physical_device_display_properties_khr( 201 device.internal_object(), 202 &mut num, 203 displays.as_mut_ptr(), 204 ))?; 205 displays.set_len(num as usize); 206 displays 207 }; 208 209 Ok(displays 210 .into_iter() 211 .map(|prop| Display { 212 instance: device.instance().clone(), 213 physical_device: device.index(), 214 properties: Arc::new(prop), 215 }) 216 .collect::<Vec<_>>() 217 .into_iter()) 218 } 219 220 /// Enumerates all the displays that are available on a given physical device. 221 /// 222 /// # Panic 223 /// 224 /// - Panics if the device or host ran out of memory. 225 /// 226 // TODO: move iterator creation here from raw constructor? 227 #[inline] enumerate(device: PhysicalDevice) -> IntoIter<Display>228 pub fn enumerate(device: PhysicalDevice) -> IntoIter<Display> { 229 Display::enumerate_raw(device).unwrap() 230 } 231 232 /// Returns the name of the display. 233 #[inline] name(&self) -> &str234 pub fn name(&self) -> &str { 235 unsafe { 236 CStr::from_ptr(self.properties.display_name) 237 .to_str() 238 .expect("non UTF-8 characters in display name") 239 } 240 } 241 242 /// Returns the physical device that was used to create this display. 243 #[inline] physical_device(&self) -> PhysicalDevice244 pub fn physical_device(&self) -> PhysicalDevice { 245 PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap() 246 } 247 248 /// Returns the physical dimensions of the display in millimeters. 249 #[inline] physical_dimensions(&self) -> [u32; 2]250 pub fn physical_dimensions(&self) -> [u32; 2] { 251 let ref r = self.properties.physical_dimensions; 252 [r.width, r.height] 253 } 254 255 /// Returns the physical, native, or preferred resolution of the display. 256 /// 257 /// > **Note**: The display is usually still capable of displaying other resolutions. This is 258 /// > only the "best" resolution. 259 #[inline] physical_resolution(&self) -> [u32; 2]260 pub fn physical_resolution(&self) -> [u32; 2] { 261 let ref r = self.properties.physical_resolution; 262 [r.width, r.height] 263 } 264 265 /// Returns the transforms supported by this display. 266 #[inline] supported_transforms(&self) -> SupportedSurfaceTransforms267 pub fn supported_transforms(&self) -> SupportedSurfaceTransforms { 268 self.properties.supported_transforms.into() 269 } 270 271 /// Returns true if TODO. 272 #[inline] plane_reorder_possible(&self) -> bool273 pub fn plane_reorder_possible(&self) -> bool { 274 self.properties.plane_reorder_possible != 0 275 } 276 277 /// Returns true if TODO. 278 #[inline] persistent_content(&self) -> bool279 pub fn persistent_content(&self) -> bool { 280 self.properties.persistent_content != 0 281 } 282 283 /// See the docs of display_modes(). display_modes_raw(&self) -> Result<IntoIter<DisplayMode>, OomError>284 pub fn display_modes_raw(&self) -> Result<IntoIter<DisplayMode>, OomError> { 285 let fns = self.instance.fns(); 286 287 let num = unsafe { 288 let mut num = 0; 289 check_errors(fns.khr_display.get_display_mode_properties_khr( 290 self.physical_device().internal_object(), 291 self.properties.display, 292 &mut num, 293 ptr::null_mut(), 294 ))?; 295 num 296 }; 297 298 let modes: Vec<ash::vk::DisplayModePropertiesKHR> = unsafe { 299 let mut modes = Vec::with_capacity(num as usize); 300 let mut num = num; 301 check_errors(fns.khr_display.get_display_mode_properties_khr( 302 self.physical_device().internal_object(), 303 self.properties.display, 304 &mut num, 305 modes.as_mut_ptr(), 306 ))?; 307 modes.set_len(num as usize); 308 modes 309 }; 310 311 Ok(modes 312 .into_iter() 313 .map(|mode| DisplayMode { 314 display: self.clone(), 315 display_mode: mode.display_mode, 316 parameters: mode.parameters, 317 }) 318 .collect::<Vec<_>>() 319 .into_iter()) 320 } 321 322 /// Returns a list of all modes available on this display. 323 /// 324 /// # Panic 325 /// 326 /// - Panics if the device or host ran out of memory. 327 /// 328 // TODO: move iterator creation here from display_modes_raw? 329 #[inline] display_modes(&self) -> IntoIter<DisplayMode>330 pub fn display_modes(&self) -> IntoIter<DisplayMode> { 331 self.display_modes_raw().unwrap() 332 } 333 } 334 335 unsafe impl VulkanObject for Display { 336 type Object = ash::vk::DisplayKHR; 337 338 #[inline] internal_object(&self) -> ash::vk::DisplayKHR339 fn internal_object(&self) -> ash::vk::DisplayKHR { 340 self.properties.display 341 } 342 } 343 344 /// Represents a mode on a specific display. 345 /// 346 /// A display mode describes a supported display resolution and refresh rate. 347 pub struct DisplayMode { 348 display: Display, 349 display_mode: ash::vk::DisplayModeKHR, 350 parameters: ash::vk::DisplayModeParametersKHR, 351 } 352 353 impl DisplayMode { 354 /*pub fn new(display: &Display) -> Result<Arc<DisplayMode>, OomError> { 355 let fns = instance.fns(); 356 assert!(device.instance().enabled_extensions().khr_display); // TODO: return error instead 357 358 let parameters = ash::vk::DisplayModeParametersKHR { 359 visibleRegion: ash::vk::Extent2D { width: , height: }, 360 refreshRate: , 361 }; 362 363 let display_mode = { 364 let infos = ash::vk::DisplayModeCreateInfoKHR { 365 flags: ash::vk::DisplayModeCreateFlags::empty(), 366 parameters: parameters, 367 ..Default::default() 368 }; 369 370 let mut output = mem::uninitialized(); 371 check_errors(fns.v1_0.CreateDisplayModeKHR(display.device.internal_object(), 372 display.display, &infos, ptr::null(), 373 &mut output))?; 374 output 375 }; 376 377 Ok(Arc::new(DisplayMode { 378 instance: display.device.instance().clone(), 379 display_mode: display_mode, 380 parameters: , 381 })) 382 }*/ 383 384 /// Returns the display corresponding to this mode. 385 #[inline] display(&self) -> &Display386 pub fn display(&self) -> &Display { 387 &self.display 388 } 389 390 /// Returns the dimensions of the region that is visible on the monitor. 391 #[inline] visible_region(&self) -> [u32; 2]392 pub fn visible_region(&self) -> [u32; 2] { 393 let ref d = self.parameters.visible_region; 394 [d.width, d.height] 395 } 396 397 /// Returns the refresh rate of this mode. 398 /// 399 /// The returned value is multiplied by 1000. As such the value is in terms of millihertz (mHz). 400 /// For example, a 60Hz display mode would have a refresh rate of 60,000 mHz. 401 #[inline] refresh_rate(&self) -> u32402 pub fn refresh_rate(&self) -> u32 { 403 self.parameters.refresh_rate 404 } 405 } 406 407 impl fmt::Display for DisplayMode { 408 #[inline] fmt(&self, f: &mut Formatter<'_>) -> fmt::Result409 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 410 let visible_region = self.visible_region(); 411 412 write!( 413 f, 414 "{}×{}px @ {}.{:03} Hz", 415 visible_region[0], 416 visible_region[1], 417 self.refresh_rate() / 1000, 418 self.refresh_rate() % 1000 419 ) 420 } 421 } 422 423 unsafe impl VulkanObject for DisplayMode { 424 type Object = ash::vk::DisplayModeKHR; 425 426 #[inline] internal_object(&self) -> ash::vk::DisplayModeKHR427 fn internal_object(&self) -> ash::vk::DisplayModeKHR { 428 self.display_mode 429 } 430 } 431