Render quads with anti-aliased rounded corners

Antonio Scandurra created

Change summary

gpui/src/platform/mac/renderer.rs           | 15 ++++++++++-----
gpui/src/platform/mac/shaders/shaders.h     |  1 +
gpui/src/platform/mac/shaders/shaders.metal | 13 +++++++++++--
3 files changed, 22 insertions(+), 7 deletions(-)

Detailed changes

gpui/src/platform/mac/renderer.rs 🔗

@@ -104,6 +104,7 @@ impl Renderer {
                         .background
                         .unwrap_or(ColorU::transparent_black())
                         .to_uchar4(),
+                    corner_radius: quad.corner_radius * scene.scale_factor(),
                 };
                 unsafe {
                     *(buffer_contents.offset(ix as isize)) = shader_quad;
@@ -143,11 +144,15 @@ fn build_pipeline_state(
     descriptor.set_label(label);
     descriptor.set_vertex_function(Some(vertex_fn.as_ref()));
     descriptor.set_fragment_function(Some(fragment_fn.as_ref()));
-    descriptor
-        .color_attachments()
-        .object_at(0)
-        .unwrap()
-        .set_pixel_format(pixel_format);
+    let color_attachment = descriptor.color_attachments().object_at(0).unwrap();
+    color_attachment.set_pixel_format(pixel_format);
+    color_attachment.set_blending_enabled(true);
+    color_attachment.set_rgb_blend_operation(metal::MTLBlendOperation::Add);
+    color_attachment.set_alpha_blend_operation(metal::MTLBlendOperation::Add);
+    color_attachment.set_source_rgb_blend_factor(metal::MTLBlendFactor::SourceAlpha);
+    color_attachment.set_source_alpha_blend_factor(metal::MTLBlendFactor::SourceAlpha);
+    color_attachment.set_destination_rgb_blend_factor(metal::MTLBlendFactor::OneMinusSourceAlpha);
+    color_attachment.set_destination_alpha_blend_factor(metal::MTLBlendFactor::OneMinusSourceAlpha);
 
     device
         .new_render_pipeline_state(&descriptor)

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

@@ -30,6 +30,15 @@ vertex QuadFragmentInput quad_vertex(
     };
 }
 
-fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]]) {
-    return coloru_to_colorf(input.quad.background_color);
+fragment float4 quad_fragment(
+    QuadFragmentInput input [[stage_in]],
+    constant GPUIQuadUniforms *uniforms [[buffer(GPUIQuadInputIndexUniforms)]]
+) {
+    float2 half_size = input.quad.size / 2.;
+    float2 center = input.quad.origin + half_size;
+    float2 center_to_point = abs(input.position.xy - center) - half_size + input.quad.corner_radius;
+    float distance = length(max(0.0, center_to_point)) + min(0.0, max(center_to_point.x, center_to_point.y)) - input.quad.corner_radius;
+
+    float4 coverage = float4(1.0, 1.0, 1.0, saturate(0.5 - distance));
+    return coverage * coloru_to_colorf(input.quad.background_color);
 }