Vulkan LunarG-SDK Sampleで勉強する 01-init_instance
あらすじ
前回 あらたにVulkanAPIを勉強する事にし、ドライバのインストールと 現在オフィシャルの LunarGという VulkanSDKをインストールし Sampleのビルドまで行った
ので、Sampleを参考に Vulkanの勉強をする
サンプル一覧
Samplesの下だけでも46個あった。 非常に多いのだが1つだけ注意点
なぜかこのサンプルたち、見た限りでは レンダーループが作られておらず 1秒後に終了するように作っている
おそらくは、Windows、Android、Linuxに対応するために、レンダーループを共通化するのが面倒だったのでは? と思うが 真意不明
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 でインスタンスを解放すれば終了
初回なので丁寧に見たが、面倒なだけで そこまで難しくはなさそうだ