use bevy_ecs::system::{Res, ResMut}; use engine_vulkan::{VulkanCommandBufferAllocator, VulkanDevice, VulkanGraphicsQueue}; use vulkano::{ Validated, VulkanError, command_buffer::{ AutoCommandBufferBuilder, CommandBufferUsage, RenderingAttachmentInfo, RenderingInfo, }, render_pass::{AttachmentLoadOp, AttachmentStoreOp}, swapchain::{SwapchainAcquireFuture, SwapchainPresentInfo, acquire_next_image}, sync::{self, GpuFuture}, }; use crate::window::{WindowSurface, WindowSurfaceData}; pub fn can_render(window_surface: Res) -> bool { window_surface.surface.is_some() } pub fn render_system( mut window_surface: ResMut, command_buffer_allocator: Res, graphics_queue: Res, device: Res, ) { { let surface = window_surface.surface.as_ref().unwrap(); if surface.viewport.extent[0] == 0.0 || surface.viewport.extent[1] == 0.0 { return; } } let (image_index, acquire_future) = match acquire_image(&mut window_surface.surface.as_mut().unwrap()) { Some(r) => r, None => return, }; let mut builder = AutoCommandBufferBuilder::primary( command_buffer_allocator.0.clone(), graphics_queue.0.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) .expect("failed to create command buffer builder"); { let surface = window_surface.surface.as_ref().unwrap(); builder .begin_rendering(RenderingInfo { color_attachments: vec![Some(RenderingAttachmentInfo { load_op: AttachmentLoadOp::Clear, store_op: AttachmentStoreOp::Store, clear_value: Some([0.0, 0.0, 0.0, 0.0].into()), ..RenderingAttachmentInfo::image_view( surface.attachment_image_views[image_index as usize].clone(), ) })], ..Default::default() }) .unwrap() .set_viewport(0, [surface.viewport.clone()].into_iter().collect()) .unwrap(); } builder.end_rendering().unwrap(); let command_buffer = builder.build().unwrap(); { let surface = window_surface.surface.as_mut().unwrap(); let future = surface .previous_frame_end .take() .unwrap() .join(acquire_future) .then_execute(graphics_queue.0.clone(), command_buffer) .unwrap() .then_swapchain_present( graphics_queue.0.clone(), SwapchainPresentInfo::swapchain_image_index(surface.swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); match future.map_err(Validated::unwrap) { Ok(future) => { surface.previous_frame_end = Some(future.boxed_send_sync()); } Err(VulkanError::OutOfDate) => { surface.recreate_swapchain = true; surface.previous_frame_end = Some(sync::now(device.0.clone()).boxed_send_sync()); } Err(e) => { println!("failed to flush future: {e}"); surface.previous_frame_end = Some(sync::now(device.0.clone()).boxed_send_sync()); } } } } fn acquire_image(surface: &mut WindowSurfaceData) -> Option<(u32, SwapchainAcquireFuture)> { surface .previous_frame_end .as_mut() .unwrap() .cleanup_finished(); let (image_index, suboptimal, acquire_future) = match acquire_next_image(surface.swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, Err(VulkanError::OutOfDate) => { surface.recreate_swapchain = true; return None; } Err(e) => panic!("failed to acquire next image: {e}"), }; if suboptimal { surface.recreate_swapchain = true; } Some((image_index, acquire_future)) }