Checkpoint

This commit is contained in:
Antonio Scandurra
2023-09-23 09:10:33 -06:00
parent 6a95f9e349
commit df388d9f33
14 changed files with 298 additions and 699 deletions
+2 -2
View File
@@ -57,8 +57,6 @@ waker-fn = "1.1.0"
slotmap = "1.0.6"
bytemuck = "1.14.0"
schemars.workspace = true
raw-window-handle = "0.5.2"
wgpu = "0.17.0"
plane-split = "0.18.0"
[dev-dependencies]
@@ -71,6 +69,7 @@ simplelog = "0.9"
[build-dependencies]
bindgen = "0.65.1"
cbindgen = "0.26.0"
[target.'cfg(target_os = "macos")'.dependencies]
media = { path = "../media" }
@@ -83,4 +82,5 @@ core-text = "19.2"
font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "b2f77d56f450338aa4f7dd2f0197d8c9acb0cf18" }
foreign-types = "0.3"
log.workspace = true
metal = "0.21.0"
objc = "0.2"
+82 -1
View File
@@ -1,7 +1,13 @@
use std::{env, path::PathBuf};
use std::{
env,
path::{Path, PathBuf},
process::{self, Command},
};
fn main() {
generate_dispatch_bindings();
let header_path = generate_shader_bindings();
compile_metal_shaders(&header_path);
}
fn generate_dispatch_bindings() {
@@ -22,3 +28,78 @@ fn generate_dispatch_bindings() {
.write_to_file(out_path.join("dispatch_sys.rs"))
.expect("couldn't write dispatch bindings");
}
fn generate_shader_bindings() -> PathBuf {
let output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("scene.h");
let crate_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
cbindgen::Builder::new()
.with_language(cbindgen::Language::C)
.with_include_guard("SCENE_H")
.with_src(crate_dir.join("src/scene.rs"))
.with_src(crate_dir.join("src/geometry.rs"))
.with_src(crate_dir.join("src/color.rs"))
.with_no_includes()
.include_item("Quad")
.include_item("Bounds")
.include_item("Corners")
.include_item("Edges")
.include_item("Size")
.include_item("Pixels")
.include_item("Point")
.include_item("Hsla")
.generate()
.expect("Unable to generate bindings")
.write_to_file(&output_path);
output_path
}
fn compile_metal_shaders(header_path: &Path) {
let shader_path = "./src/platform/mac/shaders.metal";
let air_output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.air");
let metallib_output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.metallib");
println!("cargo:rerun-if-changed={}", header_path.display());
println!("cargo:rerun-if-changed={}", shader_path);
let output = Command::new("xcrun")
.args([
"-sdk",
"macosx",
"metal",
"-gline-tables-only",
"-mmacosx-version-min=10.15.7",
"-MO",
"-c",
shader_path,
"-include",
&header_path.to_str().unwrap(),
"-o",
])
.arg(&air_output_path)
.output()
.unwrap();
if !output.status.success() {
eprintln!(
"metal shader compilation failed:\n{}",
String::from_utf8_lossy(&output.stderr)
);
process::exit(1);
}
let output = Command::new("xcrun")
.args(["-sdk", "macosx", "metallib"])
.arg(air_output_path)
.arg("-o")
.arg(metallib_output_path)
.output()
.unwrap();
if !output.status.success() {
eprintln!(
"metallib compilation failed:\n{}",
String::from_utf8_lossy(&output.stderr)
);
process::exit(1);
}
}
+4
View File
@@ -77,6 +77,7 @@ unsafe impl<T: Clone + Debug + Zeroable + Pod> Pod for Point<T> {}
#[derive(Refineable, Default, Clone, Copy, Debug, PartialEq)]
#[refineable(debug)]
#[repr(C)]
pub struct Size<T: Clone + Debug> {
pub width: T,
pub height: T,
@@ -133,6 +134,7 @@ impl Size<Length> {
#[derive(Refineable, Clone, Default, Debug, PartialEq)]
#[refineable(debug)]
#[repr(C)]
pub struct Bounds<T: Clone + Debug> {
pub origin: Point<T>,
pub size: Size<T>,
@@ -170,6 +172,7 @@ impl<T: Clone + Debug + Copy> Copy for Bounds<T> {}
#[derive(Refineable, Clone, Default, Debug)]
#[refineable(debug)]
#[repr(C)]
pub struct Edges<T: Clone + Debug> {
pub top: T,
pub right: T,
@@ -242,6 +245,7 @@ impl Edges<Pixels> {
#[derive(Refineable, Clone, Default, Debug)]
#[refineable(debug)]
#[repr(C)]
pub struct Corners<T: Clone + Debug> {
pub top_left: T,
pub top_right: T,
-2
View File
@@ -5,7 +5,6 @@ mod elements;
mod executor;
mod geometry;
mod platform;
mod renderer;
mod scene;
mod style;
mod style_helpers;
@@ -26,7 +25,6 @@ pub use geometry::*;
pub use gpui3_macros::*;
pub use platform::*;
pub use refineable::*;
use renderer::*;
pub use scene::*;
pub use serde;
pub use serde_json;
+1 -26
View File
@@ -7,14 +7,11 @@ mod test;
use crate::{
AnyWindowHandle, Bounds, FontFeatures, FontId, FontMetrics, FontStyle, FontWeight, GlyphId,
LineLayout, Pixels, Point, RenderTarget, Result, RunStyle, SharedString, Size,
LineLayout, Pixels, Point, Result, RunStyle, SharedString, Size,
};
use anyhow::anyhow;
use async_task::Runnable;
use futures::channel::oneshot;
use raw_window_handle::{
HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
};
use seahash::SeaHasher;
use serde::{Deserialize, Serialize};
use std::ffi::c_void;
@@ -117,9 +114,6 @@ impl Debug for PlatformScreenHandle {
unsafe impl Send for PlatformScreenHandle {}
pub trait PlatformWindow {
fn raw_window_handle(&self) -> RawWindowHandle;
fn raw_display_handle(&self) -> RawDisplayHandle;
fn bounds(&self) -> WindowBounds;
fn content_size(&self) -> Size<Pixels>;
fn scale_factor(&self) -> f32;
@@ -153,25 +147,6 @@ pub trait PlatformWindow {
fn is_topmost_for_position(&self, position: Point<Pixels>) -> bool;
}
unsafe impl<'a> HasRawWindowHandle for &'a dyn PlatformWindow {
fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
(*self).raw_window_handle()
}
}
unsafe impl<'a> HasRawDisplayHandle for &'a dyn PlatformWindow {
fn raw_display_handle(&self) -> raw_window_handle::RawDisplayHandle {
(*self).raw_display_handle()
}
}
impl<'a> RenderTarget for &'a dyn PlatformWindow {
fn content_device_size(&self) -> Size<crate::DevicePixels> {
self.content_size()
.map(|d| d.to_device_pixels(self.scale_factor()))
}
}
pub trait PlatformDispatcher: Send + Sync {
fn is_main_thread(&self) -> bool;
fn run_on_main_thread(&self, task: Runnable);
+1
View File
@@ -2,6 +2,7 @@
///! an origin at the bottom left of the main display.
mod dispatcher;
mod events;
mod metal_renderer;
mod open_type;
mod platform;
mod screen;
@@ -0,0 +1,153 @@
// use cocoa::{
// base::{NO, YES},
// foundation::NSUInteger,
// quartzcore::AutoresizingMask,
// };
// use core_foundation::base::TCFType;
// use foreign_types::ForeignTypeRef;
// use log::warn;
// use media::core_video::{self, CVMetalTextureCache};
// use metal::{CommandQueue, MTLPixelFormat, MTLResourceOptions, NSRange};
// use objc::{self, msg_send, sel, sel_impl};
// use shaders::ToFloat2 as _;
// use std::{collections::HashMap, ffi::c_void, iter::Peekable, mem, ptr, sync::Arc, vec};
// use crate::{Quad, Scene};
// const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib"));
// const BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value.
// pub struct Renderer {
// layer: metal::MetalLayer,
// command_queue: CommandQueue,
// quad_pipeline_state: metal::RenderPipelineState,
// buffer: metal::Buffer,
// }
// impl Renderer {
// pub fn new(is_opaque: bool, fonts: Arc<dyn platform::FontSystem>) -> Self {
// const PIXEL_FORMAT: MTLPixelFormat = MTLPixelFormat::BGRA8Unorm;
// let device: metal::Device = if let Some(device) = metal::Device::system_default() {
// device
// } else {
// log::error!("unable to access a compatible graphics device");
// std::process::exit(1);
// };
// let layer = metal::MetalLayer::new();
// layer.set_device(&device);
// layer.set_pixel_format(PIXEL_FORMAT);
// layer.set_presents_with_transaction(true);
// layer.set_opaque(is_opaque);
// unsafe {
// let _: () = msg_send![&*layer, setAllowsNextDrawableTimeout: NO];
// let _: () = msg_send![&*layer, setNeedsDisplayOnBoundsChange: YES];
// let _: () = msg_send![
// &*layer,
// setAutoresizingMask: AutoresizingMask::WIDTH_SIZABLE
// | AutoresizingMask::HEIGHT_SIZABLE
// ];
// }
// let library = device
// .new_library_with_data(SHADERS_METALLIB)
// .expect("error building metal library");
// let buffer = device.new_buffer(BUFFER_SIZE as u64, MTLResourceOptions::StorageModeManaged);
// let quad_pipeline_state = build_pipeline_state(
// &device,
// &library,
// "quad",
// "quad_vertex",
// "quad_fragment",
// PIXEL_FORMAT,
// );
// Self {
// layer,
// command_queue: device.new_command_queue(),
// quad_pipeline_state,
// buffer,
// }
// }
// pub fn draw(&mut self, scene: &Scene) {
// draw_quads(scene);
// }
// fn draw_quads(
// &mut self,
// quads: &[Quad],
// scale_factor: f32,
// offset: &mut usize,
// drawable_size: Vector2F,
// command_encoder: &metal::RenderCommandEncoderRef,
// ) {
// if quads.is_empty() {
// return;
// }
// align_offset(offset);
// let next_offset = *offset + quads.len() * mem::size_of::<shaders::GPUIQuad>();
// assert!(
// next_offset <= INSTANCE_BUFFER_SIZE,
// "instance buffer exhausted"
// );
// command_encoder.set_render_pipeline_state(&self.quad_pipeline_state);
// command_encoder.set_vertex_buffer(
// shaders::GPUIQuadInputIndex_GPUIQuadInputIndexVertices as u64,
// Some(&self.unit_vertices),
// 0,
// );
// command_encoder.set_vertex_buffer(
// shaders::GPUIQuadInputIndex_GPUIQuadInputIndexQuads as u64,
// Some(&self.instances),
// *offset as u64,
// );
// command_encoder.set_vertex_bytes(
// shaders::GPUIQuadInputIndex_GPUIQuadInputIndexUniforms as u64,
// mem::size_of::<shaders::GPUIUniforms>() as u64,
// [shaders::GPUIUniforms {
// viewport_size: drawable_size.to_float2(),
// }]
// .as_ptr() as *const c_void,
// );
// let buffer_contents = unsafe {
// (self.instances.contents() as *mut u8).add(*offset) as *mut shaders::GPUIQuad
// };
// for (ix, quad) in quads.iter().enumerate() {
// let bounds = quad.bounds * scale_factor;
// let shader_quad = shaders::GPUIQuad {
// origin: bounds.origin().round().to_float2(),
// size: bounds.size().round().to_float2(),
// background_color: quad
// .background
// .unwrap_or_else(Color::transparent_black)
// .to_uchar4(),
// border_top: quad.border.top * scale_factor,
// border_right: quad.border.right * scale_factor,
// border_bottom: quad.border.bottom * scale_factor,
// border_left: quad.border.left * scale_factor,
// border_color: quad.border.color.to_uchar4(),
// corner_radius_top_left: quad.corner_radii.top_left * scale_factor,
// corner_radius_top_right: quad.corner_radii.top_right * scale_factor,
// corner_radius_bottom_right: quad.corner_radii.bottom_right * scale_factor,
// corner_radius_bottom_left: quad.corner_radii.bottom_left * scale_factor,
// };
// unsafe {
// *(buffer_contents.add(ix)) = shader_quad;
// }
// }
// command_encoder.draw_primitives_instanced(
// metal::MTLPrimitiveType::Triangle,
// 0,
// 6,
// quads.len() as u64,
// );
// *offset = next_offset;
// }
// }
+5 -22
View File
@@ -1,9 +1,9 @@
use crate::{
point, px, size, AnyWindowHandle, Bounds, DevicePixels, Event, InputHandler, KeyDownEvent,
Keystroke, MacScreen, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent,
MouseMovedEvent, MouseUpEvent, NSRectExt, Pixels, Platform, PlatformDispatcher, PlatformScreen,
PlatformWindow, Point, RenderTarget, Size, Timer, WindowAppearance, WindowBounds, WindowKind,
WindowOptions, WindowPromptLevel,
point, px, size, AnyWindowHandle, Bounds, Event, InputHandler, KeyDownEvent, Keystroke,
MacScreen, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent,
MouseUpEvent, NSRectExt, Pixels, Platform, PlatformDispatcher, PlatformScreen, PlatformWindow,
Point, Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions,
WindowPromptLevel,
};
use block::ConcreteBlock;
use cocoa::{
@@ -26,10 +26,6 @@ use objc::{
sel, sel_impl,
};
use parking_lot::Mutex;
use raw_window_handle::{
AppKitDisplayHandle, AppKitWindowHandle, HasRawDisplayHandle, HasRawWindowHandle,
RawDisplayHandle, RawWindowHandle,
};
use std::{
any::Any,
cell::{Cell, RefCell},
@@ -626,19 +622,6 @@ impl Drop for MacWindow {
}
impl PlatformWindow for MacWindow {
fn raw_window_handle(&self) -> RawWindowHandle {
let ns_window = self.0.lock().native_window;
let ns_view = unsafe { ns_window.contentView() };
let mut handle = AppKitWindowHandle::empty();
handle.ns_window = ns_window as *mut c_void;
handle.ns_view = ns_view as *mut c_void;
handle.into()
}
fn raw_display_handle(&self) -> RawDisplayHandle {
AppKitDisplayHandle::empty().into()
}
fn bounds(&self) -> WindowBounds {
self.0.as_ref().lock().bounds()
}
-180
View File
@@ -1,180 +0,0 @@
use crate::{DevicePixels, Scene, Size};
use futures::{future::BoxFuture, FutureExt};
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
use wgpu::Backends;
pub struct Renderer {
device: wgpu::Device,
queue: wgpu::Queue,
surface: wgpu::Surface,
surface_config: wgpu::SurfaceConfiguration,
quad_pipeline: wgpu::RenderPipeline,
vertex_buffer: wgpu::Buffer,
vertex_count: u32,
uniforms_buffer: wgpu::Buffer,
}
pub(crate) trait RenderTarget: HasRawWindowHandle + HasRawDisplayHandle {
fn content_device_size(&self) -> Size<DevicePixels>;
}
impl Renderer {
pub(crate) fn new<'a, W>(window: &'a W) -> BoxFuture<'static, Self>
where
W: RenderTarget,
{
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: Backends::METAL,
..Default::default()
});
let surface = unsafe { instance.create_surface(window).unwrap() };
let width = window.content_device_size().width;
let height = window.content_device_size().height;
async move {
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: width.into(),
height: height.into(),
// "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,
// 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).
// 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 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: &[],
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 quad_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &vs_module,
entry_point: "quad",
buffers: &[],
},
fragment: Some(wgpu::FragmentState {
module: &fs_module,
entry_point: "quad",
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,
quad_pipeline,
vertex_buffer,
vertex_count: 0,
uniforms_buffer,
}
}
.boxed()
}
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.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);
}
self.queue.submit(std::iter::once(encoder.finish()));
}
}
+10
View File
@@ -102,6 +102,16 @@ impl From<Quad> for Primitive {
}
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub(crate) struct QuadUniforms {
viewport_size: [f32; 2],
}
unsafe impl Zeroable for QuadUniforms {}
unsafe impl Pod for QuadUniforms {}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct RenderedGlyph {
-88
View File
@@ -1,88 +0,0 @@
[[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;
}
+3 -7
View File
@@ -1,7 +1,7 @@
use crate::{
px, renderer::Renderer, taffy::LayoutId, AppContext, AvailableSpace, Bounds, Context, EntityId,
Handle, MainThreadOnly, Pixels, Platform, PlatformWindow, Point, Reference, Size, Style,
TaffyLayoutEngine, TextStyle, TextStyleRefinement, WindowOptions,
px, AppContext, AvailableSpace, Bounds, Context, EntityId, Handle, LayoutId, MainThreadOnly,
Pixels, Platform, PlatformWindow, Point, Reference, Size, Style, TaffyLayoutEngine, TextStyle,
TextStyleRefinement, WindowOptions,
};
use anyhow::Result;
use derive_more::{Deref, DerefMut};
@@ -18,7 +18,6 @@ pub struct AnyWindow {}
pub struct Window {
handle: AnyWindowHandle,
platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
renderer: Renderer,
rem_size: Pixels,
layout_engine: TaffyLayoutEngine,
text_style_stack: Vec<TextStyleRefinement>,
@@ -33,16 +32,13 @@ impl Window {
platform: &dyn Platform,
) -> impl Future<Output = Window> + 'static {
let platform_window = platform.open_window(handle, options);
let renderer = Renderer::new(&platform_window.as_ref());
let mouse_position = platform_window.mouse_position();
let platform_window = MainThreadOnly::new(Arc::new(platform_window), platform.dispatcher());
async move {
let renderer = renderer.await;
Window {
handle,
platform_window,
renderer,
rem_size: px(16.),
layout_engine: TaffyLayoutEngine::new(),
text_style_stack: Vec::new(),