vkobject_rs/
context.rs

1
2use crate::prelude::*;
3use std::{
4	fmt::{self, Debug, Formatter},
5	mem::MaybeUninit,
6	ptr::null,
7	sync::{
8		Arc,
9		RwLock,
10		atomic::{
11			AtomicBool,
12			Ordering,
13		},
14	},
15};
16
17/// The struct to provide the information of the surface
18#[derive(Debug)]
19pub struct VulkanSurfaceInfo<'a> {
20	#[cfg(any(feature = "glfw", test))]
21	/// The window from GLFW
22	pub window: &'a glfw::PWindow,
23
24	#[cfg(feature = "win32_khr")]
25	/// The Windows window handle
26	pub hwnd: HWND,
27	#[cfg(feature = "win32_khr")]
28	/// The Windows application instance handle
29	pub hinstance: HINSTANCE,
30
31	#[cfg(feature = "android_khr")]
32	/// The Android window
33	pub window: *const ANativeWindow,
34
35	#[cfg(feature = "ios_mvk")]
36	/// The IOS view
37	pub view: *const c_void,
38
39	#[cfg(feature = "macos_mvk")]
40	/// The MacOS view
41	pub view: *const c_void,
42
43	#[cfg(feature = "metal_ext")]
44	/// The Metal layer
45	pub metal_layer: *const CAMetalLayer,
46
47	#[cfg(feature = "wayland_khr")]
48	/// The Wayland display
49	pub display: *const c_void,
50	#[cfg(feature = "wayland_khr")]
51	/// The Wayland surface
52	pub surface: *const c_void,
53
54	#[cfg(feature = "xcb_khr")]
55	/// The XCB connection
56	pub connection: *const c_void,
57	#[cfg(feature = "xcb_khr")]
58	/// The XCB window
59	pub window: xcb_window_t,
60}
61
62/// The policy of using V-Sync for the smoothest `present()` or the minimum-latency tearing `present()`.
63#[derive(Debug, Clone, Copy)]
64pub enum PresentInterval {
65	/// Enable V-Sync for the smoothest `present()` with minimum power consumption.
66	/// * If your device supports adaptive presentation interval, it will be automatically enabled.
67	VSync,
68
69	/// Disable V-Sync for maximum framerate with minimum-latency tearing `present()`.
70	/// * The `usize` is the max concurrent frames; if the device doesn't limit the max concurrent frames, you have to provide one.
71	/// * If you give zero, a default number of the max concurrent frames will be used.
72	/// * The greater the number you give, the higher the framerate you could achieve, but the more memory will be used to store the framebuffer.
73	MinLatencyPresent(usize),
74}
75
76impl PresentInterval {
77	/// Is V-Sync requested?
78	pub fn is_vsync(&self) -> bool {
79		matches!(self, Self::VSync)
80	}
81
82	/// Is minimum-latency tearing `present()` requested?
83	pub fn is_minimum_latency_present(&self) -> Option<usize> {
84		if let Self::MinLatencyPresent(maximum_frames) = self {
85			Some(*maximum_frames)
86		} else {
87			None
88		}
89	}
90}
91
92/// The requirements of choosing a GPU
93#[derive(Debug, Clone)]
94pub struct DeviceRequirement<'a> {
95	/// Choose a GPU by requiring the graphics ability
96	pub can_graphics: bool,
97
98	/// Choose a GPU by requiring the compute ability
99	pub can_compute: bool,
100
101	/// Choose a GPU by a substring in its name. If this field is an empty string, there are no requirements on the name of the GPU.
102	pub name_subtring: &'a str,
103}
104
105impl<'a> Default for DeviceRequirement<'a> {
106	fn default() -> Self {
107		Self {
108			can_graphics: true,
109			can_compute: false,
110			name_subtring: "",
111		}
112	}
113}
114
115/// The struct to create the `VulkanContext`
116#[derive(Debug)]
117pub struct VulkanContextCreateInfo<'a, 'b> {
118	/// The most important thing: the Vulkan driver is here
119	pub vkcore: Arc<VkCore>,
120
121	/// The requirements of choosing a GPU
122	pub device_requirements: DeviceRequirement<'a>,
123
124	/// The surface, the target you want to render to
125	pub surface: VulkanSurfaceInfo<'b>,
126
127	/// V-Sync should be on or off?
128	/// * It's recommended to enable V-Sync for most usage since this could be the smoothest achieve and lower the power consumption, **except** for players who play PVP and want to win with the lowest latency (You are designing these sorts of games)
129	pub present_interval: PresentInterval,
130
131	/// How many scenes could be rendered concurrently?
132	/// **NOTE** You could create a multi-threaded rendering engine, recording draw commands concurrently, and the GPU could render multiple scenes concurrently.
133	pub cpu_renderer_threads: usize,
134
135	/// The size for the descriptor pool
136	pub desc_pool_size: DescriptorPoolSize,
137
138	/// Is this a VR project?
139	pub is_vr: bool,
140}
141
142/// The Vulkan context has device, surface, swapchain, and command pools
143///
144/// # Important
145///
146/// The `VulkanContext` would not going to own the surface. For example, if you are using GLFW, the surface is the GLFW window.
147/// If your surface is dropped earlier than then context, the context could not be dropped safely.
148/// **You must make sure the context is dropped before the surface is dropped.**
149#[derive(Debug)]
150pub struct VulkanContext {
151	/// The swapchain
152	pub(crate) swapchain: Arc<RwLock<VulkanSwapchain>>,
153
154	/// The pipeline cache here for a global usage
155	pub pipeline_cache: Arc<VulkanPipelineCache>,
156
157	/// The descriptor pool here is normally for a global usage
158	pub desc_pool: Arc<DescriptorPool>,
159
160	/// The command pools
161	pub(crate) cmdpools: Vec<VulkanCommandPool>,
162
163	/// The surface in use
164	pub surface: Arc<VulkanSurface>,
165
166	/// The device in use
167	pub device: Arc<VulkanDevice>,
168
169	/// The Vulkan driver
170	pub(crate) vkcore: Arc<VkCore>,
171
172	/// How many scenes could be rendered concurrently?
173	pub cpu_renderer_threads: usize,
174}
175
176unsafe impl Send for VulkanContext {}
177unsafe impl Sync for VulkanContext {}
178
179impl VulkanContext {
180	/// Create a new `VulkanContext`
181	pub fn new(create_info: VulkanContextCreateInfo) -> Result<Self, VulkanError> {
182		let cpu_renderer_threads = create_info.cpu_renderer_threads;
183		let vkcore = create_info.vkcore.clone();
184		let devreq = &create_info.device_requirements;
185		let (can_graphics, can_compute, name_substr) = (devreq.can_graphics, devreq.can_compute, &devreq.name_subtring);
186		let device = Arc::new(match (can_graphics, can_compute) {
187			(false, false) => VulkanDevice::choose_gpu_anyway(vkcore.clone(), name_substr)?,
188			(true, false) => VulkanDevice::choose_gpu_with_graphics(vkcore.clone(), name_substr)?,
189			(false, true) => VulkanDevice::choose_gpu_with_compute(vkcore.clone(), name_substr)?,
190			(true, true) => VulkanDevice::choose_gpu_with_graphics_and_compute(vkcore.clone(), name_substr)?,
191		});
192		let surface = &create_info.surface;
193
194		#[cfg(any(feature = "glfw", test))]
195		let surface = Arc::new(VulkanSurface::new(vkcore.clone(), &device, surface.window)?);
196		#[cfg(feature = "win32_khr")]
197		let surface = Arc::new(VulkanSurface::new(vkcore.clone(), &device, surface.hwnd, surface.hinstance)?);
198		#[cfg(feature = "android_khr")]
199		let surface = Arc::new(VulkanSurface::new(vkcore.clone(), &device, surface.window)?);
200		#[cfg(feature = "ios_mvk")]
201		let surface = Arc::new(VulkanSurface::new(vkcore.clone(), &device, surface.view)?);
202		#[cfg(feature = "macos_mvk")]
203		let surface = Arc::new(VulkanSurface::new(vkcore.clone(), &device, surface.view)?);
204		#[cfg(feature = "metal_ext")]
205		let surface = Arc::new(VulkanSurface::new(vkcore.clone(), &device, surface.metal_layer)?);
206		#[cfg(feature = "wayland_khr")]
207		let surface = Arc::new(VulkanSurface::new(vkcore.clone(), &device, surface.display, surface.surface)?);
208		#[cfg(feature = "xcb_khr")]
209		let surface = Arc::new(VulkanSurface::new(vkcore.clone(), &device, surface.connection, surface.window)?);
210
211		let mut cmdpools: Vec<VulkanCommandPool> = Vec::with_capacity(cpu_renderer_threads);
212		for _ in 0..cpu_renderer_threads {
213			cmdpools.push(VulkanCommandPool::new(device.clone(), 2)?);
214		}
215		let desc_pool = Arc::new(DescriptorPool::new(device.clone(), create_info.desc_pool_size)?);
216		let pipeline_cache = Arc::new(VulkanPipelineCache::new(device.clone(), Some(&load_cache("global_pipeline_cache", None).unwrap_or(Vec::new())))?);
217		let size = Self::get_surface_size_(&vkcore, &device, &surface)?;
218		let swapchain = Arc::new(RwLock::new(VulkanSwapchain::new(device.clone(), surface.clone(), size.width, size.height, create_info.present_interval, cpu_renderer_threads, create_info.is_vr, None)?));
219		let ret = Self {
220			vkcore,
221			device,
222			surface,
223			swapchain,
224			cmdpools,
225			desc_pool,
226			pipeline_cache,
227			cpu_renderer_threads,
228		};
229		Ok(ret)
230	}
231
232	/// Get the Vulkan instance
233	pub(crate) fn get_instance(&self) -> VkInstance {
234		self.vkcore.get_instance()
235	}
236
237	/// get the `VkCore`
238	pub(crate) fn get_vkcore(&self) -> Arc<VkCore> {
239		self.vkcore.clone()
240	}
241
242	/// Get the `VkPhysicalDevice` in use
243	pub(crate) fn get_vk_physical_device(&self) -> VkPhysicalDevice {
244		self.device.get_vk_physical_device()
245	}
246
247	/// Get the `VkDevice` in use
248	pub(crate) fn get_vk_device(&self) -> VkDevice {
249		self.device.get_vk_device()
250	}
251
252	/// Get a queue for the current device. To submit commands to a queue concurrently, the queue must be locked.
253	pub(crate) fn get_vk_queue(&self) -> VkQueue {
254		self.device.get_vk_queue()
255	}
256
257	/// Get the `VkSurfaceKHR`
258	pub(crate) fn get_vk_surface(&self) -> VkSurfaceKHR {
259		self.surface.get_vk_surface()
260	}
261
262	/// Get the current surface format
263	pub(crate) fn get_vk_surface_format(&self) -> &VkSurfaceFormatKHR {
264		self.surface.get_vk_surface_format()
265	}
266
267	/// Get the swapchain
268	pub fn get_swapchain(&self) -> Arc<RwLock<VulkanSwapchain>> {
269		self.swapchain.clone()
270	}
271
272	/// Get the `VkSwapchainKHR`
273	pub(crate) fn get_vk_swapchain(&self) -> VkSwapchainKHR {
274		self.swapchain.read().unwrap().get_vk_swapchain()
275	}
276
277	/// Get the current swapchain extent(the framebuffer size)
278	pub fn get_swapchain_extent(&self) -> VkExtent2D {
279		self.swapchain.read().unwrap().get_swapchain_extent()
280	}
281
282	/// Get the surface size, a.k.a. the frame buffer size
283	pub fn get_surface_size_(vkcore: &VkCore, device: &VulkanDevice, surface: &VulkanSurface) -> Result<VkExtent2D, VulkanError> {
284		let mut surface_properties: VkSurfaceCapabilitiesKHR = unsafe {MaybeUninit::zeroed().assume_init()};
285		vkcore.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device.get_vk_physical_device(), surface.get_vk_surface(), &mut surface_properties)?;
286		Ok(surface_properties.currentExtent)
287	}
288
289	/// Get the surface size, a.k.a. the frame buffer size
290	pub fn get_surface_size(&self) -> Result<VkExtent2D, VulkanError> {
291		Self::get_surface_size_(&self.vkcore, &self.device, &self.surface)
292	}
293
294	/// Get the number of CPU renderer threads that supports
295	pub fn get_supported_number_of_cpu_renderer_threads(&self) -> usize {
296		self.cpu_renderer_threads
297	}
298
299	/// Create a pipeline builder
300	pub fn create_pipeline_builder(&self, mesh: Arc<GenericMeshWithMaterial>, shaders: Arc<DrawShaders>, desc_props: Arc<DescriptorProps>) -> Result<PipelineBuilder, VulkanError> {
301		PipelineBuilder::new(self.device.clone(), mesh, shaders, self.desc_pool.clone(), desc_props, self.swapchain.read().unwrap().renderpass.clone(), self.pipeline_cache.clone())
302	}
303
304	/// Recreate the swapchain when users toggle the switch of `vsync` or the framebuffer size changes
305	pub fn recreate_swapchain(&self, width: u32, height: u32, present_interval: PresentInterval, is_vr: bool) -> Result<(), VulkanError> {
306		self.device.wait_idle()?;
307		let old_swapchain = self.swapchain.read().unwrap().get_vk_swapchain();
308		*self.swapchain.write().unwrap() = VulkanSwapchain::new(self.device.clone(), self.surface.clone(), width, height, present_interval, self.cpu_renderer_threads, is_vr, Some(old_swapchain))?;
309		Ok(())
310	}
311
312	/// When the windows was resized, call this method to recreate the swapchain to fit the new size
313	pub fn on_resize(&self) -> Result<bool, VulkanError> {
314		let surface_size = self.get_surface_size()?;
315		let swapchain_extent = self.get_swapchain_extent();
316		if	swapchain_extent.width == surface_size.width &&
317			swapchain_extent.height == surface_size.height {
318			Ok(false)
319		} else {
320			let swapchain_lock = self.swapchain.read().unwrap();
321			let present_interval = swapchain_lock.get_present_interval();
322			let is_vr = swapchain_lock.get_is_vr();
323			drop(swapchain_lock);
324			self.recreate_swapchain(surface_size.width, surface_size.height, present_interval, is_vr)?;
325			Ok(true)
326		}
327	}
328
329	/// Acquire a command buffer and a queue, start recording the commands
330	/// * You could call this function in different threads, in order to achieve concurrent frame rendering
331	pub fn begin_scene<'a>(&'a self, pool_index: usize, rt_props: Option<Arc<RenderTargetProps>>) -> Result<VulkanContextScene<'a>, VulkanError> {
332		let present_image_index;
333		let swapchain;
334		let pool_in_use = if let Some(rt_props) = rt_props {
335			swapchain = None;
336			present_image_index = None;
337			self.cmdpools[pool_index].use_pool(Some(rt_props))?
338		} else {
339			loop {
340				if self.swapchain.read().unwrap().need_recreate_swapchain.load(Ordering::Acquire) {
341					self.on_resize()?;
342				}
343				match self.swapchain.read().unwrap().acquire_next_image(pool_index, u64::MAX) {
344					Ok(index) => {
345						present_image_index = Some(index);
346						swapchain = Some(self.swapchain.clone());
347						break;
348					}
349					Err(e) => if let Some(ve) = e.is_vkerror() {
350						match ve {
351							VkError::VkErrorOutOfDateKhr(_) => {
352								self.on_resize()?;
353							}
354							_ => return Err(VulkanError::VkError(ve.clone())),
355						}
356					} else {
357						return Err(e)
358					}
359				};
360			}
361			self.cmdpools[pool_index].use_pool(Some(self.swapchain.read().unwrap().get_image(present_image_index.unwrap()).rt_props.clone()))?
362		};
363		VulkanContextScene::new(self.device.vkcore.clone(), self.device.clone(), swapchain, pool_in_use, present_image_index)
364	}
365}
366
367impl Drop for VulkanContext {
368	fn drop(&mut self) {
369		match self.pipeline_cache.dump_cache() {
370			Ok(cache_data) => if let Err(reason) = save_cache("global_pipeline_cache", None, &cache_data) {
371				eprintln!("Save pipeline cache data failed: {reason:?}");
372			}
373			Err(reason) => eprintln!("Dump pipeline cache data failed: {reason:?}"),
374		}
375	}
376}
377
378pub struct VulkanContextScene<'a> {
379	pub vkcore: Arc<VkCore>,
380	pub device: Arc<VulkanDevice>,
381	pub pool_in_use: VulkanCommandPoolInUse<'a>,
382	swapchain: Option<Arc<RwLock<VulkanSwapchain>>>,
383	present_image_index: Option<usize>,
384	present_queued: AtomicBool,
385}
386
387impl<'a> VulkanContextScene<'a> {
388	pub(crate) fn new(vkcore: Arc<VkCore>, device: Arc<VulkanDevice>, swapchain: Option<Arc<RwLock<VulkanSwapchain>>>, pool_in_use: VulkanCommandPoolInUse<'a>, present_image_index: Option<usize>) -> Result<Self, VulkanError> {
389		let mut barrier = VkImageMemoryBarrier {
390			sType: VkStructureType::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
391			pNext: null(),
392			srcAccessMask: 0,
393			dstAccessMask: VkAccessFlagBits::VK_ACCESS_TRANSFER_WRITE_BIT as VkAccessFlags,
394			oldLayout: VkImageLayout::VK_IMAGE_LAYOUT_UNDEFINED,
395			newLayout: VkImageLayout::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
396			srcQueueFamilyIndex: VK_QUEUE_FAMILY_IGNORED,
397			dstQueueFamilyIndex: VK_QUEUE_FAMILY_IGNORED,
398			image: null(),
399			subresourceRange: VkImageSubresourceRange {
400				aspectMask: 0,
401				baseMipLevel: 0,
402				levelCount: 1,
403				baseArrayLayer: 0,
404				layerCount: 1,
405			},
406		};
407		for image in pool_in_use.rt_props.as_ref().unwrap().attachments.iter() {
408			barrier.image = image.get_vk_image();
409			barrier.subresourceRange.aspectMask = if image.is_depth_stencil() {
410				VkImageAspectFlagBits::VK_IMAGE_ASPECT_DEPTH_BIT as VkImageAspectFlags |
411				VkImageAspectFlagBits::VK_IMAGE_ASPECT_STENCIL_BIT as VkImageAspectFlags
412			} else {
413				VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT as VkImageAspectFlags
414			};
415			vkcore.vkCmdPipelineBarrier(
416				pool_in_use.cmdbuf,
417				VkPipelineStageFlagBits::VK_PIPELINE_STAGE_ALL_COMMANDS_BIT as VkPipelineStageFlags,
418				VkPipelineStageFlagBits::VK_PIPELINE_STAGE_TRANSFER_BIT as VkPipelineStageFlags,
419				0,
420				0, null(),
421				0, null(),
422				1, &barrier
423			)?;
424		}
425		Ok(Self {
426			vkcore,
427			device,
428			pool_in_use,
429			swapchain,
430			present_image_index,
431			present_queued: AtomicBool::new(false),
432		})
433	}
434
435	/// Get the current command buffer in use
436	pub fn get_cmdbuf(&self) -> VkCommandBuffer {
437		self.pool_in_use.cmdbuf
438	}
439
440	/// Get the render target extent
441	pub fn get_rendertarget_extent(&self) -> &VkExtent2D {
442		self.pool_in_use.rt_props.as_ref().unwrap().get_extent()
443	}
444
445	/// Setup viewport
446	pub fn set_viewport(&self, x: f32, y: f32, width: f32, height: f32, min_depth: f32, max_depth: f32) -> Result<(), VulkanError> {
447		let viewport = VkViewport {
448			x,
449			y,
450			width,
451			height,
452			minDepth: min_depth,
453			maxDepth: max_depth,
454		};
455		let cmdbuf = self.pool_in_use.cmdbuf;
456		self.vkcore.vkCmdSetViewport(cmdbuf, 0, 1, &viewport)?;
457		Ok(())
458	}
459
460	/// Set the viewport size to the swapchain image size
461	pub fn set_viewport_swapchain(&self, min_depth: f32, max_depth: f32) -> Result<(), VulkanError> {
462		let extent = self.get_rendertarget_extent();
463		self.set_viewport(0.0, 0.0, extent.width as f32, extent.height as f32, min_depth, max_depth)
464	}
465
466	/// Set scissor
467	pub fn set_scissor(&self, extent: VkExtent2D) -> Result<(), VulkanError> {
468		let scissor = VkRect2D {
469			offset: VkOffset2D {
470				x: 0,
471				y: 0,
472			},
473			extent,
474		};
475		self.vkcore.vkCmdSetScissor(self.pool_in_use.cmdbuf, 0, 1, &scissor)?;
476		Ok(())
477	}
478
479	/// Set scissor to the swapchain image size
480	pub fn set_scissor_swapchain(&self) -> Result<(), VulkanError> {
481		self.set_scissor(*self.get_rendertarget_extent())
482	}
483
484	/// Clear draw buffer
485	pub fn clear(&self, color: Vec4, depth: f32, stencil: u32) -> Result<(), VulkanError> {
486		let cmdbuf = self.pool_in_use.cmdbuf;
487		for image in self.pool_in_use.rt_props.as_ref().unwrap().attachments.iter() {
488			if !image.is_depth_stencil() {
489				let color_clear_value = VkClearColorValue {
490					float32: [color.x, color.y, color.z, color.w],
491				};
492				let range = VkImageSubresourceRange {
493					aspectMask: VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT as VkImageAspectFlags,
494					baseMipLevel: 0,
495					levelCount: 1,
496					baseArrayLayer: 0,
497					layerCount: 1,
498				};
499				self.vkcore.vkCmdClearColorImage(cmdbuf, image.get_vk_image(), VkImageLayout::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &color_clear_value, 1, &range)?;
500			} else {
501				let depth_stencil_clear_value = VkClearDepthStencilValue {
502					depth,
503					stencil,
504				};
505				let range = VkImageSubresourceRange {
506					aspectMask: 
507						VkImageAspectFlagBits::VK_IMAGE_ASPECT_DEPTH_BIT as VkImageAspectFlags |
508						VkImageAspectFlagBits::VK_IMAGE_ASPECT_STENCIL_BIT as VkImageAspectFlags,
509					baseMipLevel: 0,
510					levelCount: 1,
511					baseArrayLayer: 0,
512					layerCount: 1,
513				};
514				self.vkcore.vkCmdClearDepthStencilImage(cmdbuf, image.get_vk_image(), VkImageLayout::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &depth_stencil_clear_value, 1, &range)?;
515			}
516		}
517		Ok(())
518	}
519
520	/// Begin the renderpass
521	pub fn begin_renderpass(&self, clear_color: Vec4, clear_depth: f32, clear_stencil: u32) -> Result<(), VulkanError> {
522		let rt_props = self.pool_in_use.rt_props.as_ref().unwrap();
523		let mut clear_values: Vec<VkClearValue> = Vec::with_capacity(rt_props.attachments.len());
524		for image in rt_props.attachments.iter() {
525			if !image.is_depth_stencil() {
526				clear_values.push(VkClearValue {color: VkClearColorValue {
527					float32: [clear_color.x, clear_color.y, clear_color.z, clear_color.w],
528				}});
529			} else {
530				clear_values.push(VkClearValue {depthStencil: VkClearDepthStencilValue {
531					depth: clear_depth,
532					stencil: clear_stencil,
533				}});
534			}
535		}
536		let renderpass_bi = VkRenderPassBeginInfo {
537			sType: VkStructureType::VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
538			pNext: null(),
539			renderPass: rt_props.get_vk_renderpass(),
540			framebuffer: rt_props.get_vk_framebuffer(),
541			renderArea: VkRect2D {
542				offset: VkOffset2D {
543					x: 0,
544					y: 0,
545				},
546				extent: *rt_props.get_extent(),
547			},
548			clearValueCount: clear_values.len() as u32,
549			pClearValues: clear_values.as_ptr(),
550		};
551		self.vkcore.vkCmdBeginRenderPass(self.pool_in_use.cmdbuf, &renderpass_bi, VkSubpassContents::VK_SUBPASS_CONTENTS_INLINE)?;
552		Ok(())
553	}
554
555	/// End the renderpass
556	pub fn end_renderpass(&self) -> Result<(), VulkanError> {
557		Ok(self.vkcore.vkCmdEndRenderPass(self.pool_in_use.cmdbuf)?)
558	}
559
560	/// Present the image, make it to be visible
561	pub fn present(&self) -> Result<(), VulkanError> {
562		if self.present_queued.fetch_or(true, Ordering::Acquire) {
563			panic!("Duplicated call to `VulkanContextScene::present()`.");
564		}
565		let mut barrier = VkImageMemoryBarrier {
566			sType: VkStructureType::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
567			pNext: null(),
568			srcAccessMask: VkAccessFlagBits::VK_ACCESS_TRANSFER_WRITE_BIT as VkAccessFlags,
569			dstAccessMask: 0,
570			oldLayout: VkImageLayout::VK_IMAGE_LAYOUT_UNDEFINED,
571			newLayout: VkImageLayout::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
572			srcQueueFamilyIndex: VK_QUEUE_FAMILY_IGNORED,
573			dstQueueFamilyIndex: VK_QUEUE_FAMILY_IGNORED,
574			image: null(),
575			subresourceRange: VkImageSubresourceRange {
576				aspectMask: 0,
577				baseMipLevel: 0,
578				levelCount: 1,
579				baseArrayLayer: 0,
580				layerCount: 1,
581			},
582		};
583		for image in self.pool_in_use.rt_props.as_ref().unwrap().attachments.iter() {
584			barrier.image = image.get_vk_image();
585			barrier.subresourceRange.aspectMask = if image.is_depth_stencil() {
586				VkImageAspectFlagBits::VK_IMAGE_ASPECT_DEPTH_BIT as VkImageAspectFlags |
587				VkImageAspectFlagBits::VK_IMAGE_ASPECT_STENCIL_BIT as VkImageAspectFlags
588			} else {
589				VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT as VkImageAspectFlags
590			};
591			self.vkcore.vkCmdPipelineBarrier(
592				self.pool_in_use.cmdbuf,
593				VkPipelineStageFlagBits::VK_PIPELINE_STAGE_ALL_COMMANDS_BIT as VkPipelineStageFlags,
594				VkPipelineStageFlagBits::VK_PIPELINE_STAGE_TRANSFER_BIT as VkPipelineStageFlags,
595				0,
596				0, null(),
597				0, null(),
598				1, &barrier
599			)?;
600		}
601		self.pool_in_use.submit()?;
602		match self.swapchain.as_ref().unwrap().read().unwrap().queue_present(self.present_image_index.unwrap()) {
603			Ok(_) => Ok(()),
604			Err(e) => {
605				self.present_queued.store(false, Ordering::Release);
606				if let Some(ve) = e.is_vkerror() {
607					match ve {
608						VkError::VkErrorOutOfDateKhr(_) => Ok(()),
609						_ => Err(VulkanError::VkError(ve.clone())),
610					}
611				} else {
612					Err(e)
613				}
614			}
615		}?;
616		Ok(())
617	}
618
619	/// Finish up
620	pub fn finish(self) {}
621}
622
623impl Debug for VulkanContextScene<'_> {
624	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
625		f.debug_struct("VulkanContextScene")
626		.field("pool_in_use", &self.pool_in_use)
627		.field("swapchain", &self.swapchain)
628		.field("present_image_index", &self.present_image_index)
629		.field("present_queued", &self.present_queued)
630		.finish()
631	}
632}
633
634impl Drop for VulkanContextScene<'_> {
635	fn drop(&mut self) {
636		if self.present_image_index.is_some() {
637			if !self.present_queued.load(Ordering::Acquire) {
638				proceed_run(self.present())
639			}
640		} else {
641			proceed_run(self.pool_in_use.submit())
642		}
643	}
644}