D言語でVulkanする件について。
https://github.com/ousttrue/VulkanOnD
もともとはDでDirectXするつもりであったのだけど、
Vulkanの機が熟したのでやってみた。
ひとつ前に書いた
Vulkanことはじめ
のC++をベタにD言語に移植したものです。
D-Vulkan
を使った。
環境は Windows10上のDMD + dub + VisualD。
64bitビルドはリンクがいろいろ嵌るので、32bitビルドに妥協。
D-Vulkanのコード生成
バインディングを手作りしたのかと思ったら、何やらpythonでコード生成している。
辿っていくとkhronosの公式APIがxmlで管理されていて、そこからpythonでCのヘッダやドキュメントを出力するシステムがあった。
- https://www.khronos.org/registry/vulkan/specs/1.0/registry.html#_output_generator_script_span_class_monospaced_generator_py_span
- https://github.com/KhronosGroup/Vulkan-Docs
D-VulkanはこれをベースにしたD言語バインディングの出力スクリプトを作っていた。
dvulkan> python.exe vkdgen.py ../Vulkan-Docs/src/spec source/dvulkan
とするとtypes.dとfunction.dが更新される。
dvulkanに手を入れるときはvkdgen.pyに手を入れるとよい。
D-Vulkanちょっと改造
Cのコールバックにextern(C)を付けるのと、最新のxmlを使うとエクステンションが増えるのでそれを防ぐ処置など。
https://github.com/ousttrue/dvulkan
Win32Surfaceのバインディング
alias PFN_vkCreateWin32SurfaceKHR
= extern(C) VkResult function(VkInstance instance,
const(VkWin32SurfaceCreateInfoKHR)* pCreateInfo
, const(VkAllocationCallbacks)* pAllocator
,VkSurfaceKHR* pSurface);
PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;
auto p=vkGetInstanceProcAddr(inst.get(), "vkCreateWin32SurfaceKHR");
vkCreateWin32SurfaceKHR = cast(PFN_vkCreateWin32SurfaceKHR) p;
struct VkWin32SurfaceCreateInfoKHR
{
VkStructureType sType = VkStructureType.VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
const(void)* pNext;
VkFlags flags;
HINSTANCE hinstance;
HWND hwnd;
};
vkdgen.pyの除外エクステンションからWin32Surfaceを外す手もあったのだけど、モジュールがプラットフォーム固有の型で汚染されるので見送り。アプリ側で手動定義した。
D-Vulkan使用上の注意
VkInstance inst;
VkResult res = vkCreateInstance(&inst_info, null, &inst);
if (res != VK_SUCCESS) {
return null;
}
loadInstanceFunctions(inst); // <- これ
vkCreateInstanceしたらloadInstanceFunctionsを呼ばないとほとんどの関数が呼べる状態にならない。
呼ばないとnullの関数ポインタをコールしてAccessViolationが出て頭をひねることになるので注意。
他は、Cバージョンとだいたい同じなのでD固有の注意点はない。
おわり
久しぶりにDを再開したのだが、C++のコードをDに移植するのが楽すぎてびっくりした。
まるで、std::shared_ptrとstd::vectorとstd::stringが内包されたC++のような使い勝手になっている。
自分のC++のスタイルにすごくフィットしている感じで実に快適。
CのAPIに対してポインタを渡す時に、&struct, array.ptr, string.ptrとするだけでできてしまうのでわかりやすい。
C#のDllImportと比べてかなり楽に使える。
localのclass変数にscopeを付けると、structにしなくても寿命がgc管理ではなくscopeアウトまでにできるのもよい。
scope auto uniform_buffer=new BufferResource(device);
開発環境にはVisualDを使った。
VisualDのソリューションはdubで生成できる。
> dub generate visuald
ブレイクポイントを置いてステップ実行することができるので十分使える。
括弧の中で改行したときなどインデントがちょっとキモイ場合があるとか、実行時にエラーが発生すると死亡するときがあるなどまだ開発版な感じがするが使っていく。
CG方面でD言語は有望だと思うので試してみようと思っている。