From 76cec1b1fd533dda37aa53c40ef7665ed3b406b6 Mon Sep 17 00:00:00 2001 From: David Huculak Date: Sun, 3 Sep 2023 19:32:38 -0400 Subject: use @interpolate(flat) attribute as per the WebGPU spec: User-defined vertex outputs and fragment inputs of scalar or vector integer type must always be specified as @interpolate(flat) https://www.w3.org/TR/WGSL/#interpolation --- wgpu/src/shader/quad.wgsl | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'wgpu/src/shader/quad.wgsl') diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index fb402158..87055339 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -147,12 +147,12 @@ fn solid_fs_main( struct GradientVertexInput { @location(0) v_pos: vec2, - @location(1) colors_1: vec4, - @location(2) colors_2: vec4, - @location(3) colors_3: vec4, - @location(4) colors_4: vec4, - @location(5) offsets: vec4, - @location(6) direction: vec4, + @location(1) @interpolate(flat) colors_1: vec4, + @location(2) @interpolate(flat) colors_2: vec4, + @location(3) @interpolate(flat) colors_3: vec4, + @location(4) @interpolate(flat) colors_4: vec4, + @location(5) @interpolate(flat) offsets: vec4, + @location(6) @interpolate(flat) direction: vec4, @location(7) position_and_scale: vec4, @location(8) border_color: vec4, @location(9) border_radius: vec4, @@ -161,11 +161,11 @@ struct GradientVertexInput { struct GradientVertexOutput { @builtin(position) position: vec4, - @location(1) colors_1: vec4, - @location(2) colors_2: vec4, - @location(3) colors_3: vec4, - @location(4) colors_4: vec4, - @location(5) offsets: vec4, + @location(1) @interpolate(flat) colors_1: vec4, + @location(2) @interpolate(flat) colors_2: vec4, + @location(3) @interpolate(flat) colors_3: vec4, + @location(4) @interpolate(flat) colors_4: vec4, + @location(5) @interpolate(flat) offsets: vec4, @location(6) direction: vec4, @location(7) position_and_scale: vec4, @location(8) border_color: vec4, -- cgit From 87800095e27353557adb39ef42ee6f82a0075bc1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 7 Sep 2023 05:43:03 +0200 Subject: Remove unnecessary `interpolate(flat)` in `quad.wgsl` --- wgpu/src/shader/quad.wgsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu/src/shader/quad.wgsl') diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index 87055339..023b5a6d 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -152,7 +152,7 @@ struct GradientVertexInput { @location(3) @interpolate(flat) colors_3: vec4, @location(4) @interpolate(flat) colors_4: vec4, @location(5) @interpolate(flat) offsets: vec4, - @location(6) @interpolate(flat) direction: vec4, + @location(6) direction: vec4, @location(7) position_and_scale: vec4, @location(8) border_color: vec4, @location(9) border_radius: vec4, -- cgit From 181708a1c0f4920f7491df4516b0de3f61993391 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Mon, 28 Aug 2023 22:56:47 +0200 Subject: Compute gradients in Oklab color space --- wgpu/src/shader/quad.wgsl | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'wgpu/src/shader/quad.wgsl') diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index 023b5a6d..cba7e5a4 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -230,6 +230,18 @@ fn gradient( let unit = normalize(v1); let coord_offset = dot(unit, v2) / length(v1); + let to_lms: mat3x4 = mat3x4( + vec4(0.4121656120, 0.2118591070, 0.0883097947, 0.0), + vec4(0.5362752080, 0.6807189584, 0.2818474174, 0.0), + vec4(0.0514575653, 0.1074065790, 0.6302613616, 0.0), + ); + + let to_rgb: mat3x4 = mat3x4( + vec4( 4.0767245293, -3.3072168827, 0.2307590544, 0.0), + vec4(-1.2681437731, 2.6093323231, -0.3411344290, 0.0), + vec4(-0.0041119885, -0.7034763098, 1.7068625689, 0.0), + ); + //need to store these as a var to use dynamic indexing in a loop //this is already added to wgsl spec but not in wgpu yet var colors_arr = colors; @@ -248,11 +260,15 @@ fn gradient( } if (curr_offset <= coord_offset && coord_offset <= next_offset) { - color = mix(colors_arr[i], colors_arr[i+1], smoothstep( - curr_offset, - next_offset, - coord_offset, - )); + // blend in OKLab + let factor = smoothstep(curr_offset, next_offset, coord_offset); + let lms_a = pow(colors_arr[i] * to_lms, vec3(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)); + let lms_b = pow(colors_arr[i+1] * to_lms, vec3(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)); + let mixed = mix(lms_a, lms_b, factor); + + // back to sRGB + color = to_rgb * (mixed * mixed * mixed); + color.a = mix(colors_arr[i].a, colors_arr[i+1].a, factor); } if (coord_offset >= offsets_arr[last_index]) { -- cgit From 10d0b257f929296b1991a440f62c87487c0076dc Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 7 Sep 2023 07:24:32 +0200 Subject: Use Oklab color interpolation only with `color::GAMMA_CORRECTION` --- wgpu/src/shader/quad.wgsl | 322 ---------------------------------------------- 1 file changed, 322 deletions(-) (limited to 'wgpu/src/shader/quad.wgsl') diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index cba7e5a4..f919cfe2 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -37,325 +37,3 @@ fn select_border_radius(radi: vec4, position: vec2, center: vec2) rx = select(rx, ry, position.y > center.y); return rx; } - -fn unpack_u32(color: vec2) -> vec4 { - let rg: vec2 = unpack2x16float(color.x); - let ba: vec2 = unpack2x16float(color.y); - - return vec4(rg.y, rg.x, ba.y, ba.x); -} - -struct SolidVertexInput { - @location(0) v_pos: vec2, - @location(1) color: vec4, - @location(2) pos: vec2, - @location(3) scale: vec2, - @location(4) border_color: vec4, - @location(5) border_radius: vec4, - @location(6) border_width: f32, -} - -struct SolidVertexOutput { - @builtin(position) position: vec4, - @location(0) color: vec4, - @location(1) border_color: vec4, - @location(2) pos: vec2, - @location(3) scale: vec2, - @location(4) border_radius: vec4, - @location(5) border_width: f32, -} - -@vertex -fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput { - var out: SolidVertexOutput; - - var pos: vec2 = input.pos * globals.scale; - var scale: vec2 = input.scale * globals.scale; - - var min_border_radius = min(input.scale.x, input.scale.y) * 0.5; - var border_radius: vec4 = vec4( - min(input.border_radius.x, min_border_radius), - min(input.border_radius.y, min_border_radius), - min(input.border_radius.z, min_border_radius), - min(input.border_radius.w, min_border_radius) - ); - - var transform: mat4x4 = mat4x4( - vec4(scale.x + 1.0, 0.0, 0.0, 0.0), - vec4(0.0, scale.y + 1.0, 0.0, 0.0), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(pos - vec2(0.5, 0.5), 0.0, 1.0) - ); - - out.position = globals.transform * transform * vec4(input.v_pos, 0.0, 1.0); - out.color = input.color; - out.border_color = input.border_color; - out.pos = pos; - out.scale = scale; - out.border_radius = border_radius * globals.scale; - out.border_width = input.border_width * globals.scale; - - return out; -} - -@fragment -fn solid_fs_main( - input: SolidVertexOutput -) -> @location(0) vec4 { - var mixed_color: vec4 = input.color; - - var border_radius = select_border_radius( - input.border_radius, - input.position.xy, - (input.pos + input.scale * 0.5).xy - ); - - if (input.border_width > 0.0) { - var internal_border: f32 = max(border_radius - input.border_width, 0.0); - - var internal_distance: f32 = distance_alg( - input.position.xy, - input.pos + vec2(input.border_width, input.border_width), - input.scale - vec2(input.border_width * 2.0, input.border_width * 2.0), - internal_border - ); - - var border_mix: f32 = smoothstep( - max(internal_border - 0.5, 0.0), - internal_border + 0.5, - internal_distance - ); - - mixed_color = mix(input.color, input.border_color, vec4(border_mix, border_mix, border_mix, border_mix)); - } - - var dist: f32 = distance_alg( - vec2(input.position.x, input.position.y), - input.pos, - input.scale, - border_radius - ); - - var radius_alpha: f32 = 1.0 - smoothstep( - max(border_radius - 0.5, 0.0), - border_radius + 0.5, - dist - ); - - return vec4(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); -} - -struct GradientVertexInput { - @location(0) v_pos: vec2, - @location(1) @interpolate(flat) colors_1: vec4, - @location(2) @interpolate(flat) colors_2: vec4, - @location(3) @interpolate(flat) colors_3: vec4, - @location(4) @interpolate(flat) colors_4: vec4, - @location(5) @interpolate(flat) offsets: vec4, - @location(6) direction: vec4, - @location(7) position_and_scale: vec4, - @location(8) border_color: vec4, - @location(9) border_radius: vec4, - @location(10) border_width: f32, -} - -struct GradientVertexOutput { - @builtin(position) position: vec4, - @location(1) @interpolate(flat) colors_1: vec4, - @location(2) @interpolate(flat) colors_2: vec4, - @location(3) @interpolate(flat) colors_3: vec4, - @location(4) @interpolate(flat) colors_4: vec4, - @location(5) @interpolate(flat) offsets: vec4, - @location(6) direction: vec4, - @location(7) position_and_scale: vec4, - @location(8) border_color: vec4, - @location(9) border_radius: vec4, - @location(10) border_width: f32, -} - -@vertex -fn gradient_vs_main(input: GradientVertexInput) -> GradientVertexOutput { - var out: GradientVertexOutput; - - var pos: vec2 = input.position_and_scale.xy * globals.scale; - var scale: vec2 = input.position_and_scale.zw * globals.scale; - - var min_border_radius = min(input.position_and_scale.z, input.position_and_scale.w) * 0.5; - var border_radius: vec4 = vec4( - min(input.border_radius.x, min_border_radius), - min(input.border_radius.y, min_border_radius), - min(input.border_radius.z, min_border_radius), - min(input.border_radius.w, min_border_radius) - ); - - var transform: mat4x4 = mat4x4( - vec4(scale.x + 1.0, 0.0, 0.0, 0.0), - vec4(0.0, scale.y + 1.0, 0.0, 0.0), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(pos - vec2(0.5, 0.5), 0.0, 1.0) - ); - - out.position = globals.transform * transform * vec4(input.v_pos, 0.0, 1.0); - out.colors_1 = input.colors_1; - out.colors_2 = input.colors_2; - out.colors_3 = input.colors_3; - out.colors_4 = input.colors_4; - out.offsets = input.offsets; - out.direction = input.direction * globals.scale; - out.position_and_scale = vec4(pos, scale); - out.border_color = input.border_color; - out.border_radius = border_radius * globals.scale; - out.border_width = input.border_width * globals.scale; - - return out; -} - -fn random(coords: vec2) -> f32 { - return fract(sin(dot(coords, vec2(12.9898,78.233))) * 43758.5453); -} - -/// Returns the current interpolated color with a max 8-stop gradient -fn gradient( - raw_position: vec2, - direction: vec4, - colors: array, 8>, - offsets: array, - last_index: i32 -) -> vec4 { - let start = direction.xy; - let end = direction.zw; - - let v1 = end - start; - let v2 = raw_position - start; - let unit = normalize(v1); - let coord_offset = dot(unit, v2) / length(v1); - - let to_lms: mat3x4 = mat3x4( - vec4(0.4121656120, 0.2118591070, 0.0883097947, 0.0), - vec4(0.5362752080, 0.6807189584, 0.2818474174, 0.0), - vec4(0.0514575653, 0.1074065790, 0.6302613616, 0.0), - ); - - let to_rgb: mat3x4 = mat3x4( - vec4( 4.0767245293, -3.3072168827, 0.2307590544, 0.0), - vec4(-1.2681437731, 2.6093323231, -0.3411344290, 0.0), - vec4(-0.0041119885, -0.7034763098, 1.7068625689, 0.0), - ); - - //need to store these as a var to use dynamic indexing in a loop - //this is already added to wgsl spec but not in wgpu yet - var colors_arr = colors; - var offsets_arr = offsets; - - var color: vec4; - - let noise_granularity: f32 = 0.3/255.0; - - for (var i: i32 = 0; i < last_index; i++) { - let curr_offset = offsets_arr[i]; - let next_offset = offsets_arr[i+1]; - - if (coord_offset <= offsets_arr[0]) { - color = colors_arr[0]; - } - - if (curr_offset <= coord_offset && coord_offset <= next_offset) { - // blend in OKLab - let factor = smoothstep(curr_offset, next_offset, coord_offset); - let lms_a = pow(colors_arr[i] * to_lms, vec3(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)); - let lms_b = pow(colors_arr[i+1] * to_lms, vec3(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)); - let mixed = mix(lms_a, lms_b, factor); - - // back to sRGB - color = to_rgb * (mixed * mixed * mixed); - color.a = mix(colors_arr[i].a, colors_arr[i+1].a, factor); - } - - if (coord_offset >= offsets_arr[last_index]) { - color = colors_arr[last_index]; - } - } - - return color + mix(-noise_granularity, noise_granularity, random(raw_position)); -} - -@fragment -fn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4 { - let colors = array, 8>( - unpack_u32(input.colors_1.xy), - unpack_u32(input.colors_1.zw), - unpack_u32(input.colors_2.xy), - unpack_u32(input.colors_2.zw), - unpack_u32(input.colors_3.xy), - unpack_u32(input.colors_3.zw), - unpack_u32(input.colors_4.xy), - unpack_u32(input.colors_4.zw), - ); - - let offsets_1: vec4 = unpack_u32(input.offsets.xy); - let offsets_2: vec4 = unpack_u32(input.offsets.zw); - - var offsets = array( - offsets_1.x, - offsets_1.y, - offsets_1.z, - offsets_1.w, - offsets_2.x, - offsets_2.y, - offsets_2.z, - offsets_2.w, - ); - - //TODO could just pass this in to the shader but is probably more performant to just check it here - var last_index = 7; - for (var i: i32 = 0; i <= 7; i++) { - if (offsets[i] > 1.0) { - last_index = i - 1; - break; - } - } - - var mixed_color: vec4 = gradient(input.position.xy, input.direction, colors, offsets, last_index); - - let pos = input.position_and_scale.xy; - let scale = input.position_and_scale.zw; - - var border_radius = select_border_radius( - input.border_radius, - input.position.xy, - (pos + scale * 0.5).xy - ); - - if (input.border_width > 0.0) { - var internal_border: f32 = max(border_radius - input.border_width, 0.0); - - var internal_distance: f32 = distance_alg( - input.position.xy, - pos + vec2(input.border_width, input.border_width), - scale - vec2(input.border_width * 2.0, input.border_width * 2.0), - internal_border - ); - - var border_mix: f32 = smoothstep( - max(internal_border - 0.5, 0.0), - internal_border + 0.5, - internal_distance - ); - - mixed_color = mix(mixed_color, input.border_color, vec4(border_mix, border_mix, border_mix, border_mix)); - } - - var dist: f32 = distance_alg( - input.position.xy, - pos, - scale, - border_radius - ); - - var radius_alpha: f32 = 1.0 - smoothstep( - max(border_radius - 0.5, 0.0), - border_radius + 0.5, - dist); - - return vec4(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); -} -- cgit