HDR support with canvas tone mapping mode
Web developers have limited options for delivering HDR content, relying primarily on <img>
and <video>
elements. The <canvas>
element, however, remains restricted to SDR. Generating dynamic HDR content within a canvas requires encoding its contents as an HDR image before displaying it (for an example see this demo).
The new GPUCanvasToneMappingMode
parameter in the WebGPU canvas configuration now allows WebGPU to draw colors brighter than white (#FFFFFF
). It does so through the following modes:
"standard"
: The default behavior restricts content to the SDR range of the screen. This mode is accomplished by clamping all color values in the color space of the screen to the[0, 1]
interval."extended"
: Unlocks the full HDR range of the screen. This mode matches"standard"
in the[0, 1]
range of the screen. Clamping or projection is done to the extended dynamic range of the screen but not[0, 1]
.
The following code snippet shows you to configure a canvas for high dynamic range.
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const canvas = document.querySelector("canvas");
const context = canvas.getContext("webgpu");
context.configure({
device,
format: "rgba16float",
toneMapping: { mode: "extended" },
});
Explore HDR with WebGPU by checking out the Particles (HDR) sample and WebGPU HDR example, and see the chromestatus entry.
Expanded subgroups support
Following the announcement of subgroups experimentation, the subgroup built-ins functions are now available for use in both compute shaders and fragment shaders. They are no longer restricted to just compute shaders. See issue 354738715.
Note that the subgroup_size
built-in value is currently buggy in fragment shaders. Avoid it for now.
Furthermore, the following subgroup built-ins functions have been added:
subgroupAdd(value)
: Returns the summation of all active invocationsvalue
s across the subgroup.subgroupExclusiveAdd(value)
: Returns the exclusive scan summation of all active invocationsvalue
s across the subgroup.subgroupMul(value)
: Returns the multiplication of all active invocationsvalue
s across the subgroup.subgroupExclusiveMul(value)
: Returns the exclusive scan multiplication of all active invocationsvalue
s across the subgroup.subgroupAnd(value)
: Returns the binary AND of all active invocationsvalue
s across the subgroup.subgroupOr(value)
: Returns the binary OR of all active invocationsvalue
s across the subgroup.subgroupXor(value)
: Returns the binary XOR of all active invocationsvalue
s across the subgroup.subgroupMin(value)
: Returns the minimal value of all active invocationsvalue
s across the subgroup.subgroupMax(value)
: Returns the maximal value of all active invocationsvalue
s across the subgroup.subgroupAll(value)
: Returns true ifvalue
is true for all active invocations in the subgroup.subgroupAny(value)
: Returns true ifvalue
is true for any active invocation in the subgroup.subgroupElect()
: Returns true if this invocation has the lowestsubgroup_invocation_id
among active invocations in the subgroup.subgroupBroadcastFirst(value)
: Broadcastsvalue
from the active invocation with the lowestsubgroup_invocation_id
in the subgroup to all other active invocations.subgroupShuffle(value, id)
: Returnsvalue
from the active invocation whosesubgroup_invocation_id
matchesid
.subgroupShuffleXor(value, mask)
: Returnsvalue
from the active invocation whosesubgroup_invocation_id
matchessubgroup_invocation_id ^ mask
.mask
must be dynamically uniform.subgroupShuffleUp(value, delta)
: Returnsvalue
from the active invocation whosesubgroup_invocation_id
matchessubgroup_invocation_id - delta
.subgroupShuffleDown(value, delta)
: Returnsvalue
from the active invocation whosesubgroup_invocation_id
matchessubgroup_invocation_id + delta
.quadBroadcast(value, id)
: Broadcastsvalue
from the quad invocation with id equal toid
.id
must be a constant-expression.quadSwapX(value)
: Swapsvalue
between invocations in the quad in the X direction.quadSwapY(value)
: Swapsvalue
between invocations in the quad in the Y direction.quadSwapDiagonal(value)
: Swapsvalue
between invocations in the quad diagonally.
Dawn updates
The wgpu::PrimitiveState
struct now directly includes depth clip control setting, eliminating the need for a separate wgpu::PrimitiveDepthClipControl
struct. To learn more, see the following code snippet and the webgpu-headers PR.
// Before
wgpu::PrimitiveState primitive = {};
wgpu::PrimitiveDepthClipControl depthClipControl;
depthClipControl.unclippedDepth = true;
primitive.nextInChain = &depthClipControl;
// Now
wgpu::PrimitiveState primitive = {};
primitive.unclippedDepth = true;
This covers only some of the key highlights. Check out the exhaustive list of commits.
What's New in WebGPU
A list of everything that has been covered in the What's New in WebGPU series.
Chrome 131
- Clip distances in WGSL
- GPUCanvasContext getConfiguration()
- Point and line primitives must not have depth bias
- Inclusive scan built-in functions for subgroups
- Experimental support for multi-draw indirect
- Shader module compilation option strict math
- Remove GPUAdapter requestAdapterInfo()
- Dawn updates
Chrome 130
- Dual source blending
- Shader compilation time improvements on Metal
- Deprecation of GPUAdapter requestAdapterInfo()
- Dawn updates
Chrome 129
Chrome 128
- Experimenting with subgroups
- Deprecate setting depth bias for lines and points
- Hide uncaptured error DevTools warning if preventDefault
- WGSL interpolate sampling first and either
- Dawn updates
Chrome 127
- Experimental support for OpenGL ES on Android
- GPUAdapter info attribute
- WebAssembly interop improvements
- Improved command encoder errors
- Dawn updates
Chrome 126
- Increase maxTextureArrayLayers limit
- Buffer upload optimization for Vulkan backend
- Shader compilation time improvements
- Submitted command buffers must be unique
- Dawn updates
Chrome 125
Chrome 124
- Read-only and read-write storage textures
- Service workers and shared workers support
- New adapter information attributes
- Bug fixes
- Dawn updates
Chrome 123
- DP4a built-in functions support in WGSL
- Unrestricted pointer parameters in WGSL
- Syntax sugar for dereferencing composites in WGSL
- Separate read-only state for stencil and depth aspects
- Dawn updates
Chrome 122
- Expand reach with compatibility mode (feature in development)
- Increase maxVertexAttributes limit
- Dawn updates
Chrome 121
- Support WebGPU on Android
- Use DXC instead of FXC for shader compilation on Windows
- Timestamp queries in compute and render passes
- Default entry points to shader modules
- Support display-p3 as GPUExternalTexture color space
- Memory heaps info
- Dawn updates
Chrome 120
- Support for 16-bit floating-point values in WGSL
- Push the limits
- Changes to depth-stencil state
- Adapter information updates
- Timestamp queries quantization
- Spring-cleaning features
Chrome 119
- Filterable 32-bit float textures
- unorm10-10-10-2 vertex format
- rgb10a2uint texture format
- Dawn updates
Chrome 118
- HTMLImageElement and ImageData support in
copyExternalImageToTexture()
- Experimental support for read-write and read-only storage texture
- Dawn updates
Chrome 117
- Unset vertex buffer
- Unset bind group
- Silence errors from async pipeline creation when device is lost
- SPIR-V shader module creation updates
- Improving developer experience
- Caching pipelines with automatically generated layout
- Dawn updates
Chrome 116
- WebCodecs integration
- Lost device returned by GPUAdapter
requestDevice()
- Keep video playback smooth if
importExternalTexture()
is called - Spec conformance
- Improving developer experience
- Dawn updates
Chrome 115
- Supported WGSL language extensions
- Experimental support for Direct3D 11
- Get discrete GPU by default on AC power
- Improving developer experience
- Dawn updates
Chrome 114
- Optimize JavaScript
- getCurrentTexture() on unconfigured canvas throws InvalidStateError
- WGSL updates
- Dawn updates