Do you want to know how your customers use your applications and devices? Try Qt Insight Beta.
最新版Qt 6.3已正式发布。 了解更多。
最新バージョンQt 6.3がご利用いただけます。 詳細はこちら

macOS での Valkan 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