Checkpoint

This commit is contained in:
Nathan Sobo
2023-09-18 17:40:47 -06:00
parent 0a2a5be71c
commit df9a05ba92
10 changed files with 677 additions and 69 deletions
+4
View File
@@ -10,10 +10,13 @@ path = "src/storybook.rs"
[dependencies]
anyhow.workspace = true
bytemuck = "1.14.0"
derive_more.workspace = true
gpui2 = { path = "../gpui2" }
itertools = "0.11.0"
log.workspace = true
plane-split = "0.18.0"
raw-window-handle = "0.5.2"
refineable = { path = "../refineable" }
rust-embed.workspace = true
serde.workspace = true
@@ -22,6 +25,7 @@ simplelog = "0.9"
slotmap = "1.0.6"
theme = { path = "../theme" }
util = { path = "../util" }
wgpu = "0.17.0"
[dev-dependencies]
gpui2 = { path = "../gpui2", features = ["test-support"] }
+12
View File
@@ -1,5 +1,6 @@
#![allow(dead_code)]
use bytemuck::{Pod, Zeroable};
use serde::de::{self, Deserialize, Deserializer, Visitor};
use std::fmt;
use std::num::ParseIntError;
@@ -101,6 +102,7 @@ impl TryFrom<&'_ str> for Rgba {
}
#[derive(Default, Copy, Clone, Debug, PartialEq)]
#[repr(C)]
pub struct Hsla {
pub h: f32,
pub s: f32,
@@ -108,6 +110,9 @@ pub struct Hsla {
pub a: f32,
}
unsafe impl Zeroable for Hsla {}
unsafe impl Pod for Hsla {}
pub fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla {
Hsla {
h: h.clamp(0., 1.),
@@ -126,6 +131,13 @@ pub fn black() -> Hsla {
}
}
impl Hsla {
/// Returns true if the HSLA color is fully transparent, false otherwise.
pub fn is_transparent(&self) -> bool {
self.a == 0.0
}
}
impl From<Rgba> for Hsla {
fn from(color: Rgba) -> Self {
let r = color.r;
+19 -1
View File
@@ -1,3 +1,4 @@
use bytemuck::{Pod, Zeroable};
use core::fmt::Debug;
use derive_more::{Add, AddAssign, Div, Mul, Sub};
use refineable::Refineable;
@@ -5,11 +6,18 @@ use std::ops::Mul;
#[derive(Refineable, Default, Add, AddAssign, Sub, Mul, Div, Copy, Debug, PartialEq, Eq, Hash)]
#[refineable(debug)]
#[repr(C)]
pub struct Point<T: Clone + Debug> {
pub x: T,
pub y: T,
}
impl<T: Clone + Debug> Point<T> {
pub fn new(x: T, y: T) -> Self {
Self { x, y }
}
}
impl<T: Clone + Debug> Clone for Point<T> {
fn clone(&self) -> Self {
Self {
@@ -19,7 +27,11 @@ impl<T: Clone + Debug> Clone for Point<T> {
}
}
#[derive(Refineable, Default, Clone, Debug)]
unsafe impl<T: Clone + Debug + Zeroable + Pod> Zeroable for Point<T> {}
unsafe impl<T: Clone + Debug + Zeroable + Pod> Pod for Point<T> {}
#[derive(Refineable, Default, Clone, Copy, Debug)]
#[refineable(debug)]
pub struct Size<T: Clone + Debug> {
pub width: T,
@@ -60,6 +72,8 @@ pub struct Bounds<T: Clone + Debug> {
pub size: Size<T>,
}
impl<T: Clone + Debug + Copy> Copy for Bounds<T> {}
#[derive(Refineable, Clone, Default, Debug)]
#[refineable(debug)]
pub struct Edges<T: Clone + Debug> {
@@ -127,8 +141,12 @@ impl Edges<Pixels> {
}
#[derive(Clone, Copy, Default, Add, AddAssign, Sub, Mul, Div, PartialEq)]
#[repr(transparent)]
pub struct Pixels(pub(crate) f32);
unsafe impl bytemuck::Pod for Pixels {}
unsafe impl bytemuck::Zeroable for Pixels {}
impl Debug for Pixels {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} px", self.0)
+1 -2
View File
@@ -3,7 +3,7 @@ mod color;
mod element;
mod elements;
mod geometry;
mod ordered;
mod renderer;
mod scene;
mod style;
mod taffy;
@@ -18,7 +18,6 @@ pub use elements::*;
pub use geometry::*;
pub use gpui2::ArcCow;
use gpui2::Reference;
use ordered::*;
pub use scene::*;
pub use style::*;
pub use taffy::LayoutId;
-24
View File
@@ -1,24 +0,0 @@
pub struct Ordered<P> {
pub order: u32,
pub primitive: P,
}
impl<P> Ord for Ordered<P> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.order.cmp(&other.order)
}
}
impl<P> PartialOrd for Ordered<P> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<P> Eq for Ordered<P> {}
impl<P> PartialEq for Ordered<P> {
fn eq(&self, other: &Self) -> bool {
self.order == other.order
}
}
+164
View File
@@ -0,0 +1,164 @@
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
use super::{Scene, Size};
pub struct Renderer {
device: wgpu::Device,
queue: wgpu::Queue,
surface: wgpu::Surface,
surface_config: wgpu::SurfaceConfiguration,
pipeline: wgpu::RenderPipeline,
vertex_buffer: wgpu::Buffer,
vertex_count: u32,
}
pub trait Window: HasRawWindowHandle + HasRawDisplayHandle {
fn inner_size(&self) -> Size<u32>;
}
impl Renderer {
pub async fn new<W>(window: &W) -> Self
where
W: Window,
{
let instance = wgpu::Instance::new(Default::default());
let surface = unsafe { instance.create_surface(window).unwrap() };
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions::default())
.await
.unwrap();
let (device, queue) = adapter
.request_device(&wgpu::DeviceDescriptor::default(), None)
.await
.unwrap();
let surface_config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: wgpu::TextureFormat::Bgra8UnormSrgb,
width: window.inner_size().width,
height: window.inner_size().height,
// "FIFO" mode renders frames in queue synced with the display's refresh rate.
// Avoids screen tearing but may not offer the lowest latency. Ideal when image
// 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,
// 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).
// sRGB is the standard color space for displaying images and video on digital displays,
// as it optimises color accuracy and consistency.
view_formats: vec![wgpu::TextureFormat::Bgra8UnormSrgb],
};
surface.configure(&device, &surface_config);
let vs_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Vertex Shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shader.vert.wgsl").into()),
});
let fs_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Fragment Shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shader.frag.wgsl").into()),
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"),
bind_group_layouts: &[],
push_constant_ranges: &[],
});
let vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Vertex Buffer"),
size: 0,
usage: wgpu::BufferUsages::VERTEX,
mapped_at_creation: false,
});
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &vs_module,
entry_point: "main",
buffers: &[],
},
fragment: Some(wgpu::FragmentState {
module: &fs_module,
entry_point: "main",
targets: &[Some(wgpu::ColorTargetState {
format: surface_config.format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleStrip,
..Default::default()
},
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview: None,
});
Self {
device,
queue,
surface,
surface_config,
pipeline,
vertex_buffer,
vertex_count: 0,
}
}
pub fn render(&mut self, scene: &Scene) {
let frame = self.surface.get_current_texture().unwrap();
let view = frame
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
self.queue.write_buffer(
&self.vertex_buffer,
0,
bytemuck::cast_slice(&scene.opaque_primitives().quads),
);
self.vertex_count = scene.opaque_primitives().quads.len() as u32;
let mut encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
});
{
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
store: true,
},
})],
depth_stencil_attachment: None,
});
render_pass.set_pipeline(&self.pipeline);
render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
render_pass.draw(0..self.vertex_count, 0..1);
}
self.queue.submit(std::iter::once(encoder.finish()));
}
}
+91 -25
View File
@@ -1,45 +1,111 @@
use super::Ordered;
use super::{Bounds, Hsla, Pixels, Point};
use bytemuck::{Pod, Zeroable};
use plane_split::BspSplitter;
/// A platform neutral representation of all geometry to be drawn for the current frame.
pub struct Scene {
quads: Vec<Ordered<Quad>>,
glyphs: Vec<Ordered<Glyph>>,
opaque_primitives: PrimitiveBatch,
transparent_primitives: slotmap::SlotMap<slotmap::DefaultKey, Primitive>,
splitter: BspSplitter<slotmap::DefaultKey>,
}
impl Scene {
pub fn new() -> Self {
pub fn new() -> Scene {
Scene {
quads: Vec::new(),
glyphs: Vec::new(),
opaque_primitives: PrimitiveBatch::default(),
transparent_primitives: slotmap::SlotMap::new(),
splitter: BspSplitter::new(),
}
}
pub fn add(&mut self, order: u32, primitive: impl Into<Primitive>) {
match primitive.into() {
Primitive::Quad(primitive) => self.quads.push(Ordered { order, primitive }),
Primitive::Glyph(primitive) => self.glyphs.push(Ordered { order, primitive }),
pub fn insert(&mut self, primitive: impl Into<Primitive>, is_transparent: bool) {
if is_transparent {
self.transparent_primitives.insert(primitive.into());
} else {
match primitive.into() {
Primitive::Quad(quad) => self.opaque_primitives.quads.push(quad),
Primitive::Glyph(glyph) => self.opaque_primitives.glyphs.push(glyph),
}
}
}
pub fn draw(&mut self) {
self.quads.sort_unstable();
self.glyphs.sort_unstable();
pub fn opaque_primitives(&self) -> &PrimitiveBatch {
&self.opaque_primitives
}
}
#[derive(Clone, Debug)]
pub enum Primitive {
Quad(Quad),
Glyph(Glyph),
// Icon(Icon),
// Image(Image),
// Shadow(Shadow),
// Curve(Curve),
}
#[derive(Eq, Ord, PartialEq, PartialOrd)]
pub struct Quad {}
pub struct Glyph {}
// pub struct Icon {}
// pub struct Image {}
// pub struct Shadow {}
// pub struct Curve {}
impl Primitive {
pub fn is_transparent(&self) -> bool {
match self {
Primitive::Quad(quad) => {
quad.background.is_transparent() && quad.border_color.is_transparent()
}
Primitive::Glyph(glyph) => glyph.color.is_transparent(),
}
}
}
#[derive(Default)]
pub struct PrimitiveBatch {
pub quads: Vec<Quad>,
pub glyphs: Vec<Glyph>,
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct Quad {
pub order: f32,
pub bounds: Bounds<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,
}
impl Quad {
pub fn vertices(&self) -> impl Iterator<Item = Point<Pixels>> {
let x1 = self.bounds.origin.x;
let y1 = self.bounds.origin.y;
let x2 = x1 + self.bounds.size.width;
let y2 = y1 + self.bounds.size.height;
[
Point::new(x1, y1),
Point::new(x2, y1),
Point::new(x2, y2),
Point::new(x1, y2),
]
.into_iter()
}
}
unsafe impl Zeroable for Quad {}
unsafe impl Pod for Quad {}
#[derive(Debug, Clone)]
pub struct Glyph {
pub order: f32,
pub bounds: Bounds<Pixels>,
pub color: Hsla,
// ...
}
impl From<Quad> for Primitive {
fn from(quad: Quad) -> Self {
Primitive::Quad(quad)
}
}
impl From<Glyph> for Primitive {
fn from(glyph: Glyph) -> Self {
Primitive::Glyph(glyph)
}
}
@@ -0,0 +1 @@