3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Vulkan Tutorial (Drawing a triangle/Setup/Instance) 日本語訳

Last updated at Posted at 2022-07-04

インスタンス (Instance)

インスタンスの作成 (Creating an instance)

あなたがまずはじめにやらなければいけないことは、インスタンス を作ることでVulkanライブラリを初期化することです。インスタンスとはアプリケーションとVulkanライブラリのコネクションで、作成するにはアプリケーションの詳細をドライバに指定する必要があります。

はじめにcreateInstance関数を追加し、initVulkan関数から呼び出します。

void initVulkan() {
    createInstance();
}

加えて、インスタンスへのハンドルをメンバ変数に追加します。

private:
VkInstance instance;

次に、インスタンスを作成するために、アプリケーションについての情報を構造体に設定する必要があります。このデータは技術的にはオプションですが、特定のアプリケーションを最適化するためにドライバに有益な情報を提供するかもしれません(例えば、特定の特殊な振る舞いをする、有名なグラフィックスエンジンを使っているためなど)。この構造体はVkApplicationInfoと呼ばれます。

void createInstance() {
    VkApplicationInfo appInfo{};
    appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
    appInfo.pApplicationName = "Hello Triangle";
    appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
    appInfo.pEngineName = "No Engine";
    appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
    appInfo.apiVersion = VK_API_VERSION_1_0;
}

前述したように、Vulkanの多くの構造体はsTypeメンバで明示的に型を指定するように要求します。これもまた多くの構造体で、pNextメンバで将来の拡張情報を設定できます。私たちは、ここでは値初期化を使って、これをnullptrのままにしておきます。

Vulkanでは多くの情報は関数の引数の代わりに構造体で渡されます。そしてインスタンスを作るのに十分な情報を提供するために、もう一つの構造体を設定する必要があります。この構造体はオプションではなく、どのグローバル拡張とバリデーションレイヤを使いたいかをVulkanドライバに伝えます。ここでグローバルとは、特定のデバイスではなくプログラム全体に適用されるということを意味しています。これは次のいくつかの章ではっきりとします。

VkInstanceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;

最初の2つのパラメータは単純です。次の2つのレイヤは要求するグローバル拡張を指定します。概要の章で述べた通り、Vulkanはプラットフォーム不可知論者のAPIなので、ウィンドウシステムのインターフェースに拡張が必要になるということを意味しています。GLFWはそれに必要な拡張を返す便利な組み込み関数を持っていて、私たちはそれをそのまま構造体にわたすことができます。

uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;

glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);

createInfo.enabledExtensionCount = glfwExtensionCount;
createInfo.ppEnabledExtensionNames = glfwExtensions;

構造体の最後の2つのメンバで、有効にするグローバルバリデーションレイヤを決定します。私たちはこれについて次の章でより深く解説するので、今はこれを空のままにしておきます。

createInfo.enabledLayerCount = 0;

これで、Vulkanがインスタンスを作るために必要なものは全て設定したので、ようやくvkCreateInstanceを呼び出すことができます。

VkResult result = vkCreateInstance(&createInfo, nullptr, &instance);

ご覧のとおり、Vulkanでオブジェクトを作成する関数の引数の一般的なパターンは:

  • 作成情報の構造体へのポインタ
  • カスタムアロケータのコールバックへのポインタ。このチュートリアルでは常にnullptr
  • 新しいオブジェクトへのハンドルを格納する変数へのポインタ

全てが上手く行けばVkInstance型のメンバ変数にインスタンスへのハンドルが格納されます。ほとんど全てのVulkan関数はVkResult型の値を返し、それはVK_SUCCESSまたはエラーコードのいずれかです。インスタンスの作成に成功したかどうかチェックするのに、結果を変数に格納する必要はなく、たんに成功値かどうかチェックするだけです。

if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
    throw std::runtime_error("failed to create instance!");
}

ここで、インスタンスの作成に成功しているかどうか確認するためにプログラムを実行してください。

拡張サポートのチェック (Checking for extension support)

vkCreateInstanceのドキュメントを見ると、可能性のあるエラーコードの一つにVK_ERROR_EXTENSION_NOT_PRESENTがあります。私たちは単純に要求する拡張を指定して、このエラーコードが帰ってきたら停止することもできます。これはウィンドウシステムのインターフェースのような基本的な拡張機能なら理にかなっていますが、オプションの機能についてチェックしたいとしたら、どうしたらいいのでしょうか?

インスタンスを作成する前にサポートされている拡張機能のリストを取得するために、vkEnumerateInstanceExtensionProperties関数があります。この関数は、拡張機能の数を格納する変数へのポインタと、拡張機能の詳細を格納するVkExtensionPropertiesの配列を受け取ります。また、最初にオプションの引数を取り、特定のバリデーションレイヤによって拡張機能をフィルタリングできますが、今は無視します。

拡張機能の詳細を格納するための配列を確保するため、最初にいくつそれがあるかを知る必要があります。最後の引数を空にしておくことで、拡張機能の数を取得することができます。

uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);

次に、拡張機能の詳細を格納する配列を確保します。(include <vector>)

std::vector<VkExtensionProperties> extensions(extensionCount);

最後に、拡張機能の詳細を問い合わせます。

vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());

それぞれのVkExtensionProperties構造体は、拡張機能の名前とバージョン番号を含みます。シンプルなforループでこれらをリストすることができます。(\tはインデントのためのタブです)

std::cout << "available extensions:\n";

for (const auto& extension : extensions) {
    std::cout << '\t' << extension.extensionName << '\n';
}

あなたがもしVulkanサポートについていくつかの詳細を提供したいなら、このコードをcreateInstance関数に追加することができます。課題として、glfwGetRequiredInstanceExtensions関数から返された全ての拡張機能が、サポートされている拡張機能のリストに含まれているかどうか、チェックする関数を作成してみてください。

クリーンアップ (Cleaning up)

VkInstanceはプログラムが終了する直前に破棄されなければいけません。cleanupの中でvkDestroyInstance関数を呼び出すことで破棄することができます。

void cleanup() {
    vkDestroyInstance(instance, nullptr);

    glfwDestroyWindow(window);

    glfwTerminate();
}

vkDestroyInstance関数の引数は簡単です。前の章で述べた通り、Vulkanの確保と開放関数はオプションのアロケータのコールバックを持ち、私たちはnullptrを渡してこれを無視します。この後に続く章で作成する他の全てのVulkanリソースは、インスタンスが破棄される前にクリーンアップされる必要があります。

インスタンスの作成の後もっと複雑なステップに進む前に、バリデーションレイヤをチェックすることでデバッグオプションを評価するときが来ました。

C++ code

前の記事
次の記事

3
2
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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?