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