代碼見: https://github.com/onsummer/my-dev-notes/tree/master/webgpu-Notes/01-triangle

如果本篇的代碼不能跑了,請聯系我或自己看看檔案試試修改,
2021年3月31日
入口:navigator.gpu
WebGL1 或 WebGL2 是從 canvas.getContext('webgl') 這樣獲取一個背景關系物件來進行一切操作的,
而 WebGPU 則直接從瀏覽器物件中獲取一個附件一樣的東西:navigator.gpu,如果你在控制臺獲取這玩意兒獲取不到,說明你沒開實驗特性或瀏覽器壓根不支持 WebGPU,
這就很像從主機里掏出一張顯卡一樣,
配接器 & 設備
代碼最開始要從這個 gpu 物件里請求一個“配接器(adapter,是 er 不是 or)”,然后從配接器里請求一個“設備(device)”,
const adapter = await navigator.gpu.requestAdapter()
const device = await adapter.requestDevice()
配接器,指的是物理顯卡,聰明的你一定能猜到,除了N卡,還有高通驍龍上面的 SoC 圖形處理器,所以這個 requestAdapter() 是可以傳遞引數的,
設備,即把物理顯卡進行邏輯物件化,當呼叫 requestDevice() 時,允許請求一些顯卡的擴展特性,就像 WebGL 會通過請求擴展來引入額外的功能一樣,
后續代碼中,大量的操作均以函式呼叫的方式,由設備發出,這個設備物件,就類似 WebGL 的 context,區別的地方,就是“設備”它是顯卡功能的集合體,更接近顯卡本身,而 context 只是與顯卡對話的中間人,是一個背景關系物件,
休息一下!
交換鏈、渲染管線、WebGPU背景關系、編碼器
不理解 WebGPU 的渲染流程,就沒辦法進行下一步的,
關于交換鏈的描述,這里 講得比我好,
- canvas -創建-> WebGPU背景關系 -創建-> 交換鏈 -創建-> canvas像素記憶體視圖(視圖用于操作像素記憶體,輔助交換鏈的交換作業,將顯卡上渲染好的資料寫入像素記憶體)
- 設備 -創建-> “命令”編碼器 -創建-> “渲染通道”編碼器
渲染進行時,渲染通道編碼器 會將 “渲染通道描述物件”,通過 交換鏈 繪制到 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()
})
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/270800.html
標籤:其他
上一篇:2021簡單規劃
