Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 25 additions & 13 deletions crates/rendering/src/shaders/composite-video-frame.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ struct VertexOutput {
@location(0) uv: vec2<f32>,
};

const SQUIRCLE_POWER: f32 = 4.5;

@vertex
fn vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {
var positions = array<vec2<f32>, 3>(
Expand All @@ -45,8 +47,20 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {
}

fn sdf_rounded_rect(p: vec2<f32>, b: vec2<f32>, r: f32) -> f32 {
let q = abs(p) - b + vec2<f32>(r);
return length(max(q, vec2<f32>(0.0))) + min(max(q.x, q.y), 0.0) - r;
let clamped_r = clamp(r, 0.0, min(b.x, b.y));
let q = abs(p) - b + vec2<f32>(clamped_r);
let outside = max(q, vec2<f32>(0.0));
let inside = min(max(q.x, q.y), 0.0);

if clamped_r <= 0.0 {
return length(outside) + inside;
}
Comment on lines +55 to +57
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Verify numerical stability for very small radius values.

While the zero-radius guard is good, consider whether very small positive values (e.g., 0.001) might cause numerical instability in the power calculations on Line 60-61.


🏁 Script executed:

#!/bin/bash
# Search for any related numerical stability handling or similar guards in shader code
rg -n --type=rust -C3 "clamp.*0\.0.*min" 
rg -n -g "*.wgsl" -C3 "pow.*pow" 

Length of output: 671


Guard clamped_r with a small epsilon before dividing to avoid overflow/NaN
The code only returns when clamped_r <= 0.0, but normalized = outside / vec2(clamped_r) and the subsequent pow(...) (crates/rendering/src/shaders/composite-video-frame.wgsl, ~lines 59–61) can produce huge values or overflow/NaN for very small positive radii (e.g., 1e-3). Clamp clamped_r to a safe minimum or early-return when clamped_r < EPS (or use max(clamped_r, EPS)) before the division.

🤖 Prompt for AI Agents
In crates/rendering/src/shaders/composite-video-frame.wgsl around lines 55 to
57, the branch only checks clamped_r <= 0.0 but later divides by clamped_r and
uses pow(...), which can overflow/NaN for very small positive radii; fix by
guarding the divisor with a small EPS (e.g., const EPS = 1e-6) — either
early-return when clamped_r < EPS or replace the divisor with max(clamped_r,
EPS) before normalizing outside and before any pow calls so divisions and
exponentiation use a safe minimum value.


let normalized = outside / vec2<f32>(clamped_r);
let super_len = pow(pow(normalized.x, SQUIRCLE_POWER) + pow(normalized.y, SQUIRCLE_POWER), 1.0 / SQUIRCLE_POWER);
let metric = super_len * clamped_r;

return metric + inside - clamped_r;
}

@fragment
Expand Down Expand Up @@ -223,20 +237,18 @@ fn sample_texture(uv: vec2<f32>, crop_bounds_uv: vec4<f32>) -> vec4<f32> {
}

fn apply_rounded_corners(current_color: vec4<f32>, target_uv: vec2<f32>) -> vec4<f32> {
let target_coord = abs(target_uv * uniforms.target_size - uniforms.target_size / 2.0);
let rounding_point = uniforms.target_size / 2.0 - uniforms.rounding_px;
let target_rounding_coord = target_coord - rounding_point;

let distance = abs(length(target_rounding_coord)) - uniforms.rounding_px;
if uniforms.rounding_px <= 0.0 {
return current_color;
}

let distance_blur = 1.0;
let half_size = uniforms.target_size * 0.5;
let frag_pos = target_uv * uniforms.target_size - half_size;
let dist = sdf_rounded_rect(frag_pos, half_size, uniforms.rounding_px);

if target_rounding_coord.x >= 0.0 && target_rounding_coord.y >= 0.0 && distance >= -distance_blur/2.0 {
return vec4<f32>(0.0);
// return mix(current_color, vec4<f32>(0.0), min(distance / distance_blur + 0.5, 1.0));
}
let edge_softness = max(fwidth(dist), 0.75);
let mask = 1.0 - smoothstep(0.0, edge_softness, dist);

return current_color;
return vec4<f32>(current_color.rgb * mask, current_color.a * mask);
}

fn rand(co: vec2<f32>) -> f32 {
Expand Down
Loading