2016年7月5日火曜日

Vulkan - レイヤーの列挙

最近ブログ書いてなかったので,Vulkanについて調べたり試したことを書いていこうかと思います.

環境

OS Windows 10 Pro
GPU NVIDIA GeForce GTX 860M (ドライバー 368.22)
Vulkan SDKバージョン 1.0.17.0

レイヤーとは

Vulkanのインスタンス,またはインスタンスを介して生成されたオブジェクトに対して発行されるVulkanのコマンドに対して,割り込みをかけるための機能です.

例えば,VK_LAYER_LUNARG_api_dumpというレイヤーは,VulkanのAPIを実行した際に,実引数をダンプしてくれます.

レイヤーは,Vulkanのインスタンスを生成する際に指定することで有効になります.

レイヤーの列挙

利用可能なレイヤーの一覧を取得するには,次のvkEnumerateInstanceLayerProperties()を利用します.
VkResult vkEnumerateInstanceLayerProperties(
    uint32_t * pPropertyCount,
    VkLayerProperties * pProperties
);

まず,pPropertyCountに変数へのポインタ,pPropertiesにnullptrを渡すことでレイヤーの数を取得します.
uint32_t count;
vkEnumerateInstanceLayerProperties(&count, nullptr);

次に,必要なバッファを用意して各レイヤーの情報を取得します.ここでは,vectorクラスを利用しています.
vector<VkLayerProperties> layers {};
VkResult result = vkEnumerateInstanceLayerProperties(&count, layers.data());

実際に各レイヤーの情報を取得する際に,レイヤーの数を取得してから情報を取得するまでの間に,レイヤーが追加される場合があります.そんな珍しい状況が発生した場合,vkEnumerateInstanceLayerProperties()はVK_INCOMPLETEを返します.VK_INCOMPLETEが返された場合,レイヤー数の取得からやり直します.

取得されたレイヤーの情報は,次のような構造体に格納されます.

struct VkLayerProperties {
    char        layerName[VK_MAX_EXTENSION_NAME_SIZE];
    uint32_t    specVersion;
    uint32_t    implementationVersion;
    char        description[VK_MAX_DESCRIPTION_SIZE];
};

サンプルコード

以下のコードは,vkEnumerateInstanceLayerProperties()を使って,全てのレイヤー情報をダンプするものです.Vulkanのバージョン情報を分かりやすい形で表示するために,versionクラスを導入しています.

#include <iostream>
#include <vector>
#include <vulkan/vulkan.h>

#pragma comment(lib, "vulkan-1")

using namespace std;

class version
{
public:
    version(uint32_t value) : mValue(value) {}

    //! 値を返す
    uint32_t value() const { return mValue; }

    //! メジャーバージョンを返す
    uint32_t major() const { return VK_VERSION_MAJOR(mValue); }

    //! マイナーバージョンを返す
    uint32_t minor() const { return VK_VERSION_MINOR(mValue); }

    //! パッチバージョンを返す
    uint32_t patch() const { return VK_VERSION_PATCH(mValue); }

private:
    uint32_t mValue;
};

std::ostream & operator<<(std::ostream & out, const version & v)
{
    out << v.major() << "." << v.minor() << "." << v.patch();
    return out;
}

int main()
{
    VkResult result = VK_SUCCESS;
    vector layers {};
    do {
        // レイヤー数を取得
        uint32_t count = 0;
        result = vkEnumerateInstanceLayerProperties(&count, nullptr);
        if(result != VK_SUCCESS)
        {
            break;
        }

        // 各レイヤーのプロパティを取得
        layers.resize(count);
        result = vkEnumerateInstanceLayerProperties(&count, layers.data());

        // 全てのレイヤーを取得していない場合,やり直す
    } while(result == VK_INCOMPLETE);

    // 各レイヤーのプロパティを出力する
    for(auto layer : layers)
    {
        cout << "Layer Name             : " << layer.layerName << endl;
        cout << "Specification Version  : " << version(layer.specVersion) << endl;
        cout << "Implementation Version : " << version(layer.implementationVersion) << endl;
        cout << "Description            : " << layer.description << endl;
        cout << endl;
    }
}

インスタンスを生成する際には上記の手順で取得したレイヤーを指定すれば良いのですが,まだ問題が起きるレイヤーがあります.しばらくは,レイヤーの使用に問題が無いか確認してから,本番環境で有効化するか検討した方が良いでしょう.

サンプルコードは,ryutorion/LearningVulkan (GitHubリポジトリ)の001_EnumerateInstanceLayerにもあります.

0 件のコメント:

コメントを投稿