Detailed changes
@@ -138,6 +138,9 @@ pub struct Bounds<T: Clone + Debug> {
pub size: Size<T>,
}
+unsafe impl<T: Clone + Debug + Zeroable + Pod> Zeroable for Bounds<T> {}
+unsafe impl<T: Clone + Debug + Zeroable + Pod> Pod for Bounds<T> {}
+
impl<T: Clone + Debug + Copy + Add<T, Output = T>> Bounds<T> {
pub fn upper_right(&self) -> Point<T> {
Point {
@@ -174,6 +177,12 @@ pub struct Edges<T: Clone + Debug> {
pub left: T,
}
+impl<T: Clone + Debug + Copy> Copy for Edges<T> {}
+
+unsafe impl<T: Clone + Debug + Zeroable + Pod> Zeroable for Edges<T> {}
+
+unsafe impl<T: Clone + Debug + Zeroable + Pod> Pod for Edges<T> {}
+
impl Edges<Length> {
pub fn auto() -> Self {
Self {
@@ -231,6 +240,21 @@ impl Edges<Pixels> {
}
}
+#[derive(Refineable, Clone, Default, Debug)]
+#[refineable(debug)]
+pub struct Corners<T: Clone + Debug> {
+ pub top_left: T,
+ pub top_right: T,
+ pub bottom_right: T,
+ pub bottom_left: T,
+}
+
+impl<T: Clone + Debug + Copy> Copy for Corners<T> {}
+
+unsafe impl<T: Clone + Debug + Zeroable + Pod> Zeroable for Corners<T> {}
+
+unsafe impl<T: Clone + Debug + Zeroable + Pod> Pod for Corners<T> {}
+
#[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct Pixels(pub(crate) f32);
@@ -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::<QuadUniforms>() 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);
}
@@ -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<Pixels>,
+ pub clip_bounds: Bounds<Pixels>,
+ pub clip_corner_radii: Corners<Pixels>,
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<Pixels>,
+ pub border_widths: Edges<Pixels>,
}
impl Quad {
@@ -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<f32> = (input.bounds_origin / uniforms.window_size) * 2.0 - 1.0;
+
+ output.position = vec4<f32>(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<Pixels>,
+// pub clip_bounds: Bounds<Pixels>,
+// pub clip_corner_radii: Corners<Pixels>,
+// pub background: Hsla,
+// pub border_color: Hsla,
+// pub corner_radii: Corners<Pixels>,
+// pub border_widths: Edges<Pixels>,
+// }
+
+struct QuadVertexInput {
+ [[location(0)]] order: f32;
+ [[location(1)]] bounds: vec4<f32>; // Bounds<Pixels>
+ [[location(2)]] clip_bounds: vec4<f32>; // Bounds<Pixels>
+ [[location(3)]] clip_corner_radii: vec4<f32>; // Corners<Pixels>
+ [[location(4)]] color: vec4<f32>; // Hsla
+ [[location(5)]] border_color: vec4<f32>; // Hsla
+ [[location(6)]] corner_radii: vec4<f32>; // Corners<Pixels>
+ [[location(7)]] border_widths: vec4<f32>; // Edges<Pixels>
+};
+
+[[block]]
+struct Uniforms {
+ viewport: vec2<f32>;
+};
+
+[[binding(0), group(0)]] var<uniform> uniforms: Uniforms;
+
+struct QuadVertexOutput {
+ [[builtin(position)]] position: vec4<f32>;
+ [[location(0)]] color: vec4<f32>;
+ [[location(1)]] border_color: vec4<f32>;
+ [[location(2)]] bounds: vec4<f32>;
+ [[location(3)]] corner_radii: vec4<f32>; // assuming topLeft, topRight, bottomRight, bottomLeft
+ [[location(4)]] clip_bounds: vec4<f32>;
+ [[location(5)]] clip_corner_radii: vec4<f32>;
+ [[location(6)]] border_widths: vec4<f32>;
+};
+
+[[stage(fragment)]]
+fn quad_fragment(input: QuadVertexOutput) -> [[location(0)]] vec4<f32> {
+ var output_color: vec4<f32>;
+ 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<f32> = 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<f32> = 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<f32>, b: vec2<f32>, r: vec4<f32>) -> f32 {
+ var rx: vec2<f32>;
+ 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<f32> = abs(p)-b+rx.x;
+ return min(max(q.x,q.y),0.0) + length(max(q, vec2<f32>(0.0, 0.0))) - rx.x;
+}
@@ -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<AbsoluteLength>,
/// The color of text within this element. Cascades to children unless overridden.
pub text_color: Option<Hsla>,
@@ -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,