Vulkan TutorialのRust版をやってみた 〜Window編〜
Vulkanの入門をRustでやっていきます。目次はこちら。今回までの実装をしたGitHubはこちら。
Vulkanで描画
前回はVulkanといいながら一切GUIが出てこない回でしたが、ついにウィンドウを描画します。といっても、ウィンドウそのものはVulkan関係ないですが。
winitでウィンドウ表示
Rustの場合ウィンドウ表示にはwinitを使うことが多いので、ここでもwinitを使っていきます。以下では、最低限のウィンドウ表示とウィドウを閉じる処理をしています。
let event_loop = EventLoop::new();
let _window = WindowBuilder::new().build(&event_loop).unwrap();
event_loop.run(|event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
*control_flow = ControlFlow::Exit;
}
_ => {}
};
});
winitは割と頻繁にAPIが変わっているのでいつも慣れない感じですが、winit = "0.22.0"
の段階ではこう書くのが正しいようです。
Surface
の作成
Vulkanが描画するのはVkSurfaceKHR
に対してであり、これは各プラットフォーム固有の部分とVulkanを繋ぐため、各ウィンドウライブラリに対応したSurface
を用意する必要があります。今回の場合vulkano-winがそれに相当するので、それを使ってSurface
を作成します。
まず、InstanceExtensions
を変更します。これまでは、
InstanceExtensions::supported_by_core().unwrap()
と書いていたところを、
vulkano_win::required_extensions()
とします。次に、上で
WindowBuilder::new().build(&event_loop)
のところを
WindowBuilder::new().build_vk_surface(&event_loop, instance)
に変更します。これで得られる値がWindow
からSurface<Window>
に変わります。
Queue
の追加
前回では論理デバイスの作成時にsupports_graphics
を満たすQueue
だけを要求していましたが、今回は表示用のQueue
も必要なのでこれを加えます。
[追記] ここでQueueFamily
が重複しないようにしてください。そうでないと、実行時エラーで強制終了します。 [追記終了]
let (_device, mut queues) = PhysicalDevice::enumerate(&instance)
.filter_map(|device| {
let graphics_queue_family = device
.queue_families()
.find(|queue_family| queue_family.supports_graphics());
let present_queue_family = device
.queue_families()
.find(|queue_family| surface.is_supported(*queue_family) == Ok(true));
let mut queue_families_set = HashSet::new();
let unique_queue_families: Vec<_> = vec![graphics_queue_family, present_queue_family]
.iter()
.filter_map(|queue_family| *queue_family)
.filter(|queue_family| queue_families_set.insert(queue_family.id()))
.collect();
Some((device, unique_queue_families))
})
.filter_map(|(device, queue_families)| {
Device::new(
device,
&Features::none(),
&DeviceExtensions::supported_by_device(device),
queue_families
.iter()
.map(|queue_family| (*queue_family, 1.0)),
)
.ok()
})
.next()
.expect("Could not find any GPU");
少し長くなってしまいましたが、前回は1つだけ渡していたQueueFamily
を複数渡せるようにしたためです。
swap chainの作成
swap chainとは いわゆるダブルバッファリングやトリプルバッファリングのことだと思います。 [追記]どうやら違うようです。単に表示待ちの画像のキューということらしいですが、理解不足です。[追記終了]
(画像はhttps://vulkan.lunarg.com/doc/sdk/1.2.131.2/linux/tutorial/html/05-init_swapchain.htmlから引用)
swap chainに対応しているかの確認
デバイスがswap chainに対応していない場合もあるので、論理デバイスの作成時にDeviceExtensions
としてswap chainを要求します。
let extensions = DeviceExtensions {
khr_swapchain: true,
..DeviceExtensions::supported_by_device(device)
};
Device::new(
device,
&Features::none(),
&extensions,
queue_families
.iter()
.map(|queue_family| (*queue_family, 1.0)),
)
.ok()
swap chainの要求
上記で得られたデバイスはswap chainに対応しているので、次は作りたいswap chainの設定をして、要求します。なお、Swapchain::new
で全ての設定を引数に渡していくのですが数が多く、また参考元の値をほぼそのまま写しているだけなので個々の設定については省略します。
let (_swapchain, _swapchain_image) = Swapchain::new(...).unwrap();
まとめと感想
今回はウィンドウの表示とswap chainの作成を行いました。swap chainはたしかに細かく設定できそうですがその分記述量が多くて大変という、Vulkanらしさ(?)を味わいました。まだ実質何も表示できていないですが、次回からいよいよシェーダに関われそうです。
Author And Source
この問題について(Vulkan TutorialのRust版をやってみた 〜Window編〜), 我々は、より多くの情報をここで見つけました https://qiita.com/kbone/items/9cefcb960fc1f58e9131著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .