Add a case for shadows when blur_radius = 0 (#22441)

Nate Butler created

Closes #22433

Before/After (macOS):

![CleanShot 2024-12-26 at 22 41
11@2x](https://github.com/user-attachments/assets/1701da2e-3db7-4dd1-a680-0f63824cbdf5)

For some reason the non-blurred one seems much lower quality, so we may
need to tinker with the samples, or something else.

![CleanShot 2024-12-26 at 22 42
12@2x](https://github.com/user-attachments/assets/5a43330d-137b-4d45-a67a-fd10ef6a8ff8)

I'm unsure if this is a problem on Linux/in the Blade renderer, but
since no changes were made outside of the medal shaders we can probably
take this macOS-specific win for now.

Release Notes:

- gpui: Fixed an issue where shadows with a `blur_radius` of 0 would not
render.

Change summary

crates/gpui/src/platform/mac/shaders.metal | 36 ++++++++++++++----------
1 file changed, 21 insertions(+), 15 deletions(-)

Detailed changes

crates/gpui/src/platform/mac/shaders.metal 🔗

@@ -227,21 +227,27 @@ fragment float4 shadow_fragment(ShadowFragmentInput input [[stage_in]],
     }
   }
 
-  // The signal is only non-zero in a limited range, so don't waste samples
-  float low = point.y - half_size.y;
-  float high = point.y + half_size.y;
-  float start = clamp(-3. * shadow.blur_radius, low, high);
-  float end = clamp(3. * shadow.blur_radius, low, high);
-
-  // Accumulate samples (we can get away with surprisingly few samples)
-  float step = (end - start) / 4.;
-  float y = start + step * 0.5;
-  float alpha = 0.;
-  for (int i = 0; i < 4; i++) {
-    alpha += blur_along_x(point.x, point.y - y, shadow.blur_radius,
-                          corner_radius, half_size) *
-             gaussian(y, shadow.blur_radius) * step;
-    y += step;
+  float alpha;
+  if (shadow.blur_radius == 0.) {
+    float distance = quad_sdf(input.position.xy, shadow.bounds, shadow.corner_radii);
+    alpha = saturate(0.5 - distance);
+  } else {
+    // The signal is only non-zero in a limited range, so don't waste samples
+    float low = point.y - half_size.y;
+    float high = point.y + half_size.y;
+    float start = clamp(-3. * shadow.blur_radius, low, high);
+    float end = clamp(3. * shadow.blur_radius, low, high);
+
+    // Accumulate samples (we can get away with surprisingly few samples)
+    float step = (end - start) / 4.;
+    float y = start + step * 0.5;
+    alpha = 0.;
+    for (int i = 0; i < 4; i++) {
+      alpha += blur_along_x(point.x, point.y - y, shadow.blur_radius,
+                            corner_radius, half_size) *
+               gaussian(y, shadow.blur_radius) * step;
+      y += step;
+    }
   }
 
   return input.color * float4(1., 1., 1., alpha);