vulkano/examples/multi-window-game-of-life/render_pass.rs
Katt 9a35fb0221
Make image_index and final_views accessible, and add new example. (#2473)
* Make image_index and final_views accessible, and new example.

The first 2 changes should make creating frame buffers easier.
The new example should make it easier to learn vulkano-util.

* Remove unnecessary imports, and run clippy.

* Run fmt.

* .acquire() no longer returns image_index

* rename final_views() to swapchain_image_views()

The name change makes it more consistent with swapchain_image_view().

Personally I don't understand why the field name is final_views, yet we externally in function names refer to it as swapchain image views and such like.

* Fractal example no longer creates framebuffer every frame.

* Game of life example no longer creates framebuffer every frame.

(Also removed a piece of code I had commented out, but had forgotten to remove from the fractal example.)

* Rename if_recreate_swapchain to on_recreate_swapchain and update acquire() documentation. to on_recreate_swapchain

* on_recreate_swapchain is now impl FnOnce instead of generics based FnMut

Thanks marc0246!

Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com>

* Replace empty comment with an actual comment.

---------

Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com>
2024-02-21 09:08:50 +01:00

147 lines
4.9 KiB
Rust

use crate::{app::App, pixels_draw::PixelsDrawPipeline};
use std::sync::Arc;
use vulkano::{
command_buffer::{
allocator::StandardCommandBufferAllocator, CommandBufferBeginInfo, CommandBufferLevel,
CommandBufferUsage, RecordingCommandBuffer, RenderPassBeginInfo, SubpassBeginInfo,
SubpassContents,
},
device::Queue,
image::view::ImageView,
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sync::GpuFuture,
};
use vulkano_util::renderer::VulkanoWindowRenderer;
/// A render pass which places an incoming image over the frame, filling it.
pub struct RenderPassPlaceOverFrame {
gfx_queue: Arc<Queue>,
render_pass: Arc<RenderPass>,
pixels_draw_pipeline: PixelsDrawPipeline,
command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
framebuffers: Vec<Arc<Framebuffer>>,
}
impl RenderPassPlaceOverFrame {
pub fn new(
app: &App,
gfx_queue: Arc<Queue>,
window_renderer: &VulkanoWindowRenderer,
) -> RenderPassPlaceOverFrame {
let render_pass = vulkano::single_pass_renderpass!(
gfx_queue.device().clone(),
attachments: {
color: {
format: window_renderer.swapchain_format(),
samples: 1,
load_op: Clear,
store_op: Store,
},
},
pass: {
color: [color],
depth_stencil: {},
},
)
.unwrap();
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
let pixels_draw_pipeline = PixelsDrawPipeline::new(app, gfx_queue.clone(), subpass);
RenderPassPlaceOverFrame {
gfx_queue,
render_pass: render_pass.clone(),
pixels_draw_pipeline,
command_buffer_allocator: app.command_buffer_allocator.clone(),
framebuffers: create_framebuffers(window_renderer.swapchain_image_views(), render_pass),
}
}
/// Places the view exactly over the target swapchain image. The texture draw pipeline uses a
/// quad onto which it places the view.
pub fn render<F>(
&self,
before_future: F,
image_view: Arc<ImageView>,
target: Arc<ImageView>,
image_index: u32,
) -> Box<dyn GpuFuture>
where
F: GpuFuture + 'static,
{
// Get the dimensions.
let img_dims: [u32; 2] = target.image().extent()[0..2].try_into().unwrap();
// Create a primary command buffer builder.
let mut command_buffer_builder = RecordingCommandBuffer::new(
self.command_buffer_allocator.clone(),
self.gfx_queue.queue_family_index(),
CommandBufferLevel::Primary,
CommandBufferBeginInfo {
usage: CommandBufferUsage::OneTimeSubmit,
..Default::default()
},
)
.unwrap();
// Begin the render pass.
command_buffer_builder
.begin_render_pass(
RenderPassBeginInfo {
clear_values: vec![Some([0.0; 4].into())],
..RenderPassBeginInfo::framebuffer(
self.framebuffers[image_index as usize].clone(),
)
},
SubpassBeginInfo {
contents: SubpassContents::SecondaryCommandBuffers,
..Default::default()
},
)
.unwrap();
// Create a secondary command buffer from the texture pipeline & send draw commands.
let cb = self.pixels_draw_pipeline.draw(img_dims, image_view);
// Execute above commands (subpass).
command_buffer_builder.execute_commands(cb).unwrap();
// End the render pass.
command_buffer_builder
.end_render_pass(Default::default())
.unwrap();
// Build the command buffer.
let command_buffer = command_buffer_builder.end().unwrap();
// Execute primary command buffer.
let after_future = before_future
.then_execute(self.gfx_queue.clone(), command_buffer)
.unwrap();
after_future.boxed()
}
pub fn recreate_framebuffers(&mut self, swapchain_image_views: &[Arc<ImageView>]) {
self.framebuffers = create_framebuffers(swapchain_image_views, self.render_pass.clone());
}
}
fn create_framebuffers(
swapchain_image_views: &[Arc<ImageView>],
render_pass: Arc<RenderPass>,
) -> Vec<Arc<Framebuffer>> {
swapchain_image_views
.iter()
.map(|swapchain_image_view| {
Framebuffer::new(
render_pass.clone(),
FramebufferCreateInfo {
attachments: vec![swapchain_image_view.clone()],
..Default::default()
},
)
.unwrap()
})
.collect::<Vec<_>>()
}