From a208b5bc9aba7c3a2ab16a05a8f1336a23db4a57 Mon Sep 17 00:00:00 2001 From: Gregg Tavares Date: Sun, 5 Nov 2023 00:56:02 +0900 Subject: [PATCH] constants --- .vscode/settings.json | 1 + webgpu/lessons/webgpu-constants.md | 131 ++++++++++++++++++++++++- webgpu/webgpu-constants-override.html | 132 ++++++++++++++++++++++++++ webgpu/webgpu-constants.html | 127 +++++++++++++++++++++++++ 4 files changed, 390 insertions(+), 1 deletion(-) create mode 100644 webgpu/webgpu-constants-override.html create mode 100644 webgpu/webgpu-constants.html diff --git a/.vscode/settings.json b/.vscode/settings.json index ba18e887..88cd3fe3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -32,6 +32,7 @@ "noborder", "noinvertdark", "nonull", + "overridable", "rasterizes", "rdparty", "rgba", diff --git a/webgpu/lessons/webgpu-constants.md b/webgpu/lessons/webgpu-constants.md index 52570db4..5c176859 100644 --- a/webgpu/lessons/webgpu-constants.md +++ b/webgpu/lessons/webgpu-constants.md @@ -2,5 +2,134 @@ Title: WebGPU Shader Constants Description: The fundamentals of WebGPU TOC: Constants -TBD +I'm not sure this topic deserves to considered an input to the shader. +but, from one point of view it is so lets cover it. +Constants, or more formally, *pipeline-overridable constants* are a type +of constant you declare in your shader but you can change when you use +that shader to create a pipeline. + +A simple example would be something like this + +```wgsl +override red = 0.0; +override green = 0.0; +override blue = 0.0; + +@fragment fn fs() -> @location(0) vec4f { + return vec4f(red, green, blue, 1.0); +} +``` + +Using this fragment shader with the vertex shader from [the article on fundamentals](webgpu-fundamentals.html) + +```wgsl +@vertex fn vs( + @builtin(vertex_index) vertexIndex : u32 +) -> @builtin(position) vec4f { + let pos = array( + vec2f( 0.0, 0.5), // top center + vec2f(-0.5, -0.5), // bottom left + vec2f( 0.5, -0.5) // bottom right + ); + + return vec4f(pos[vertexIndex], 0.0, 1.0); +} +``` + +Now if we use this shader as is we'll get a black triangle + +{{{example url="../webgpu-constants.html"}}} + +But, we can change those constants, or "override" them when we specify the pipeline. + +```js + const pipeline = device.createRenderPipeline({ + label: 'our hardcoded triangle pipeline', + layout: 'auto', + vertex: { + module, + entryPoint: 'vs', + }, + fragment: { + module, + entryPoint: 'fs', + targets: [{ format: presentationFormat }], ++ constants: { ++ red: 1, ++ green: 0.5, ++ blue: 1, ++ }, + }, + }); +``` + +And now we get a pinkish color. + +{{{example url="../webgpu-constants-override.html"}}} + +Pipeline overridable constants can only be scalar values so boolean (true/false), +integers, floating point numbers. They can not be vectors or matrices. + +If you don't specify a value in the shader then you **must** supply one in +the pipeline. You can also give them a numeric id and then refer to them +by their id. + +Example: + +```wgsl +override red: f32; // Must be specified in the pipeline +@id(123) override green = 0.0; // May be specified by 'green' or by 123 +override blue = 0.0; + +@fragment fn fs() -> @location(0) vec4f { + return vec4f(red, green, blue, 1.0); +} +``` + +You might ask, what is the point? I can just as easily do this when I +create the WGSL. For example + +```js +const red = 0.5; +const blue = 0.7; +const green = 1.0; + +const code = ` +const red = ${red}; +const green = ${green}; +const blue = ${blue}; + +@fragment fn fs() -> @location(0) vec4f { + return vec4f(red, green, blue, 1.0); +} +`; +``` + +Or even more directly + +```js +const red = 0.5; +const blue = 0.7; +const green = 1.0; + +const code = ` +@fragment fn fs() -> @location(0) vec4f { + return vec4f(${red}, ${green}, ${blue}, 1.0); +} +`; +``` + +The difference is, pipeline overridable constants can be applied AFTER +the shader module has been created which makes them technically faster +to apply then creating a new shader module. Creating a pipeline is +not a fast operation though so it's not clear how much time this saves +on the overall process of creating a pipeline. I'd suspect the more +complex the shader the more time it saves. + +In any case, it is one way to get some small amount of data into a shader. + +It is **not** common to use pipeline overridable constants to pass in a color. +That example was used because it's easy to understand and to show the results. +It would instead be useful for an iteration count, the size of an array (for +example the number of lights), etc... diff --git a/webgpu/webgpu-constants-override.html b/webgpu/webgpu-constants-override.html new file mode 100644 index 00000000..09960940 --- /dev/null +++ b/webgpu/webgpu-constants-override.html @@ -0,0 +1,132 @@ + + + + WebGPU Simple Triangle with Canvas CSS + + + + + + + diff --git a/webgpu/webgpu-constants.html b/webgpu/webgpu-constants.html new file mode 100644 index 00000000..79087747 --- /dev/null +++ b/webgpu/webgpu-constants.html @@ -0,0 +1,127 @@ + + + + WebGPU Simple Triangle with Canvas CSS + + + + + + +