2
0

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 3 years have passed since last update.

Vulkan で DLL 解決しないと使用できない関数を使えるようにする手順

Posted at

発端

Visual Studio 2019 環境で Vulkan のコードを書いている際に vkCmdSetPrimitiveTopologyEXT を使おうとしたら次のエラーが出ました。

LNK2019	未解決の外部シンボル vkCmdSetPrimitiveTopologyEXT が関数 "public: void __cdecl vk::DispatchLoaderStatic::vkCmdSetPrimitiveTopologyEXT(struct VkCommandBuffer_T *,enum VkPrimitiveTopology)const " (?vkCmdSetPrimitiveTopologyEXT@DispatchLoaderStatic@vk@@QEBAXPEAUVkCommandBuffer_T@@W4VkPrimitiveTopology@@@Z) で参照されました

どうやら Vulkan の一部関数は static リンクだけでは使えないようです。

これの解決方法を日本語で全て解説しているサイトが見当たらなかったので書いておきます。

公式情報

https://github.com/KhronosGroup/Vulkan-HppExtensions / Per Device function pointers に記載されています。

解決方法

大きく3つの手順をこなす必要があります。

  1. プリプロセッサを定義
  2. DispatchLoaderDynamic のインスタンスを定義
  3. 関数を解決する処理を追加

1. プリプロセッサを定義

vulkan.hpp をインクルードする前に VULKAN_HPP_DISPATCH_LOADER_DYNAMIC を定義してください。

// 例
# define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
# include <vulkan/vk_sdk_platform.h>
# include <vulkan/vulkan.hpp>

上記の例のようにコード上に書いても良いですし、VisualStudio のプロジェクトファイルで定義しても大丈夫です。

この対応をすることで、関数解決がリンク時ではなく実行時になるようです。

ちなみにこの対応をした状態でビルドするとリンク時に以下のエラーが出力されます。

エラー	LNK2001	外部シンボル "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A) は未解決です

2. DispatchLoaderDynamic の実体を定義

先ほどのエラーを解決するために ::vk::defaultDispatchLoaderDynamic の実体を定義してあげる必要があります。

どこかの cpp ファイルに vulkan.hpp をインクルードした上で以下のコードを追加してください。

// #define はつけないように注意!
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE

これをすることで vulkan.hpp で extern 宣言されていた ::vk::defaultDispatchLoaderDynamic の実体が定義されます。

ヘッダファイルに定義すると多重定義になるため、必ず cpp ファイルで定義してください。

でもこのコード、ちょっと何しているのかイメージしづらいですよね…?
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE の中身は以下のようになっています。

#    define VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE                     \
      namespace VULKAN_HPP_NAMESPACE                                               \
      {                                                                            \
        VULKAN_HPP_STORAGE_API DispatchLoaderDynamic defaultDispatchLoaderDynamic; \
      }

ちなみにこの対応をした状態でビルドするとビルドには成功します。しかし、実行時に vulkan の関数を実行しようとすると null アクセスが発生してエラーになります。

3. 関数を解決する処理を追加

vulkan の関数に有効なポインタが代入されていくように処理を書きます。

まず、 vulkan の関数を実行する前に vk::DynamicLoader クラスのインスタンスを作成してください。これは全ての vulkan の関数の実行で必要なため、アプリケーションの終了時まで破棄しないことをオススメします。

そして、生成したローダーオブジェクトを使いつつ vk::Instance の作成に必要な関数を使用できるようにします。

// 例
::vk::DynamicLoader loader;
VULKAN_HPP_DEFAULT_DISPATCHER.init(loader.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"));

次に、::vk::createInstancevk::Instance を作成後、同様のコードを追加します。

// 例
::vk::Instance instance;
::vk::createInstance(&info, nullptr, &instance);
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance); // この処理を追加

この処理を追加することで ::vk::Device の作成に必要な関数を使用できるようになります。

最後に、::vk::Device を作成後に同様のコードを追加します。

// 例
::vk::Device device;
physicalDevice.createDevice(&info, nullptr, &device);
VULKAN_HPP_DEFAULT_DISPATCHER.init(device); // この処理を追加

これで Device に関わる全ての関数が使用できるようになります。

おわり

お疲れ様でした!

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?