やっていくVulkan入門

2-1. インスタンスと物理デバイス

インスタンスの作成

まず最初にインスタンスという物を作ります。Vulkanを使う場合、全ての機能はこのインスタンスを介して利用します。

main関数に以下のコードを追加しましょう。

vk::InstanceCreateInfo instCreateInfo;
vk::Instance instance = vk::createInstance(instCreateInfo);

instance.destroy();

vk::createInstance 関数でインスタンスを作成しています。

エラーなく実行できましたか?おめでとうございます。これであなたはVulkanインスタンスを作って壊すことに成功しました。これからあなたはVulkanインスタンスを作ってから壊すまでの間に色々な処理を書いていくことになります。

ところで、このコードではインスタンスを destroy メソッドで明示的に破棄していますが、VulkanのC++向けラッパーであるVulkan-HppではもっとC++らしい書き方ができるように作られています。一般的なC++erであれば何かしらのオブジェクトの破棄処理を見た場合、そんな処理はプログラマーの手動ではなくデストラクタに任せたいと思うはずです。上記の処理を以下のように書き換えましょう。

vk::InstanceCreateInfo instCreateInfo;
vk::UniqueInstance instance = vk::createInstanceUnique(instCreateInfo); 

vk::Instancevk::UniqueInstance に、vk::createInstancevk::createInstanceUnique になっていますね。

このようにVulkan-Hppでは、破棄処理の必要なほぼ全てのオブジェクト型についてvk::Unique《オブジェクト型名》という対応する型があり、またそれに対応したcreate《オブジェクト型名》Uniqueという関数が存在します。Vulkanの仕様の話というよりはVulkan-HppとC++の仕様の話になりますが、積極的に使っていきましょう。Unique付きの型の特性はC++標準のstd::unique_ptrと大体同じです。メソッドはドット演算子.の代わりにアロー演算子->でアクセスできます。

インスタンス作成時のオプション

先ほど示したソースコードに vk::InstanceCreateInfo なる構造体がありました。これに色々情報を乗っけることで、例えばVulkanの拡張機能をオンにしたりだとかデバッグ情報を表示させるといったことができます。オプション的なものなのでこれの説明は後ほどに回そうと思います。

物理デバイスの取得

インスタンスを作成したら次は物理デバイスを選びます。物理デバイスというのは、実際にコンピューターに刺さっている一枚一枚のグラボだとかに対応したオブジェクトです。例えばGTX1060とintel Core i7が刺さっている構成のコンピュータであれば、物理デバイスは2つ取得できるはずです(今のintelのCPUにはintel HD GraphicsというGPUが内蔵されています)。

我々は描画する仕事をGPUに頼みたい訳なので、GPUが複数あるなら頼む相手をまず選ぶ必要があります。特殊なことでもやらない限り基本的に1つ選べば良いのですが、GPUの型式などによってサポートしている機能とサポートしていない機能があったりするため、だいたい「インスタンスを介して物理デバイスを列挙する」→「それぞれの物理デバイスの情報を取得する」→「一番いいのを頼む」という流れになります。

なお、ここで言う「選ぶ」とは、特定のGPUを完全に占有してしまうとかそういう話ではありません。詳しくは「2-2. 論理デバイス」の項で説明します。物理デバイスの一覧はvk::InstanceenumeratePhysicalDevices 関数で取得できます。

std::vector<vk::PhysicalDevice> physicalDevices = instance->enumeratePhysicalDevices(); 

物理デバイスは vk::PhysicalDevice 型で表されます。enumeratePhysicalDevices を呼ぶとstd::vectorで一覧を返してくれます。

ここで本来であれば各物理デバイスの情報を取得して、どれを使用するか吟味して決めるプログラムを書きます。ですが、ここではそれに必要な知識をまだ説明していないので、とりあえず最初の物理デバイスを採用してしまいましょう。

vk::PhysicalDevice physicalDevice = physicalDevices[0];

ちなみにvk::Instanceにはそれに対応するvk::UniqueInstanceが存在しましたが、vk::PhysicalDeviceに対応するvk::UniquePhysicalDevice は存在しません。 destroyなどを呼ぶ必要もありません。vk::PhysicalDeviceは単に物理的なデバイスの情報を表しているに過ぎないので、構築したり破棄したりする必要がある類のオブジェクトではないのです。


この節ではインスタンスの作成と物理デバイスの選択をやりました。次節では論理デバイスの作成をやります。

この節のコード
#include <vulkan/vulkan.hpp>
#include <vector>

int main() {
     vk::InstanceCreateInfo instCreateInfo;

     vk::UniqueInstance instance;
     instance = vk::createInstanceUnique(instCreateInfo);

     std::vector<vk::PhysicalDevice> physicalDevices = instance->enumeratePhysicalDevices();

     vk::PhysicalDevice physicalDevice = physicalDevices[0];

     return 0;
}
cmake_minimum_required(VERSION 3.22)

project(vulkan-test)

set(CMAKE_CXX_STANDARD 17)

add_executable(app main.cpp)

find_package(Vulkan REQUIRED)
target_include_directories(app PRIVATE ${Vulkan_INCLUDE_DIRS})
target_link_libraries(app PRIVATE ${Vulkan_LIBRARIES})