Chromium Experimental Static Samplers

The chromium_experimental_static_samplers extension is an experimental extension that allows the use of static samplers in WGSL. Static samplers translate to immutable samplers in Vulkan, constexpr samplers in Metal Shading Language, and static samplers in Direct3D 12.

Status

This extension is experimental and the syntax is being discussed. No official WebGPU specification has been written yet.

Design considerations

const or var

@group(X) @binding(Y) const mySampler; or @group(X) @binding(Y) var mySampler;

In HLSL and SPIR-V, static samplers need a binding slot, hence the @group(X) @binding(Y) syntax. Vulkan and Direct3D 12 supply static samplers via the API. Metal Shading Language declares static samplers with constexpr, which is ready to be used in the shader without Metal API interaction.

Normal samplers in WGSL are declared with var because they have a handle address space, which is read-only. Using the const keyword for static samplers is sensible, as static samplers are immutable objects. However, const does not have a handle address space which is required for HLSL and SPIR-V and would require spec changes to support it.

Using var for static samplers is recommended for consistency with the rest of the language and they are already immutable.

Using a struct

@group(X) @binding(Y) const mySampler = sampler {
  addressModeU: mirror_repeat, // enumerant
  magFilter: linear,
  lodMinClamp: 1, // abstract float
  ...
};

The sampler is a built-in struct that can be used to define samplers. Advantages are its readability and similarity to the WebGPU API's GPUSamplerDescriptor struct.

This approach would require a new WGSL feature for initializing struct values.

If the new WGSL feature is introduced, this approach is recommended for readability and intuitiveness. However, for the initial implementation, it is not desirable to introduce a substantial change in WGSL.

Using a function

const clamp_to_edge = 0;
const mirror_repeat = 1;
...
sampler(mirror_repeat, linear, 0.0, 16);
sampler_comparison(mirror_repeat, linear, 0.0, 16);

or

sampler<mirror_repeat, linear>(0.0, 16);
sampler_comparison<mirror_repeat, linear>(0.0, 16);

In both cases, sampler is a built-in function that returns a static sampler. The first approach takes a list of arguments. These arguments are predefined constant values and not enums. The second approach takes a list of enum template parameters and a list of arguments. The arguments are LOD min and max clamps, because they are not enums.

Both approaches are readable and intuitive but due to the large amount of parameters that can be set on a sampler, the approaches may become hard to read and write. The approaches do not need any new WGSL features and are sufficient for a prototype implementation.

For the prototype implementation, the first function approach is good for its simplicity.

Pseudo-specification

This extension adds sampler(...) and sampler_comparison(...) functions to return a sampler type. The functions take integer values that are predefined constants. If a sampler is initialized with any of the two functions, it is considered a static sampler, otherwise it is a normal sampler. The predefined constant variable names are similar to the WebGPU API enums.

Function restrictions include:

  • The function can only be called to initialize a static sampler.
  • Only built-in functions can return a sampler, user-defined functions cannot.
  • The function can not be used in an expression, only in a declaration.

Order of arguments:

  • addressModeU
  • addressModeV
  • addressModeW
  • magFilter
  • minFilter
  • mipmapFilter
  • compare (only for sampler_comparison(...))
  • lodMinClamp
  • lodMaxClamp

New Constants:

  • Address Mode:
    • WGSL: clamp_to_edge=0, repeat=1, mirror_repeat=2
    • WebGPU equivalent: "clamp-to-edge", "repeat", "mirror-repeat"
  • Filter Mode:
    • WGSL: nearest=0, linear=1
    • WebGPU equivalent: "nearest", "linear"
  • Mipmap Filter Mode:
    • WGSL: mipmap_nearest=0, mipmap_linear=1
    • WebGPU equivalent: "nearest", "linear"
  • Comparison Function:
    • WGSL: never=0, less=1, equal=2, less_equal=3, greater=4, not_equal=5, greater_equal=6, always=7
    • WebGPU equivalent: "never", "less", "equal", "less-equal", "greater", "not-equal", "greater-equal", "always"

Example usage

@group(0) @binding(0) var mySampler = sampler(mirror_repeat, clamp_to_edge, mirror_repeat, linear, linear, mipmap_linear, 0.0, 16.0)

@group(0) @binding(1) var myComparisonSampler = sampler_comparison(mirror_repeat, clamp_to_edge, mirror_repeat, linear, linear, mipmap_linear, less, 0.0, 16.0)