• <menu id="w2i4a"></menu>
  • logo Qt使用教程2020

    文檔首頁(yè)>>Qt使用教程2020>>C++界面開(kāi)發(fā)程序Qt使用教程:在Vulkan,Metal和Direct3D上運(yùn)行Qt Quick-第3部分

    C++界面開(kāi)發(fā)程序Qt使用教程:在Vulkan,Metal和Direct3D上運(yùn)行Qt Quick-第3部分


    Qt是目前最先進(jìn)、最完整的跨平臺(tái)C++開(kāi)發(fā)工具。它不僅完全實(shí)現(xiàn)了一次編寫(xiě),所有平臺(tái)無(wú)差別運(yùn)行,更提供了幾乎所有開(kāi)發(fā)過(guò)程中需要用到的工具。如今,Qt已被運(yùn)用于超過(guò)70個(gè)行業(yè)、數(shù)千家企業(yè),支持?jǐn)?shù)百萬(wàn)設(shè)備及應(yīng)用。

    點(diǎn)擊下載Qt最新版

    在Qt圖形系列文章的第三部分(第一部分第二部分),我們會(huì)了解在Qt 5.14中,將Qt Quick的Scene Graph切換到通過(guò)QRhi (Qt渲染硬件接口)渲染時(shí),著色器是如何工作的。我們先研究著色器的處理方式,然后再深入研究RHI,因?yàn)樵赒t Quick中當(dāng)需要使用ShaderEffect Item或自定義材質(zhì)時(shí),必須自己編寫(xiě)片段和/或頂點(diǎn)著色器代碼,因此必需要了解新的著色器處理方法(到Qt 6時(shí)才能升級(jí))。

    說(shuō)到Qt 6:雖然我們?cè)谶@里描述的內(nèi)容只會(huì)應(yīng)用到Qt 5.14,后面的版本還會(huì)有許多修改,但是我們現(xiàn)在闡述的內(nèi)容極有可能是Qt 6中處理圖形和通用計(jì)算著色器的基礎(chǔ),當(dāng)然到時(shí)細(xì)節(jié)內(nèi)容會(huì)打磨得更加精致

    為什么加入新東西?

    問(wèn)題一

    查看qtdeclarative源代碼樹(shù)(即包含QtQml 、QtQuick和相關(guān)模塊的git代碼倉(cāng)庫(kù)),然后進(jìn)入著色器目錄,其中包含了Qt Quick Scene Graph內(nèi)建材質(zhì)的頂點(diǎn)著色器和片段著色器代碼,你會(huì)發(fā)現(xiàn)Qt Quick已為每個(gè)GLSL頂點(diǎn)和片段著色器準(zhǔn)備了兩個(gè)版本:

    C++界面開(kāi)發(fā)程序Qt使用教程:在Vulkan,Metal和Direct3D上運(yùn)行Qt Quick-第3部分

    為什么這樣處理呢?這是為了兼容支持使用了核心配置(core profile)的OpenGL(對(duì)應(yīng)OpenGL 3.2及以上)。由于OpenGL標(biāo)準(zhǔn)并沒(méi)有要求新版本的OpenGL實(shí)現(xiàn)必須支持GLSL 100/110/120的編譯(即老的GLSL版本),因此Qt不得不準(zhǔn)備了兩個(gè)版本的GLSL:一個(gè)適配OpenGL ES 2.0、OpenGL 2.1和兼容性配置(compatibility profile),另一個(gè)(GLSL版本號(hào)為150)專門(mén)用于適配核心配置。如本系列博客第一部分所述,在需要把自定義OpenGL渲染和基礎(chǔ)的Qt Quick UI結(jié)合的使用場(chǎng)景中,提供兩個(gè)版本的著色器代碼才能使開(kāi)發(fā)者可以自由選擇使用哪個(gè)版本的OpenGL。因?yàn)椴徽撨x擇兼容性配置還是核心配置,Qt Quick都可以正常渲染。

    當(dāng)著色器版本的數(shù)量是2時(shí),這種實(shí)現(xiàn)方式還是可以正常實(shí)施的。但如果現(xiàn)在我們還需要添加Vulkan風(fēng)格的GLSL、HLSL和MSL呢?遺憾的是,這種方式無(wú)法規(guī)?;瘮U(kuò)展。

    問(wèn)題二

    與OpenGL不同,一些較新的圖形API不再支持內(nèi)置著色器編譯。(再見(jiàn)了,glCompileShader)。而即使最終還是支持著色器編譯,這部分功能可能變成了一個(gè)分離的庫(kù),但它們可能不提供運(yùn)行時(shí)反射機(jī)制,這意味著沒(méi)有辦法動(dòng)態(tài)定位輸入頂點(diǎn)以及其他頂點(diǎn)、片段或通用計(jì)算著色器所需要的材質(zhì),以及這些材質(zhì)的布局。(例如,一個(gè)uniform變量的名稱和偏移量)

    問(wèn)題三

    一個(gè)內(nèi)部細(xì)節(jié):Qt Quick Scene Graph的批次處理系統(tǒng)需要對(duì)頂點(diǎn)著色器進(jìn)行一些調(diào)整,在一個(gè)稱為合并批次中調(diào)整材質(zhì)(就是當(dāng)多個(gè)幾何節(jié)點(diǎn)最終合并到一個(gè)draw調(diào)用后得到的結(jié)果)。把著色器傳送到glCompileShader之前動(dòng)態(tài)修改,這種方式適用于只有一種著色語(yǔ)言在使用的情況,不能簡(jiǎn)單擴(kuò)展到必須為多種不同語(yǔ)言實(shí)現(xiàn)相同邏輯的情況。

    如何改變呢?

    看看Khronos的SPIR頁(yè)面,里面有一張很好的關(guān)于SPIR-V開(kāi)源生態(tài)系統(tǒng)的信息圖片。為什么不嘗試在此基礎(chǔ)上進(jìn)行開(kāi)發(fā)呢?

    我們感興趣的關(guān)鍵組件如下:

    • glslang, 從GLSL(OpenGL 或 Vulkan 風(fēng)格)到SPIR-V的編譯器, 結(jié)果是一個(gè)中間語(yǔ)言。
    • SPIRV-Cross,把SPIR-V向高級(jí)語(yǔ)言進(jìn)行反射和反匯編的庫(kù),比如 GLSL、HLSL和MSL。

    因此,如果我們“標(biāo)準(zhǔn)化”一種語(yǔ)言,比如Vulkan風(fēng)格的GLSL,把它編譯成SPIR-V,我們就可以適配Vulkan了。然后,如果我們通過(guò)SPIRV-Cross運(yùn)行SPIR-V的二進(jìn)制文件,就可以獲得所需的反射信息,并可以為各種版本的GLSL、HLSL和Metal著色器語(yǔ)言生成源代碼。

    (是的,GLSL仍然至關(guān)重要,因?yàn)殡m然有讓OpenGL可以直接使用SPIR-V的擴(kuò)展,但是指望這套方式在實(shí)際中應(yīng)用并不現(xiàn)實(shí),因?yàn)檫@樣的擴(kuò)展在90%的Qt目標(biāo)平臺(tái)和設(shè)備上不存在——例如,OpenGL ES 2.0在2019年仍然常見(jiàn)。)

    最后,將所有這些(包括元數(shù)據(jù)反射特性)打包到一個(gè)可以方便(反)序列化的包中,這樣就得到了我們的解決方案。

    因此,設(shè)置QSG_RHI=1然后運(yùn)行Qt Quick應(yīng)用程序,其后端渲染管道是這樣的:

    Vulkan-flavor GLSL
    
    [ -> generate batching-friendly variant for vertex shaders]
    
    -> glslang : SPIR-V bytecode
    
    -> SPIRV-Cross : reflection metadata + GLSL/HLSL/MSL source
    
    -> pack it all together and serialize to a .qsb file

    .qsb擴(kuò)展名來(lái)自于執(zhí)行上述步驟的命令行工具的名稱——qsb,Qt Shader Baker的縮寫(xiě)。(不要與qbs混淆)

    在運(yùn)行時(shí),.qsb文件被反序列化成QShader實(shí)例。它是一個(gè)相當(dāng)簡(jiǎn)單的容器,遵循標(biāo)準(zhǔn)的Qt模式,如隱式共享,并為一個(gè)著色器托管多個(gè)版本的源碼和字節(jié)碼以及包含反射數(shù)據(jù)的QShaderDescription。與RHI的其他部分一樣,這些類目前都是私有的API。

    圖形層直接使用QShader實(shí)例。圖形流水線的狀態(tài)對(duì)象為每個(gè)激活的著色步驟分配一個(gè)QShader。然后QRhi后端從QShader容器中選擇適當(dāng)?shù)闹靼姹尽?

    在Qt 5.14中,具體選擇規(guī)則如下:

    • 當(dāng)目標(biāo)是Vulkan時(shí),選則SPIR-V 1.0
    • 當(dāng)目標(biāo)是 D3D11時(shí),選擇HLSL源碼或DXBC Shader Model 5.0
    • 當(dāng)目標(biāo)為Metal時(shí),選擇兼容MSL的Metal 1.2或者預(yù)編譯的metallib
    • 當(dāng)目標(biāo)為OpenGL ES 上下文時(shí), 分別選擇版本為320 es、310 es、300 es和100 es的GLSL源代碼(從上下文支持的最高版本開(kāi)始降序排列)
    • 當(dāng)目標(biāo)為OpenGL核心配置的上下文時(shí),選擇版本為460、450、…、330、150的GLSL源代碼(從上下文支持的最高版本開(kāi)始降序排列)
    • 當(dāng)目標(biāo)是非核心配置的OpenGL上下文時(shí),選擇版本為120或者110的GLSL源代碼(按同樣的優(yōu)先級(jí)排序)。

    上表中的HLSL和MSL條目初看可能會(huì)有些奇怪。這是因?yàn)槲覀兗纯梢栽谶\(yùn)行時(shí)源碼編譯HLSL和MSL(我們的默認(rèn)方法),同時(shí)也做了一些實(shí)驗(yàn),允許在.qsb包中包含預(yù)編譯的中間格式。在實(shí)踐中,這意味著調(diào)用fxc(目前還不支持dxc——它也在計(jì)劃中,但只有在我們開(kāi)始研究D3D12時(shí)才真正相關(guān))或Metal命令行工具,然后再在管道中執(zhí)行上面所示的“打包”步驟。這里的挑戰(zhàn)當(dāng)然是這些工具與它們的平臺(tái)(分別是Windows和macOS)綁定在一起,因此qsb只有當(dāng)在該平臺(tái)上運(yùn)行時(shí)才能被啟用。例如,在Linux上手動(dòng)生成.qsb文件不可行。從長(zhǎng)遠(yuǎn)來(lái)看,這可能不是什么大問(wèn)題,因?yàn)樵赒t 6的規(guī)劃中,我們會(huì)研究更好地與構(gòu)建系統(tǒng)集成,所以像qsb這樣的手動(dòng)運(yùn)行工具就不那么常見(jiàn)了。

    等等,qsb是怎么來(lái)的?

    來(lái)自Qt Shader Tools模塊。它提供了一個(gè)稱為QShaderBaker的API以及一個(gè)稱為qsb的命令行工具來(lái)執(zhí)行上面描述的編譯、轉(zhuǎn)換和打包步驟。

    這里有一點(diǎn)需要注意:這是一個(gè)Qt-labs模塊,所以它不會(huì)隨Qt 5.14一起發(fā)布。

    為什么呢?主要是因?yàn)榈谌揭蕾?,例如glslang和SPIRV-Cross。涉及到需要在我們所有的目標(biāo)平臺(tái)上編譯和運(yùn)行的情況時(shí),就會(huì)有許多事情需要調(diào)查和確認(rèn),有些與許可證相關(guān)。如果所有這些聽(tīng)起來(lái)都很熟悉,那是因?yàn)樵诒静┛拖盗械牡谝徊糠钟懻揂PI轉(zhuǎn)換解決方案時(shí)提到了其中的一些問(wèn)題。因此,現(xiàn)在生成.qsb包就牽涉到了該模塊的檢查和構(gòu)建,然后才能手動(dòng)運(yùn)行.qsb工具。

    盡管我們還是需要一個(gè)新的集成打包在Qt中的解決方案,目前依賴一個(gè)離線著色處理并不是件壞事。不管發(fā)生什么,它都是Qt 6的目標(biāo)之一。我們的愿景是擁有一些與Qt構(gòu)建系統(tǒng)集成的東西,這樣上述的著色器處理步驟就可以在應(yīng)用程序(或庫(kù))構(gòu)建時(shí)完成。但這推遲到成為一個(gè)未來(lái)的目標(biāo),主要是因?yàn)榧磳⒌絹?lái)的qmake -> cmake切換。一旦情況穩(wěn)定下來(lái),我們就可以開(kāi)始在新系統(tǒng)上構(gòu)建解決方案了。

    那么Qt Quick在Qt 5.14中表現(xiàn)怎么樣?

    看看qt/ src/quick/scenegraph/shaders_ng,答案很明顯:通過(guò)手動(dòng)運(yùn)行qsb(注意名稱很貼切的compile.bat),并通過(guò)Qt資源系統(tǒng)在Qt quick庫(kù)中引入生成的.qsb文件。正如上面所概述的,稍后應(yīng)該會(huì)變得更加精巧一些,但是現(xiàn)在已經(jīng)完成了任務(wù)。

    .vert和.frag文件包含了與Vulkan兼容的GLSL代碼,并且沒(méi)有包含在Qt Quick 構(gòu)建中。scenegraph.qrc中只有.qsb文件。

    每個(gè)材質(zhì)只有一對(duì)頂點(diǎn)和片段著色器,總是以與Vulkan兼容的GLSL的形式編寫(xiě),遵循一些簡(jiǎn)單的約定(比如只使用一個(gè)uniform緩沖區(qū),位于binding 0處)。

    所有這些文件都通過(guò)著色器機(jī)制運(yùn)行,產(chǎn)生一個(gè)QShader包。在這個(gè)例子中,結(jié)果是相同著色器的六個(gè)版本,加上反射數(shù)據(jù)(qsb可以打印為JSON文本;然而.qsb文件本身是壓縮的不可讀的二進(jìn)制文件)。這樣就解決了上面的問(wèn)題一和二。

    注意著色器列表中的[Standard]標(biāo)簽。如果這是一個(gè)頂點(diǎn)著色器,并且指定了-b參數(shù),輸出著色器的數(shù)量將是12個(gè),而不是6個(gè)。另外的6個(gè)將被標(biāo)記為[Batchable],這表明它們是非常友好的批處理,對(duì)Qt Quick scenegraph的渲染器做了輕微的修改。這解決了問(wèn)題3,代價(jià)是存儲(chǔ)會(huì)有所提高。(由于減少了運(yùn)行時(shí)工作,所以最終是值得的)

    本文涵蓋了新著色器管道背后的核心概念。我們將會(huì)在另一篇文章中討論ShaderEffect和QSGMaterial?;舅枷耄≦t 5.14中的)是傳遞.qsb文件的名稱,而不是著色器源碼字符串,但對(duì)于材質(zhì)需要特別注意幾個(gè)問(wèn)題(主要是由于使用uniform緩沖區(qū)代替了單一的緩沖區(qū),而且由于沒(méi)有了線程上下文的概念,因此任何人都可以隨意改變狀態(tài))。下次再詳細(xì)講。


    想要購(gòu)買(mǎi)Qt正版授權(quán)的朋友可以點(diǎn)擊"咨詢?cè)诰€客服"哦~~~

    掃碼咨詢


    添加微信 立即咨詢

    電話咨詢

    客服熱線
    023-68661681

    TOP
    三级成人熟女影院,欧美午夜成人精品视频,亚洲国产成人乱色在线观看,色中色成人论坛 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();