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#[derive(Debug)]
19pub struct VulkanSurfaceInfo<'a> {
20 #[cfg(any(feature = "glfw", test))]
21 pub window: &'a glfw::PWindow,
23
24 #[cfg(feature = "win32_khr")]
25 pub hwnd: HWND,
27 #[cfg(feature = "win32_khr")]
28 pub hinstance: HINSTANCE,
30
31 #[cfg(feature = "android_khr")]
32 pub window: *const ANativeWindow,
34
35 #[cfg(feature = "ios_mvk")]
36 pub view: *const c_void,
38
39 #[cfg(feature = "macos_mvk")]
40 pub view: *const c_void,
42
43 #[cfg(feature = "metal_ext")]
44 pub metal_layer: *const CAMetalLayer,
46
47 #[cfg(feature = "wayland_khr")]
48 pub display: *const c_void,
50 #[cfg(feature = "wayland_khr")]
51 pub surface: *const c_void,
53
54 #[cfg(feature = "xcb_khr")]
55 pub connection: *const c_void,
57 #[cfg(feature = "xcb_khr")]
58 pub window: xcb_window_t,
60}
61
62#[derive(Debug, Clone, Copy)]
64pub enum PresentInterval {
65 VSync,
68
69 MinLatencyPresent(usize),
74}
75
76impl PresentInterval {
77 pub fn is_vsync(&self) -> bool {
79 matches!(self, Self::VSync)
80 }
81
82 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#[derive(Debug, Clone)]
94pub struct DeviceRequirement<'a> {
95 pub can_graphics: bool,
97
98 pub can_compute: bool,
100
101 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#[derive(Debug)]
117pub struct VulkanContextCreateInfo<'a, 'b> {
118 pub vkcore: Arc<VkCore>,
120
121 pub device_requirements: DeviceRequirement<'a>,
123
124 pub surface: VulkanSurfaceInfo<'b>,
126
127 pub present_interval: PresentInterval,
130
131 pub cpu_renderer_threads: usize,
134
135 pub desc_pool_size: DescriptorPoolSize,
137
138 pub is_vr: bool,
140}
141
142#[derive(Debug)]
150pub struct VulkanContext {
151 pub(crate) swapchain: Arc<RwLock<VulkanSwapchain>>,
153
154 pub pipeline_cache: Arc<VulkanPipelineCache>,
156
157 pub desc_pool: Arc<DescriptorPool>,
159
160 pub(crate) cmdpools: Vec<VulkanCommandPool>,
162
163 pub surface: Arc<VulkanSurface>,
165
166 pub device: Arc<VulkanDevice>,
168
169 pub(crate) vkcore: Arc<VkCore>,
171
172 pub cpu_renderer_threads: usize,
174}
175
176unsafe impl Send for VulkanContext {}
177unsafe impl Sync for VulkanContext {}
178
179impl VulkanContext {
180 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 pub(crate) fn get_instance(&self) -> VkInstance {
234 self.vkcore.get_instance()
235 }
236
237 pub(crate) fn get_vkcore(&self) -> Arc<VkCore> {
239 self.vkcore.clone()
240 }
241
242 pub(crate) fn get_vk_physical_device(&self) -> VkPhysicalDevice {
244 self.device.get_vk_physical_device()
245 }
246
247 pub(crate) fn get_vk_device(&self) -> VkDevice {
249 self.device.get_vk_device()
250 }
251
252 pub(crate) fn get_vk_queue(&self) -> VkQueue {
254 self.device.get_vk_queue()
255 }
256
257 pub(crate) fn get_vk_surface(&self) -> VkSurfaceKHR {
259 self.surface.get_vk_surface()
260 }
261
262 pub(crate) fn get_vk_surface_format(&self) -> &VkSurfaceFormatKHR {
264 self.surface.get_vk_surface_format()
265 }
266
267 pub fn get_swapchain(&self) -> Arc<RwLock<VulkanSwapchain>> {
269 self.swapchain.clone()
270 }
271
272 pub(crate) fn get_vk_swapchain(&self) -> VkSwapchainKHR {
274 self.swapchain.read().unwrap().get_vk_swapchain()
275 }
276
277 pub fn get_swapchain_extent(&self) -> VkExtent2D {
279 self.swapchain.read().unwrap().get_swapchain_extent()
280 }
281
282 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 pub fn get_surface_size(&self) -> Result<VkExtent2D, VulkanError> {
291 Self::get_surface_size_(&self.vkcore, &self.device, &self.surface)
292 }
293
294 pub fn get_supported_number_of_cpu_renderer_threads(&self) -> usize {
296 self.cpu_renderer_threads
297 }
298
299 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 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 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 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 pub fn get_cmdbuf(&self) -> VkCommandBuffer {
437 self.pool_in_use.cmdbuf
438 }
439
440 pub fn get_rendertarget_extent(&self) -> &VkExtent2D {
442 self.pool_in_use.rt_props.as_ref().unwrap().get_extent()
443 }
444
445 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 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 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 pub fn set_scissor_swapchain(&self) -> Result<(), VulkanError> {
481 self.set_scissor(*self.get_rendertarget_extent())
482 }
483
484 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 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 pub fn end_renderpass(&self) -> Result<(), VulkanError> {
557 Ok(self.vkcore.vkCmdEndRenderPass(self.pool_in_use.cmdbuf)?)
558 }
559
560 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 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}