大量数据+同步+多线程_Vulkan 多线程渲染
1. Overview of Vulkan
1.1 計(jì)算機(jī)圖形軟件
圖形軟件有兩個(gè)大類:專用軟件包(special-purpose packages)和通用編程軟件包(general programming packages)。
專用軟件包通常提供一種UI設(shè)計(jì)語言,讓用戶直接生成想要的圖形,不用關(guān)心內(nèi)部實(shí)現(xiàn)。這類軟件例子是PS、CAD等等。
相反,通用編程軟件包提供一個(gè)可使用C、C++或Java等高級語言編程的圖形函數(shù)庫。圖形函數(shù)庫中提供幾何圖元、矩陣變換等操作,提供了間接操作硬件的軟件接口,所以這組圖形函數(shù)又被稱為計(jì)算機(jī)圖形應(yīng)用編程接口(computer-graphics application programming interface,CG API)。OpenGL、Vulkan、DirectX、Metal皆在此列。
1.2 Vulkan多線程的設(shè)計(jì)理念
Vulkan不僅僅是圖形(graphics)API,而是一個(gè)面向圖形和計(jì)算的編程接口(graphics and compute)。支持Vulkan的設(shè)備可以是GPU,也可以是DSP或者固定功能的硬件。
Vulkan中的計(jì)算模型主要基于并行計(jì)算,因此支持多線程是Vulkan設(shè)計(jì)的核心理念之一。
為了較少Vulkan內(nèi)部因?yàn)榛コ馔降炔僮髟斐傻目D問題,Vulkan內(nèi)部默認(rèn)認(rèn)為對任何資源的訪問不存在多線程競爭,所有的資源同步操作由應(yīng)用開發(fā)者去負(fù)責(zé),因?yàn)閷Y源的訪問和使用沒有人比應(yīng)用開發(fā)者自己更加清楚。Vulkan稱之為外部同步(external synchronization)。
因?yàn)檫@個(gè)原因,資源管理和線程同步工作成為編寫Vulkan程序的最大難點(diǎn)之一。想要讓Vulkan多線程正常運(yùn)行,你需要做大量的工作。當(dāng)然,換來的是Vulkan有了更加干凈的線程模型以及比其它CG API高得多的性能。
image-20200730105359314.png1.3. Instances, Devices, and Queues
在正式研究Vulkan多線程之前,有三個(gè)重要的基礎(chǔ)概念需要了解—Instances, Devices, and Queues。
Instances可以看做是應(yīng)用的子系統(tǒng),從邏輯上把Vulkan與應(yīng)用程序上下文中的其他邏輯隔開。Instances可以看做是Vulkan的上下文,它會跟蹤所有狀態(tài),從邏輯上把所有支持Vulkan的設(shè)備整合在一起。
Devices有兩個(gè)概念:Physical devices和Logical device。
Physical devices通常代表一個(gè)或者多個(gè)支持Vulkan的硬件設(shè)備,這些設(shè)備具有特定功能,可以提供一系列Queues。圖形顯卡、加速器、DSP等都可以是Vulkan的Physical devices。
Logical device是Physical devices的軟件抽象,用于預(yù)訂一些硬件資源。
Queues可以理解為一個(gè)“GPU線程”,它是實(shí)現(xiàn)Vulkan多線程的關(guān)鍵元素之一,用于響應(yīng)應(yīng)用的請求,大部分時(shí)間,應(yīng)用都在與其交互。
Vulkan功能的層次結(jié)構(gòu)圖如下:
image-20200730105801733.png2. Queues and Command Buffer
2.1 Queues
Queue代表一個(gè)GPU線程,Vulkan設(shè)備執(zhí)行的就是提交到Queues中的工作。物理設(shè)備中Queue可能不止一個(gè),每一個(gè)Queue都被包含在Queue Families中。
Queue Families是一個(gè)有相同功能的Queues的集合,它們的性能水平和對系統(tǒng)資源的訪問是相同的,并且在它們之間數(shù)據(jù)傳輸工作沒有任何成本(同步之外)。
一個(gè)物理設(shè)備中可以存在多個(gè)Queue Families,不同的Queue Families有不同的特性。相同Queue Families中的Queues的功能相同,并且可以并行運(yùn)行。
按照Queue的能力,可以將其劃分為:
- Graphics(圖形)
- 該系列中的Queues支持圖形操作,例如繪制點(diǎn),線和三角形。
- Compute(計(jì)算)
- 該系列中的Queues支持諸如computer shader之類的計(jì)算操作。
- Transfer(傳輸,拷貝)
- 該系列中的Queues支持傳輸操作,例如復(fù)制緩沖區(qū)和圖像內(nèi)容。
- Sparse binding(稀疏綁定)
- 該系列中的隊(duì)列支持用于更新稀疏資源(sparse resource)的內(nèi)存綁定操作。
2.2 Command Buffer
2.2.1 單線程的性能瓶頸
傳統(tǒng)CG API是單線程的,性能的提升只能依賴于CPU主頻的提高。能有的優(yōu)化方案也不外乎主線程和渲染線程分開,或者某些資源的異步加載、離線處理。
image-20200730114946379.png但是在實(shí)際應(yīng)用中我們還是經(jīng)常遇到傳統(tǒng)CG API導(dǎo)致的性能瓶頸。
以手機(jī)終端為例,CPU主頻提升有限,各大芯片廠商開始向多核多線程發(fā)展,考慮到功耗溫控問題,又不能把CPU頻率升的太高,越來越高的刷新率對實(shí)時(shí)渲染的速度要求越來越苛刻。
image-20200730115516772.pngVulkan為了充分發(fā)揮CPU多核多線程的作用,引入了command buffer的概念。多個(gè)線程可以同時(shí)協(xié)作,每個(gè)CPU線程都可以往自己的command buffer中提交渲染命令,然后統(tǒng)一提交到對應(yīng)的Queue中,大大提高了CPU的利用率。
image-20200730115609709.png2.2.2 Command Buffer的作用
應(yīng)用在繪制時(shí)會提交一系列繪制命令給GPU驅(qū)動,但是這些繪制命令不會立刻被執(zhí)行,而是被簡單的添加到Command Buffer的末尾。
在其他CG APIs中,驅(qū)動程序在應(yīng)用不感知的情況下,把API調(diào)用翻譯成GPU command并儲存在command buffer中,最終提交給GPU處理。command buffer的創(chuàng)建和銷毀都由驅(qū)動負(fù)責(zé)。
在Vulkan中,你需要自己從Command Buffer Pool中申請command buffer,將想要記錄的命令放入command buffer中。
Command Buffer Pool:
image-20200730142932026.png2.2.3 Recording command
Command Buffer可以記錄(Record)很多命令,比如:設(shè)置狀態(tài)、繪制操作、數(shù)據(jù)拷貝...
image-20200730142958943.pngimage-20200730142302468.png理論上,一個(gè)線程可以把Command記錄到多個(gè)Command Buffer中,多個(gè)線程也可以共享同一個(gè)Command Buffer,但是一般不鼓勵(lì)多個(gè)線程共享一個(gè)Command Buffer。
Vulkan的關(guān)鍵設(shè)計(jì)原則之一就是做到高效的多線程。想實(shí)現(xiàn)這一點(diǎn),應(yīng)用程序要注意因?yàn)橘Y源競爭導(dǎo)致的多線程彼此阻塞。因此,每個(gè)線程最好有一個(gè)或者對個(gè)Command Buffer,不要嘗試共享一個(gè)。另外,Command Buffer由Command Buffer Pool分配,應(yīng)用可以為每一個(gè)線程創(chuàng)建一個(gè)Command Buffer Pool,讓各個(gè)工作線程從Command Buffer Pool中分配Command Buffer,無需參與競爭。
image-20200730144149412.png2.2.4 Submitting Command Buffers
提交過程使用示意圖更加好理解一點(diǎn)。
單線程Command Buffer提交過程:
submit cb1.PNGsubmit cb5.PNGsubmit cb2.PNG多線程Command Buffer提交過程:
submit cb3.PNGsubmit cb4.PNG整體流程如下:
image-20200730144906368.png3. Synchronization
3.1 顯示同步操作
Vulkan把同步的操作交給了應(yīng)用(external synchronization),絕大多數(shù)的Vulkan命令根本不提供同步,需要應(yīng)用自己負(fù)責(zé)。Vulkan給應(yīng)用提供了同步原語,幫助應(yīng)用進(jìn)行同步操作。
Vulkan中主要有四種同步原語(synchronization primitives):
- Fences
- 最大顆粒度的同步原語,目的是給CPU端提供一種方法,可以知道GPU或者其他Vulkan Device什么時(shí)候把提交的工作全部做完。
- 如果你熟悉Android顯示機(jī)制的話,acquire fence或者retire fence就是類似的作用
- Semaphores
- 顆粒度比Fences更小一點(diǎn),通常用于不同Queue之間的數(shù)據(jù)同步操作
- Events
- 顆粒度更小,可以用于Command Buffer之間的同步工作
- Barriers
- Vulkan流水線(Pipeline)階段內(nèi)用于內(nèi)存訪問管理和資源狀態(tài)移動的同步機(jī)制
下面這張圖取自NVIDIA公司Vulkan 多線程講解的PPT:
image-20200730145823767.png3.2 隱藏的執(zhí)行順序
Vulkan是顯式的API沒錯(cuò),號稱是“沒有秘密的API”。但是在多線程同步時(shí),還是存在一些潛規(guī)則。
以下面這張圖為例,同一個(gè)Queue中,Command Buffer1 和Command Buffer2 誰先執(zhí)行?Command Buffer中記錄的一堆命令是如何執(zhí)行的?
image-20200730144906368.pngVulkan的執(zhí)行順序其實(shí)是有一定的潛規(guī)則的,在沒有同步原語的情況下:
- Command Buffer中的Command,先記錄的先執(zhí)行
- 先提交的Command Buffer先執(zhí)行
- 同一個(gè)Queue中,一起提交的Command Buffer1 和Command Buffer2 按照下標(biāo)的順序執(zhí)行,Command Buffer1 先執(zhí)行
3.3 Barriers
所有的同步原語中,Barriers使用起來最為困難。Barriers用于顯式的控制buffer或者image的訪問范圍,避免hazards(RaW,WaR,and WaW),保證數(shù)據(jù)一致性。
Barriers需要開發(fā)者了解渲染管線的各個(gè)階段,能清晰的把握管線中每個(gè)步驟對資源的讀寫順序。
Vulkan中將Pipeline的各個(gè)階段定義為:
- TOP_OF_PIPE_BIT
- DRAW_INDIRECT_BIT
- VERTEX_INPUT_BIT
- VERTEX_SHADER_BIT
- TESSELLATION_CONTROL_SHADER_BIT
- TESSELLATION_EVALUATION_SHADER_BIT
- GEOMETRY_SHADER_BIT
- FRAGMENT_SHADER_BIT
- EARLY_FRAGMENT_TESTS_BIT
- LATE_FRAGMENT_TESTS_BIT
- COLOR_ATTACHMENT_OUTPUT_BIT
- TRANSFER_BIT
- COMPUTE_SHADER_BIT
- BOTTOM_OF_PIPE_BIT
對應(yīng):
image-20200730152820973.png假設(shè)我們有個(gè)兩個(gè)渲染管線P1 和 P2,P1會通過Vertex Shader往buffer寫入頂點(diǎn)數(shù)據(jù),P2需要在Compute Shader中使用這些數(shù)據(jù)。
如果使用fence去同步,你的流程應(yīng)該是這樣:P1的Command提交后,P2通過fence確保P1的操作已經(jīng)被全部執(zhí)行完,再開始工作。
image-20200730153109052.png但是這種大顆粒度的同步操作無疑造成了耗時(shí)操作:P1的數(shù)據(jù)在Vertex Shader階段就已經(jīng)準(zhǔn)備好了,我們?yōu)槭裁匆鹊剿胁僮鲌?zhí)行完再開始?P2平白多等待了很長時(shí)間,而且在這個(gè)期間P2的其他階段并沒有使用到P1的數(shù)據(jù),也是可以執(zhí)行的啊。
Barriers的引入完全解決了這個(gè)問題,我們只需要告訴Vulkan,我們在P2的Compute Shader階段才會等待P1 Vertex Shader里面的數(shù)據(jù),其他階段并不關(guān)心,可以同步進(jìn)行。
image-20200730152521195.png使用方法:
image-20200730153743130.png參考文檔:
本系列文章匯總:
- Vulkan 簡介
- Vulkan 多線程渲染
- Vulkan 內(nèi)存管理
- Vulkan 繪制與顯示
- Vulkan 資源綁定和狀態(tài)管理
總結(jié)
以上是生活随笔為你收集整理的大量数据+同步+多线程_Vulkan 多线程渲染的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win2019微软更新服务器,微软201
- 下一篇: 免流微信抢红包插件