WebGPU學習(五): 現代圖形API技術要點和WebGPU支援情況調研
大家好,本文整理了現代圖形API的技術要點,重點研究了並行和GPU Driven Render Pipeline相關的知識點,調查了WebGPU的相關支援情況。
另外,本文對實時光線追蹤也進行了簡要的分析。這是我非常感興趣的技術方向,也是圖形學的發展方向之一。本系列後續文章會圍繞這個方向進行更多的研究和實現相關的Demo。
上一篇博文:
WebGPU學習(四):Alpha To Coverage
本文內容
- 前置知識
- 技術要點
- 並行
- Multiple Queues
- 同步
- 多執行緒
- 記憶體管理
- 延遲渲染
- Defer Shading
- Textureless Defer Render
- GPU Driven Render Pipeline
- Approaching zero driver overhead
- GPU Cull
- GPU Lod
- Hybrid Render For Real-time Ray Tracing
- 混合渲染
- 如何使用WebGPU學習和實現Ray Tracing
- 學習資料
- 其它
- Bindless Texture
- Virtual Texture
- Tessellation
- Mesh Shader
前置知識
現代圖形API包括哪些API?
包括DX12、Vulkan、MetalMVP是什麼?
是WebGPU的最小可用版本。
在1.0版本釋出前,先發布MVP版本。
技術要點
現代圖形API包含下面的技術要點:
下面依次進行分析:
並行
為了提高多核CPU和GPU的利用率,現代圖形API充分支援了並行。
並行包含下面的技術要點:
Multiple Queues
介紹
為了提高GPU利用率,可以將不同種類的任務對應的command buffer提交到3種佇列中:
graphics queue
copy queue
compute queue
不同佇列的任務能夠在GPU中並行執行,從而實現Async Compute,提高利用率。
參考資料
Multi-engine synchronization
WebGPU支援情況
根據Multiple Queues skeleton proposal,MVP只支援單佇列:
what single queue is exposed in the MVP
同步
介紹
有3個技術可以實現CPU與GPU之間以及GPU內部的同步:
- semaphores
我不瞭解它,它應該是用來同步佇列的
- memory barrier
它用來避免GPU因為資源依賴關係造成等待,以及避免CPU和GPU之間發生Race Condition。
現代圖形API更加底層,以前GPU做的同步工作也交給了圖形程式設計師,更加靈活的同時也加重了程式設計師的負擔。
參考資料
Breaking Down Barriers
- fence
它用來在CPU和GPU之間同步。
這3個技術的關係可以參考Vulkan Multi-Threading:
WebGPU支援情況
- semaphores
因為目前只支援單佇列,所以不需要它
- memory barrier
大家都表示memory barrier不容易實現,所以barriers由WebGPU幫我們做了(參考Memory barriers investigations、Memory Barriers portability、The case for passes -> Synchronization and validation),我們只需要給WebGPU一些提示(如指定buffer的usage)
- fence
支援以計數的方式實現fence。
參考資料
TimelineFences
多執行緒
介紹
可以線上程中執行現代圖形API相關的渲染任務:
線上程中更新資源
如更新buffer並行地編譯shader
並行地建立pipeline state
線上程中建立command buffer
參考Vulkan Multi-Threading:
WebGPU支援情況
有兩種方法實現多執行緒:
- 通過OffscreenCanvas API,實現主執行緒與渲染執行緒分離
根據Rendering to OffscreenCanvas on non-yielding workers:
WebGPU支援OffScreenCanvas API,但是目前Chrome不能使用它。
- 建立worker,在worker中執行WebGPU相關的渲染任務
Create a proposal for multi-worker中提出了WebGPU如何在worker中執行渲染任務:
1.Asynchronous texture & buffer uploads
2.Asynchronous shader compilation
3.Asynchronous pipeline state creation
4.Using MTLParallelRenderEncoder
5.Each thread in a thread pool records into its own command buffer
根據Minutes for GPU Web meeting 2019-08-05 -> Multi threading:
其中的1,2,3正在實現中;
4, 5會最終實現(沒有說好久實現);
根據我目前的調查:
1.shader編譯和建立pipeline state目前是同步的,還不是非同步的。
2.在WebGPU 規範中,GPUTexture,GPUBuffer,GPUDevice,GPUComputePipeline,GPURenderPipeline,GPUShaderModule是Serializable的,意味著可以傳給worker。
那是不是現在已經可以在worker中使用它們,從而實現1,2,3呢?需要進一步驗證!
擴充套件閱讀
引擎對於多執行緒的封裝:
Parallelizing the Naughty Dog Engine using Fibers
Destiny’s Multi-threaded Renderer Architecture
記憶體管理
介紹
與memory barriers類似,現代圖形API需要程式設計師自己管理GPU的資源。
如Memory Management in Vulkan™ and DX12所示:
參考資料
Memory Management in Vulkan™ and DX12
WebGPU支援情況
根據WebGPU as low level graphics API:
WebGPU compares closest to Metal (probably since Apple is the one that originally proposed it)--both don't require manual memory management while DX12 and Vulkan do
不需要手動管理memory,WebGPU會幫我們管理
延遲渲染
defer shading
包括兩個步驟:
第一個pass遍歷gameObjects,建立gbuffer;
第二個pass遍歷lights,使用gbuffer計算光照。
相對於前向渲染,它的優點是隻在螢幕上出現的畫素中計算SHADING,從而使複雜度由O(M * N)將為O(M) + O(N)
WebGPU支援情況
因為支援MRT(多渲染目標),所以支援延遲渲染。
值得一提的是兩個優化的方向:
- 優化記憶體訪問
在Investigation: Managing on-chip memory中提到:
第一個pass建立gbuffer後,gbuffer的資料會從on-chip記憶體移到主記憶體中;
第二個pass讀取gbuffer時,將gbuffer的資料從主記憶體移到on-chip記憶體。
gbuffer的資料來回移動,造成了效能損失。
因此在Add render sub-passes中,建議增加render的子pass,在子pass中讀取gbuffer,從而實現在建立和讀取gbuffer期間,gbuffer的資料一直在on-chip記憶體中。
Minutes for GPU Web meeting 2019-10-28也討論了這一點。
WebGPU可能會在extension中支援這個優化。
- 針對tile-based defer shading,使用compute shader,在第二個pass中剔除光源,剩餘的光源參與光照計算
正如DirectX 11 Rendering in Battlefield 3所說:
Hybrid Graphics/Compute shading pipeline:
› Graphics pipeline rasterizes gbuffers for opaque surfaces
› Compute pipeline uses gbuffers, culls lights, computes lighting &
combines with shading
› Graphics pipeline renders transparent surfaces on top
參考資料
延遲著色法
Optimizing tile-based light culling
DirectX 11 Rendering in Battlefield 3
textureless defer render
介紹
在defer shading的第一個pass中,我們將gameObject的幾何資料(如Position, Normal等)和材質貼圖資料(如從diffuse map中獲得的diffuse)存到gbuffer中。
有了bindless texture的支援,我們可以對此進行優化:
- gbuffer不再儲存材質貼圖的資料,而是儲存uv和material id。在第二個pass中,shader根據它們去獲取對應材質貼圖texture的資料
這樣做的優點是:
1.減少了gbuffer的大小
2.只在可見的畫素中,取樣texture的資料,減少了取樣次數
這樣做也存在一些問題,不過都是可以解決的:
具體可以參考什麼是deferred material shading?是否會在未來流行開來?:
1.多材質如何做deferred shading?總不能每個畫素做動態分支,一個一個判斷吧。有人提出了做tile把畫素區塊合併,然後一次性dispatch,效能會高很多。至於vgpr,sgpr,lds佔用率之類需要通盤考慮,偏向一邊都會影響效能。
2.結果SSAO,SSR之類的post effect還是需要用到normal,roughness之類的g-bufffer資訊。應用上還是需要權衡利弊。
以及參考Deferred Texturing:
What about mip levels, or derivatives?
- gbuffer不儲存幾何資料,而是儲存primitive ID。在第二個pass中,接收vertex data,在每個可見畫素上執行vertex shader
具體可以參考Deferred Texturing -> Defer All The Things:
It stores only primitive IDs in its G-buffer; then in a later pass, it fetches vertex data, re-runs the vertex shader per pixel (!), finds the barycentric coordinates of each fragment within its triangle, interpolates the vertex attributes, then finally samples all the textures and does the shading work.
WebGPU支援情況
根據本文後面bindless texture的分析,目前WebGPU不支援bindless texture
或許可用texture 2d array代替bindless texture,從而使用WebGPU實現textureless defer render
參考資料
Deferred Texturing
什麼是deferred material shading?是否會在未來流行開來?
BINDLESS TEXTURING FOR DEFERRED RENDERING AND DECALS
Modern textureless deferred rendering techniques
GPU Driven Render Pipeline
介紹
這個技術應該是在[Siggraph15] GPU-Driven Rendering Pipelines中提出來的。它的思想是把渲染任務從CPU端移到GPU端,減少CPU與GPU的同步和資料傳輸,實現1個draw call就渲染整個場景,從而提高GPU的利用率。
優點
GPU更細粒度的Visibility
不需要在CPU和GPU之間來回傳遞資料
應用場景
繪製大量的靜態物體
繪製人群
繪製模組化半自動生成內容
主要步驟
離線處理
1.分解gameObject的mesh為多個cluster
參考GPU Driven Pipeline — 工具鏈與進階渲染
CPU
1.對gameObject進行粗粒度的frustum cull
2.使用persistent map buffer,準備GPU的資料
可以按照資料的型別,建立多個mapped buffer(如一個buffer儲存人群的資料,另一個buffer儲存所有靜態物體的資料)
3.使用virtual texture處理texture
所有的texture資料一次性全部準備好,只繫結一次texture
4.用indirect draw發起multi draw call,提交mapped buffer
WebGPU目前不支援multi draw,因此需要發起多個draw call,每個draw call使用indirect draw提交對應的mapped buffer
GPU
1.對gameObject進行frustum cull和occlusion cull
2.對gameObject的cluster進行frustum cull和occlusion cull
3.修改index buffer,生成新的indices資料
根據Proposal: Run all index buffers through a compute shader validator:
I'm inclined to propose that WebGPU MVP doesn't support index buffers changed on the GPU, since this is quite a bit of headache, but eventually we can do that.
...
In an actual 1.0 release we'll absolutely need to support GPU-generated indices, there is no question here.
WebGPU MVP不會支援在GPU端修改index buffer,1.0版本會支援。
4.multi draw call
根據ExecuteIndirect investigation:
In order to issue draw calls on the CPU, there must be a synchronization point where the CPU waits for the GPU update to complete. This is particularly devastating for WebGPU, where if the CPU has to wait for the GPU, you miss your implicit present and now you're a frame late. Being able to issue these commands on the GPU directly means the rendering and update steps can be in sync.
在GPU端發起draw call可以去掉“CPU和GPU同步”的開銷。
However, making it an extension seems valuable.
可能會在WebGPU extension中支援該特性。
總結
GPU Driven Render Pipeline可以一次性取得所有mesh data,通過virtual texture可以取得所有texture,意味著整個場景只需要一次drawcall
參考資料
[Siggraph15] GPU-Driven Rendering Pipelines
[GDC16] Optimizing the Graphics Pipeline with Compute
知乎大神MaxwellGeng關於GPU Driven Rendering Pipelines的相關文章1
知乎大神MaxwellGeng關於GPU Driven Rendering Pipelines的相關文章2
現在我們介紹下GPU Driven Render Pipeline相關的概念和技術要點:
Approaching zero driver overhead
這個概念(簡稱為AZDO)出自approaching-zero-driver-overhead,它分析了OpenGL如何使用GPU實現CPU端0負載,具體包括下面幾個方面:
- persistent map buffer
介紹
該技術是為了在“CPU把資料傳輸到GPU“時減小資料傳輸的開銷。
它包括下面的步驟:
1.對映GPU的buffer到CPU
2.在CPU端修改這個mapped buffer的資料(因為mapped buffer在shared memory中,CPU和GPU都可以訪問它,所以要使用fence同步來確保GPU沒操作這個buffer)
3.提交修改buffer資料的command
4.GPU執行該command,更新buffer資料
通過上面的步驟,不再需要“從CPU傳輸新buffer的資料到GPU”了,減小了開銷
參考資料:
Persistent mapped buffers
Persistent Mapped Buffers in OpenGL
WebGPU支援情況
有兩種方式實現“CPU把資料傳輸到GPU“:
1.呼叫GPUBuffer->setSubData方法
該方法效能差,需要從CPU傳輸資料到GPU(WebGPU規範並沒有定義該方法,但是Chrome的WebGPU實現目前有該方法)
2.使用persistent map buffer技術
對於該方法,有以下的要點要說明:
1)不需要fence
WebGPU提供了GPUBuffer->unmap方法,該方法將buffer設定為unmapped state,使該buffer能夠被GPU使用。
WebGPU應該在該方法中幫我們做了fence同步的工作。
2)如何建立mapped buffer?
有兩種方式建立:
a)呼叫GPUDevice->createBufferMapped方法,建立mapped buffer
Make it easier to upload data into buffers correctly指出:
createBufferMapped建立的buffer會使記憶體增加,因此需要destory它。
b)呼叫GPUBuffer->mapReadAsync,mapWriteAsync,將buffer設定為mapped buffer
Make it easier to upload data into buffers correctly指出,使用mapWriteAsync會造成一些問題:
in WebGPU, have an implicit present after rAF() returns
...
Using mapWriteAsync() requires you to wait on a promise, so if you do the naive thing and just wait on the promise inside rAF(), you’ll miss your present
...
Could we replace mapWriteAsync returning a Promise with it taking a callback that is guaranteed to execute before any submitted queue bundles are executed?
其中“rAF”指“requestAnimationFrame”
我們根據示例程式碼來說明下這個問題:
function frame(time){
...
const vertexBuffer = device.createBuffer({
...
usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.COPY_SRC,
});
vertexBuffer.mapWriteAsync().then((vertexBufferData) => {
設定vertexBufferData
vertexBuffer.unmap();
提交修改buffer資料的command到佇列中
...
});
window.requestAnimationFrame(frame);
}
因為mapWriteAsync是非同步操作,而frame函式是同步操作,所以當執行到unmap時,可能已經執行了好幾次frame(過了好幾幀)。
在這幾幀中,可能提交了其它的command到佇列,WebGPU可能會在這幾幀之間提交了佇列中的command到GPU,GPU可能已經執行了其中的一些command。
執行unmap時,我們預期GPU還沒有執行其它的command,但實際上可能已經執行了。這樣會造成不同步的錯誤。
為了解決該問題,或許可以使用await關鍵字,將mapWriteAsync變成同步操作。
示例程式碼如下:
async function frame(time){
...
var vertexBufferData = await vertexBuffer.mapWriteAsync();
設定vertexBufferData
vertexBuffer.unmap();
提交修改buffer資料的command到佇列
...
}
這裡給出使用persistent map buffer技術的參考程式碼(來自Buffer operations)
(參考程式碼通過“呼叫GPUDevice->createBufferMapped方法”來建立mapped buffer):
//Updating data to an existing buffer(destBuffer)
function bufferSubData(device, destBuffer, destOffset, srcArrayBuffer) {
const byteCount = srcArrayBuffer.byteLength;
const [srcBuffer, arrayBuffer] = device.createBufferMapped({
size: byteCount,
usage: GPUBufferUsage.COPY_SRC
});
new Uint8Array(arrayBuffer).set(new Uint8Array(srcArrayBuffer)); // memcpy
srcBuffer.unmap();
const encoder = device.createCommandEncoder();
encoder.copyBufferToBuffer(srcBuffer, 0, destBuffer, destOffset, byteCount);
const commandBuffer = encoder.finish();
const queue = device.getQueue();
queue.submit([commandBuffer]);
srcBuffer.destroy();
}
參考資料
Make it easier to upload data into buffers correctly
Buffer operations
Minutes for GPU Web meeting 2019-10-21
- indirect draw
介紹
以WebGPU為例,draw方法需要指定頂點個數、例項個數等資料,每次只能繪製一個gameObject(可以批量繪製多個例項instance):
void draw(unsigned long vertexCount, unsigned long instanceCount, unsigned long firstVertex, unsigned long firstInstance);
而indirect draw可以使用buffer進行批量繪製多個gameObject(也可以批量繪製多個例項),這個buffer包含了每個gameObject的頂點個數等資料:
void drawIndirect(GPUBuffer indirectBuffer, GPUBufferSize indirectOffset);
優點
1.可以在compute shader修改buffer的資料,從而實現gpu cull
2.減少了繪製gameObject的次數
3.減少了CPU和GPU之間的同步開銷
WebGPU支援情況
支援Indirect draw/dispatch,相關討論參考 Indirect draw/dispatch commands investigation
參考資料
What are the advantage of using indirect rendering in OpenGL?
vulkan Indirect drawing
INDIRECT RENDERING : “A WAY TO A MILLION DRAW CALLS”
Surviving without gl_DrawID
- bindless texture and virtual texture
bindless texture和virtual texture可以結合使用,實現“只繫結一次texture”。
具體參見本文後面的說明:
其它->Bindless Texture
其它->Virtual Texture
GPU Cull
在GPU端實現剔除。
實現思路
1.建立persistent map buffer,indirect draw該buffer
2.在compute shader進行cull操作,將剩餘的gameObject對應的draw call資料(如頂點個數)寫到該buffer中
相關技術要點
- 剔除的目標可以是gameObject的整個mesh,也可以是部分mesh(以cluster為單位)
具體可參考GPU Driven Pipeline — 工具鏈與進階渲染
- frustum cull
通過判斷目標是否在主相機的視錐體中,來實現剔除
具體可參考(程式向)Unity3D GPU繪製管線(1)
- occlusion cull
通過判斷目標是否被遮擋,來實現剔除
具體可參考Hi-Z GPU Occlusion Culling
GPU Lod
在GPU端實現lod。
這個我沒有仔細研究,讀者可以參考相關資料:
谷歌搜尋結果
GPU based dynamic geometry LOD
Hybrid Render For Real-time Ray Tracing
介紹
以前Ray Tracing只在離線渲染中使用(如製作CG電影,一般會使用path tracing來加快收斂速度),現在隨著DXR(DirectX Raytracing)的釋出,新增了Ray Tracing管線,提出了專為Ray Tracing設計的shader,再配合上新的降噪方法(如使用SVGF降噪演算法或者NVDIA提供的基於AI的降噪SDK),能夠實現實時的Ray Tracing!
混合渲染
完全用Ray Tracing來渲染太耗效能,所以目前業界使用混合方案來實現實時Ray Tracing:
如果支援DXR,可以使用“光柵化管線 + Ray Tracing管線”來實現;
如果不支援DXR,可以使用“光柵化管線 + Compute管線(即使用compute shader)”來實現。
我們可以把渲染分解為:
如何使用WebGPU學習和實現Ray Tracing
可以按照下面的步驟:
1.廣泛收集相關資料,對整個技術體系有初步的瞭解(讀者可以看下面的“學習資料”)
2.參考Ray Tracing in One Weekend、Ray Tracing: The Next Week、對應的詳解,使用fragment shader,從0實現Ray Tracing。
目前只需要渲染球體或者立方體就好了,不用渲染模型。
3.使用compute shader實現Ray Tracing
4.使用混合渲染(如使用光柵化實現GBuffer和直接光照,使用Ray Tracing實現陰影和反射)
5.實現降噪演算法
直接實現SVGF很有難度,可以先實現其中的子環節(如temporal anti aliasing、tone map、Edge-Avoiding À-Trous等),然後再把它們組裝起來,實現SVGF
6.渲染模型
需要實現BVH
7.進一步研究和實現,探索path tracing、優化取樣、優化光線排序和連貫性、支援更多的材質等方向
學習資料
一篇光線追蹤的入門
光線追蹤與實時渲染的未來
Introduction to NVIDIA RTX and DirectX Ray Tracing
如何評價微軟的 DXR(DirectX Raytracing)?
Daily Pathtracer!安利下不錯的Pathtracer學習資料
Ray Tracing in One Weekend
Ray Tracing: The Next Week
Ray Tracing in One Weekend和Ray Tracing: The Next Week的詳解
基於OpenGL的GPU光線追蹤
Webgl中採用PBR的實時光線追蹤
Spatiotemporal Variance-Guided Filter, 向實時光線追蹤邁進
系統學習Ray Tracing的資料:Ray Tracing Gems
其它
Bindless Texture
在WebGPU中,什麼是bind texture?
Investigation: Bindless resources提到:
Currently, in WebGPU, if a draw/dispatch call wants to use a resource, that resource must be part of a pre-baked "bind group" and then associated with the draw call inside the current render/compute pass. This means that all the resources that the draw/dispatch call could possibly access are explicitly listed by the programmer at the draw/dispatch site.
也就是說,我們需要定義每個texture在shader的binding,然後在每次提交command時,繫結該texture。
我們來看具體的textureCube sample:
繫結的texture需要在shader中指定binding:
//在fragment shader中指定binding為2
const fragmentShaderGLSL = `#version 450
...
layout(set = 0, binding = 2) uniform texture2D myTexture;
在BindGroup中,設定binding為2的相關資料:
const bindGroupLayout = device.createBindGroupLayout({
bindings: [
...
{
// Texture view
binding: 2,
visibility: GPUShaderStage.FRAGMENT,
type: "sampled-texture"
}]
});
...
const uniformBindGroup = device.createBindGroup({
layout: bindGroupLayout,
bindings: [
...
{
binding: 2,
resource: cubeTexture.createView(),
}],
});
把BindGroup設定到Pipeline中:
const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] });
const pipeline = device.createRenderPipeline({
layout: pipelineLayout,
...
});
提交command時,設定該bind group和pipeline:
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setPipeline(pipeline);
passEncoder.setBindGroup(0, uniformBindGroup);
...
passEncoder.endPass();
在WebGPU中,什麼是bindless texture?
Investigation: Bindless resources提到:
"Bindless" is a model where the programmer doesn't explicitly list all of the available resources at the draw/dispatch site. Instead, a large swath of resources are made available to the GPU ahead of time (e.g. during application launch) and then shaders can access any/all of them at runtime.
可以將所有的texture設定到一個buffer中,將其傳給GPU,然後shader可以在執行時操作任意的texture。
這樣的好處是我們不需要在每次提交command時繫結特定的texture,只需要繫結一次。
如果不支援bindless texture,可以使用texture 2d array替代
參考approaching-zero-driver-overhead->36頁,我們可以使用texture 2d array代替bindless texture,只需要繫結一次texture 2d array,不需要在每次提交command時繫結特定的texture。
texture 2d array的優點參考:
為什麼要強調Texture2DArray在地形上的應用?
缺點是texture array中的每個texture的大小、格式要相同,而bindless texture沒有該要求。
為了解決該缺點,我們可以按照大小和格式,把texture劃分為多組,對應多個texture 2d array。
WebGPU支援情況
從Minutes for GPU Web meeting 2019-08-12中得知,目前還未決定何時實現bindless texture,可能實現為extension,可能在1.0版本後實現。
所以目前可考慮用texture 2d array作為替代品
參考資料
OPENGL AZDO : BINDLESS TEXTURES : BATCHING PROBLEM SOLVED
Virtual Texture
思想
把所有要用到的texture拼到一起,組成physic texture;
通過索引,只把當前要用到的texture載入到記憶體中。
優點
1.只繫結一次texture
2.組成physic texture的子紋理的格式和mipmap等可以不一樣;
3.減小了記憶體佔用(記憶體中只有當前使用的texture)
缺點
因為要不斷地在記憶體中載入/解除安裝texture,所以增加了IO開銷
應用場景
- 地形紋理
WebGPU支援情況
有人提出了Investigation: Sparse Resources, 希望WebGPU增加操作堆heap的API。不過目前沒有迴應。
我目前不清楚WebGPU是否能實現virtual texture
參考資料
approaching-zero-driver-overhead -> Sparse Texture
知乎->Virtual Texture Tools & Practices
關於對virtual texture的淺顯認識
Tessellation
根據Investigation: Tessellation:
Let's wait until after the release of a MVP
WebGPU應該會在MVP後考慮加入Tessellation shader
Mesh Shader
介紹
NVDIA在Turing架構中推出了新的管線,用來替代光柵化管線。新管線只保留了Pixel Shader(即fragment shader),新增了Task Shader和Mesh Shader,如下圖所示:
新管線更適合於GPU Driven Render Pipeline的理念,包括以下的特性:
類似於Compute管線(compute shader),具有強大的計算能力;
把Mesh分解為Meshlet(類似於GPU Driven Render Pipeline中提到的Cluster),更好地支援cluster cull。
WebGPU支援情況
根據Investigation: Tessellation中的討論,因為Vulkan和Metal還沒支援Mesh Shader,所以WebGPU至少要等它們支援後才會考慮支援。
參考資料
DX12支援了Mesh Shader
Introduction to Turing Mesh Shaders
怎麼評價nvidia 推出mesh shader管線