Vulkan for Qt on macOS

Sometimes, development efforts align such that new use cases can be enabled with modest extra effort. The QtBase dev branch (which will become Qt 5.12) now has experimental Vulkan support, courtesy of MoltenVK and prior work in Qt. Let's take a look at what has happened.

hellomacosvulcancubes

Backstory

Last year, Laszlo wrote about Vulkan support in Qt on Windows, Linux, and Android. This work included adding QSurface::VulkanSurface and also adding cross-platform classes such as QVulkanInstance and QVulkanWindow

Then, a couple of months ago, the MoltenVK Vulkan to Metal translation library was open sourced. One of the issues raised in the bug reporter was how to make this work with Qt; this requires configuring the NSView used by QWindow to be layer-backed by a CAMetalLayer.

And, as it happens we were already looking at making use of Metal in Qt, starting with adding support for CAMetalLayer as a backing layer. We’re also looking at different ways to integrate application Metal code with Qt, but that’s a topic for another blogpost.


// 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

With all this in place the missing parts was then the platform plugin glue code which adds support for QSurface::VulkanSurface (on macOS) and also implements a QPlatformVulkanInstance subclass that abstracts over platform-specific Vulkan tasks such as creating a Vulkan surface for a native surface.

How do I use it?

The minimal way

Call setSurfaceType(QSurface::VulkanSurface) in the constructor of your QWindow subclass. You can now access the NSView with QWindow::winId(), and pass that on to MoltenVK. The NSView is configured in such a way that MoltenVK can render to it. See also MotelVK issue #78 for more info. Note that I have not actually tried this myself :)

This does not require enabling Vulkan support when building Qt, which again means that the Qt binary package can be used (from 5.12 onwards).

The using the Qt API way

This makes using QVulkanWindow and friends possible, at the cost of having to build Qt from source.

Configure and build Qt with Vulkan support by adding the MoltenVK includes (build MoltenVK according to instructions first):

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

You should now see "Vulkan: yes" on the configure report; if so the QVulkan* classes are available.

Then, tell Qt the location of libMoltenVK.dylib before starting apps or examples:

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

This re-uses the existing Qt code which loads and resolves the Vulcan library at run-time. On macOS we might want to link against MoltenVK.framework instead, but we'll leave that as a future improvement for now.

Finally

I'd like to round off by repeating the "experimental" warning. In particular we don't have enough insight into the inner workings of MoltenVK to know if there are potential points of incompatibility. Please report any findings below or in a QTBUG.


Blog Topics:

Comments