122 lines
4 KiB
Rust
122 lines
4 KiB
Rust
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<WindowSurface>) -> bool {
|
|
window_surface.surface.is_some()
|
|
}
|
|
|
|
pub fn render_system(
|
|
mut window_surface: ResMut<WindowSurface>,
|
|
command_buffer_allocator: Res<VulkanCommandBufferAllocator>,
|
|
graphics_queue: Res<VulkanGraphicsQueue>,
|
|
device: Res<VulkanDevice>,
|
|
) {
|
|
{
|
|
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))
|
|
}
|