代碼見: https://github.com/onsummer/my-dev-notes/tree/master/webgpu-Notes/01-trianglegit
若是本篇的代碼不能跑了,請聯繫我或本身看看文檔試試修改。
2021年3月31日github
WebGL1 或 WebGL2 是從 canvas.getContext('webgl')
這樣獲取一個上下文對象來進行一切操做的。web
而 WebGPU 則直接從瀏覽器對象中獲取一個附件同樣的東西:navigator.gpu
,若是你在控制檯獲取這玩意兒獲取不到,說明你沒開實驗特性或瀏覽器壓根不支持 WebGPU。canvas
這就很像從主機裏掏出一張顯卡同樣。瀏覽器
代碼最開始要從這個 gpu 對象裏請求一個「適配器(adapter,是 er 不是 or)」,而後從適配器裏請求一個「設備(device)」。架構
const adapter = await navigator.gpu.requestAdapter() const device = await adapter.requestDevice()
適配器,指的是物理顯卡。聰明的你必定能猜到,除了N卡,還有高通驍龍上面的 SoC 圖形處理器,因此這個 requestAdapter()
是能夠傳遞參數的。異步
設備,即把物理顯卡進行邏輯對象化。當調用 requestDevice()
時,容許請求一些顯卡的擴展特性,就像 WebGL 會經過請求擴展來引入額外的功能同樣。async
後續代碼中,大量的操做均以函數調用的方式,由設備發出。這個設備對象,就相似 WebGL 的 context。區別的地方,就是「設備」它是顯卡功能的集合體,更接近顯卡自己,而 context 只是與顯卡對話的中間人,是一個上下文對象。函數
休息一下!佈局
不理解 WebGPU 的渲染流程,就沒辦法進行下一步的。
關於交換鏈的描述,這裏 講得比我好。
渲染進行時,渲染通道編碼器 會將 「渲染通道描述對象」,經過 交換鏈 繪製到 canvas 上。
編碼器如何訪問canvas?經過 this.swapChain.getCurrentTexture().createView()
建立出來的對象來訪問 canvas 上的像素內存,把顯存裏繪製好的數據寫入 canvas 上的像素內存。
const textureView = swapChain.getCurrentTexture().createView() const renderPassDescriptor = { colorAttachments: [{ attachment: textureView, loadValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 } }] } const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor)
「命令」編碼器經過傳遞進來的參數與交換鏈上的 canvas 像素內存做綁定,返回一個 「渲染通道」編碼器,「渲染通道」編碼器則經過設置渲染管線、調用函數來完成繪製。
passEncoder.setPipeline(pipeline) passEncoder.draw(3, 1, 0, 0)
最後,結束此渲染通道,結束指令編碼器,全部指令扔給設備。
passEncoder.endPass() device.queue.submit([commandEncoder.finish()])
若要進行代碼結構優化,不想堆屎山,恭喜你,一個將來將來的架構師正在發芽,當前進度:新建文件夾。
優化的第一步,先把如下三個對象提高生命週期:
渲染一次(幀)所需的着色器、編碼器、管線和數據可能不盡同樣,可是以上仨貨基本不變。
如今頂點數據寫死在着色器中,後續會從內存中讀取並傳入,相似 WebGLBuffer。
大體結構可佈局以下:
const adapter = // 請求適配器 const gtx4090ti = // 請求設備 const swapChain = // 從canvas上下文中獲取交換鏈 // 經典的 rAF function requestNewFrame() { const pipeline = // 建立管線 const cmdEncoder = // 建立命令編碼器 const passEncoder = // 建立渲染通道編碼器 /* passEncoder 設置繪製命令 */ // 搞定了當前幀的全部準備,提交給設備 requestAnimationFrame(requestNewFrame) } requestNewFrame()
或者使用異步的寫法
async function init(/*參數*/) { const adapter = await ...// 請求適配器 const gtx4090ti = await ...// 請求設備 const swapChain = // 從canvas上下文中獲取交換鏈 const requestNewFrame = () => { /* 建立管線、編碼器,使用編碼器進行繪製 */ requestAnimationFrame(requestNewFrame) } return requestNewFrame } init(/*傳參*/).then(requestFn => { requestFn() })