git: Shader for checkerboard pattern for side-by-side diff (#48417)

Cameron Mcloughlin and Cole Miller created

Adds `checkerboard` to `Background`, and use it for the side-by-side
diff.
Note that, since the blockmap can contain multiple `Spacer`s without any
gaps
in between, we ensure that the checkerboard pattern always shows an even
integer number of squares per line, so there are no obvious
discontinuities
in the pattern when this happens.

<img width="590" height="300" alt="image"
src="https://github.com/user-attachments/assets/e8f75f90-b230-4078-bce0-cb3c15613fe7"
/>


Release Notes:

- N/A *or* Added/Fixed/Improved ...

---------

Co-authored-by: Cole Miller <cole@zed.dev>

Change summary

crates/editor/src/element.rs                  | 61 ++++++++++++++++++--
crates/gpui/src/color.rs                      | 41 +++++++++----
crates/gpui/src/platform/blade/shaders.wgsl   | 16 +++++
crates/gpui/src/platform/mac/shaders.metal    | 15 ++++
crates/gpui/src/platform/windows/shaders.hlsl | 15 ++++
crates/gpui/src/style.rs                      |  6 +
6 files changed, 128 insertions(+), 26 deletions(-)

Detailed changes

crates/editor/src/element.rs 🔗

@@ -47,8 +47,8 @@ use gpui::{
     MouseDownEvent, MouseMoveEvent, MousePressureEvent, MouseUpEvent, PaintQuad, ParentElement,
     Pixels, PressureStage, ScrollDelta, ScrollHandle, ScrollWheelEvent, ShapedLine, SharedString,
     Size, StatefulInteractiveElement, Style, Styled, StyledText, TextAlign, TextRun,
-    TextStyleRefinement, WeakEntity, Window, anchored, deferred, div, fill, linear_color_stop,
-    linear_gradient, outline, pattern_slash, point, px, quad, relative, size, solid_background,
+    TextStyleRefinement, WeakEntity, Window, anchored, checkerboard, deferred, div, fill,
+    linear_color_stop, linear_gradient, outline, point, px, quad, relative, size, solid_background,
     transparent_black,
 };
 use itertools::Itertools;
@@ -60,6 +60,7 @@ use multi_buffer::{
 };
 
 use edit_prediction_types::EditPredictionGranularity;
+
 use project::{
     DisableAiSettings, Entry, ProjectPath,
     debugger::breakpoint_store::{Breakpoint, BreakpointSessionState},
@@ -4007,11 +4008,11 @@ impl EditorElement {
                 .id(block_id)
                 .w_full()
                 .h((*height as f32) * line_height)
-                .bg(pattern_slash(
-                    cx.theme().colors().panel_background,
-                    8.0,
-                    8.0,
-                ))
+                .bg(checkerboard(cx.theme().colors().panel_background, {
+                    let target_size = 16.0;
+                    let scale = window.scale_factor();
+                    Self::checkerboard_size(f32::from(line_height) * scale, target_size * scale)
+                }))
                 .into_any(),
         };
 
@@ -4073,6 +4074,24 @@ impl EditorElement {
         Some((element, final_size, row, x_offset))
     }
 
+    /// The checkerboard pattern height must be an even factor of the line
+    /// height, so that two consecutive spacer blocks can render contiguously
+    /// without an obvious break in the pattern.
+    fn checkerboard_size(line_height: f32, target_height: f32) -> f32 {
+        let k_approx = line_height / (2.0 * target_height);
+        let k_floor = (k_approx.floor() as u32).max(1);
+        let k_ceil = (k_approx.ceil() as u32).max(1);
+
+        let size_floor = line_height / (2 * k_floor) as f32;
+        let size_ceil = line_height / (2 * k_ceil) as f32;
+
+        if (size_floor - target_height).abs() <= (size_ceil - target_height).abs() {
+            size_floor
+        } else {
+            size_ceil
+        }
+    }
+
     fn render_buffer_header(
         &self,
         for_excerpt: &ExcerptInfo,
@@ -12123,6 +12142,7 @@ mod tests {
     use gpui::{TestAppContext, VisualTestContext};
     use language::{Buffer, language_settings, tree_sitter_python};
     use log::info;
+    use rand::{RngCore, rngs::StdRng};
     use std::num::NonZeroU32;
     use util::test::sample_text;
 
@@ -13224,4 +13244,31 @@ mod tests {
             assert_eq!(out[3].color, adjusted_bg1);
         }
     }
+
+    #[test]
+    fn test_checkerboard_size() {
+        // line height is smaller than target height, so we just return half the line height
+        assert_eq!(EditorElement::checkerboard_size(10.0, 20.0), 5.0);
+
+        // line height is exactly half the target height, perfect match
+        assert_eq!(EditorElement::checkerboard_size(20.0, 10.0), 10.0);
+
+        // line height is close to half the target height
+        assert_eq!(EditorElement::checkerboard_size(20.0, 9.0), 10.0);
+
+        // line height is close to 1/4 the target height
+        assert_eq!(EditorElement::checkerboard_size(20.0, 4.8), 5.0);
+    }
+
+    #[gpui::test(iterations = 100)]
+    fn test_random_checkerboard_size(mut rng: StdRng) {
+        let line_height = rng.next_u32() as f32;
+        let target_height = rng.next_u32() as f32;
+
+        let result = EditorElement::checkerboard_size(line_height, target_height);
+
+        let k = line_height / result;
+        assert!(k - k.round() < 0.0000001); // approximately integer
+        assert!((k.round() as u32).is_multiple_of(2));
+    }
 }

crates/gpui/src/color.rs 🔗

@@ -658,6 +658,7 @@ pub(crate) enum BackgroundTag {
     Solid = 0,
     LinearGradient = 1,
     PatternSlash = 2,
+    Checkerboard = 3,
 }
 
 /// A color space for color interpolation.
@@ -701,20 +702,21 @@ impl std::fmt::Debug for Background {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         match self.tag {
             BackgroundTag::Solid => write!(f, "Solid({:?})", self.solid),
-            BackgroundTag::LinearGradient => {
-                write!(
-                    f,
-                    "LinearGradient({}, {:?}, {:?})",
-                    self.gradient_angle_or_pattern_height, self.colors[0], self.colors[1]
-                )
-            }
-            BackgroundTag::PatternSlash => {
-                write!(
-                    f,
-                    "PatternSlash({:?}, {})",
-                    self.solid, self.gradient_angle_or_pattern_height
-                )
-            }
+            BackgroundTag::LinearGradient => write!(
+                f,
+                "LinearGradient({}, {:?}, {:?})",
+                self.gradient_angle_or_pattern_height, self.colors[0], self.colors[1]
+            ),
+            BackgroundTag::PatternSlash => write!(
+                f,
+                "PatternSlash({:?}, {})",
+                self.solid, self.gradient_angle_or_pattern_height
+            ),
+            BackgroundTag::Checkerboard => write!(
+                f,
+                "Checkerboard({:?}, {})",
+                self.solid, self.gradient_angle_or_pattern_height
+            ),
         }
     }
 }
@@ -747,6 +749,16 @@ pub fn pattern_slash(color: impl Into<Hsla>, width: f32, interval: f32) -> Backg
     }
 }
 
+/// Creates a checkerboard pattern background
+pub fn checkerboard(color: impl Into<Hsla>, size: f32) -> Background {
+    Background {
+        tag: BackgroundTag::Checkerboard,
+        solid: color.into(),
+        gradient_angle_or_pattern_height: size,
+        ..Default::default()
+    }
+}
+
 /// Creates a solid background color.
 pub fn solid_background(color: impl Into<Hsla>) -> Background {
     Background {
@@ -833,6 +845,7 @@ impl Background {
             BackgroundTag::Solid => self.solid.is_transparent(),
             BackgroundTag::LinearGradient => self.colors.iter().all(|c| c.color.is_transparent()),
             BackgroundTag::PatternSlash => self.solid.is_transparent(),
+            BackgroundTag::Checkerboard => self.solid.is_transparent(),
         }
     }
 }

crates/gpui/src/platform/blade/shaders.wgsl 🔗

@@ -129,6 +129,7 @@ struct Background {
     // 0u is Solid
     // 1u is LinearGradient
     // 2u is PatternSlash
+    // 3u is Checkerboard
     tag: u32,
     // 0u is sRGB linear color
     // 1u is Oklab color
@@ -399,7 +400,7 @@ fn prepare_gradient_color(tag: u32, color_space: u32,
     solid: Hsla, colors: array<LinearColorStop, 2>) -> GradientColor {
     var result = GradientColor();
 
-    if (tag == 0u || tag == 2u) {
+    if (tag == 0u || tag == 2u || tag == 3u) {
         result.solid = hsla_to_rgba(solid);
     } else if (tag == 1u) {
         // The hsla_to_rgba is returns a linear sRGB color
@@ -473,6 +474,7 @@ fn gradient_color(background: Background, position: vec2<f32>, bounds: Bounds,
             }
         }
         case 2u: {
+            // pattern slash
             let gradient_angle_or_pattern_height = background.gradient_angle_or_pattern_height;
             let pattern_width = (gradient_angle_or_pattern_height / 65535.0f) / 255.0f;
             let pattern_interval = (gradient_angle_or_pattern_height % 65535.0f) / 255.0f;
@@ -490,6 +492,18 @@ fn gradient_color(background: Background, position: vec2<f32>, bounds: Bounds,
             background_color = solid_color;
             background_color.a *= saturate(0.5 - distance);
         }
+        case 3u: {
+            // checkerboard
+            let size = background.gradient_angle_or_pattern_height;
+            let relative_position = position - bounds.origin;
+            
+            let x_index = floor(relative_position.x / size);
+            let y_index = floor(relative_position.y / size);
+            let should_be_colored = (x_index + y_index) % 2.0;
+            
+            background_color = solid_color;
+            background_color.a *= saturate(should_be_colored);
+        }
     }
 
     return background_color;

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

@@ -1140,7 +1140,7 @@ float4 over(float4 below, float4 above) {
 GradientColor prepare_fill_color(uint tag, uint color_space, Hsla solid,
                                      Hsla color0, Hsla color1) {
   GradientColor out;
-  if (tag == 0 || tag == 2) {
+  if (tag == 0 || tag == 2 || tag == 3) {
     out.solid = hsla_to_rgba(solid);
   } else if (tag == 1) {
     out.color0 = hsla_to_rgba(color0);
@@ -1233,6 +1233,19 @@ float4 fill_color(Background background,
         color.a *= saturate(0.5 - distance);
         break;
     }
+    case 3: {
+        // checkerboard
+        float size = background.gradient_angle_or_pattern_height;
+        float2 relative_position = position - float2(bounds.origin.x, bounds.origin.y);
+        
+        float x_index = floor(relative_position.x / size);
+        float y_index = floor(relative_position.y / size);
+        float should_be_colored = fmod(x_index + y_index, 2.0);
+        
+        color = solid_color;
+        color.a *= saturate(should_be_colored);
+        break; 
+    }
   }
 
   return color;

crates/gpui/src/platform/windows/shaders.hlsl 🔗

@@ -309,7 +309,7 @@ float quad_sdf(float2 pt, Bounds bounds, Corners corner_radii) {
 
 GradientColor prepare_gradient_color(uint tag, uint color_space, Hsla solid, LinearColorStop colors[2]) {
     GradientColor output;
-    if (tag == 0 || tag == 2) {
+    if (tag == 0 || tag == 2 || tag == 3) {
         output.solid = hsla_to_rgba(solid);
     } else if (tag == 1) {
         output.color0 = hsla_to_rgba(colors[0].color);
@@ -402,6 +402,19 @@ float4 gradient_color(Background background,
             color.a *= saturate(0.5 - distance);
             break;
         }
+        case 3: {
+            // checkerboard
+            float size = background.gradient_angle_or_pattern_height;
+            float2 relative_position = position - bounds.origin;
+            
+            float x_index = floor(relative_position.x / size);
+            float y_index = floor(relative_position.y / size);
+            float should_be_colored = (x_index + y_index) % 2.0;
+            
+            color = solid_color;
+            color.a *= saturate(should_be_colored);
+            break;
+        }
     }
 
     return color;

crates/gpui/src/style.rs 🔗

@@ -639,13 +639,15 @@ impl Style {
         if background_color.is_some_and(|color| !color.is_transparent()) {
             let mut border_color = match background_color {
                 Some(color) => match color.tag {
-                    BackgroundTag::Solid => color.solid,
+                    BackgroundTag::Solid
+                    | BackgroundTag::PatternSlash
+                    | BackgroundTag::Checkerboard => color.solid,
+
                     BackgroundTag::LinearGradient => color
                         .colors
                         .first()
                         .map(|stop| stop.color)
                         .unwrap_or_default(),
-                    BackgroundTag::PatternSlash => color.solid,
                 },
                 None => Hsla::default(),
             };