owned this note
owned this note
Published
Linked with GitHub
# PSA for Chromium / Dawn WebGPU API updates 2021-04-07
Chromium's WebGPU implementation and Dawn's API try to closely follow changes to the WebGPU specification. When the WebGPU IDL changes, Chromium and Dawn will try to support both the deprecated and the new version of the IDL at the same time so prototypes can be updated. In JavaScript, uses of the deprecated path will result in a console warning, while when using Dawn directly, the deprecated path will print a warning to stderr.
Note that all changes to Dawn's API make it closer to [`webgpu.h`](https://github.com/webgpu-native/webgpu-headers/blob/master/webgpu.h) that we hope will allow applications to target both [Dawn](https://dawn.googlesource.com/dawn), and [wgpu](https://github.com/gfx-rs/wgpu/) in native before being compiled in WASM. Emscripten will also be updated from the "old" to the "new" API but won't have the smooth transition since developers control which version of emscripten they use.
A couple weeks after an update like this one, the "old" version will be removed. This means that the "old" version of the items below will start being removed from Chromium/Dawn starting on 2021-04-21.
Previous PSAs:
- [PSA for Chromium / Dawn WebGPU API updates 2020-10-19](https://hackmd.io/uH1MI9cnQBG9GGOZG20COw)
- [PSA for Chromium / Dawn WebGPU API updates 2020-07-28](https://hackmd.io/szV68rOVQ56GYzPJMBko8A)
- [PSA for Chromium / Dawn WebGPU API updates 2020-04-28](https://hackmd.io/Et7xlhoaThmi8dEX_s-xSw)
## WGSL improvements
The WGSL specification has made a lot of progress with most of the builtin functions specified and nice ergonomics improvements (with more likely coming). The implementation in Chromium is still evolving rapidly to catch up with the specification so we aren't offering a gradual deprecation like for the WebGPU API yet.
Around the last PSA, WGSL code looked like this:
```rust=
type MyData = [[block]] struct {
[[offset 0]] modelViewProjectionMatrix : mat4x4<f32>;
[[offset 64]] positionOffset : vec4<f32>;
};
[[binding 0, set 0]] var<uniform> u : MyData;
[[location 0]] var<in> position : vec4<f32>;]
[[builtin position]] var<out> Position : vec4<f32>;
[[location 0]] var<out> FragUV : vec2<f32>;
fn main() -> void {
const fixedPosition : vec4<f32> = position + u.positionOffset;
FragUV = position.xy * 0.5;
Position = u.modelViewProjectionMatrix * fixedPosition;
return;
}
entry_point vertex as "main" = main;
```
It now looks like this:
```rust=
[[block]] struct MyData {
modelViewProjectionMatrix : mat4x4<f32>;
positionOffset : vec4<f32>;
};
[[group(0), binding(0)]] var<uniform> u : MyData;
struct Outputs {
[[builtin(position)]] position : vec4<f32>;
[[location(0)]] fragUV: vec2<f32>;
};
[[stage(vertex)]] fn main([[location(0)]] position : vec2<f32>) -> Outputs {
let fixedPosition = position + u.positionOffset;
var outputs : Outputs;
outputs.fragUV = position.xy * 0.5;
outputs.position = u.modelViewProjectionMatrix * fixedPosition;
return outputs;
}
```
## Breaking changes
There are a lot of breaking changes this time, and a couple of them might require large changes (`GPUBindGroupLayoutEntry` and `GPURenderPipelineDescriptor`). The changes come both from feedback of WebGPU early adopters as well as some more focus on ergonomics from the WebGPU group.
The group looked at most of the API to see if changes are needed and no breaking changes are in the pipeline. That's why we are hopeful that there will be fewer breaking changed in the future.
### `OUTPUT_ATTACHMENT` -> `RENDER_ATTACHMENT`
WebGPU [PR](https://github.com/gpuweb/gpuweb/pull/1168)
Contrary to Vulkan, WebGPU doesn't have "input attachment" so there is not symmetry needed with `OUTPUT_ATTACHMENT`. For clarity it is renamed to `RENDER_ATTACHMENT`. In JavaScript the following changes are needed:
```diff=
const texture = device.createTexture({
dimension: '2d',
size: [4, 4],
format: 'rgba8unorm',
- usage: GPUTextureUsage.OUTPUT_ATTACHMENT,
+ usage: GPUTextureUsage.RENDER_ATTACHMENT,
});
```
Likewise when using Dawn’s API, changes are needed:
```diff=
wgpu::TextureDescriptor desc;
desc.dimension = wgpu::TextureDimension::e2D;
desc.size = {4, 4};
desc.format = wgpu::TextureFormat::RGBA8Unorm;
-desc.usage = wgpu::TextureUsage::OutputAttachment;
+desc.usage = wgpu::TextureUsage::RenderAttachment;
wgpu::Texture texture = device.CreateTexture(&desc);
```
### `GPUBindGroupLayoutEntry` changes
Main WebGPU [PR](https://github.com/gpuweb/gpuweb/pull/1223)
In order to keep the complexity of `BindGroupLayoutEntry` from exploding as more capabilities are added, it was refactored to isolate the properties needed for each type of binding.
An example of the change needed in JavaScript:
```diff=
const bindGroupLayout = device.createBindGroupLayout({
entries: [{
binding: 0,
visibility: GPUShaderStage.VERTEX,
- type: 'uniform-buffer'
+ buffer: {}
}, {
binding: 1,
visibility: GPUShaderStage.FRAGMENT,
- type: 'sampler'
+ sampler: {}
}, {
binding: 2,
visibility: GPUShaderStage.FRAGMENT,
- type: 'sampled-texture'
+ texture: {}
}, {
binding: 3,
visibility: GPUShaderStage.COMPUTE,
- type: 'storage-buffer'
+ buffer: { type: 'storage' }
}, {
binding: 4,
visibility: GPUShaderStage.FRAGMENT,
- type: 'sampled-texture'
- viewDimension: 'cube'
+ texture: { viewDimension: 'cube' }
}]
});
```
An example of the changes needed when using Dawn's API (note that at least one of `buffer.type`, `sampler.type`, `texture.sampleType` or `storageTexture.access+format` must be set):
```diff=
wgpu::BindGroupLayoutEntry entries[5];
entries[0].binding = 0;
entries[0].visibility = wgpu::ShaderStage::Vertex;
-entries[0].bindingType = wgpu::BindingType::UniformBuffer;
+entries[0].buffer.type = wgpu::BufferBindingType::Uniform;
entries[1].binding = 1;
entries[1].visibility = wgpu::ShaderStage::Fragment;
-entries[1].bindingType = wgpu::BindingType::Sampler;
+entries[1].sampler.type = wgpu::SamplerBindingType::Filtering;
entries[2].binding = 2;
entries[2].visibility = wgpu::ShaderStage::Fragment;
-entries[2].bindingType = wgpu::BindingType::SampledTexture;
+entries[2].texture.sampleType = wgpu::TextureSampleType::Float;
entries[3].binding = 3;
entries[3].visibility = wgpu::ShaderStage::Compute;
-entries[3].bindingType = wgpu::BindingType::StorageBuffer;
+entries[0].buffer.type = wgpu::BufferBindingType::Storage;
entries[4].binding = 4;
entries[4].visibility = wgpu::ShaderStage::Compute;
-entries[4].bindingType = wgpu::BindingType::StorageTexture;
-entries[4].format = wgpu::TextureFormat::RGBA8Unorm;
+entries[4].storageTexture.access = wgpu::StorageTextureAccess::ReadOnly;
+entries[4].storageTexture.format = wgpu::TextureFormat::RGBA8Unorm;
```
### Render pipeline changes
Main WebGPU [PR](https://github.com/gpuweb/gpuweb/pull/1352)
The GPURenderPipelineDescriptor format has been re-organized for clarity. See the table below for converting deprecated GPURenderPipelineDescriptors to the new format.
[Dawn Tracking Bug](https://bugs.chromium.org/p/dawn/issues/detail?id=642)
| Old key | New Key |
|------------------------------------------|--------------------------------------|
| `vertexStage.module` | `vertex.module` |
| `vertexStage.entryPoint` | `vertex.entryPoint` |
| `vertexState.vertexBuffers` | `vertex.buffers` |
| `vertexState.indexFormat` | `primitive.stripIndexFormat` |
| `primitiveTopology` | `primitive.topology` |
| `rasterizationState.frontFace` | `primitive.frontFace` |
| `rasterizationState.cullMode` | `primitive.cullMode` |
| `rasterizationState.depthBias` | `depthStencil.depthBias` |
| `rasterizationState.depthBiasSlopeScale` | `depthStencil.depthBiasSlopeScale` |
| `rasterizationState.depthBiasClamp` | `depthStencil.depthBiasClamp` |
| `depthStencilState.format` | `depthStencil.format` |
| `depthStencilState.depthWriteEnabled` | `depthStencil.depthWriteEnabled` |
| `depthStencilState.depthCompare` | `depthStencil.depthCompare` |
| `depthStencilState.stencilFront` | `depthStencil.stencilFront` |
| `depthStencilState.stencilBack` | `depthStencil.stencilBack` |
| `depthStencilState.stencilReadMask` | `depthStencil.stencilReadMask` |
| `depthStencilState.stencilWriteMask` | `depthStencil.stencilWriteMask` |
| `sampleCount` | `multisample.count` |
| `sampleMask` | `multisample.mask` |
| `alphaToCoverageEnabled` | `multisample.alphaToCoverageEnabled` |
| `fragmentStage.module` | `fragment.module` |
| `fragmentStage.entryPoint` | `fragment.entryPoint` |
| `colorStates[i].format` | `fragment.targets[i].format` |
| `colorStates[i].writeMask` | `fragment.targets[i].writeMask` |
| `colorStates[i].colorBlend` | `fragment.targets[i].blend.color` |
| `colorStates[i].alphaBlend` | `fragment.targets[i].blend.alpha` |
Note that Chromium/Dawn will now validate that `fragment.targets[i].blend` is `undefined` / `nullptr` if `fragment.targets[i].format` is a non-filterable format (i.e. integer or float32).
Some types part of the `GPUPipelineDescriptor` have been renamed. No changes are needed in JavaScript, but the following updates are required when using Dawn's API:
| Previous type | New type |
|-|-|
|`wgpu::BlendDescriptor`|`wgpu::BlendComponent`|
|`wgpu::StencilFaceStateDescriptor`|`wgpu::StencilFaceState`|
|`wgpu::VertexAttributeDescriptor`|`wgpu::VertexAttributes`|
|`wgpu::VertexBufferLayoutDescriptor`|`wgpu::VertexBufferLayout`|
Also when using Dawn's API the new render pipeline descriptor is called `wgpu::RenderPipelineDescriptor2` and passed to `wgpu::Device::CreateRenderPipeline2`. Of course this is only temporary and after the deprecation period, the "2" variant will be deprecated in favor of the old names (but with the new structure).
### `GPUDevice.defaultQueue` -> `GPUDevice.queue`
WebGPU [PR](https://github.com/gpuweb/gpuweb/pull/1367)
Since WebGPU does not yet support multiple queues, and many applications will only ever need one queue, the `GPUDevice`'s default queue has been renamed to simply `queue` to reduce the amount of typing needed.
An example of the change needed in JavaScript:
```diff=
-device.defaultQueue.submit([commandEncoder.finish()]);
+device.queue.submit([commandEncoder.finish()]);
```
Likewise when using Dawn’s API, changes are needed:
```diff=
-wgpu::Queue queue = device.GetDefaultQueue();
+wgpu::Queue queue = device.GetQueue();
```
### `GPUFence` -> `GPUQueue.onSubmittedWorkDone`
WebGPU [PR](https://github.com/gpuweb/gpuweb/pull/1217)
Since WebGPU does not yet support multiple queues, the `GPUFence` could only be used to watch the completion of work submitted to queues. Because of this extremely limited use, they are replaced with `GPUQueue.onSubmittedWorkDone` which is a `Promise` that resolves when the queue is done processing work submitted until this point.
In JavaScript the following changes are needed:
```diff=
-const fence = queue.createFence();
-queue.signal(fence, 1);
-await fence.onCompletion(1);
+await queue.onSubmittedWorkDone();
```
Likewise when using Dawn’s API, changes are needed:
```diff=
-wgpu::Fence fence = queue.CreateFence();
-queue.Signal(fence, 1);
-fence.OnCompletion(CompletionCallback, userdata);
+queue.OnSubmittedWorkDone(CompletionCallback, userdata);
```
### VertexFormat rename.
WebGPU [PR](https://github.com/gpuweb/gpuweb/pull/1322)
WebGPU's vertex formats were using `"char"`, `"short"` and similar terminology which wasn't used anywhere else (and isn't very descriptive if you don't know C/C++). To make it more clear it has been changed to use names like `"uint8"`, `"sint16"` and `"float32"`. See the table below for correspondances in the JavaScript API and Dawn's API.
| Old Javascript | New Javascript | Old Dawn | New Dawn |
|-|-|-|-|
| `"uchar2"` | `"uint8x2"` | `UChar2` | `Uint8x2` |
| `"uchar4"` | `"uint8x4"` | `UChar4` | `Uint8x4` |
| `"char2"` | `"sint8x2"` | `Char2` | `Sint8x2` |
| `"char4"` | `"sint8x4"` | `Char4` | `Sint8x4` |
| `"uchar2norm"` | `"unorm8x2"` | `UChar2Norm` | `Unorm8x2` |
| `"uchar4norm"` | `"unorm8x4"` | `UChar4Norm` | `Unorm8x4` |
| `"char2norm"` | `"snorm8x2"` | `Char2Norm` | `Snorm8x2` |
| `"char4norm"` | `"snorm8x4"` | `Char4Norm` | `Snorm8x4` |
| `"ushort2"` | `"uint16x2"` | `UShort2` | `Uint16x2` |
| `"ushort4"` | `"uint16x4"` | `UShort4` | `Uint16x4` |
| `"short2"` | `"sint16x2"` | `Short2` | `Sint16x2` |
| `"short4"` | `"sint16x4"` | `Short4` | `Sint16x4` |
| `"ushort2norm"` | `"unorm16x2"` | `UShort2Norm` | `Unorm16x2` |
| `"ushort4norm"` | `"unorm16x4"` | `UShort4Norm` | `Unorm16x4` |
| `"short2norm"` | `"snorm16x2"` | `Short2Norm` | `Snorm16x2` |
| `"short4norm"` | `"snorm16x4"` | `Short4Norm` | `Snorm16x4` |
| `"half2"` | `"float16x2"` | `Half2` | `Float16x2` |
| `"half4"` | `"float16x4"` | `Half4` | `Float16x4` |
| `"float"` | `"float32"` | `Float` | `Float32` |
| `"float2"` | `"float32x2"` | `Float2` | `Float32x2` |
| `"float3"` | `"float32x3"` | `Float3` | `Float32x3` |
| `"float4"` | `"float32x4"` | `Float4` | `Float32x4` |
| `"uint"` | `"uint32"` | `UInt` | `Uint32` |
| `"uint2"` | `"uint32x2"` | `UInt2` | `Uint32x2` |
| `"uint3"` | `"uint32x3"` | `UInt3` | `Uint32x3` |
| `"uint4"` | `"uint32x4"` | `UInt4` | `Uint32x4` |
| `"int"` | `"sint32"` | `SInt` | `Uint32` |
| `"int2"` | `"sint32x2"` | `Int2` | `Sint32x2` |
| `"int3"` | `"sint32x3"` | `Int3` | `Sint32x3` |
| `"int4"` | `"sint32x4"` | `Int4` | `Sint32x4` |
### CopyView type renames
WebGPU [PR](https://github.com/gpuweb/gpuweb/pull/1375)
To avoid confusion with the concept of `TextureView`s, the types `BufferCopyView`, `TextureCopyView`, and `ImageBitmapCopyView` have been renamed to `ImageCopyBuffer`, `ImageCopyTexture`, and `ImageCopyImageBitmap` respectively.
Since these types are dictionaries this rename has no effect on JavaScript code, other than to make the documentation a bit clearer.
When using Dawn's API, changes are needed:
```diff=
-wgpu::BufferCopyView bufferSrc;
+wgpu::ImageCopyBuffer bufferSrc;
bufferSrc.buffer = buffer;
bufferSrc.layout.offset = 0;
bufferSrc.layout.bytesPerRow = 1024;
bufferSrc.layout.rowsPerImage = wgpu::kCopyStrideUndefined;
-wgpu::TextureCopyView textureDst;
+wgpu::ImageCopyTexture textureDst;
textureDst.texture = texture;
textureDst.mipLevel = 0;
textureDst.origin = {0, 0, 0};
textureDst.aspect = wgpu::TextureAspect::All;
wgpu::Extent3D copySize = {1024, 1024, 1};
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.CopyBufferToTexture(&bufferSrc, &textureDst, ©Size);
```
### Dawn API `bytesPerRow` and `rowsPerImage` changes
Previously when doing 1D copies, validation ignored the value `bytesPerRow` so it was valid to set it to 0, or another value too small. This will now cause a validation error. Instead set `bytesPerRow` to `wgpu::kCopyStrideUndefined` (the default struct member value) or a value larger than the copy's size in bytes.
Likewise previously when doing 2D copies, validation ignored the value `rowsPerImage`. To avoid a validation error it must now be set to `wgpu::kCopyStrideUndefined` (the default struct member value) or a value larger than the copy's height.
Finally when doing 3D copies, a 0 value for `rowsPerImage` caused it to default to the copy height. This will now produce a validation error and you should use `wgpu::kCopyStrideUndefined` instead (the default struct member value
These changes are made to be closer to the Javascript API where `undefined` and 0 have different behaviors, and makes it easier to implement the Javascript API using Dawn's API.
### GPUExtent3DDict depth -> depthOrArrayLayers
WebGPU [PR](https://github.com/gpuweb/gpuweb/pull/1390)
Depending on context, the 3rd element of a `GPUExtent3DDict` may represent either a depth, as in the case of a 3D texture, or the number of layers, as in the case of a 2D array texture. To clarify this dual purpose, the `depth` attribute has been renamed to `depthOrArrayLayers`.
An example of the change needed in JavaScript:
```diff=
const texture = device.createTexture({
- size: { width: 16, height: 16, depth: 16 },
+ size: { width: 16, height: 16, depthOrArrayLayers: 16 },
dimension: '3d';
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.SAMPLED
});
```
Likewise when using Dawn’s API, changes are needed:
```diff=
wgpu::TextureDescriptor descriptor;
descriptor.size.width = 16;
descriptor.size.height = 16;
-descriptor.size.depth = 16;
+descriptor.size.depthOrArrayLayers = 16;
descriptor.dimension = wgpu::TextureDimension::e3D;
descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::Sampled;
wgpu::Texture texture = device.CreateTexture(&descriptor);
```
Note that both Javascript and Dawn's API support shorthand declarations with unspecified values defaulting to one.
In Javascript:
```js
[w, h] // Same as {width: w, height: h, depthOrArrayLayers: 1}
```
Using Dawn's API:
```cpp=
wgpu::Extent3D extent = {w, h};
// Is the same as
wgpu::Extent3D extent;
extent.width = w;
extent.height = h;
extent.depthOrArrayLayers = 1;
```
### getSwapChainPreferredFormat
It was determined that `getSwapChainPreferredFormat` didn't need to be asynchronous, and that it was more appropriate for it to accept a `GPUAdapter` than a `GPUDevice`.
An example of the change needed in JavaScript:
```diff=
const context = canvas.getContext('gpupresent');
-const swapChainFormat = await context.getSwapChainPreferredFormat(device);
+const swapChainFormat = context.getSwapChainPreferredFormat(adapter);
const swapChain = context.configureSwapChain({
device: device,
format: swapChainFormat
});
```
The Dawn API does not currently have an equivalent call, so no changes are needed.
### `SetIndexBufferWithFormat` -> `SetIndexBuffer`
In Dawn's API `SetIndexBuffer` was temporarily renamed to `SetIndexBufferWithFormat` while its signature was changed. Now that the signature is changed, `SetIndexBufferWithFormat` is deprecated in favor of `SetIndexBuffer` (with the updated signature).
### extensions->features rename
WebGPU [PR](https://github.com/gpuweb/gpuweb/pull/1097)
The WebGPU specification has started referring to what was previously called "Extensions" as "Features". This is because they include functionality that is present in the base spec but is not universally supported, and as such needs to be enabled explicitly (such as compressed texture formats).
In service of this change the `extensions` attribute on both `GPUAdapter` and `GPUDevice` has been renamed to `features`. Also, the `extensions` key of the `GPUDeviceDescriptor` dictionary has beed renamed to `nonGuaranteedFeatures`. The name `nonGuaranteedFeatures` was chosen to emphasize that the features requested in this array are not guaranteed to be supported on all platforms and devices, and as such should be verified against the `GPUAdapter.features` list prior to requesting. As was the case prior to the rename, specifying a feature in the `nonGuaranteedFeatures` that is not supported by the `GPUAdapter` will cause `requestDevice()` to fail.
An example of the change needed in JavaScript:
```diff=
let deviceDescriptor = {};
-const hasBCCompression = adapter.extensions.indexOf('texture-compression-bc') != -1;
+const hasBCCompression = adapter.features.indexOf('texture-compression-bc') != -1;
if (hasBCCompression) {
- deviceDescriptor.extensions = ['texture-compression-bc'];
+ deviceDescriptor.nonGuaranteedFeatures = ['texture-compression-bc'];
}
let device = await adapter.requestDevice(deviceDescriptor);
```
This change has not yet been made in Dawn, so no changes are required yet.
## New features and improvements
Most of the improvements to Dawn / Chromium for WebGPU are happening under the hood. Recently our focus has been on massively improving the security of our implementation in preparation for a future WebGPU Origin Trial. This includes reworking large parts of our cross-process remoting architecture, vastly expanded test coverage (and fixing all the tiny issues found in the spec etc), automatic fuzzing, etc.
Another huge effort is expanding usage of [Tint](https://dawn.googlesource.com/tint), our WGSL compiler. Previously it directly converted WGSL to SPIR-V and we were using [SPIRV-Cross](https://github.com/KhronosGroup/SPIRV-Cross) for translation to MSL / HLSL / GLSL and reflection. SPIRV-Cross is a mature library but is not meant to handle untrusted/malicious inputs like you can find on the Web. Tint has been expanded to the point where Dawn can use it for shader reflection and WGSL -> HLSL translation.
### OffscreenCanvas support
OffscreenCanvas now supports the `"gpupresent"` context type! It can currently be used to detach the content of the canvas into and ImageBitmap with `transferToImageBitmap()`. Additional features like using WebGPU on an `OffscreenCanvas` received from `transferToOffscreenCanvas()` and `OffscreenCanvas.convertToBlob()` will follow shortly.
### Create\*PipelineAsync
When a `GPURenderPipeline` or `GPUComputePipeline` is created with `GPUDevice.createRenderPipeline()` or `GPUDevice.createComputePipeline()` respectively, they return immediately. On the GPU process side it means that the pipelines have to be compiled immediately and stall the execution of further commands (because they could be used for drawing immediately). This can easily cause frame hitching and at worst compiling a lot of pipelines can trigger the "GPU watchdog" that will lose the WebGPU devices.
New methods for creating pipelines asynchronously, `GPUDevice.createRenderPipelineAsync()` and `GPUDevice.createComputePipelineAsync()`, have been added to address this. These methods accept the same descriptors as their synchronous counterparts but asynchronously return the pipeline once it is fully ready to be used. Using pipelines returned from the `create*PipelineAsync()` methods can help reduce hitches on first use compared to those returned from `create*Pipeline()`. This is a similar idea to WebGL's [`KHR_parallel_shader_compile`](https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/) but more Javacript-idiomatic.
Note that currently these methods aren't completely asynchronous internally but work is ongoing to improve their performance.
Using the feature in Javascript is done like below:
```javascript=
const computePipeline = await device.createComputePipelineAsync({
compute: {
module: device.createShaderModule({ code }),
entryPoint: 'main'
}
});
const commandEncoder = device.createCommandEncoder();
const passEncoder = commandEncoder.beginComputePass();
passEncoder.setPipeline(computePipeline);
passEncoder.dispatch(1024, 1024);
passEncoder.endPass();
device.queue.submit([commandEncoder.finish()]);
```
Using the feature in Dawn's API is done like below:
```cpp=
wgpu::ComputePipelineDescriptor desc;
// Fill `desc` as usual.
device->CreateComputePipeline(&desc,
[](WGPUCreatePipelineAsyncStatus status, WGPUComputePipeline pipeline,
const char* message, void* userdata) {
if (status == WGPUCreatePipelineAsyncStatus::WGPUCreatePipelineAsyncStatus_Success) {
// pipeline can now be used as usual.
}
},
nullptr // userdata passed to the callback.
);
```
### Depth clamping
`"depth-clamping"` is a new optional WebGPU feature that allows controlling the behavior of fragments with a depth that fall outside of the `[0, 1]` range. By default without this extension they are discarded, instead when setting `GPUPrimitiveState.clampDepth = true` the fragments will be kept and their depth clamped to [0, 1]. This is particularly useful when rendering shadow maps so that geometry outside of the light's frustum still occludes geometry correctly (otherwise it would just "disappear" from the shadow).
Using the feature in Javascript is done like below:
```javascript=
// Check that our adapter has the feature available.
const adapter = await navigator.gpu.requestAdapter();
if (!adapter.features.includes("depth-clamping")) {
alert("Need GPUAdapter with depth clamping support!");
return;
}
// Create the device, requesting the feature to be enabled.
const device = await adapter.requestDevice({
nonGuaranteedFeatures: ["depth-clamping"]
});
// Create a pipeline that uses the feature.
const pipeline = device.createRenderPipeline({
primitive: {
clampDepth: true,
// ...
},
// ...
});
```
Using the feature in Dawn's API, when a `wgpu::Device` with the feature has been created is done like below. Extensibility of descriptors in C++ is done with "chained structures" a bit like Vulkan:
```cpp=
wgpu::RenderPipelineDescriptor desc;
// Fill `desc` as usual.
// Chain our depth clamping state in desc.primitive.
wgpu::PrimitiveDepthClampingState depthClampState;
depthClampState.clampDepth = true;
desc.primitive.nextInChain = &depthClampState;
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
```
### maxAnisotropy
It is now possible to specify a `GPUSampler`'s maximum anisotropy for [anisotropic filtering](https://en.wikipedia.org/wiki/Anisotropic_filtering). For historical reasons this features is not guaranteed to be everywhere so the WebGPU specification doesn't require that values higher than 1 do something, but that should be the case everywhere in practice.
Using the feature is done by adding `maxAnisotropy` to the descriptor passed to `GPUDevice.createSampler`:
```js=
const sampler = device.createSampler({
magFilter: "linear",
minFilter: "linear",
mipmapFilter: "linear",
maxAnisotropy: 4,
});
```
When using Dawn's API `maxAnisotropy` can be set in a similar way:
```cpp=
wgpu::SamplerDescriptor desc;
desc.magFilter = wgpu::FilterMode::Linear;
desc.minFilter = wgpu::FilterMode::Linear;
desc.mipmapFilter = wgpu::FilterMode::Linear;
desc.maxAnisotropy = 4;
wgpu::Sampler sampler = device.CreateSampler(&desc);
```