C++幼女先輩

プログラミング成分多め

Vulkan LunarG-SDK Sampleで勉強する 01-init_instance

あらすじ

前回 あらたにVulkanAPIを勉強する事にし、ドライバのインストールと 現在オフィシャルの LunarGという VulkanSDKをインストールし Sampleのビルドまで行った

ので、Sampleを参考に Vulkanの勉強をする

サンプル一覧

Samplesの下だけでも46個あった。 非常に多いのだが1つだけ注意点

なぜかこのサンプルたち、見た限りでは レンダーループが作られておらず 1秒後に終了するように作っている

おそらくは、WindowsAndroidLinuxに対応するために、レンダーループを共通化するのが面倒だったのでは? と思うが 真意不明

46個のサンプルのうち チュートリアルになっている15個から見てみよう

チュートリアル01は init_instanceで、Vulkanのインスタンスを初期化するサンプルのようである チュートリアルを順にならべると

init_instance Vulkanインスタンスの初期化 enumerate_device デバイスの列挙 init_device デバイス初期化 init_command_buffer コマンドバッファの初期化 init_swapchain スワップチェインの初期化 init_depth_buffer 深度バッファの初期化 init_uniform_buffer Uniformバッファの初期化 init_pipeline_layout パイプラインレイアウト初期化 init_descriptor_set でスクリプタセット初期化 init_render_pass レンダーパス初期化 init_shaders シェーダー初期化 init_frame_buffers フレームバッファ初期化 init_vertex_buffer 頂点バッファ初期化 init_pipeline パイプライン初期化 draw_cube キューブ描画

やれやれ・・ たかがキューブ描画のために、初期化こんなにあるのか・・

01-init_instance

#include <iostream>
#include <cstdlib>
#include <util_init.hpp>

#define APP_SHORT_NAME "vulkansamples_instance"

int sample_main(int argc, char *argv[]) {
    struct sample_info info = {};
    init_global_layer_properties(info);

    /* VULKAN_KEY_START */

    // initialize the VkApplicationInfo structure
    VkApplicationInfo app_info = {};
    app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
    app_info.pNext = NULL;
    app_info.pApplicationName = APP_SHORT_NAME;
    app_info.applicationVersion = 1;
    app_info.pEngineName = APP_SHORT_NAME;
    app_info.engineVersion = 1;
    app_info.apiVersion = VK_API_VERSION_1_0;

    // initialize the VkInstanceCreateInfo structure
    VkInstanceCreateInfo inst_info = {};
    inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
    inst_info.pNext = NULL;
    inst_info.flags = 0;
    inst_info.pApplicationInfo = &app_info;
    inst_info.enabledExtensionCount = 0;
    inst_info.ppEnabledExtensionNames = NULL;
    inst_info.enabledLayerCount = 0;
    inst_info.ppEnabledLayerNames = NULL;

    VkInstance inst;
    VkResult res;

    res = vkCreateInstance(&inst_info, NULL, &inst);
    if (res == VK_ERROR_INCOMPATIBLE_DRIVER) {
        std::cout << "cannot find a compatible Vulkan ICD\n";
        exit(-1);
    } else if (res) {
        std::cout << "unknown error\n";
        exit(-1);
    }

    vkDestroyInstance(inst, NULL);

    /* VULKAN_KEY_END */

    return 0;
}

短いので全部乗せた。 初回なので少しだけ丁寧に

vkで始まる関数がVulkanのAPIである かなりC言語臭いが、それをラップしてC++っぽくしたライブラリもあるので今度紹介する

#include <util_init.hpp>

これはサンプルの独自のUtilであるが、大したことをしていない。今回で言えば sample_mainの定義がある程度

ここで少し気になる sample_main() という関数 そう、エントリーポイント関数がないやん? きっとこれがエントリーポイントだろ? すぐわかるが、一応調べると

#ifndef __ANDROID__
int main(int argc, char **argv) { sample_main(argc, argv); }
#endif

Android以外は単純に sample_mainを呼ぶだけである

Androidの場合は Android_handle_cmdで sample_mainを登録したり NDKから呼ぶため特別処理になっている

とりあえずは sample_mainはエントリーポイントだと思って良い

レイヤー列挙

init_global_layer_properties(info); の中身は

    do {
        res = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL);
        if (res)
            return res;

        if (instance_layer_count == 0) {
            return VK_SUCCESS;
        }

        vk_props = (VkLayerProperties *)realloc(
            vk_props, instance_layer_count * sizeof(VkLayerProperties));

        res =
            vkEnumerateInstanceLayerProperties(&instance_layer_count, vk_props);
    } while (res == VK_INCOMPLETE);

    /*
     * Now gather the extension list for each instance layer.
     */
    for (uint32_t i = 0; i < instance_layer_count; i++) {
        layer_properties layer_props;
        layer_props.properties = vk_props[i];
        res = init_global_extension_properties(layer_props);
        if (res)
            return res;
        info.instance_layer_properties.push_back(layer_props);
    }
    free(vk_props);

    return res;

となっている。 まずレイヤーとは何かだが、まだ詳細につかめていないが Vulkanのコマンドに割り込んで色々なことをするものらしい 例えば デバッグに使う

vkEnumerateInstanceLayerProperties の2番目の引数にnullptrを入れると、取得可能なレイヤー数が取れるので レイヤー数を取得したあと reallocで個数分確保している まことにC言語である

列挙中に極まれにレイヤーが追加されることがあるらしく VK_INCOMPLETE が返ってきたら、カウントからやり直すようになっている

インスタンス作成

vkCreateInstanceを呼ぶことで、Vulkanのインスタンスを作成する これが チュートリアル01のゴールだ。

インスタンス作成は単純で、VkApplicationInfoとVkInstanceCreateInfo を設定して渡せばよい 第一引数に VkInstanceCreateInfo  第二引数は 通常はnullptrでよい。必要があれば下記 MemoryAllocationを読む事 第三引数に Vulkanのインスタンスが入る

MemoryAllocation https://vulkan.lunarg.com/doc/view/1.0.33.0/linux/vkspec.chunked/ch10.html

vkDestroyInstance でインスタンスを解放すれば終了

初回なので丁寧に見たが、面倒なだけで そこまで難しくはなさそうだ