WebGPU入门

1. 引言

前序博客:

WebGPU——Draft 2023.7.17 由苹果、谷歌、Mozilla团队发起,当前处于草稿阶段,旨在成为W3C推荐标准。

WebGPU为 在图形处理单元(GPU)上执行诸如渲染和计算之类的操作 提供了API。

GPU支持丰富的渲染和并行计算应用。WebGPU是通过API,将GPU的硬件能力 供Web使用。WebGPU API为对原生GPU API进行高效映射。WebGPU与WebGL无关,且不明确锚定OpenGL ES (OpenGL for Embedded Systems)。

WebGPU:

  • 1)将物理GPU硬件看成是GPUAdapter。
  • 2)通过GPUDevice来连接GPUAdapter。
  • 3)GPUDevice的GPUQueue用于执行指令。
  • 4)GPUDevice可能有自身的内存,可高速访问处理器单元。
  • 5)GPUBuffer和GPUTexture是由GPU内存支持的物理资源。
  • 6)GPUCommandBuffer和GPURenderBundle是用户录制(user-recorded)指令的容器。
    GPU执行编码在GPUCommandBuffer内的指令,通过pipeline来喂入数据。
    • 6.1)GPUCommandBuffer:由fixed-function和programmable stages混合组成。
      • Programmable stages执行shaders,shaders为设计运行于GPU硬件上的特定程序。shaders代码运行在GPU硬件的计算单元内。
    • 6.2)pipeline:大多数pipeline状态由GPURenderPipeline或GPUComputePipeline对象定义。
      不包含在pipeline对象中的状态则通过指令编码阶段设定,如beginRenderPass()或setBlendConstant()。
  • 7)GPUShaderModule包含着色器(shader)代码。
  • 8)GPUSampler或GPUBindGroup,用于配置GPU使用物理资源的方式。
  • 9)未来将通过Web Workers来支持多线程。

2. 坐标系统

渲染(rendering)操作可采用如下坐标系统:【注意,WebGPU的坐标系统 与 某graphics pipeline内的DirectX坐标系统 匹配。】

  • 1)归一化设备坐标(Normalized device coordinates(NDC)):具有3个维度:

    • − 1.0 ≤ x ≤ 1.0 -1.0\leq x \leq 1.0 1.0x1.0
    • − 1.0 ≤ y ≤ 1.0 -1.0\leq y \leq 1.0 1.0y1.0
    • 0.0 ≤ z ≤ 1.0 0.0\leq z \leq 1.0 0.0z1.0
    • 左下角坐标为 ( − 1.0 , − 1.0 , z ) (-1.0, -1.0, z) (1.0,1.0,z)
  • 2)Clip space坐标:具有4个维度 ( x , y , z , w ) (x,y,z,w) (x,y,z,w)

    • 2.1)Clip space坐标可:
      • 用作某vertex的clip position(即某vertex shader的position output)。
      • 用作clip volume。
    • 2.2)Clip space坐标 与 归一化设备坐标 之间的关系为:
      • 若point p = ( p . x , p . y , p . z , p . w ) p=(p.x,p.y,p.z,p.w) p=(p.x,p.y,p.z,p.w)在clip volume内,则其归一化设备坐标为 ( p . x ÷ p . w , p . y ÷ p . w , p . z ÷ p . w ) (p.x\div p.w, p.y \div p.w, p.z \div p.w) (p.x÷p.w,p.y÷p.w,p.z÷p.w)
  • 3)Framebuffer坐标:用于对framebuffer内的pixels进行寻址:

    • 3.1)具有2个维度。
    • 3.2)每个pixel在 x x x y y y维度的单位为1。
    • 3.3)左上角坐标为 ( 0.0 , 0.0 ) (0.0, 0.0) (0.0,0.0)
    • 3.4) x x x向右侧增长。
    • 3.5) y y y向下侧增长。
  • 4)Viewport坐标:在Framebuffer坐标 x , y x,y x,y维度的基础上,增加了depth z z z

    • 通常 0.0 ≤ z ≤ 1.0 0.0\leq z\leq 1.0 0.0z1.0,但可通过setViewport()来修改minDepth和maxDepth。
  • 5)Fragment坐标:与vIewport坐标匹配。

  • 6)UV坐标:用于sample textures,具有2个维度:

    • 0 ≤ u ≤ 1.0 0\leq u\leq 1.0 0u1.0
    • 0 ≤ v ≤ 1.0 0\leq v\leq 1.0 0v1.0
    • ( 0.0 , 0.0 ) (0.0, 0.0) (0.0,0.0)为texture内存地址顺序上的首个texel。
    • ( 1.0 , 1.0 ) (1.0, 1.0) (1.0,1.0)为texture内存地址顺序上的最后一个texel。
  • 7)Window坐标 或 present坐标:与framebuffer坐标匹配,用于与外部显示等接口交互。

3. WebGPU编程模型

3.1 Timeline

WebGPU的行为以“timeline”来表示。算法内的每个操作都发生在某timeline。timeline会明确定义操作顺序以及某操作对应某state。
WebGPU的timeline类型有:【Immutable value可用于任意timeline】

  • 1)Content timeline:与Web script执行关联。包含了调用本协议的所有方法。
  • 2)Device timeline:与User agent发布的GPU device operations关联。包括:
    • 创建adapters、devices、GPU resources以及state objects。从user agent角度来看,这些为经典的同步操作。
  • 3)Queue timeline:与GPU计算单元内的操作执行关联。包含实际运行在GPU之上的draw、copy、compute jobs。

如GPUDevice.createBuffer():

  • 1)用户填充GPUBufferDescriptor 并为其创建一个GPUBuffer。这发生在Content timeline。
  • 2)User agent在Device timeline创建一个底层buffer。

3.2 内存模型

一旦在应用初始化阶段获得了某GPUDevice,则可将WebGPU平台描述为如下层次:

  • 1)User agent:用于实现本协议。
  • 2)具有该设备底层原生API驱动的操作系统。
  • 3)实际的CPU和GPU硬件。

不同层次具有不同的内存类型,user agent在实现本协议时需考虑到:

  • 1)script-owned内存:如由script创建的某ArrayBuffer,通常对GPU驱动不可访问。
  • 2)user agenet可能有不同的进程来负责运行与GPU驱动的content和communication。此时,使用跨进程共享内存来传输数据。
  • 3)特定的GPU有其自身的高带宽内存,这些集成GPU通常与系统共享内存。

为使GPU的渲染或计算高效,大多数物理资源都以内存形式分配。当用户需要为GPU提供新数据时:【以下为最差情况,实际实现时,通常不需要跨越进程边界、或者可将驱动管理内存直接暴露给用户的ArrayBuffer,从而可避免数据拷贝。】

  • 1)数据可能首先得跨越进程边界,到达与GPU驱动通信的user agent部分。
  • 2)然后,可能需要使其对驱动可见,有时需要将其拷贝到驱动分配的staging memory中。
  • 3)最后,可能需要将数据传输到GPU专用内存中,可能会将内部layout转换为对GPU来说更可高效处理的方式。

所有以上数据转换同时通过WebGPU的user agentLai shixian d .

4. 关键内部对象

4.1 adapters

adapter用于标识某WebGPU实现:

  • 既为某浏览器的计算或渲染功能实例
  • 也为某浏览器的WebGPU实现实例。

adapter不会唯一标识底层实现,多次调用requestAdapter(),每次会返回不同的adapter对象。

每个adapter对象仅可用于创建一个device:

  • 当requestDevice()返回成功之后,该adapter将失效。
  • 此外,adapter对象可随时过期。

从而可确保应用使用 所选择的最新adapter系统状态来创建device,同时也增加了更多场景下的鲁棒性。

adapter暴露为GPUAdapter。

4.2 Devices

device为某adapter的逻辑实例化,从而创建了内部对象。可跨多个agents(如专用workers)共享。

device为 基于该device创建的所有内部对象的 外部owner:

  • 当device失效(lost或destroyed)时,基于该device创建的所有对象(通过createTexture()直接创建,或,通过createView()简介创建)都将implicitly 不可用。

5. 关键函数

  • 1)navigator.gpu:返回可用的GPU对象。

  • 2)gpu.requestAdapter():从user agent请求某adapter。

  • 3)adapter.requestDevice():向某adapter请求某device。

  • 4)adapter.requestAdapterInfo();获取某adapter的GPUAdapterInfo。

  • 5)device.destroy():destroy某device,防止未来对该device进行操作。异步操作将失败。可对同一device多次destroy。

  • 6)device.createBuffer():创建GPUBuffer。GPUBuffer表示用于GPU运算的一块内存。数据存储在linear layout中,即意味着分配的每个字节都可根据GPUBuffer起始位置的偏移来寻址,取决于具体运算有对齐限制。某些GPUBuffer可映射,使得可通过ArrayBuffer来访问该内存块。

  • 7)GPUBuffer.destroy():destroy GPUBuffer。

  • 8)GPUBuffer.mapAsync(mode, offset, size):其中mode有2种模式——读或写。映射之后可通过ArrayBuffer来访问GPUBuffer中的内容。

  • 9)GPUBuffer.getMappedRange(offset, size):返回GPUBuffer中指定映射范围的内容,为ArrayBuffer。

  • 10)GPUBuffer.unmap():解除映射,使得其内容可再次供GPU使用。

  • 11)device.createBindGroupLayout():表示将单个shader资源绑定到某GPUBindGroupLayout中。【与wgsl源文件的数量对应】
    其中 GPUShaderStage有3种类型:

    • VERTEX:可供vertex shaders访问。
    • FRAGMENT:可供fragment shaders访问。
    • COMPUTE:可供compute shaders访问。
  • 12)device.createBindGroup():创建GPUBindGroup。

  • 13)device.createShaderModule():创建GPUShaderModule。

  • 14)device.createPipelineLayout():创建GPUPipelineLayout。

  • 15) device.createComputePipeline():使用immediate pipline creation方式来创建GPUComputePipeline。

  • 16)device.createCommandEncoder():创建GPUCommandEncoder。

  • 17)GPUCommandEncoder.beginComputePass(descriptor):开始对由descriptor描述的某compute pass进行编码。

  • 18)dispatchWorkgroups(workgroupCountX, workgroupCountY, workgroupCountZ):将work分发给当前GPUComputePipeline执行。其中:

    • workgroupCountX:为X dimension of the grid of workgroups to dispatch。
    • workgroupCountY:为Y dimension of the grid of workgroups to dispatch。
    • workgroupCountZ:为Z dimension of the grid of workgroups to dispatch。

    即意味着,若某GPUShaderModule定义的entry point具有@workgroup_size(4, 4) 且 该work通过调用 computePass.dispatchWorkgroups(8, 8) 分发,则该entry point将总共触发1024次:

    • 分发4x4 workgroup 沿X轴8次,沿Y轴8次: 4 ∗ 4 ∗ 8 ∗ 8 = 1024 4*4*8*8=1024 4488=1024
  • 19)copyBufferToBuffer(source, sourceOffset, destination, destinationOffset, size):为GPUCommandEncoder中的命令,用于将某GPUBuffer sub-region内的数据 拷贝至 另一GPUBuffer的某sub-region。

  • 20)clearBuffer(buffer, offset, size):将某GPUBuffer的某sub-region数据清空,全部设置为0。

  • 21)device.queue.writeBuffer(buffer, bufferOffset, data, dataOffset, size):将特定数据写入GPUBuffer特定区域。

  • 22)device.queue.submit(commandBuffers):对GPU该queue中的command buffers执行进行调度。已提交的command buffers将不可再次使用。

  • 23)device.queue.onSubmittedWorkDone():当该queue完成了当前已提交的所有work时,会返回一个Promise。

参考资料

[1] WebGPU——Draft 2023.7.17

猜你喜欢

转载自blog.csdn.net/mutourend/article/details/131991107