First work with vulkano
This commit is contained in:
parent
cbadffc41f
commit
0597579115
36 changed files with 1059 additions and 1847 deletions
133
src/renderer/render_context.rs
Normal file
133
src/renderer/render_context.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue