1. Core Concepts
This part will not be expanded in detail, and will be in-depth when writing tutorials later. The following are just the core concepts, which most WebGPU native programs need to touch, but not all.
① Adapters and equipment
The adapter, which is GPUAdapter
, refers to the real physical graphics card, and WebGPU gives an object to replace it:
const adapter = await navigator.gpu.requestAdapter()
It provides one of the most important behaviors, requesting a device object GPUDevice
:
const device = await adapter.requestDevice()
So what is Device? Actually, the graphics card is busy.
A WebGPU program is just an "upper-level package" of one of the three major graphics APIs. Except for WebGPU, there are far more programs that call the three major graphics APIs. Games, 3D modeling tools, and video codecs may all be called, or even directly. Call the SDK or driver provided by the GPU manufacturer.
Obviously, as a graphics card "itself", in order to work extremely efficiently, the adapter feeds it with data resources and instructions that have been translated, and perform calculations as focused as possible - just like a big boss can't manage all the machines, it's best The decision-making materials given to the boss have been sorted, and all he has to do is to use his years of experience to make decisions and sign quickly (the efficient boss = RTX4090, the small supermarket boss = GT1030).
So, who is responsible for communicating specific business with the heads of various departments (each program that requires graphics cards)?
I think it is the discretionary agent of the boss, usually the secretary + deputy general manager.
Different packages have different concepts, at least in WebGPU, this agent is called "device", GPUDevice
, it is almost the avatar of the graphics card, the resources to be called, the objects to be created, and the triggers to be triggered in the WebGPU program The behavior is handed over to the device object to implement.
Each WebGPU program should have its own GPUDevice
, Buffer, Texture and other resources created by different device objects are not interoperable, and the adapter is generally the same, unless you put the The graphics card of the computer has been changed. It was a standalone display a while ago, and it may be a nuclear display after a while (this sentence has yet to be technically verified, just my irresponsible guess).
If you have written native WebGL, you may think of gl context variables. Yes, device objects are mostly the role of gl context, but there are essential differences.
② Buffer, texture, sampler
Buffers and textures, namely GPUBuffer
and GPUTexture
are all data objects in GPU memory, which can be organized and created in client code (or JavaScript on the browser side if not specified) , upload data, convert each other, read data back.
When WebGPU renders drawing, Canvas is a special GPUTexture
.
The sampler is the parameter encapsulation when the shader program samples the texture.
It seems to be WebGL-like objects WebGLBuffer
, WebGLTexture
and the "upgrade" of the texture sampling function. In fact, it provides more detailed parameter transfer when data upload, texture and buffer conversion , and then read from the video memory to the memory "mapping mechanism" is very different.
These three objects are called "resources" and are created by GPUDevice
.
③ Binding group
Binding group, I prefer to call it "resource binding group", ie GPUBindGroup
; resources are any combination of "buffer, texture, sampler".
Using binding groups allows you to "group" a set of resources you need into the shader code, which is closely related to the "pipeline" below.
Why team up? Why can't I write a function to GPUBuffer
, GPUTexture
, GPUSampler
to a certain binding point one by one like WebGL?
There are two reasons:
- Performance point of view: grouping itself is a way to reduce the signal communication between CPU and GPU. Think about your hard disk, is it faster to transfer large continuous files or smaller files?
- Reuse perspective: Different coloring behaviors may use the same resource set, and the same binding group can be reused at this time; think about it, meat stuffing stuffed into a bun is called meat bun, and dumpling skin is meat Dumplings.
Binding groups are created by GPUDevice
which are called by the Programmable Channel Encoder in Section ⑤ and actually work with the pipeline.
④ Shaders and pipelines
The shader is GPUShaderModule
, and the pipeline generally refers to GPURenderPipeline
and GPUComputePipeline
.
The shader supports mixing any shader in a string. Vertex shaders, fragment shaders, and compute shaders can share a GPUShaderModule
object, just specify the entry function, which is separate from WebGL to create VS , FS is different.
The pipeline is not an upgrade of ---f99058b240725b5b49c1ecd27f74583d WebGLProgram
, although gl.useProgram
and passEncoder.setPipeline
have a similar effect in behavior, that is, switch to the specified behavior process, however, in WebGPU These two pipeline objects, in addition to attaching the corresponding shader objects, also define the state parameters corresponding to different stages of the pipeline. There are three state parameters corresponding to the two major pipelines:
- vertex, fragment
- compute
E.g:
/*
---------
这里不详细展开,仅作为简略
---------
*/
const positionAttribDesc: GPUVertexAttribute = {
shaderLocation: 0, // wgsl - @location(0)
offset: 0,
format: 'float32x3'
}
const colorAttribDesc: GPUVertexAttribute = {
shaderLocation: 1, // wgsl - @location(1)
offset: 0,
format: 'float32x3'
}
const positionBufferDesc: GPUVertexBufferLayout = {
attributes: [positionAttribDesc],
arrayStride: 4 * 3, // sizeof(float) * 3
}
const colorBufferDesc: GPUVertexBufferLayout = {
attributes: [colorAttribDesc],
arrayStride: 4 * 3, // sizeof(float) * 3
}
// --- 创建 state 参数对象
const vertexState: GPUVertexState = {
module: shaderModule,
entryPoint: 'vs_main',
buffers: [positionBufferDesc, colorBufferDesc]
}
const fragmentState: GPUFragmentState = {
module: shaderModule,
entryPoint: 'fs_main',
targets: [{
format: navigator.gpu.getPreferredCanvasFormat()
}],
}
const primitiveState: GPUPrimitiveState = {
topology: 'triangle-list'
}
// --- 渲染管线 ---
const renderPipeline = device.createRenderPipeline({
layout: 'auto',
vertex: vertexState,
fragment: fragmentState,
primitive: primitiveState
})
// --- 计算管线 ---
const computePipeline = device.createComputePipeline({
layout: 'auto',
compute: {
module: shaderModule,
entryPoint: 'cs_main',
}
})
Corresponding to GPUVertexState
, GPUFragmentState
, GPUComputeState
type; the above-mentioned binding group is closely related to the pipeline, these state parameter objects, and the binding group Each resource object in has a corresponding relationship.
Shader module objects and pipeline objects are also created by GPUDevice
and pipeline objects even provide methods for asynchronous creation.
⑤ Encoder and queue
WebGPU uses "encoders" to "record" what to do in a frame, such as switching pipelines, setting what buffers to use next, binding groups, and then what to do (drawing or triggering parallel computing).
What's the benefit of this?
The encoder "records" these actions, which is done on the CPU side, i.e. JavaScript, which solves the problem of WebGL's global state object: changing a state requires initiating one or more GL function calls (although using extensions or In WebGL 2.0, various techniques are used to make up, but also do not actually solve the problem).
After the encoding and recording is completed, an object called "instruction buffer" will be generated on the CPU side, and all the instruction buffers of the current frame will be submitted to a queue at one time, then the current frame will end the battle.
It is reasonable, most of the logical organization is done by the CPU that is better at handling these things, and finally sent to the GPU in a centralized manner, which is one of the advantages of WebGPU over WebGL.
What are the encoders?
The above paragraph is rather sketchy.
First of all, in order to distinguish between drawing operations and GPU general computing operations, WebGPU uses "rendering channel encoder" and "computing channel encoder", that is, GPURenderPassEncoder
, GPUComputePassEncoder
to achieve their respective behaviors Encoding and recording; take rendering channel encoding as an example:
The above image is referenced from the blog Raw WebGPU .
The "channel encoder" that can create these two specific GPU calculations is called an "instruction encoder", which is GPUCommandEncoder
:
In addition to carrying the encoding results of the above two channel encoders, the instruction encoder additionally provides encoding of resource copy behavior and query behavior, such as mutual copying between textures and buffer objects:
In the actual code, it is recorded in the order in which a method is called by GPUCommandEncoder
, for example, beginRenderPass()
, copyBufferToTexture()
and so on.
Queues and Instruction Buffers
The finish
method of the instruction encoder returns an instruction buffer object, ie GPUCommandBuffer
, which can be submitted to the queue object GPUQueue
, which is an instance of the device object field.
In addition to the instruction buffer, there are also behaviors on the "queue timeline" issued by the queue itself, such as writing buffer data, writing texture data, etc. The diagram is as follows:
2. Important Mechanisms
① Buffer mapping mechanism
Buffer mapping, simply put, is a mechanism that allows buffered data in memory and video memory to be exchanged. For detailed articles, please refer to:
# Buffer mapping mechanism in WebGPU
② Timeline
Different behaviors in the WebGPU specification may occur at different levels, and each level has its own timeline in the process of operation. The specification gives three timelines:
- Content timeline: Most of the behaviors on the content timeline are the creation of JavaScript objects and the invocation of JavaScript methods, which is the top layer;
- Device Timeline: This "device" is not
GPUDevice
; most of the behaviors on the device timeline refer to changes in the browser's underlying WebGPU implementation. Such behaviors are at a lower level than JavaScript execution. is an "internal object", but has not yet reached the part that the GPU executes, such as generating instruction buffers; - Queue timeline: This "queue" is not
GPUQueue
; the behavior that occurs on the queue timeline usually refers to the execution of specific tasks in the GPU, such as drawing, resource uploading, resource copying, general computing scheduling, etc.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。