First work with vulkano

This commit is contained in:
Florian RICHER 2024-12-08 18:19:37 +01:00
parent cbadffc41f
commit 0597579115
Signed by: florian.richer
GPG key ID: C73D37CBED7BFC77
36 changed files with 1059 additions and 1847 deletions

View file

@ -0,0 +1,133 @@
use std::sync::Arc;
use vulkano::device::Device;
use vulkano::image::{Image, ImageUsage};
use vulkano::image::view::ImageView;
use vulkano::pipeline::graphics::subpass::PipelineRenderingCreateInfo;
use vulkano::pipeline::graphics::viewport::Viewport;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, RenderPass};
use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo};
use vulkano::sync;
use vulkano::sync::GpuFuture;
use winit::window::Window;
use crate::renderer::window_size_dependent_setup;
pub struct RenderContext {
pub(super) window: Arc<Window>,
pub(super) swapchain: Arc<Swapchain>,
pub(super) attachment_image_views: Vec<Arc<ImageView>>,
pub(super) viewport: Viewport,
pub(super) recreate_swapchain: bool,
pub(super) previous_frame_end: Option<Box<dyn GpuFuture>>,
}
impl RenderContext {
pub fn new(window: Arc<Window>, surface: Arc<Surface>, device: &Arc<Device>) -> Self {
let window_size = window.inner_size();
// Before we can draw on the surface, we have to create what is called a swapchain.
// Creating a swapchain allocates the color buffers that will contain the image that will
// ultimately be visible on the screen. These images are returned alongside the swapchain.
let (swapchain, images) = {
// Querying the capabilities of the surface. When we create the swapchain we can only
// pass values that are allowed by the capabilities.
let surface_capabilities = device
.physical_device()
.surface_capabilities(&surface, Default::default())
.unwrap();
// Choosing the internal format that the images will have.
let (image_format, _) = device
.physical_device()
.surface_formats(&surface, Default::default())
.unwrap()[0];
// Please take a look at the docs for the meaning of the parameters we didn't mention.
Swapchain::new(
device.clone(),
surface,
SwapchainCreateInfo {
// Some drivers report an `min_image_count` of 1, but fullscreen mode requires
// at least 2. Therefore we must ensure the count is at least 2, otherwise the
// program would crash when entering fullscreen mode on those drivers.
min_image_count: surface_capabilities.min_image_count.max(2),
image_format,
// The size of the window, only used to initially setup the swapchain.
//
// NOTE:
// On some drivers the swapchain extent is specified by
// `surface_capabilities.current_extent` and the swapchain size must use this
// extent. This extent is always the same as the window size.
//
// However, other drivers don't specify a value, i.e.
// `surface_capabilities.current_extent` is `None`. These drivers will allow
// anything, but the only sensible value is the window size.
//
// Both of these cases need the swapchain to use the window size, so we just
// use that.
image_extent: window_size.into(),
image_usage: ImageUsage::COLOR_ATTACHMENT,
// The alpha mode indicates how the alpha value of the final image will behave.
// For example, you can choose whether the window will be opaque or
// transparent.
composite_alpha: surface_capabilities
.supported_composite_alpha
.into_iter()
.next()
.unwrap(),
..Default::default()
},
)
.unwrap()
};
// When creating the swapchain, we only created plain images. To use them as an attachment
// for rendering, we must wrap then in an image view.
//
// Since we need to draw to multiple images, we are going to create a different image view
// for each image.
let attachment_image_views = window_size_dependent_setup(&images);
// Dynamic viewports allow us to recreate just the viewport when the window is resized.
// Otherwise we would have to recreate the whole pipeline.
let viewport = Viewport {
offset: [0.0, 0.0],
extent: window_size.into(),
depth_range: 0.0..=1.0,
};
// In some situations, the swapchain will become invalid by itself. This includes for
// example when the window is resized (as the images of the swapchain will no longer match
// the window's) or, on Android, when the application went to the background and goes back
// to the foreground.
//
// In this situation, acquiring a swapchain image or presenting it will return an error.
// Rendering to an image of that swapchain will not produce any error, but may or may not
// work. To continue rendering, we need to recreate the swapchain by creating a new
// swapchain. Here, we remember that we need to do this for the next loop iteration.
let recreate_swapchain = false;
// In the loop below we are going to submit commands to the GPU. Submitting a command
// produces an object that implements the `GpuFuture` trait, which holds the resources for
// as long as they are in use by the GPU.
//
// Destroying the `GpuFuture` blocks until the GPU is finished executing it. In order to
// avoid that, we store the submission of the previous frame here.
let previous_frame_end = Some(sync::now(device.clone()).boxed());
Self {
window,
swapchain,
attachment_image_views,
viewport,
recreate_swapchain,
previous_frame_end,
}
}
}