diff --git a/crates/gpui3/src/geometry.rs b/crates/gpui3/src/geometry.rs index fadff5778570b97b4fbed92c2fe55b14746be9fd..2eb91146746262ed455cbb07267cf8b8350da31c 100644 --- a/crates/gpui3/src/geometry.rs +++ b/crates/gpui3/src/geometry.rs @@ -138,6 +138,9 @@ pub struct Bounds { pub size: Size, } +unsafe impl Zeroable for Bounds {} +unsafe impl Pod for Bounds {} + impl> Bounds { pub fn upper_right(&self) -> Point { Point { @@ -174,6 +177,12 @@ pub struct Edges { pub left: T, } +impl Copy for Edges {} + +unsafe impl Zeroable for Edges {} + +unsafe impl Pod for Edges {} + impl Edges { pub fn auto() -> Self { Self { @@ -231,6 +240,21 @@ impl Edges { } } +#[derive(Refineable, Clone, Default, Debug)] +#[refineable(debug)] +pub struct Corners { + pub top_left: T, + pub top_right: T, + pub bottom_right: T, + pub bottom_left: T, +} + +impl Copy for Corners {} + +unsafe impl Zeroable for Corners {} + +unsafe impl Pod for Corners {} + #[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, PartialEq, PartialOrd)] #[repr(transparent)] pub struct Pixels(pub(crate) f32); diff --git a/crates/gpui3/src/renderer.rs b/crates/gpui3/src/renderer.rs index eed29c93c8d2165190eb61e5a77aa22092427fde..5fae274241777d161cdeba3cf7bb809c035a1a1e 100644 --- a/crates/gpui3/src/renderer.rs +++ b/crates/gpui3/src/renderer.rs @@ -8,9 +8,10 @@ pub struct Renderer { queue: wgpu::Queue, surface: wgpu::Surface, surface_config: wgpu::SurfaceConfiguration, - pipeline: wgpu::RenderPipeline, + quad_pipeline: wgpu::RenderPipeline, vertex_buffer: wgpu::Buffer, vertex_count: u32, + uniforms_buffer: wgpu::Buffer, } pub(crate) trait RenderTarget: HasRawWindowHandle + HasRawDisplayHandle { @@ -52,12 +53,9 @@ impl Renderer { // quality takes priority over input latency. present_mode: wgpu::PresentMode::Fifo, - // Use the Premultiplied alpha mode. With premultiplication, the color components - // are multiplied by the alpha value before storage or blending, meaning calculations - // with colors already factor in the influence of alpha. This typically results - // in better performance and avoids a separate multiplication operation during blending. - alpha_mode: wgpu::CompositeAlphaMode::PreMultiplied, - + // When blending, assume the RGB have not yet been multiplied by the alpha channel. + alpha_mode: wgpu::CompositeAlphaMode::PostMultiplied, +PostMultiplied // Specify the color formats for the views the surface can have. // In this case, the format is BGRA (blue, green, red, alpha) with unsigned // normalised integers in the 8-bit range and the color space is sRGB (standard RGB). @@ -78,6 +76,13 @@ impl Renderer { source: wgpu::ShaderSource::Wgsl(include_str!("shader.frag.wgsl").into()), }); + let uniforms_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("Uniforms Buffer"), + size: std::mem::size_of::() as wgpu::BufferAddress, + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Render Pipeline Layout"), bind_group_layouts: &[], @@ -91,17 +96,17 @@ impl Renderer { mapped_at_creation: false, }); - let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + let quad_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("Render Pipeline"), layout: Some(&pipeline_layout), vertex: wgpu::VertexState { module: &vs_module, - entry_point: "main", + entry_point: "quad", buffers: &[], }, fragment: Some(wgpu::FragmentState { module: &fs_module, - entry_point: "main", + entry_point: "quad", targets: &[Some(wgpu::ColorTargetState { format: surface_config.format, blend: Some(wgpu::BlendState::REPLACE), @@ -122,9 +127,10 @@ impl Renderer { queue, surface, surface_config, - pipeline, + quad_pipeline, vertex_buffer, vertex_count: 0, + uniforms_buffer, } } .boxed() @@ -163,8 +169,9 @@ impl Renderer { depth_stencil_attachment: None, }); - render_pass.set_pipeline(&self.pipeline); + render_pass.set_pipeline(&self.quad_pipeline); render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); + render_pass.set_bind_group(0, &self.uniforms_buffer, &[]); render_pass.draw(0..self.vertex_count, 0..1); } diff --git a/crates/gpui3/src/scene.rs b/crates/gpui3/src/scene.rs index ea39f232188110697f8c17cc8e2877cba143a3f8..c26f98851b37a6973f95f98afbb1c31bca81f166 100644 --- a/crates/gpui3/src/scene.rs +++ b/crates/gpui3/src/scene.rs @@ -1,6 +1,5 @@ -use crate::{FontId, GlyphId}; - use super::{Bounds, Hsla, Pixels, Point}; +use crate::{Corners, Edges, FontId, GlyphId}; use bytemuck::{Pod, Zeroable}; use plane_split::BspSplitter; @@ -69,13 +68,12 @@ pub struct PrimitiveBatch { pub struct Quad { pub order: f32, pub bounds: Bounds, + pub clip_bounds: Bounds, + pub clip_corner_radii: Corners, pub background: Hsla, pub border_color: Hsla, - pub corner_radius: Pixels, - pub border_left: Pixels, - pub border_right: Pixels, - pub border_top: Pixels, - pub border_bottom: Pixels, + pub corner_radii: Corners, + pub border_widths: Edges, } impl Quad { diff --git a/crates/gpui3/src/shader.vert.wgsl b/crates/gpui3/src/shader.vert.wgsl index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..094edbe81e0fac9e16cd2ecded90e971cdcdebaf 100644 --- a/crates/gpui3/src/shader.vert.wgsl +++ b/crates/gpui3/src/shader.vert.wgsl @@ -0,0 +1,88 @@ +[[stage(vertex)]] +fn quad_vertex(input: QuadVertexInput) -> QuadVertexOutput { + var output: QuadVertexOutput; + + // Apply clip bounds + input.bounds_origin = max(input.bounds_origin, input.clip_bounds.xy); + input.bounds_size = min(input.bounds_size, input.clip_bounds.zw); + + var ndc: vec2 = (input.bounds_origin / uniforms.window_size) * 2.0 - 1.0; + + output.position = vec4(ndc, 0.0, 1.0); + output.position.y = -output.position.y; // Inverting since NDC's origin is at the center and y is up + output.color = input.color; + output.bounds = input.bounds_size / uniforms.window_size; // Convert size to NDC + output.corner_radii = input.corner_radii / uniforms.window_size; // Convert corner radii to NDC + output.clip_bounds = input.clip_bounds / uniforms.window_size; // Convert clip bounds to NDC + output.clip_corner_radii = input.corner_radii / uniforms.window_size; // Convert clip corner radii to NDC + + return output; +} + +// #[derive(Debug, Clone, Copy)] +// #[repr(C)] +// pub struct gpui3::scene::Quad { +// pub order: f32, +// pub bounds: Bounds, +// pub clip_bounds: Bounds, +// pub clip_corner_radii: Corners, +// pub background: Hsla, +// pub border_color: Hsla, +// pub corner_radii: Corners, +// pub border_widths: Edges, +// } + +struct QuadVertexInput { + [[location(0)]] order: f32; + [[location(1)]] bounds: vec4; // Bounds + [[location(2)]] clip_bounds: vec4; // Bounds + [[location(3)]] clip_corner_radii: vec4; // Corners + [[location(4)]] color: vec4; // Hsla + [[location(5)]] border_color: vec4; // Hsla + [[location(6)]] corner_radii: vec4; // Corners + [[location(7)]] border_widths: vec4; // Edges +}; + +[[block]] +struct Uniforms { + viewport: vec2; +}; + +[[binding(0), group(0)]] var uniforms: Uniforms; + +struct QuadVertexOutput { + [[builtin(position)]] position: vec4; + [[location(0)]] color: vec4; + [[location(1)]] border_color: vec4; + [[location(2)]] bounds: vec4; + [[location(3)]] corner_radii: vec4; // assuming topLeft, topRight, bottomRight, bottomLeft + [[location(4)]] clip_bounds: vec4; + [[location(5)]] clip_corner_radii: vec4; + [[location(6)]] border_widths: vec4; +}; + +[[stage(fragment)]] +fn quad_fragment(input: QuadVertexOutput) -> [[location(0)]] vec4 { + var output_color: vec4; + var sdf = rounded_quad_sdf(input.position, input.bounds, input.corner_radii); + var alpha = clamp(1.0 - sdf, 0.0, 1.0); + var border_color: vec4 = input.border_color; + var mix_factor: f32 = 1.0 - clamp(sdf, 0.0, 1.0); // Mixing factor dependent on sdf distance + + var border_width_factor: vec4 = normalize(input.border_widths); // Normalizing the border width to account for directional widths + + output_color = mix(input.color, border_color, mix_factor * border_width_factor); // Modulate the mix_factor with the border_width_factor to handle different border widths + + output_color.a = alpha; + + return output_color; +} + +[[stage(fragment)]] +fn rounded_quad_sdf(p: vec2, b: vec2, r: vec4) -> f32 { + var rx: vec2; + rx = select(r.xy, r.zw, greaterThan(p.x, 0.0)); + rx.x = select(rx.x, rx.y, greaterThan(p.y, 0.0)); + var q: vec2 = abs(p)-b+rx.x; + return min(max(q.x,q.y),0.0) + length(max(q, vec2(0.0, 0.0))) - rx.x; +} diff --git a/crates/gpui3/src/style.rs b/crates/gpui3/src/style.rs index 37fc700b05e06f8e749c48a60d3dd230c066b902..1114b224f43f1b6af3280e6782c91edbec12ba9b 100644 --- a/crates/gpui3/src/style.rs +++ b/crates/gpui3/src/style.rs @@ -1,7 +1,7 @@ -use super::{ - rems, AbsoluteLength, Bounds, DefiniteLength, Edges, EdgesRefinement, FontStyle, FontWeight, - Hsla, Length, Pixels, Point, PointRefinement, Rems, Result, RunStyle, SharedString, Size, - SizeRefinement, ViewContext, WindowContext, +use crate::{ + rems, AbsoluteLength, Bounds, Corners, CornersRefinement, DefiniteLength, Edges, + EdgesRefinement, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rems, + Result, RunStyle, SharedString, Size, SizeRefinement, ViewContext, WindowContext, }; use refineable::Refineable; pub use taffy::style::{ @@ -86,7 +86,7 @@ pub struct Style { /// The radius of the corners of this element #[refineable] - pub corner_radii: CornerRadii, + pub corner_radii: Corners, /// The color of text within this element. Cascades to children unless overridden. pub text_color: Option, @@ -243,7 +243,7 @@ impl Default for Style { flex_basis: Length::Auto, fill: None, border_color: None, - corner_radii: CornerRadii::default(), + corner_radii: Corners::default(), text_color: None, font_size: Some(rems(1.)), font_family: None,