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_plane` 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::{ 32 device::physical::PhysicalDevice, swapchain::SurfaceTransforms, OomError, VulkanError, 33 VulkanObject, 34 }; 35 use std::{ 36 ffi::CStr, 37 fmt::{Display as FmtDisplay, Error as FmtError, Formatter}, 38 ptr, 39 sync::Arc, 40 vec::IntoIter, 41 }; 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 physical_device: Arc<PhysicalDevice>, 50 index: u32, 51 properties: ash::vk::DisplayPlanePropertiesKHR, 52 supported_displays: Vec<ash::vk::DisplayKHR>, 53 } 54 55 impl DisplayPlane { 56 /// See the docs of enumerate(). enumerate_raw( physical_device: Arc<PhysicalDevice>, ) -> Result<IntoIter<DisplayPlane>, OomError>57 pub fn enumerate_raw( 58 physical_device: Arc<PhysicalDevice>, 59 ) -> Result<IntoIter<DisplayPlane>, OomError> { 60 let fns = physical_device.instance().fns(); 61 62 assert!(physical_device.instance().enabled_extensions().khr_display); // TODO: return error instead 63 64 let display_plane_properties = unsafe { 65 loop { 66 let mut count = 0; 67 (fns.khr_display 68 .get_physical_device_display_plane_properties_khr)( 69 physical_device.handle(), 70 &mut count, 71 ptr::null_mut(), 72 ) 73 .result() 74 .map_err(VulkanError::from)?; 75 76 let mut properties = Vec::with_capacity(count as usize); 77 let result = (fns 78 .khr_display 79 .get_physical_device_display_plane_properties_khr)( 80 physical_device.handle(), 81 &mut count, 82 properties.as_mut_ptr(), 83 ); 84 85 match result { 86 ash::vk::Result::SUCCESS => { 87 properties.set_len(count as usize); 88 break properties; 89 } 90 ash::vk::Result::INCOMPLETE => (), 91 err => return Err(VulkanError::from(err).into()), 92 } 93 } 94 }; 95 96 Ok(display_plane_properties 97 .into_iter() 98 .enumerate() 99 .map(|(index, prop)| { 100 let supported_displays = unsafe { 101 loop { 102 let mut count = 0; 103 (fns.khr_display.get_display_plane_supported_displays_khr)( 104 physical_device.handle(), 105 index as u32, 106 &mut count, 107 ptr::null_mut(), 108 ) 109 .result() 110 .map_err(VulkanError::from) 111 .unwrap(); // TODO: shouldn't unwrap 112 113 let mut displays = Vec::with_capacity(count as usize); 114 let result = (fns.khr_display.get_display_plane_supported_displays_khr)( 115 physical_device.handle(), 116 index as u32, 117 &mut count, 118 displays.as_mut_ptr(), 119 ); 120 121 match result { 122 ash::vk::Result::SUCCESS => { 123 displays.set_len(count as usize); 124 break displays; 125 } 126 ash::vk::Result::INCOMPLETE => (), 127 err => todo!(), // TODO: shouldn't panic 128 } 129 } 130 }; 131 132 DisplayPlane { 133 physical_device: physical_device.clone(), 134 index: index as u32, 135 properties: prop, 136 supported_displays, 137 } 138 }) 139 .collect::<Vec<_>>() 140 .into_iter()) 141 } 142 143 /// Enumerates all the display planes that are available on a given physical device. 144 /// 145 /// # Panics 146 /// 147 /// - Panics if the device or host ran out of memory. 148 // TODO: move iterator creation here from raw constructor? 149 #[inline] enumerate(physical_device: Arc<PhysicalDevice>) -> IntoIter<DisplayPlane>150 pub fn enumerate(physical_device: Arc<PhysicalDevice>) -> IntoIter<DisplayPlane> { 151 DisplayPlane::enumerate_raw(physical_device).unwrap() 152 } 153 154 /// Returns the physical device that was used to create this display. 155 #[inline] physical_device(&self) -> &Arc<PhysicalDevice>156 pub fn physical_device(&self) -> &Arc<PhysicalDevice> { 157 &self.physical_device 158 } 159 160 /// Returns the index of the plane. 161 #[inline] index(&self) -> u32162 pub fn index(&self) -> u32 { 163 self.index 164 } 165 166 /// Returns true if this plane supports the given display. 167 #[inline] supports(&self, display: &Display) -> bool168 pub fn supports(&self, display: &Display) -> bool { 169 // making sure that the physical device is the same 170 if self.physical_device().handle() != display.physical_device().handle() { 171 return false; 172 } 173 174 self.supported_displays 175 .iter() 176 .any(|&d| d == display.handle()) 177 } 178 } 179 180 /// Represents a monitor connected to a physical device. 181 // TODO: store properties in the instance? 182 #[derive(Clone)] 183 pub struct Display { 184 physical_device: Arc<PhysicalDevice>, 185 properties: Arc<ash::vk::DisplayPropertiesKHR>, // TODO: Arc because struct isn't clone 186 } 187 188 impl Display { 189 /// See the docs of enumerate(). enumerate_raw( physical_device: Arc<PhysicalDevice>, ) -> Result<IntoIter<Display>, OomError>190 pub fn enumerate_raw( 191 physical_device: Arc<PhysicalDevice>, 192 ) -> Result<IntoIter<Display>, OomError> { 193 let fns = physical_device.instance().fns(); 194 assert!(physical_device.instance().enabled_extensions().khr_display); // TODO: return error instead 195 196 let display_properties = unsafe { 197 loop { 198 let mut count = 0; 199 (fns.khr_display.get_physical_device_display_properties_khr)( 200 physical_device.handle(), 201 &mut count, 202 ptr::null_mut(), 203 ) 204 .result() 205 .map_err(VulkanError::from)?; 206 207 let mut properties = Vec::with_capacity(count as usize); 208 let result = (fns.khr_display.get_physical_device_display_properties_khr)( 209 physical_device.handle(), 210 &mut count, 211 properties.as_mut_ptr(), 212 ); 213 214 match result { 215 ash::vk::Result::SUCCESS => { 216 properties.set_len(count as usize); 217 break properties; 218 } 219 ash::vk::Result::INCOMPLETE => (), 220 err => return Err(VulkanError::from(err).into()), 221 } 222 } 223 }; 224 225 Ok(display_properties 226 .into_iter() 227 .map(|prop| Display { 228 physical_device: physical_device.clone(), 229 properties: Arc::new(prop), 230 }) 231 .collect::<Vec<_>>() 232 .into_iter()) 233 } 234 235 /// Enumerates all the displays that are available on a given physical device. 236 /// 237 /// # Panics 238 /// 239 /// - Panics if the device or host ran out of memory. 240 // TODO: move iterator creation here from raw constructor? 241 #[inline] enumerate(physical_device: Arc<PhysicalDevice>) -> IntoIter<Display>242 pub fn enumerate(physical_device: Arc<PhysicalDevice>) -> IntoIter<Display> { 243 Display::enumerate_raw(physical_device).unwrap() 244 } 245 246 /// Returns the name of the display. 247 #[inline] name(&self) -> &str248 pub fn name(&self) -> &str { 249 unsafe { 250 CStr::from_ptr(self.properties.display_name) 251 .to_str() 252 .expect("non UTF-8 characters in display name") 253 } 254 } 255 256 /// Returns the physical device that was used to create this display. 257 #[inline] physical_device(&self) -> &Arc<PhysicalDevice>258 pub fn physical_device(&self) -> &Arc<PhysicalDevice> { 259 &self.physical_device 260 } 261 262 /// Returns the physical dimensions of the display in millimeters. 263 #[inline] physical_dimensions(&self) -> [u32; 2]264 pub fn physical_dimensions(&self) -> [u32; 2] { 265 let r = &self.properties.physical_dimensions; 266 [r.width, r.height] 267 } 268 269 /// Returns the physical, native, or preferred resolution of the display. 270 /// 271 /// > **Note**: The display is usually still capable of displaying other resolutions. This is 272 /// > only the "best" resolution. 273 #[inline] physical_resolution(&self) -> [u32; 2]274 pub fn physical_resolution(&self) -> [u32; 2] { 275 let r = &self.properties.physical_resolution; 276 [r.width, r.height] 277 } 278 279 /// Returns the transforms supported by this display. 280 #[inline] supported_transforms(&self) -> SurfaceTransforms281 pub fn supported_transforms(&self) -> SurfaceTransforms { 282 self.properties.supported_transforms.into() 283 } 284 285 /// Returns true if TODO. 286 #[inline] plane_reorder_possible(&self) -> bool287 pub fn plane_reorder_possible(&self) -> bool { 288 self.properties.plane_reorder_possible != 0 289 } 290 291 /// Returns true if TODO. 292 #[inline] persistent_content(&self) -> bool293 pub fn persistent_content(&self) -> bool { 294 self.properties.persistent_content != 0 295 } 296 297 /// See the docs of display_modes(). display_modes_raw(&self) -> Result<IntoIter<DisplayMode>, OomError>298 pub fn display_modes_raw(&self) -> Result<IntoIter<DisplayMode>, OomError> { 299 let fns = self.physical_device.instance().fns(); 300 301 let mode_properties = unsafe { 302 loop { 303 let mut count = 0; 304 (fns.khr_display.get_display_mode_properties_khr)( 305 self.physical_device().handle(), 306 self.properties.display, 307 &mut count, 308 ptr::null_mut(), 309 ) 310 .result() 311 .map_err(VulkanError::from)?; 312 313 let mut properties = Vec::with_capacity(count as usize); 314 let result = (fns.khr_display.get_display_mode_properties_khr)( 315 self.physical_device().handle(), 316 self.properties.display, 317 &mut count, 318 properties.as_mut_ptr(), 319 ); 320 321 match result { 322 ash::vk::Result::SUCCESS => { 323 properties.set_len(count as usize); 324 break properties; 325 } 326 ash::vk::Result::INCOMPLETE => (), 327 err => return Err(VulkanError::from(err).into()), 328 } 329 } 330 }; 331 332 Ok(mode_properties 333 .into_iter() 334 .map(|mode| DisplayMode { 335 display: self.clone(), 336 display_mode: mode.display_mode, 337 parameters: mode.parameters, 338 }) 339 .collect::<Vec<_>>() 340 .into_iter()) 341 } 342 343 /// Returns a list of all modes available on this display. 344 /// 345 /// # Panics 346 /// 347 /// - Panics if the device or host ran out of memory. 348 // TODO: move iterator creation here from display_modes_raw? 349 #[inline] display_modes(&self) -> IntoIter<DisplayMode>350 pub fn display_modes(&self) -> IntoIter<DisplayMode> { 351 self.display_modes_raw().unwrap() 352 } 353 } 354 355 unsafe impl VulkanObject for Display { 356 type Handle = ash::vk::DisplayKHR; 357 358 #[inline] handle(&self) -> Self::Handle359 fn handle(&self) -> Self::Handle { 360 self.properties.display 361 } 362 } 363 364 /// Represents a mode on a specific display. 365 /// 366 /// A display mode describes a supported display resolution and refresh rate. 367 pub struct DisplayMode { 368 display: Display, 369 display_mode: ash::vk::DisplayModeKHR, 370 parameters: ash::vk::DisplayModeParametersKHR, 371 } 372 373 impl DisplayMode { 374 /*pub fn new(display: &Display) -> Result<Arc<DisplayMode>, OomError> { 375 let fns = instance.fns(); 376 assert!(device.instance().enabled_extensions().khr_display); // TODO: return error instead 377 378 let parameters = ash::vk::DisplayModeParametersKHR { 379 visibleRegion: ash::vk::Extent2D { width: , height: }, 380 refreshRate: , 381 }; 382 383 let display_mode = { 384 let infos = ash::vk::DisplayModeCreateInfoKHR { 385 flags: ash::vk::DisplayModeCreateFlags::empty(), 386 parameters: parameters, 387 ..Default::default() 388 }; 389 390 let mut output = mem::uninitialized(); 391 (fns.v1_0.CreateDisplayModeKHR)(display.device.handle(), 392 display.display, &infos, ptr::null(), 393 &mut output).result().map_err(VulkanError::from)?; 394 output 395 }; 396 397 Ok(Arc::new(DisplayMode { 398 instance: display.device.instance().clone(), 399 display_mode: display_mode, 400 parameters: , 401 })) 402 }*/ 403 404 /// Returns the display corresponding to this mode. 405 #[inline] display(&self) -> &Display406 pub fn display(&self) -> &Display { 407 &self.display 408 } 409 410 /// Returns the dimensions of the region that is visible on the monitor. 411 #[inline] visible_region(&self) -> [u32; 2]412 pub fn visible_region(&self) -> [u32; 2] { 413 let d = &self.parameters.visible_region; 414 [d.width, d.height] 415 } 416 417 /// Returns the refresh rate of this mode. 418 /// 419 /// The returned value is multiplied by 1000. As such the value is in terms of millihertz (mHz). 420 /// For example, a 60Hz display mode would have a refresh rate of 60,000 mHz. 421 #[inline] refresh_rate(&self) -> u32422 pub fn refresh_rate(&self) -> u32 { 423 self.parameters.refresh_rate 424 } 425 } 426 427 impl FmtDisplay for DisplayMode { 428 #[inline] fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>429 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 430 let visible_region = self.visible_region(); 431 432 write!( 433 f, 434 "{}×{}px @ {}.{:03} Hz", 435 visible_region[0], 436 visible_region[1], 437 self.refresh_rate() / 1000, 438 self.refresh_rate() % 1000 439 ) 440 } 441 } 442 443 unsafe impl VulkanObject for DisplayMode { 444 type Handle = ash::vk::DisplayModeKHR; 445 446 #[inline] handle(&self) -> Self::Handle447 fn handle(&self) -> Self::Handle { 448 self.display_mode 449 } 450 } 451