macOS での Vulkan for Qt

この記事は The Qt BlogVulkan for Qt on macOS を翻訳したものaです。
執筆: Morten Johan Sørvig, 2018年05月30日

qtbase の dev ブランチ(Qt 5.12 になる予定)に Vulkan サポートが追加されました。こういった対応は、控えめに言っても多大な工数がかかるものですが、MoltenVK プロジェクトとこれまで Qt に対してなされた様々な作業により、スムーズに対応を行うことができました。ということで詳細を見てみましょう。

hellomacosvulcancubes

背景

昨年、Laszlo が Windows と Linux、Android の Qt の Vulkan 対応 という記事を書きました。これにより、QSurface::VulkanSurface に加え、クロスプラットフォームの QVulkanInstanceQVulkanWindow といったクラスが追加されました。

その後、いまから数か月前に、MoltenVK という Vulkan と Metal の変換ライブラリがオープンソース化されました。これを Qt として対応する というバグレポートが作成され、これには QWindow が内部で使用している NSView が CAMetalLayer を使うような変更が必要でした。

この作業を行った際に、すでに Metal を Qt で使う方法を模索し始めていて、CAMetalLayer をレイヤーとして利用できるように していました。さらに Metal 系のコードを Qt に埋め込む別の方法も研究していましたが、それはまた別の記事で紹介する事にしましょう。

// Snippet from Qt internal layer management code

@implementation QT_MANGLE_NAMESPACE(QNSView) (DrawingAPI)

- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy
{
// We need to set this this excplicitly since the super implementation
// returns LayerContentsRedrawNever for custom layers like CAMetalLayer.
return NSViewLayerContentsRedrawDuringViewResize;
}

- (void)updateMetalLayerDrawableSize:(CAMetalLayer *)layer
{
CGSize drawableSize = layer.bounds.size;
drawableSize.width *= layer.contentsScale;
drawableSize.height *= layer.contentsScale;
layer.drawableSize = drawableSize;
}

- (void)layoutSublayersOfLayer:(CALayer *)layer
{
if ([layer isKindOfClass:CAMetalLayer.class])
[self updateMetalLayerDrawableSize:static_cast(layer)];
}

- (void)viewDidChangeBackingProperties
{
CALayer *layer = self.layer;
if (!layer)
return;

layer.contentsScale = self.window.backingScaleFactor;

// Metal layers must be manually updated on e.g. screen change
if ([layer isKindOfClass:CAMetalLayer.class]) {
[self updateMetalLayerDrawableSize:static_cast(layer)];
[self setNeedsDisplay:YES];
}
}

@end

これらすべての準備ができ、残すは 貼り合わせるための platform plugin で、これにより(macOS で)QSurface::VulkanSurface が利用可能になります。ネイティブサーフェスとして Vulkan サーフェスを提供するなど Vulkan 関連のプラットフォーム固有の機能を抽象化した QPlatformVulkanInstance の実装も行っています。

どのようにつかえばいいの?

最小の方法

QWindow のサブクラスのコンストラクタで setSurfaceType(QSurface::VulkanSurface) を呼び出します。これにより QWindow::winId() で NSView にアクセスができるようになり、それを MoltenVK に渡すことができます。NSView はこのようにして MoltenVK の描画先として設定できます。詳細は MotelVK issue #78 もご覧ください。ちなみに私自身はこれを試したことがありません :)

Qt の API を使う方法

MoltenVK(をビルドした後)include 等の設定をすることで Vulkan サポートを有効にして Qt の configure とビルドをしてください。

./confgure -I /path/to/MoltenVK/Package/Release/MoltenVK/include

"Vulkan: yes" が configure の結果表示されるはずで、これにより QVulkan* クラスが利用可能になります。

それから、アプリやサンプルの起動前に、Qt に libMoltenVK.dylib の在り処を教えてあげてください。

export QT_VULKAN_LIB=
/path/to/MoltenVK/Package/Release/MoltenVK/macOS/libMoltenVK

Qt 内部で実行時に Vulkan ライブラリをロードしシンボルの解決をする箇所がこれを利用します。macOS では、MoltenVK.framework に対してリンクをしたいと思うかもしれませんが、その改善は今は置いておきます。

終わりに

「実験中」という警告をここで再度述べることで、この記事を締めたいと思います。特に、MoltenVK の内部動作の詳細について十分に把握できていないため、互換性まわりが今後問題になるかもしれません。もしなにかありましたら、QTBUG までお知らせください。


Blog Topics:

Comments