15
9

More than 3 years have passed since last update.

Vulkan TutorialのRust版をやってみた 〜準備編〜

Last updated at Posted at 2020-03-20

Vulkanの入門をRustでやっていきます。目次はこちら。今回までの実装をしたGitHubはこちら

Vulkanの概要

Vulkanではアプリケーション毎にInstanceを作り、各物理デバイスに対応したLoaderLayerを読み込み、そのLayerを通して各ドライバーを扱います。
Vulkanアーキテクチャの基本
(画像はhttps://vulkan.lunarg.com/doc/sdk/1.2.131.2/linux/tutorial/html/01-init_instance.htmlから引用)
また描画する際は、描画命令用のQueueや各OS固有のウィンドウと描画先のSurfaceを作り、レンダーパスを作り、パイプラインを構築し、Queueにコマンドを送ることで描画できるようになります。

Vulkanで描画するまでの準備

今回は準備編として、デバイス(GPU)を取得するまでを書きます。

開発環境の準備

  1. Vulkanのライブラリその他をインストール
  2. 適当なディレクトリでcargo new [プロジェクト名]をしてRustのプロジェクトを作る
  3. VulkanのRustラッパであるVulkanoCargo.tomlに追加

Validation layersの追加

現状では関係ないですが、Validation layersは不正な値がGPU側に渡らないように監視すること等ができるため、この段階からデバッグ時のみ有効にしておきます。

Layerの列挙

レイヤーを有効にするにはInstanceの作成時に引数にレイヤー名を渡す必要があるので、その前にレイヤーを列挙して名前を確認してみます。

vulkano::instance::layers_list().unwrap().for_each(|layer| ...);

列挙された名前から、今回はVK_LAYER_LUNARG_standard_validationVK_LAYER_KHRONOS_validationを読み込んでみます。

Layerが対応しているかの確認

上では先にLayerを列挙してからLayerを読み込むと書きましたが、実行環境によっては読み込みたいLayerに対応していない可能性があるため、対応しているLayerだけ抽出します。

let validation_layers = [
    "VK_LAYER_LUNARG_standard_validation",
    "VK_LAYER_KHRONOS_validation",
];
let supported_validation_layers: Vec<_> = layers_list()
    .unwrap()
    .filter(|layer| validation_layers.contains(&layer.name()))
    .collect();

VK_EXT_debug_utilsの有効化

デバッグ情報等を取得することができるようになるので、VK_EXT_debug_utilsを有効にします。Vulkanoでは、これらextensionsはInstanceの作成時に引数で渡すので、とりあえず何を有効にするのかという設定をしておきます。

let extensions = InstanceExtensions {
    ext_debug_utils: true,
    ..InstanceExtensions::supported_by_core().unwrap()
};

ext_debug_utils: trueとすることでVK_EXT_debug_utilsが有効化されます。

Instanceの作成

アプリケーション毎に用意する必要のある、vulkano::instance::Instanceを作ります。

let instance = Instance::new(
    Some(&app_info_from_cargo_toml!()),
    &extensions,
    supported_validation_layers.iter().map(|layer| layer.name()),
)
.expect("Could not build a Vulkan instance");

ここではそのまま書いていますが、Validation layersをデバッグ時のみ有効にするためにcfg!(debug_assertions)等で分岐させてください。

DebugCallbackの設定

デフォルトでValidation layersは標準出力に情報を書いていくのですが、どのレベルの情報を書くか等細かい設定をするためにはコールバックを作成する必要があります。

DebugCallback::new(&instance, severity, ty, |message| ...).ok();

注意点として、ext_debug_utils: trueとしておかないとDebugCallback::newErrを返します。

物理デバイスの取得

物理デバイスの列挙

物理デバイスはvulkano::instance::PhysicalDeviceで表されており、PhysicalDevice::enumerateで列挙できます。

PhysicalDevice::enumerate(&instance).for_each(|device| ...);

GPUの取得

列挙された物理デバイスのうちグラフィック用のQueueを持っているデバイスが必要になるので、ここでは最初に見つかったグラフィック用のQueueを持っているデバイスを取得します。参考元のサイト及びそのRust版だとちょっと面倒な感じですが、以下のように書けば同じように動作するはずです。

let device = PhysicalDevice::enumerate(&instance)
    .filter(|device| {
        device
            .queue_families()
            .any(|queue_family| queue_family.supports_graphics())
    })
    .next()
    .expect("Could not find any GPU");

論理デバイスの取得

上で取得したGPUから対応する論理デバイスを取得します。

let (_device, _queues) = PhysicalDevice::enumerate(&instance)
    .filter_map(|device| {
        device
            .queue_families()
            .filter(|queue_family| queue_family.supports_graphics())
            .map(|queue_family| (device, queue_family))
            .next()
    })
    .filter_map(|(device, queue_family)| {
        Device::new(
            device,
            &Features::none(),
            &DeviceExtensions::supported_by_device(device),
            vec![(queue_family, 1.0)],
        )
        .ok()
    })
    .next()
    .expect("Could not find any GPU");

ここまできてようやく準備が出来た形です。

まとめと感想

この段階だとまだQueue等よくわからないところも多いですが、最低限Vulkanが動いていることの確認は出来ました。また、Vulkanoのおかげで元のVulkanより大分記述が楽な気がします。ありがとうRust。ありがとうVulkano。

15
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
9