C++界面開發程序Qt使用教程:在Vulkan、Metal和Direct3D上運行Qt Quick-第1部分
Qt是目前最先進、最完整的跨平臺C++開發工具。它不僅完全實現了一次編寫,所有平臺無差別運行,更提供了幾乎所有開發過程中需要用到的工具。如今,Qt已被運用于超過70個行業、數千家企業,支持數百萬設備及應用。
Qt 5.14新功能頁面提到:添加了獨立于圖形API的Scene Graph渲染引擎,這是第一個預覽版而且是一個可選功能。這使得Qt Quick應用程序,除了OpenGL以外,還可以運行在Vulkan、Metal或Direct3D 11上
這具體是什么意思?
Qt 6技術概覽一文中說過,Qt 6的一個主要目標是避免在Qt的許多代碼中直接使用OpenGL,通過適當的抽象來兼容更多的圖形API,比如Vulkan、Metal和Direct3D。當然,OpenGL(和OpenGL ES)仍然是一種選擇。這背后的主要動機不是提升性能,而是確保Qt Everywhere在未來仍然成立,未來可能運行在不支持或不推薦使用OpenGL的平臺和設備上。同時,能有這樣一套先進的、結構簡單且清晰易懂的API還可以創造許多可能性,特別是對于那些需要提高性能的場景(比如,更少的API開銷實現更低的CPU占用率),以及在Qt Quick背后的渲染引擎和其他模塊中增加新的功能,比如最近公布的Qt Quick 3D。
此外,能夠使用平臺首選的、支持最好的圖形API來渲染用戶界面,這對于那些使用Qt來呈現UI,同時還用到原生API寫的2D或3D圖形的應用程序來說是個好消息。在這種應用中,一般Qt無法決定使用何種圖形API:例如,一個macOS上的桌面應用程序希望使用Metal去渲染自己的3D內容,同時依靠Qt Quick去呈現2D UI元素,此時如果Qt Quick也使用Metal渲染會大有好處。對于那些過去關注Qt 5.x時代圖形部分變化的人來說,這一點很熟悉:概念上,這和當時Qt Quick渲染引擎引入對OpenGL core profile上下文的操作的支持一樣 —— Qt Quick本身并不需要關心這個,但是為了能夠集成使用了core profile的外部渲染代碼,Qt Quick必須顧及和它們協同的能力。所以從這個角度看,這是Qt 5的自然延續,現在擴展到OpenGL之外的其他圖形API。
到這里,有兩個顯而易見問題:
- 這為什么與Qt 5.x有關?這不都是Qt 6的內容嗎?
- 為什么不直接使用<某種圖形API>轉化為<標準API>的圖形API轉換方案呢?
那么Qt 5.14中有什么?
對Qt所有(或至少大部分)有關圖形渲染的部分進行全面的檢查確實是Qt 6的目標。然而,停止支持Qt 5.x,然后試圖設計、開發和重構一切,并指望一切都能變好,并不現實。正如Qt開發者過去、現在仍會提及的,任何API剛開始迭代時都可能不是最優的。因此,我們采用并行開發的方法,先專注于Qt中的一種特定的UI技術:Qt Quick。
Qt 5.14將發布使用全新渲染方法的Qt Quick預覽版。默認情況下,不啟用新的渲染方法,因此對應用程序來說不需要任何特殊的更改——會像在以往版本中一樣,內部使用相同的直接基于OpenGL的渲染路徑。但是,那些希望嘗試新方法的人可以選擇通過設置環境變量或使用main()中的C++ API啟用新的渲染路徑。我們希望盡早得到反饋,我們好繼續迭代和演進,而不必等到Qt 6.0的發布。
并不是所有的應用程序都能直接使用QSG_RHI環境變量運行。在Scene Graph節點中執行OpenGL調用、或在自定義材質中使用GLSL著色器代碼定制的QQuickItem實現,就不能啟用RHI渲染。這同樣適用于帶有GLSL代碼的ShaderEffect元件。其實有更好的自定義材質和效果的辦法,但是這些需要對應用程序進行移植。在Qt 5.14和Qt 5.15之間我們會嘗試做一些適配,但是在Qt 6.0之前,不會進行大范圍的推廣和移植。另一方面,許多現有的QML應用程序應該可以正常工作,即使底層渲染引擎使用完全不同的API(如Vulkan或Metal)。
為什么不采用XYZ類型的轉換層?
首先,需要說明的是,盡管不能總是實現開箱即用,使用API和著色器轉換層(如MoltenVK、MoltenGL、ANGLE、Zink等)的可能性仍然存在。例如,MoltenVK允許基于Vulkan在macOS上渲染Qt Quick的UI。如果Qt Quick應用程序希望只使用Vulkan,并且仍然希望在macOS上運行,就也可以采用MoltenVK。(只要用戶系統中安裝了正確配置的Qt庫,MoltenVK也已經就緒,那就可以運行)
把這個轉換層變成一個強制性的依賴,并基于此將它和Qt一起部署,情況就完全不一樣了。
- 顯然,將“Qt Everywhere ”改為“Qt Only Where External Dependencies Allow”是不切實際的。Qt面對的平臺和環境比我們想象的還要復雜得多。它只能依賴那些強制性安裝、可以在各種各樣環境中運行\而且對于特定的需求可以輕松適配的第三方庫。(想想Integrity、QNX和定制的嵌入式Linux環境,圖形棧有bug的或正在開發中的系統,偶爾需要適應專有的數據和模塊,或者有時必須與各種圖形或復雜的API進行交互,也許是以廠商自己定制的非標準形式,也許是早已過時的API,所有這些都需要Qt渲染軟件棧中的每個層級都具備靈活性和可伸縮性)。
- 運行時在各種著色器語言之間轉換(或者使用中間格式)不是一個好主意。Qt 6中的著色器管道設計將會專注于離線緩存能力,或者至少在應用程序編譯時進行預緩存。在中間插入轉換層,隱藏各種實現(用了什么API,用了哪種著色器語言),之前的努力就白費了。因為我們不可能為真正底層API準備或者使用字節碼。
- 之前提到的一些選項也沒用了,因為目前實際情況是:在可預見的未來,OpenGL(ES)在大多數設備上仍舊是工作主力。因此如果繼續堅持只使用一種API,那么只能是OpenGL,或者一個能兼容OpenGL的轉換層(它也要在低性能設備上性能表現良好)。
- 有一種特殊情況,客戶自己擴展Qt渲染引擎的功能,底層的渲染代碼往往需要使用相同的API才能完美配合。當然如果轉換層允許訪問底層原生對象(比如Qt 5在Windows上使用ANGLE實現了Qt Quick 到Direct3D的轉換,它就可以擴展EGL extensions),那這也不是一種阻礙。但是不是每次都可以成功的,而且過程中可能產生新的麻煩。
- 還有許可方面的問題。可以認為Apache 2.0與GPLv2不兼容。在任何情況下,依靠純商業解決方案都是不現實的。
- 從經驗來看(有些是從ANGLE來的,有些是從MoltenVK來的),使用這樣的解決方案絕不像人們最初希望的那樣簡單。在某種程度上,保持所有選項正常運行所需要的工作可能會變得過于繁重——那么最好還是把這些精力用到對的方向:直接使用原生的API。這些API轉換方案中的某些依賴于平臺的特性也不是很理想——如果說我們需要為每個Qt的目標平臺引入一個不同的API,這很快就會變得難以忍受。
因此,Qt沒有采用依賴低級API轉換程序的方法,而是自己定義了3D圖形的高級抽象(內部使用,暫時不向應用程序開放)。抽象層的后端有許多針對特定API的實現,這和許多Qt組件的模式差不多。有些后端和操作系統平臺是固定搭配(Metal,D3D),而其他后端可以對應多個平臺(Vulkan,OpenGL)。有一個新開發的著色器管理單元來實現不同后臺的切換,它用到了一些第三方庫,比如glslang和SPIRV-Cross。更多細節將在之后的博文中詳述?,F在,讓我們的視線轉向稍高層面,看看它會給Qt 5.14中的Qt Quick帶來什么。
真的會有效嗎?
讓我們來看一個例子,即QUIt Coding著名的Qt5 Cinematic Experience演示程序。我們使用的是稍作修改的版本,其中少數Shader Effect Item被更新為同時可以使用兩種Qt Quick Scene Graph渲染路徑的格式。該版本可在這里找到。
正常啟動應用程序,設置QSG_INFO=1,得到:
就像在調試輸出中打印的日志一樣,這是在Linux桌面的OpenGL上運行的:
qt.scenegraph.general: threaded render loop qt.scenegraph.general: Using sg animation driver qt.scenegraph.general: Animation Driver: using vsync: 16.95 ms qt.scenegraph.general: opengl texture atlas dimensions: 2048x1024 qt.scenegraph.general: GL_VENDOR: X.Org qt.scenegraph.general: GL_RENDERER: AMD Radeon (TM) R9 M360 (VERDE, DRM 3.23.0, 4.15.0-62-generic, LLVM 8.0.1) qt.scenegraph.general: GL_VERSION: 4.5 (Compatibility Profile) Mesa 19.2.0-devel (git-08f1cef 2019-07-25 bionic-oibaf-ppa) qt.scenegraph.general: GL_EXTENSIONS: ... qt.scenegraph.general: Max Texture Size: 16384 qt.scenegraph.general: Debug context: false
如果我們設置QSG_RHI=1,會發生什么變化?
qt.scenegraph.general: Using QRhi with backend OpenGL 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.95 ms qt.rhi.general: Created OpenGL context QSurfaceFormat(version 4.5, options QFlags<QSurfaceFormat::FormatOption>(DeprecatedFunctions), depthBufferSize 24, redBufferSize 8, greenBufferSize 8, blueBufferSize 8, alphaBufferSize 0, stencilBufferSize 8, samples -1, swapBehavior QSurfaceFormat::DoubleBuffer, swapInterval 1, colorSpace QSurfaceFormat::DefaultColorSpace, profile QSurfaceFormat::CompatibilityProfile) qt.rhi.general: OpenGL VENDOR: X.Org RENDERER: AMD Radeon (TM) R9 M360 (VERDE, DRM 3.23.0, 4.15.0-62-generic, LLVM 8.0.1) VERSION: 4.5 (Compatibility Profile) Mesa 19.2.0-devel (git-08f1cef 2019-07-25 bionic-oibaf-ppa) qt.scenegraph.general: MSAA sample count for the swapchain is 1. Alpha channel requested = no. qt.scenegraph.general: rhi texture atlas dimensions: 2048x1024
乍一看差別不大。它似乎還在使用OpenGL。然而,內部沒有直接使用OpenGL,也沒有Qt Quick Scene Graph中各處穿插的GLSL著色器源碼。相反,會使用QRhi(即QtGui模塊中的一個私有API,全稱為Qt Rendering Hardware Interface)進行渲染。
讓我們把它變得更有趣一點。設置QSG_RHI_BACKEND=vulkan:
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.95 ms WARNING: radv is not a conformant vulkan implementation, testing use only. qt.rhi.general: Physical device 0: 'AMD RADV CAPE VERDE (LLVM 8.0.1)' 19.1.99 qt.rhi.general: using this physical device qt.rhi.general: queue family 0: flags=0xf count=1 qt.rhi.general: queue family 1: flags=0xe count=2 qt.rhi.general: 55 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 3 buffers, size 1280x720, presentation mode 2
處理的很好。顯然它現在正在通過Vulkan渲染。甚至更奇異的Qt Quick特性,如distance field text渲染、著色器效果和粒子效果都如預期的那樣存在。
在RenderDoc中運行應用程序并捕獲幀,結果如下所示。Qt Quick確實正在構建Vulkan管道狀態對象和命令緩沖區,著色器代碼以SPIR-V字節碼格式提供。
就這些了。在本系列的第二篇博文中,我們將研究Qt 5.14為macOS和Windows提供了什么。在那之后,我們將繼續研究所有這些是如何在底層工作的,以及對需要自定義材質和特效的應用程序有什么影響。
想要購買Qt正版授權的朋友可以點擊""哦~~~