Vulkanの入門をRustでやっていきます。目次はこちら。今回までの実装をしたGitHubはこちら。
Vulkanでの描画
ついに今回は三角形を描画します。描画には今までのrender pass等に加えバッファが必要になります。
framebufferの作成
framebufferはswap chainの各image毎に作るもので、render passで設定したとおりに各attachmentにデータを渡す、文字通りバッファとして働くようです。
let _framebuffers: Vec<_> = spwapchain_image
.iter()
.map(|image| {
Arc::new(
Framebuffer::start(render_pass.clone())
.add(image.clone())
.unwrap()
.build()
.expect("Could not create a framebuffer"),
)
})
.collect();
command bufferの作成
そのまんま、commandのバッファです。Vulkanoの場合はAutoCommandBufferBuilder
でcommand bufferとcommand poolを作成します。また、各framebuffer毎に作るので以下を各framebuffer毎に行います。
AutoCommandBufferBuilder::primary_simultaneous_use(
device.clone(),
graphics_queue.family()
).unwrap()
.begin_render_pass(
framebuffer.clone(),
false,
vec![[0.0, 0.0, 0.0, 1.0].into()],
).unwrap()
.draw(
graphics_pipeline.clone(),
&DynamicState::none(),
vertices,
(),
(),
).unwrap()
.end_render_pass().unwrap()
.build().unwrap()
ここで怒涛の.unwrap()
となっており、本当は独自のResult
を定義して.and_then()
等をする方が良いのだと思うのですが、簡単のため.unwrap()
にしています(ビルダーパターンなんだから本当はVulkano側でなんとかしてほしい。)
描画
ここまでの用意でようやく三角形が描画できます。なお、Vulkanoではacquire_next_image
という関数が用意されているため、semaphoreは不要です。
まず描画するための関数を呼び出す場所ですが、winit = "0.22.0"
では
match event {
Event::MainEventsCleared => {
surface.window().request_redraw(); // イベント消化後に描画要求
}
Event::RedrawRequested(_) => {
/* ここで描画 */
}
_ => {}
}
となっています。この中で描画用のimageを要求し、commandを実行させ、それを画面上に反映するという流れです。
if let Ok((image_index, _, acquire_future)) =
acquire_next_image(swapchain.clone(), None)
{
let command_buffer = command_buffers[image_index].clone();
if let Ok(future) =
acquire_future.then_execute(graphics_queue.clone(), command_buffer)
{
let _ = future
.then_swapchain_present(
present_queue.clone(),
swapchain.clone(),
image_index,
)
.then_signal_fence_and_flush()
.and_then(|future| future.wait(None));
}
}
なお今回は描画ループ内なので.unwrap()
を避けて書いてみました。
まとめと感想
ついに三角形を描画できました。まだ理解しきれていないところも多く、OpenGLと比較してもやはり難しくなっていると感じました。