As some of you may have heard, one of the new features in Qt 5.10 is the introduction of a set of basic Vulkan enablers. Now that Qt 5.9 is out, it is time to take a look at what this covers (and does not cover) in practice. In order to keep things fun and easy to read, this is going to be split into a series of shorter posts. It must also be mentioned that while the new features mentioned here are all merged to the dev branch of qtbase, there is no guarantee they will not change until the release of Qt 5.10.
Qt 5.8 started the research and implementation for gradual improvements when it comes to supporting graphics APIs other than OpenGL. There the focus was mainly on Qt Quick, and scenegraph backends that either do not involve new platform specifics (software) or are available on a single platform/windowing system only (Direct3D 12).
As shown in the pre-work for our D3D12 experiment, getting started with such APIs is easy: 1. grab the native window handle (for example, in case of Windows, QWindow::winId() is the HWND); 2. add your platform-specific code to render stuff; 3. done!
Now, the same is of course possible with Vulkan, as proven by the various projects on GitHub and elsewhere. So what is the point in touching QtGui, the QPA interfaces, and the platform plugins?
Well, things become more interesting when multiple platforms come into play: the way windowing system integration is done in Vulkan requires writing platform-specific code, likely leading to a bunch of ifdefs or similar in cross-platform applications.
Given that we have a cross-platform framework (Qt), it is fairly natural to expect that it should help with abstracting and hiding these bits.
So instead of this:
QWindow *window; #if defined(VK_USE_PLATFORM_WIN32_KHR) VkWin32SurfaceCreateInfoKHR createInfo; createInfo.hwnd = (HWND) window->winId(); ... err = vkCreateWin32SurfaceKHR(...); #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) VkWaylandSurfaceCreateInfoKHR createInfo; ... err = vkCreateWaylandSurfaceKHR(...); #elif defined(VK_USE_PLATFORM_ANDROID_KHR) VkAndroidSurfaceCreateInfoKHR createInfo; ... err = vkCreateAndroidSurfaceKHR(...) #elif defined(VK_USE_PLATFORM_XCB_KHR) VkXcbSurfaceCreateInfoKHR createInfo; ... err = vkCreateXcbSurfaceKHR(...) #elif ...
why not have something like the following:
QWindow *window; VkSurfaceKHR surface = QVulkanInstance::surfaceForWindow(window);
The windowing system specifics are now conveniently handled in Qt’s platform plugins. No more ifdefs.
The second important motivation factor is that even the D3D12 experiment has shown that many applications are happier with a higher level convenience window class, like QD3D12Window, following the example of QOpenGLWindow. These are inherently limited in some ways, but avoid the need for doing everything from scratch with QWindow (and juggling with surfaces like in the above example…).
Using QWindow directly remains the most powerful way always, giving full control to the application, but as we will see later, doing a fully featured and stable Vulkan-based QWindow is not exactly trivial (think swapchains, exposeEvent(), resizing, QPlatformSurfaceEvent, etc.). Hence the introduction of QVulkanWindow.
What This Is Not
Before moving on to the new QVulkan* classes in detail, let’s clarify quickly what the Vulkan support in Qt 5.10 really is:
- Qt 5.10 enables applications to perform cross-platform Vulkan rendering in a QWindow and the convenience subclass QVulkanWindow.
- Besides abstracting the windowing system specifics, a thin wrapper is provided for Vulkan instances and the instance and device specific functions of the core Vulkan 1.0 API.
- The Vulkan API is not abstracted or hidden in any way. Qt does what it should, i.e. helping with windowing, platform specifics, and function resolving for the core API, but no more than that.
- Vulkan-based QWindows can be combined with QWidget-based UIs using QWidget::createWindowContainer(). They are no different from OpenGL-based windows in this respect. This is excellent news for 3D tooling type of applications on the desktop using QWidgets, since there is now a Vulkan-based alternative to QGLWidget/QWindow/QOpenGLWindow.
- Vulkan support does not currently cover modules like Qt Quick, Qt 3D, Qt Canvas 3D, the OpenGL backend of QPainter, the GL composition-based QOpenGLWidget/QQuickWidget, etc.
- Vulkan support may be introduced to some of these in the future, however this is not in scope for Qt 5.10.
So what platforms are supported?
As of Qt 5.10, the situation is the following:
- Windows (desktop, not WinRT): when the LunarG SDK is installed, and thus the VULKAN_SDK environment variable is set, Vulkan support will automatically get enabled in the Qt build.
- Linux (xcb only at the moment; support in the wayland platform plugin to be added later on): enabled whenever the Vulkan headers are found during configure time.
- Android (tested on API level 23 and 24; note that the Vulkan headers (and related tools) are only present in level 24 and newer NDKs out of the box)
Note that Qt’s Vulkan support does not rely on linking to a Vulkan (or loader) library, and rather relies on resolving everything at runtime. Therefore the only hard requirement is the presence of a relatively recent set of Vulkan headers (like > 1.0.13 or so).
When it comes to the pre-built packages, we currently have some open tasks to investigate and implement support for Vulkan-enabled builds on some platforms at least. Hopefully this gets sorted out in time for Qt 5.10.
That’s it for part 1. Stay tuned for part 2, where we will start digging into the actual QVulkan classes!