本文翻译自Qt Quick on Vulkan, Metal, and Direct3D - Part2
原文作者:Laszlo Agocs,Qt公司高级开发工程师
校审:Richard Lin
让我们接着第一篇文章开始讲。前面我们看到了Qt Quick应用程序在Linux下面基于OpenGL和Vulkan运行的示例。我们也看到在RenderDoc中捕获Vulkan帧的示例,这不仅仅是Qt开发中的重要工具,对于想挖掘深层次的原理并更好地理解Qt Quick是如何在应用中渲染帧 (或排除渲染的故障)也是非常有用的。在这篇文章中,我们将重点关注Qt 5.14为macOS和Windows提供了什么功能。
macOS上的Metal
在macOS 10.13或10.14设置QSG_RHI=1(以及QSG_INFO=1)并运行qt5-cinematic-experience 示例程序,可以看到如下的结果:
qt.scenegraph.general: Using QRhi with backend Metal
graphics API debug/validation layers: 0
QRhi profiling and debug markers: 0
qt.scenegraph.general: threaded render loop
qt.scenegraph.general: Using sg animation driver
qt.scenegraph.general: Animation Driver: using vsync: 16.67 ms
qt.rhi.general: Metal device: Intel(R) HD Graphics 615
qt.scenegraph.general: MSAA sample count for the swapchain is 1. Alpha channel requested = no.
qt.scenegraph.general: rhi texture atlas dimensions: 4096x2048
qt.rhi.general: got CAMetalLayer, size 2560x1440
Qt 6的目标,是默认使用目标平台上主流的、支持最好的图形API(同时也允许应用程序选择其他图形API),在macOS上启用QRhi的渲染方式后,系统会默认使用Metal来渲染Qt Quick。
类似于在QtGui、QPA,和其他一些平台插件中添加Vulkan实例和Surface构建Vulkan渲染后台的方式,QRhi的Metal后台依赖于Qt 5.12前后引入的cocoa平台插件中的Metal的支持。带QSurface::MetalSurface标志的QWindow将获得一个NSView,NSView背后是一个CAMertalLayer。这就是QRhi的Metal后端架构。(要使能QRhi的渲染路径,并且QQuickWindow获得正确的QSurface::SurfaceType标记值,才能正常运行)
有一个非常重要的特性,即能够使用独立的渲染线程运行Qt Quick。之前由于macOS 10.14中的NSOpenGLContext以及相关API中存在一个的多线程问题,Qt在macOS上禁用了独立的OpenGL渲染线程,而把默认值改为“basic”。这导致Qt Quick动画的平滑度有所降低。对于Metal,我们没有(根据我们目前的认知)发现任何多线程的问题,因此我们又可以开启独立的渲染线程了。(通过设置QSG_RENDER_LOOP环境变量,可以改写渲染线程的设置;这个变量可与QSG_RHI配合使用)
我们之前提到了RenderDoc,它可以调试Qt应用程序的帧渲染,支持OpenGL、Vulkan以及Direct3D的运行态。对于Metal,可以使用XCode及其内置的GPU帧快照器。
有一个实用方法可以用XCode快速打开待调试的Qt项目,在命令行执行make xcodeproj && open *.xcodeproj(如果还没有执行qmake则可以执行qmake -spec macx-xcode)。按下Cmd-R,然后会立即启动调试器。在Qt开发期间我们会经常这样使用。为了防止Metal GPU获取失败,即使Qt Quick已经设置为Metal渲染,还是要检查 “Product ->Scheme->Edit scheme…”,并将GPU帧获取获改为Metal。
在XCode中调试构建应用程序时会启用Metal验证,这意味着当Metal API使用不当时,XCode将(理想情况下)返回提示性警告并中断程序执行。与其他平台不同的是,如果不通过XCode进行调试,则无法启用Metal API验证。(与Vulkan和D3D不同,设置环境变量QSG_RHI_DEBUG_LAYER无效)
iOS或者tvOS上是什么情况?
在编写本文时,(iOS和tvOS的)平台插件中缺少与Metal相关的管道,这也意味着QRhi的Metal后端还没有在这些平台上进行测试。这就是为什么Qt 5.14新特性页面关于Qt Quick的部分只提到macOS。预计在不久的将来,可能5.15中,会增加相关的支持。
如何通过MoltenVK使用Vulkan呢?
正如在第1部分中提到的,使用Vulkan发起渲染,然后依靠MoltenVK在运行时将API调用和SPIR-V着色器代码转换为Metal和Metal着色语言也是一种选择。这需要一个支持Vulkan的Qt库,这在Apple平台上不是现成提供的。有关详细信息,请参阅这篇文章,关键是使用configure参数-I来设置并确保可以在运行时使用环境变量QT_VULKAN_LIB并找到对应的库。
必须要注意,这个方式(在macOS上通过MoltenVK使用Vulkan)只是“尽我们能力”去支持。在Apple平台上首要的渲染方式是通过Metal
使用QSG_RHI_BACKEND=vulkan (使用适当配置的Qt 5.14库)运行演示应用程序,结果如下:
qt.scenegraph.general: Using QRhi with backend Vulkan
graphics API debug/validation layers: 0
QRhi profiling and debug markers: 0
qt.scenegraph.general: threaded render loop
qt.scenegraph.general: Using sg animation driver
qt.scenegraph.general: Animation Driver: using vsync: 16.67 ms
qt.rhi.general: Physical device 0: 'Intel(R) UHD Graphics 630' 0.2.1835 (api 1.0.92 vendor 0x8086 device 0x3E9B type 1)
qt.rhi.general: using this physical device
qt.rhi.general: queue family 0: flags=0x7 count=1
qt.rhi.general: 17 device extensions available
qt.scenegraph.general: MSAA sample count for the swapchain is 1. Alpha channel requested = no.
qt.scenegraph.general: rhi texture atlas dimensions: 2048x1024
qt.rhi.general: Creating new swapchain of 2 buffers, size 1280x720, presentation mode 2
值得注意的是,我在macOS 10.13上运行时遇到了问题,在使用线程渲染循环时遇到了死锁和崩溃。在升级到更新的(1.0.121)Vulkan SDK(其中包括MoltenVK)时导致了一系列新的问题,依然无法启动应用程序。(会不断收到类似于https://github.com/KhronosGroup/MoltenVK/issues/695的问题)以后再调查这个问题吧。在这里,在一个带有10.14的Mac Mini和一个半新版本的Vulkan SDK / MoltenVK上,结果却非常好,正如屏幕截图所示。
Windows是我们拥有最多选项的平台。在4个主要的QRhi后端(Vulkan、Metal、D3D11、OpenGL)中,至少有三个可以在Windows上使用:Direct3D 11、Vulkan和OpenGL。
这就引出了一个显而易见的问题:为什么只有3个而不是4个,Direct3D 12不就是第四个吗?
目前还没有D3D12的后台。以后会增加它因为有这个计划,但目前还没有实施。回到我们的主题,需要注意一件事,在Qt 5.8中添加的实验性质的Qt Quick的D3D12直接渲染后端在Qt 6中被弃用了(因为我们会以一种全新的方式来解决多图形API的问题)。
在Windows上设置QSG_RHI=1时的默认值是Direct3D 11。与往常一样,如果需要Vulkan或OpenGL,则需要使用QSG_RHI_BACKEND进行修改。
qt.scenegraph.general: Using QRhi with backend D3D11
graphics API debug/validation layers: 0
QRhi profiling and debug markers: 0
qt.scenegraph.general: threaded render loop
qt.scenegraph.general: Using sg animation driver
qt.scenegraph.general: Animation Driver: using vsync: 16.67 ms
qt.rhi.general: DXGI 1.2 = true, FLIP_DISCARD swapchain supported = true
qt.rhi.general: Adapter 0: 'NVIDIA GeForce RTX 2060' (flags 0x0)
qt.rhi.general: using this adapter
qt.rhi.general: Adapter 1: 'Microsoft Basic Render Driver' (flags 0x2)
qt.scenegraph.general: MSAA sample count for the swapchain is 1
qt.scenegraph.general: rhi texture atlas dimensions: 2048x1024
需要注意的是,我们是基于Direct3D 11.1,而不是11.0。主要是因为我们需要VSSetConstantBuffers1
(以及相关的PS和CS变量)。这应该不会出现问题,除非想在没有安装平台更新的纯Windows 7上运行。说到Windows 7,需要注意,目前基于D3D11的渲染后台在Qt 5.14的Windows 7上不能正常工作,因此在5.14的新特性页面上只提到了Windows 10。这是以后需要补充的地方(但前提是Qt6仍然会支持Windows 7)。
要启用Direct3D调试功能,请将环境变量QSG_RHI_DEBUG_LAYER设置为1。这也适用于Vulkan,只要调试功能可用(例如已安装了Vulkan SDK)。Qt能方便地将消息定向到调试输出(就好像它们是通过qDebug输出的一样)。
Vulkan和OpenGL能在Windows上正常工作,为了避免文章太长,这里就不附截图了。
与Vulkan和Metal一样,QRhi的OpenGL后端也是构建在一些(但不是全部)现有的OpenGL类库的平台管道之上的,比如QOpenGLContext、QOpenGLFunctions,以及Windows平台插件(WGL、EGL)中的底层管道。因此,原来直接运行在OpenGL上的Qt Quick应用程序的所有内容,在新的渲染平台上都有。(比如desktop, ANGLE, Software三选一参数以及各种环境变量,如QT_OPENGL)
说到ANGLE,我们的期望在Qt6中把它从直接依赖库中删除。这需要进一步调查以完全确保我们不会失去对特殊用例的支持,但是现在的计划是让QRhi-based渲染路径在Windows上支持Direct3D 11、OpenGL(通过WGL)和Vulkan,这就已经能够满足应用开发了。
这就是这篇文章的全部内容。在第3部分中,我们将最终开始深入研究QRhi是什么以及如何处理着色器。