- 1. What it is
- 2. What it is not
- 3. Window
- 4. Class
- 5. Widgets
- 6. Shaders
- 7. Graphics Debugging
- 8. Examples
Translation of official news by Laszlo Agocs
The face of graphics APIs is changing. Qt Quick 2 was released in 2012 with Qt 5.0, and built on OpenGL and OpenGL ES 2.0. Changes and improvements have since been made - the Qt Quick 2D Renderer has been introduced, software rasterization has been experimented with, and a provisioning system for the latest versions of OpenGL has been added to the entire Qt graphics stack. However, as Lars noted in his talk at the Qt World Summit 2015, things are changing: new, low-level, more efficient APIs like Vulkan, Metal, and Direct3D 12 are about to become widely available. Some of them are platform-specific, making them the best choice for targeting specific platforms, while others are expected to support a wide variety of platforms. At the same time, when making complex predictions, graphics API acceleration is not always the best choice: traditionally, desktop UI on legacy hardware is sometimes better to run with legacy CPU-based rendering.
So, not surprisingly, one of the areas of research in future versions of Qt is to make the graphics stack, and in particular Qt Quick, more flexible, with support for various graphics APIs, as well as support for software rendering.
Such research work often leads to beneficial effects, and this entry is about one such. A simple Qt module that includes integration with Direct3D 12 in a separate Qt window - or alternatively a QWidget based application - and makes it easy to start experimenting with modern D3D techniques while you continue to enjoy the familiar Qt APIs, tools and development environment and the ecosystem it offers.
What it is
The QtD3D12Window module, found in the qt-labs repository, is a Qt 5.6 module that provides a QD3D12Window class similar to QOpenGLWindow, is handled by a qmake rule to compile an HLSL shader via fxc, and has a comprehensive set of examples for basic use (like Microsoft's Hello World samples ).
What it is not
Before we go any further, let's understand what this module is not: it is not a way to run existing Qt applications on Direct3D (which is exactly what [ANGLE] provides(https://chromium.googlesource.com/angle/angle/ +/master/README.md) when it comes to D3D9 and 11), and doesn't support Qt Quick anyway. It is also not an add-on to Qt in its current form, nor is it a complete engine and framework in any form (the QD3D12Window interface obviously offers insufficient functionality for complex and multi-threaded solutions).
Window
The first step to integrate with custom rendering code is a new graphics API that creates a render target in a native window based on QWindow. Currently OpenGL is the only choice and is deeply integrated into Qt both internally (QPA interfaces, platform plugins) and externally (public APIs, see QOpenGL classes in QtGui). This is expected to change in the future, but for now, for our standalone D3D experiment, we'll do it all ourselves. Qt's window platform plugin makes it easy to get a native window handle, just as if we were using QWindow::winId() which returns the id of the Windows window in a Qt application. We can then use DXGI to enumerate the available adapters, and we can select either a hardware or a WARP adapter and create a swap chain. QD3D12Window will handle all of this, and well enough for basic typical applications.
Speaking of DXGI, this is the first such foray into graphics adapter and device management: while OpenGL and its windowing interfaces are usually limited, other APIs (especially platform-specific and model-specific drivers) may offer more options. on searching for adapters and making changes to settings, deleting and resetting during the life cycle of the application. Such functionality on platforms where APIs are available will receive more attention in Qt in the future.
When implementing QD3D12Window, it turned out that it is not necessary to create any common class - thanks to the fact that QOpenGLWindow and QRasterWindow were introduced in Qt 5.4: The common base class QPaintDeviceWindow which of course is misleading in the case of D3D, since our window is not used for rendering based on QPainter) provides all the necessary infrastructure to allow a subclass to focus on the specifics of the graphics API when developing core functionality such as the update() method. The good news is that this workaround makes it easy to experiment with other APIs in the future (QMetalWindow, QVulkanWindow, etc.).
Class
QD3D12Window is a mirror of QOpenGLWindow, which in turn is based on QOpenGLWidget/QGLWidget and the initializeGL - resizeGL - paintGL methods, with GL renamed to D3D, respectively. There are two new subclass functions that can be implemented: releaseD3D and afterPresent. The latter is called every time a Present call is issued: most simple applications will wait for the GPU in this function. The first one is used so that the application can survive device removal: when the graphics device becomes unavailable, this function is called and executed when resources are freed during initialization / redrawing / resizing. QD3D12Window will then run initializeD3D again. In this case, the application can remain functional while updating the driver or waiting for shaders to execute.
Better, of course, to show by example. Let's take a look at the hellotriangle, which shows that if you've used QOpenGLWindow or QOpenGLWidget before, then using QD3D12Window won't surprise you.
Widgets
So, now on our window we have nothing but the contents of the rendered D3D12. That's great, but what do the traditional controls do there? This can be achieved with QD3D12Window by making a child window via QWidget::createWindowContainer(). This is due to the usual limitations, which you should first read about in the documentation. However, this will work fine for the simplest purposes.
Shaders
Shader code processing and compilation is another interesting topic. With OpenGL in Qt and Qt Quick, the emphasis is on runtime compilation due to the fact that this is the only widely available solution that is independent of vendors and platform specifics. With other graphics APIs in the future, Qt is expected to focus more on offline compilation, and integration into the build system as much as possible. In addition to the obvious performance benefits, this greatly improves the development workflow: when the compiler receives information about build-time errors when running via Ctrl+B, in Qt Creator you can easily feel how the new way outperforms the "old" debugging path while the application is running.
The QtD3D12Window module comes with a simple qmake rule that allows fxc.exe to be called at build time. All examples use it to create header files where the bytecode is compiled, which is an array of characters. Take a look at the .pro file of one of them and the shader setting.
This is not entirely new to Qt: the ANGLE package in qtbase does shader compilation in the same way. However, what is hidden cannot be used in D3D application layer code like the hlsl.prf here can be copied to the mkspecs/features folder in the Qt SDK, making it available to any Qt application.
Graphics Debugging
QD3D12Window automatically turns on the D3D12 debug level. This is incredibly useful in terms of many of the common mistakes people make when starting up D3D12, especially when getting useful debug messages. However, you can turn them off when it comes to performance testing.
Another useful tool is the graphics debugger included with Visual Studio. One way to start a Qt application is to execute devenv /debugexe qtapplication.exe from the developer command line and press Alt+F5. (alternatively, creating Visual Studio project files with qmake -tp vc might also work well). It proved to be very useful during the development of simple examples - for example, its ability to look at graphic resources and also see if the MIPMAP levels are well formed.
Examples
As mentioned earlier, the module comes with a set of examples that cover the basics and can be helpful for getting started with D3D12 development. See the readme file for details.
Источник Qt Blog .