今年 SwiftShader が Vulkan 1.1 の conformance test を通過したと聞いたので、気になって手元でも試してみることにしました。
SwiftShader とは
Google 製の CPU による Vulkan 実装というところです。次の場所で公開されています。
CPUでラスタライズ処理をするため、 GPU の機能を使用しません。そのためGPUが Vulkan 非対応の環境でも使用することができるようです。なお、 SwiftShaderは Vulkan 以外にも OpenGL ES や DirectX9 の実装も現時点では持っているようです。
ただし、そのうち Vulkan のみの対応となっていくようです。(Siggraph 2019の資料より)

vulkaninfo を実行
Windows で SwiftShader を使うようにしてみたのでその紹介です。まずは vulkaninfo の結果です。
Instance Extensions:
Instance Extensions count = 7
VK_KHR_device_group_creation : extension revision 1
VK_KHR_external_fence_capabilities : extension revision 1
VK_KHR_external_memory_capabilities : extension revision 1
VK_KHR_external_semaphore_capabilities: extension revision 1
VK_KHR_get_physical_device_properties2: extension revision 2
VK_KHR_surface : extension revision 25
VK_KHR_win32_surface : extension revision 6
Layers: count = 0
Presentable Surfaces:
GPU id : 0 (SwiftShader Device)
Surface type : VK_KHR_win32_surface
Formats: count = 2
B8G8R8A8_UNORM
B8G8R8A8_SRGB
Present Modes: count = 1
FIFO_KHR
VkSurfaceCapabilitiesKHR:
(省略)
Groups :
========
Device Group Properties (Group 0) :
physicalDeviceCount = 1
SwiftShader Device (ID: 0)
subsetAllocation = 0
Device Properties and Extensions :
==================================
GPU0
VkPhysicalDeviceProperties:
===========================
apiVersion = 0x401000 (1.1.0)
driverVersion = 20971520 (0x1400000)
vendorID = 0x1ae0
deviceID = 0xc0de
deviceType = CPU
deviceName = SwiftShader Device
VkPhysicalDeviceLimits:
-----------------------
maxImageDimension1D = 8192
maxImageDimension2D = 8192
maxImageDimension3D = 1024
maxImageDimensionCube = 8192
maxImageArrayLayers = 2048
maxTexelBufferElements = 0x10000
maxUniformBufferRange = 0x4000
(省略)
maxVertexInputAttributes = 16
maxVertexInputBindings = 16
maxVertexInputAttributeOffset = 0x7ff
maxVertexInputBindingStride = 0x800
maxVertexOutputComponents = 128
maxTessellationGenerationLevel = 0
maxTessellationPatchSize = 0
maxTessellationControlPerVertexInputComponents = 0
maxTessellationControlPerVertexOutputComponents = 0
maxTessellationControlPerPatchOutputComponents = 0
maxTessellationControlTotalOutputComponents = 0
maxTessellationEvaluationInputComponents = 0
maxTessellationEvaluationOutputComponents = 0
maxGeometryShaderInvocations = 0
maxGeometryInputComponents = 0
maxGeometryOutputComponents = 0
maxGeometryOutputVertices = 0
maxGeometryTotalOutputComponents = 0
maxFragmentInputComponents = 128
maxFragmentOutputAttachments = 4
(以下省略)
このような感じにあっており、 SwiftShader でのデバイスが使えそうなことがわかります。ただし、ジオメトリシェーダーやテッセレーション関連は機能がないこともこの結果より分かりました。
cube の実行
以前に Vulkan SDK に付属していたテクスチャ付き Cube 描画のサンプルを動かしてみました。垂直同期の部分がうまく機能できていませんが、動作可能でした。

この動作中は、予想通り CPU の使用率が 100 % に張り付きました。
他のプログラムを実行
Vulkan Programming Vol.1 で使った VRM モデルを描画するものについて、 SwiftShader 経由で動作できるかを試してみました。
結果は残念ながらそのままでは動作しませんでした。
エラー内容は、「vkCreateSwapchainKHR がダイナミックリンクライブラリから見つかりませんでした」というものです。
Vulkan SDK に付属のものと比較
何がちがっているのかを見てみました。以下のものがその比較です。
(エラー内容から当たり前のものだったりしますが…)
一部の関数が含まれていないようでした。
cube.exe がどうして動作したのかをみてみたら、直接 vkCreateSwapchainKHR を呼び出していないようでした。
GitHubでのコードを確認してみたら、vkGetProcAddr を用いて各種関数を取り出すことを期待しているようでした。( https://github.com/google/swiftshader/blob/master/src/Vulkan/VkGetProcAddress.cpp )
動的に取り出すようにしたら動くようになるものと思われます。

感想
予想よりはうまく動作できて驚きました。逆にスワップチェインに関係する部分が動的に取り出さないといけない点が予想外でした。いくつかの Vulkanのサンプルでは確かにそうしているので、マルチプラットフォームを考慮したときには、このように動的取り出しのほうが主な方法なのかもしれません。
Linux には Mesa 3D の LLVMPipe というソフトウェアレンダラーがあります。こちらはOpenGLについてのCPU実装となっています。SIMD命令も活用して割と実用的な速度で動作し、機能も揃っているので大変便利です。 Vulkan においての SwiftShader がそのようなレベルにまで進んで行ってくれることに期待しています。















