1use ash::vk;
2use std::mem;
3
4impl super::Surface {
5 pub fn info(&self) -> crate::SurfaceInfo {
6 crate::SurfaceInfo {
7 format: self.swapchain.format,
8 alpha: self.swapchain.alpha,
9 }
10 }
11
12 unsafe fn deinit_swapchain(&mut self, raw_device: &ash::Device) {
13 let _ = raw_device.device_wait_idle();
14 self.device
15 .destroy_swapchain(mem::take(&mut self.swapchain.raw), None);
16 for frame in self.frames.drain(..) {
17 raw_device.destroy_image_view(frame.view, None);
18 raw_device.destroy_semaphore(frame.acquire_semaphore, None);
19 raw_device.destroy_semaphore(frame.present_semaphore, None);
20 }
21 }
22
23 pub fn acquire_frame(&mut self) -> super::Frame {
24 let acquire_semaphore = self.next_semaphore;
25 match unsafe {
26 self.device.acquire_next_image(
27 self.swapchain.raw,
28 !0,
29 acquire_semaphore,
30 vk::Fence::null(),
31 )
32 } {
33 Ok((index, _suboptimal)) => {
34 self.next_semaphore = mem::replace(
35 &mut self.frames[index as usize].acquire_semaphore,
36 acquire_semaphore,
37 );
38 super::Frame {
39 internal: self.frames[index as usize],
40 swapchain: self.swapchain,
41 image_index: Some(index),
42 }
43 }
44 Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => {
45 log::warn!("Acquire failed because the surface is out of date");
46 super::Frame {
47 internal: self.frames[0],
48 swapchain: self.swapchain,
49 image_index: None,
50 }
51 }
52 Err(other) => panic!("Aquire image error {}", other),
53 }
54 }
55}
56
57impl super::Context {
58 pub fn create_surface<
59 I: raw_window_handle::HasWindowHandle + raw_window_handle::HasDisplayHandle,
60 >(
61 &self,
62 window: &I,
63 ) -> Result<super::Surface, crate::NotSupportedError> {
64 let khr_swapchain = self
65 .device
66 .swapchain
67 .clone()
68 .ok_or(crate::NotSupportedError::NoSupportedDeviceFound)?;
69
70 let raw = unsafe {
71 ash_window::create_surface(
72 &self.entry,
73 &self.instance.core,
74 window.display_handle().unwrap().as_raw(),
75 window.window_handle().unwrap().as_raw(),
76 None,
77 )
78 .map_err(super::PlatformError::Init)?
79 };
80
81 let khr_surface = self
82 .instance
83 .surface
84 .as_ref()
85 .ok_or(crate::NotSupportedError::PlatformNotSupported)?;
86 if unsafe {
87 khr_surface.get_physical_device_surface_support(
88 self.physical_device,
89 self.queue_family_index,
90 raw,
91 ) != Ok(true)
92 } {
93 log::warn!("Rejected for not presenting to the window surface");
94 return Err(crate::NotSupportedError::PlatformNotSupported);
95 }
96
97 let mut surface_info = vk::PhysicalDeviceSurfaceInfo2KHR {
98 surface: raw,
99 ..Default::default()
100 };
101 let mut fullscreen_exclusive_win32 = vk::SurfaceFullScreenExclusiveWin32InfoEXT::default();
102 surface_info = surface_info.push_next(&mut fullscreen_exclusive_win32);
103 let mut fullscreen_exclusive_ext = vk::SurfaceCapabilitiesFullScreenExclusiveEXT::default();
104 let mut capabilities2_khr =
105 vk::SurfaceCapabilities2KHR::default().push_next(&mut fullscreen_exclusive_ext);
106 let _ = unsafe {
107 self.instance
108 .get_surface_capabilities2
109 .as_ref()
110 .unwrap()
111 .get_physical_device_surface_capabilities2(
112 self.physical_device,
113 &surface_info,
114 &mut capabilities2_khr,
115 )
116 };
117 log::debug!("{:?}", capabilities2_khr.surface_capabilities);
118
119 let semaphore_create_info = vk::SemaphoreCreateInfo::default();
120 let next_semaphore = unsafe {
121 self.device
122 .core
123 .create_semaphore(&semaphore_create_info, None)
124 .unwrap()
125 };
126
127 Ok(super::Surface {
128 device: khr_swapchain,
129 raw,
130 frames: Vec::new(),
131 next_semaphore,
132 swapchain: super::Swapchain {
133 raw: vk::SwapchainKHR::null(),
134 format: crate::TextureFormat::Rgba8Unorm,
135 alpha: crate::AlphaMode::Ignored,
136 target_size: [0; 2],
137 },
138 full_screen_exclusive: fullscreen_exclusive_ext.full_screen_exclusive_supported != 0,
139 })
140 }
141
142 pub fn destroy_surface(&self, surface: &mut super::Surface) {
143 unsafe {
144 surface.deinit_swapchain(&self.device.core);
145 self.device
146 .core
147 .destroy_semaphore(surface.next_semaphore, None)
148 };
149 if let Some(ref surface_instance) = self.instance.surface {
150 unsafe { surface_instance.destroy_surface(surface.raw, None) };
151 }
152 }
153
154 pub fn reconfigure_surface(&self, surface: &mut super::Surface, config: crate::SurfaceConfig) {
155 let khr_surface = self.instance.surface.as_ref().unwrap();
156
157 let capabilities = unsafe {
158 khr_surface
159 .get_physical_device_surface_capabilities(self.physical_device, surface.raw)
160 .unwrap()
161 };
162 if config.size.width < capabilities.min_image_extent.width
163 || config.size.width > capabilities.max_image_extent.width
164 || config.size.height < capabilities.min_image_extent.height
165 || config.size.height > capabilities.max_image_extent.height
166 {
167 log::warn!(
168 "Requested size {}x{} is outside of surface capabilities",
169 config.size.width,
170 config.size.height
171 );
172 }
173
174 let (alpha, composite_alpha) = if config.transparent {
175 if capabilities
176 .supported_composite_alpha
177 .contains(vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED)
178 {
179 (
180 crate::AlphaMode::PostMultiplied,
181 vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED,
182 )
183 } else if capabilities
184 .supported_composite_alpha
185 .contains(vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED)
186 {
187 (
188 crate::AlphaMode::PreMultiplied,
189 vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED,
190 )
191 } else {
192 log::error!(
193 "No composite alpha flag for transparency: {:?}",
194 capabilities.supported_composite_alpha
195 );
196 (
197 crate::AlphaMode::Ignored,
198 vk::CompositeAlphaFlagsKHR::OPAQUE,
199 )
200 }
201 } else {
202 (
203 crate::AlphaMode::Ignored,
204 vk::CompositeAlphaFlagsKHR::OPAQUE,
205 )
206 };
207
208 let (requested_frame_count, mode_preferences) = match config.display_sync {
209 crate::DisplaySync::Block => (3, [vk::PresentModeKHR::FIFO].as_slice()),
210 crate::DisplaySync::Recent => (
211 3,
212 [
213 vk::PresentModeKHR::MAILBOX,
214 vk::PresentModeKHR::FIFO_RELAXED,
215 vk::PresentModeKHR::IMMEDIATE,
216 ]
217 .as_slice(),
218 ),
219 crate::DisplaySync::Tear => (2, [vk::PresentModeKHR::IMMEDIATE].as_slice()),
220 };
221 let effective_frame_count = requested_frame_count.max(capabilities.min_image_count);
222
223 let present_modes = unsafe {
224 khr_surface
225 .get_physical_device_surface_present_modes(self.physical_device, surface.raw)
226 .unwrap()
227 };
228 let present_mode = *mode_preferences
229 .iter()
230 .find(|mode| present_modes.contains(mode))
231 .unwrap();
232 log::info!("Using surface present mode {:?}", present_mode);
233
234 let queue_families = [self.queue_family_index];
235
236 let mut supported_formats = Vec::new();
237 let (format, surface_format) = if surface.swapchain.target_size[0] > 0 {
238 let format = surface.swapchain.format;
239 log::info!("Retaining current format: {:?}", format);
240 let vk_color_space = match (format, config.color_space) {
241 (crate::TextureFormat::Bgra8Unorm, crate::ColorSpace::Srgb) => {
242 vk::ColorSpaceKHR::SRGB_NONLINEAR
243 }
244 (crate::TextureFormat::Bgra8Unorm, crate::ColorSpace::Linear) => {
245 vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT
246 }
247 (crate::TextureFormat::Bgra8UnormSrgb, crate::ColorSpace::Linear) => {
248 vk::ColorSpaceKHR::default()
249 }
250 _ => panic!(
251 "Unexpected format {:?} under color space {:?}",
252 format, config.color_space
253 ),
254 };
255 (
256 format,
257 vk::SurfaceFormatKHR {
258 format: super::map_texture_format(format),
259 color_space: vk_color_space,
260 },
261 )
262 } else {
263 supported_formats = unsafe {
264 khr_surface
265 .get_physical_device_surface_formats(self.physical_device, surface.raw)
266 .unwrap()
267 };
268 match config.color_space {
269 crate::ColorSpace::Linear => {
270 let surface_format = vk::SurfaceFormatKHR {
271 format: vk::Format::B8G8R8A8_UNORM,
272 color_space: vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT,
273 };
274 if supported_formats.contains(&surface_format) {
275 log::info!("Using linear SRGB color space");
276 (crate::TextureFormat::Bgra8Unorm, surface_format)
277 } else {
278 (
279 crate::TextureFormat::Bgra8UnormSrgb,
280 vk::SurfaceFormatKHR {
281 format: vk::Format::B8G8R8A8_SRGB,
282 color_space: vk::ColorSpaceKHR::default(),
283 },
284 )
285 }
286 }
287 crate::ColorSpace::Srgb => (
288 crate::TextureFormat::Bgra8Unorm,
289 vk::SurfaceFormatKHR {
290 format: vk::Format::B8G8R8A8_UNORM,
291 color_space: vk::ColorSpaceKHR::SRGB_NONLINEAR,
292 },
293 ),
294 }
295 };
296 if !supported_formats.is_empty() && !supported_formats.contains(&surface_format) {
297 log::error!("Surface formats are incompatible: {:?}", supported_formats);
298 }
299
300 let vk_usage = super::resource::map_texture_usage(config.usage, crate::TexelAspects::COLOR);
301 if !capabilities.supported_usage_flags.contains(vk_usage) {
302 log::error!(
303 "Surface usages are incompatible: {:?}",
304 capabilities.supported_usage_flags
305 );
306 }
307
308 let mut full_screen_exclusive_info = vk::SurfaceFullScreenExclusiveInfoEXT {
309 full_screen_exclusive: if config.allow_exclusive_full_screen {
310 vk::FullScreenExclusiveEXT::ALLOWED
311 } else {
312 vk::FullScreenExclusiveEXT::DISALLOWED
313 },
314 ..Default::default()
315 };
316
317 let mut create_info = vk::SwapchainCreateInfoKHR {
318 surface: surface.raw,
319 min_image_count: effective_frame_count,
320 image_format: surface_format.format,
321 image_color_space: surface_format.color_space,
322 image_extent: vk::Extent2D {
323 width: config.size.width,
324 height: config.size.height,
325 },
326 image_array_layers: 1,
327 image_usage: vk_usage,
328 pre_transform: vk::SurfaceTransformFlagsKHR::IDENTITY,
329 composite_alpha,
330 present_mode,
331 old_swapchain: surface.swapchain.raw,
332 ..Default::default()
333 }
334 .queue_family_indices(&queue_families);
335
336 if surface.full_screen_exclusive {
337 assert!(self.device.full_screen_exclusive.is_some());
338 create_info = create_info.push_next(&mut full_screen_exclusive_info);
339 log::info!(
340 "Configuring exclusive full screen: {}",
341 config.allow_exclusive_full_screen
342 );
343 }
344 let raw_swapchain = unsafe { surface.device.create_swapchain(&create_info, None).unwrap() };
345
346 unsafe {
347 surface.deinit_swapchain(&self.device.core);
348 }
349
350 let images = unsafe { surface.device.get_swapchain_images(raw_swapchain).unwrap() };
351 let target_size = [config.size.width as u16, config.size.height as u16];
352 let subresource_range = vk::ImageSubresourceRange {
353 aspect_mask: vk::ImageAspectFlags::COLOR,
354 base_mip_level: 0,
355 level_count: 1,
356 base_array_layer: 0,
357 layer_count: 1,
358 };
359 for image in images {
360 let view_create_info = vk::ImageViewCreateInfo {
361 image,
362 view_type: vk::ImageViewType::TYPE_2D,
363 format: surface_format.format,
364 subresource_range,
365 ..Default::default()
366 };
367 let view = unsafe {
368 self.device
369 .core
370 .create_image_view(&view_create_info, None)
371 .unwrap()
372 };
373 let semaphore_create_info = vk::SemaphoreCreateInfo::default();
374 let acquire_semaphore = unsafe {
375 self.device
376 .core
377 .create_semaphore(&semaphore_create_info, None)
378 .unwrap()
379 };
380 let present_semaphore = unsafe {
381 self.device
382 .core
383 .create_semaphore(&semaphore_create_info, None)
384 .unwrap()
385 };
386 surface.frames.push(super::InternalFrame {
387 acquire_semaphore,
388 present_semaphore,
389 image,
390 view,
391 });
392 }
393 surface.swapchain = super::Swapchain {
394 raw: raw_swapchain,
395 format,
396 alpha,
397 target_size,
398 };
399 }
400}