diff --git a/crates/gpui3/src/app.rs b/crates/gpui3/src/app.rs index 164a04199c..377e9701d0 100644 --- a/crates/gpui3/src/app.rs +++ b/crates/gpui3/src/app.rs @@ -3,7 +3,7 @@ use crate::{ Window, WindowContext, WindowHandle, WindowId, }; use anyhow::{anyhow, Result}; -use futures::Future; +use futures::{future, Future}; use parking_lot::Mutex; use slotmap::SlotMap; use std::{ @@ -77,7 +77,7 @@ impl AppContext { f: impl FnOnce(&dyn Platform, &mut Self) -> F + Send + 'static, ) -> impl Future where - F: Future + Send + 'static, + F: Future + 'static, R: Send + 'static, { let this = self.this.upgrade().unwrap(); @@ -94,19 +94,13 @@ impl AppContext { ) -> impl Future> { let id = self.windows.insert(None); let handle = WindowHandle::new(id); - let window = - self.spawn_on_main(move |platform, _cx| Window::new(handle.into(), options, platform)); - - let this = self.this.upgrade().unwrap(); - async move { - let mut window = window.await; - let cx = &mut *this.lock(); + self.spawn_on_main(move |platform, cx| { + let mut window = Window::new(handle.into(), options, platform); let root_view = build_root_view(&mut WindowContext::mutable(cx, &mut window)); window.root_view.replace(Box::new(root_view)); - cx.windows.get_mut(id).unwrap().replace(window); - handle - } + future::ready(handle) + }) } pub(crate) fn update_window( diff --git a/crates/gpui3/src/color.rs b/crates/gpui3/src/color.rs index fa28b14ee4..052ff8a621 100644 --- a/crates/gpui3/src/color.rs +++ b/crates/gpui3/src/color.rs @@ -5,7 +5,7 @@ use serde::de::{self, Deserialize, Deserializer, Visitor}; use std::fmt; use std::num::ParseIntError; -pub fn rgb>(hex: u32) -> C { +pub fn rgb(hex: u32) -> Rgba { let r = ((hex >> 16) & 0xFF) as f32 / 255.0; let g = ((hex >> 8) & 0xFF) as f32 / 255.0; let b = (hex & 0xFF) as f32 / 255.0; diff --git a/crates/gpui3/src/platform/mac.rs b/crates/gpui3/src/platform/mac.rs index 40d9db3c28..89b2b420fd 100644 --- a/crates/gpui3/src/platform/mac.rs +++ b/crates/gpui3/src/platform/mac.rs @@ -16,6 +16,7 @@ use cocoa::{ base::{id, nil}, foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger, NSURL}, }; +use metal_renderer::*; use objc::{ msg_send, runtime::{BOOL, NO, YES}, diff --git a/crates/gpui3/src/platform/mac/metal_renderer.rs b/crates/gpui3/src/platform/mac/metal_renderer.rs index cae902998e..c2cd484cbe 100644 --- a/crates/gpui3/src/platform/mac/metal_renderer.rs +++ b/crates/gpui3/src/platform/mac/metal_renderer.rs @@ -12,7 +12,7 @@ use std::{ffi::c_void, mem, ptr}; const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib")); const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value. -pub struct Renderer { +pub struct MetalRenderer { layer: metal::MetalLayer, command_queue: CommandQueue, quad_pipeline_state: metal::RenderPipelineState, @@ -20,7 +20,7 @@ pub struct Renderer { instances: metal::Buffer, } -impl Renderer { +impl MetalRenderer { pub fn new(is_opaque: bool) -> Self { const PIXEL_FORMAT: MTLPixelFormat = MTLPixelFormat::BGRA8Unorm; @@ -50,10 +50,26 @@ impl Renderer { .new_library_with_data(SHADERS_METALLIB) .expect("error building metal library"); - let unit_vertices = [point(1., 1.), point(1., 0.), point(0., 0.), point(0., 1.)]; + fn to_float2_bits(point: crate::PointF) -> u64 { + unsafe { + let mut output = mem::transmute::<_, u32>(point.y.to_bits()) as u64; + output <<= 32; + output |= mem::transmute::<_, u32>(point.x.to_bits()) as u64; + output + } + } + + let unit_vertices = [ + to_float2_bits(point(0., 0.)), + to_float2_bits(point(1., 0.)), + to_float2_bits(point(0., 1.)), + to_float2_bits(point(0., 1.)), + to_float2_bits(point(1., 0.)), + to_float2_bits(point(1., 1.)), + ]; let unit_vertices = device.new_buffer_with_data( unit_vertices.as_ptr() as *const c_void, - (unit_vertices.len() * mem::size_of::()) as u64, + (unit_vertices.len() * mem::size_of::()) as u64, MTLResourceOptions::StorageModeManaged, ); let instances = device.new_buffer( @@ -79,6 +95,10 @@ impl Renderer { } } + pub fn layer(&self) -> &metal::MetalLayerRef { + &*self.layer + } + pub fn draw(&mut self, scene: &Scene, scale_factor: f32) { let layer = self.layer.clone(); let viewport_size = layer.drawable_size(); @@ -125,11 +145,13 @@ impl Renderer { scene.max_order(), command_encoder, ); + command_encoder.end_encoding(); self.instances.did_modify_range(NSRange { location: 0, length: buffer_offset as NSUInteger, }); + command_buffer.commit(); command_buffer.wait_until_completed(); drawable.present(); @@ -165,6 +187,7 @@ impl Renderer { scale_factor, max_order, }; + let quad_uniform_bytes = bytemuck::bytes_of(&quad_uniforms); command_encoder.set_vertex_bytes( QuadInputIndex::Uniforms as u64, @@ -184,10 +207,11 @@ impl Renderer { "instance buffer exhausted" ); + dbg!(quads.len()); command_encoder.draw_primitives_instanced( - metal::MTLPrimitiveType::TriangleStrip, + metal::MTLPrimitiveType::Triangle, 0, - 4, + 6, quads.len() as u64, ); *offset = next_offset; @@ -235,9 +259,9 @@ fn align_offset(offset: &mut usize) { #[repr(C)] enum QuadInputIndex { - Vertices, - Quads, - Uniforms, + Vertices = 0, + Quads = 1, + Uniforms = 2, } #[derive(Debug, Clone, Copy, Zeroable, Pod)] diff --git a/crates/gpui3/src/platform/mac/screen.rs b/crates/gpui3/src/platform/mac/screen.rs index 6a7b325dee..352a36c5a1 100644 --- a/crates/gpui3/src/platform/mac/screen.rs +++ b/crates/gpui3/src/platform/mac/screen.rs @@ -1,7 +1,6 @@ use super::ns_string; use crate::{ - platform, point, px, size, Bounds, MainThreadOnly, Pixels, PlatformScreen, - PlatformScreenHandle, ScreenId, + platform, point, px, size, Bounds, Pixels, PlatformScreen, PlatformScreenHandle, ScreenId, }; use cocoa::{ appkit::NSScreen, diff --git a/crates/gpui3/src/platform/mac/shaders.metal b/crates/gpui3/src/platform/mac/shaders.metal index e06e0ebf4c..6ac1742ccf 100644 --- a/crates/gpui3/src/platform/mac/shaders.metal +++ b/crates/gpui3/src/platform/mac/shaders.metal @@ -8,6 +8,8 @@ float4 to_device_position(float2 pixel_position, uint order, uint max_order, flo struct QuadVertexOutput { float4 position [[position]]; + float4 background_color; + float4 border_color; uint quad_id; }; @@ -23,7 +25,14 @@ vertex QuadVertexOutput quad_vertex( float2 position_2d = unit_vertex * float2(quad.bounds.size.width, quad.bounds.size.height) + float2(quad.bounds.origin.x, quad.bounds.origin.y); float2 viewport_size = float2(uniforms->viewport_size.width, uniforms->viewport_size.height); float4 device_position = to_device_position(position_2d, quad.order, uniforms->max_order, viewport_size); - return QuadVertexOutput { device_position, quad_id }; + float4 background_color = hsla_to_rgba(quad.background); + float4 border_color = hsla_to_rgba(quad.border_color); + return QuadVertexOutput { + device_position, + background_color, + border_color, + quad_id + }; } fragment float4 quad_fragment(QuadVertexOutput input [[stage_in]], constant Quad *quads [[buffer(QuadInputIndex_Quads)]]) { @@ -64,26 +73,26 @@ fragment float4 quad_fragment(QuadVertexOutput input [[stage_in]], constant Quad float4 color; if (border_width == 0.) { - color = float4(quad.background.h, quad.background.s, quad.background.l, quad.background.a); + color = input.background_color; } else { float inset_distance = distance + border_width; // Decrease border's opacity as we move inside the background. - quad.border_color.a *= 1. - saturate(0.5 - inset_distance); + input.border_color.a *= 1. - saturate(0.5 - inset_distance); // Alpha-blend the border and the background. float output_alpha = quad.border_color.a + quad.background.a * (1. - quad.border_color.a); - float3 premultiplied_border_rgb = float3(quad.border_color.h, quad.border_color.s, quad.border_color.l) * quad.border_color.a; - float3 premultiplied_background_rgb = float3(quad.background.h, quad.background.s, quad.background.l) * quad.background.a; - float3 premultiplied_output_rgb = premultiplied_border_rgb + premultiplied_background_rgb * (1. - quad.border_color.a); - color = float4(premultiplied_output_rgb.x, premultiplied_output_rgb.y, premultiplied_output_rgb.z, output_alpha); + float3 premultiplied_border_rgb = input.border_color.rgb * quad.border_color.a; + float3 premultiplied_background_rgb = input.background_color.rgb * input.background_color.a; + float3 premultiplied_output_rgb = premultiplied_border_rgb + premultiplied_background_rgb * (1. - input.border_color.a); + color = float4(premultiplied_output_rgb, output_alpha); } return color; } float4 hsla_to_rgba(Hsla hsla) { - float h = hsla.h; + float h = hsla.h * 6.0; // Now, it's an angle but scaled in [0, 6) range float s = hsla.s; float l = hsla.l; float a = hsla.a; diff --git a/crates/gpui3/src/platform/mac/window.rs b/crates/gpui3/src/platform/mac/window.rs index 092cb839e5..20a9a37e1e 100644 --- a/crates/gpui3/src/platform/mac/window.rs +++ b/crates/gpui3/src/platform/mac/window.rs @@ -1,3 +1,4 @@ +use super::{ns_string, MetalRenderer, NSRange}; use crate::{ point, px, size, AnyWindowHandle, Bounds, Event, InputHandler, KeyDownEvent, Keystroke, MacScreen, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent, @@ -17,6 +18,7 @@ use cocoa::{ }; use core_graphics::display::CGRect; use ctor::ctor; +use foreign_types::{ForeignType, ForeignTypeRef}; use futures::channel::oneshot; use objc::{ class, @@ -39,8 +41,6 @@ use std::{ time::Duration, }; -use super::{ns_string, NSRange}; - const WINDOW_STATE_IVAR: &str = "windowState"; static mut WINDOW_CLASS: *const Class = ptr::null(); @@ -134,10 +134,10 @@ unsafe fn build_classes() { cancel_operation as extern "C" fn(&Object, Sel, id), ); - // decl.add_method( - // sel!(makeBackingLayer), - // make_backing_layer as extern "C" fn(&Object, Sel) -> id, - // ); + decl.add_method( + sel!(makeBackingLayer), + make_backing_layer as extern "C" fn(&Object, Sel) -> id, + ); decl.add_protocol(Protocol::get("CALayerDelegate").unwrap()); decl.add_method( @@ -277,10 +277,11 @@ struct InsertText { text: String, } -struct WindowState { +struct MacWindowState { handle: AnyWindowHandle, dispatcher: Arc, native_window: id, + renderer: MetalRenderer, kind: WindowKind, event_callback: Option bool>>, activate_callback: Option>, @@ -303,7 +304,7 @@ struct WindowState { ime_text: Option, } -impl WindowState { +impl MacWindowState { fn move_traffic_light(&self) { if let Some(traffic_light_position) = self.traffic_light_position { let titlebar_height = self.titlebar_height(); @@ -408,9 +409,9 @@ impl WindowState { } } -unsafe impl Send for WindowState {} +unsafe impl Send for MacWindowState {} -pub struct MacWindow(Arc>); +pub struct MacWindow(Arc>); impl MacWindow { pub fn open(handle: AnyWindowHandle, options: WindowOptions, platform: &dyn Platform) -> Self { @@ -475,18 +476,19 @@ impl MacWindow { assert!(!native_view.is_null()); - let window = Self(Arc::new(Mutex::new(WindowState { + let window = Self(Arc::new(Mutex::new(MacWindowState { handle, dispatcher: platform.dispatcher(), native_window, + renderer: MetalRenderer::new(true), kind: options.kind, event_callback: None, - resize_callback: None, - should_close_callback: None, - close_callback: None, activate_callback: None, + resize_callback: None, fullscreen_callback: None, moved_callback: None, + should_close_callback: None, + close_callback: None, appearance_changed_callback: None, input_handler: None, pending_key_down: None, @@ -882,9 +884,9 @@ fn get_scale_factor(native_window: id) -> f32 { } } -unsafe fn get_window_state(object: &Object) -> Arc> { +unsafe fn get_window_state(object: &Object) -> Arc> { let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR); - let rc1 = Arc::from_raw(raw as *mut Mutex); + let rc1 = Arc::from_raw(raw as *mut Mutex); let rc2 = rc1.clone(); mem::forget(rc1); rc2 @@ -892,7 +894,7 @@ unsafe fn get_window_state(object: &Object) -> Arc> { unsafe fn drop_window_state(object: &Object) { let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR); - Rc::from_raw(raw as *mut RefCell); + Rc::from_raw(raw as *mut RefCell); } extern "C" fn yes(_: &Object, _: Sel) -> BOOL { @@ -1272,33 +1274,33 @@ extern "C" fn close_window(this: &Object, _: Sel) { } } -// extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id { -// let window_state = unsafe { get_window_state(this) }; -// let window_state = window_state.as_ref().lock(); -// window_state.renderer.layer().as_ptr() as id -// } +extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id { + let window_state = unsafe { get_window_state(this) }; + let window_state = window_state.as_ref().lock(); + window_state.renderer.layer().as_ptr() as id +} extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) { let window_state = unsafe { get_window_state(this) }; let mut window_state_borrow = window_state.as_ref().lock(); - // unsafe { - // let scale_factor = window_state_borrow.scale_factor() as f64; - // let size = window_state_borrow.content_size(); - // let drawable_size: NSSize = NSSize { - // width: f64::from(size.width) * scale_factor, - // height: f64::from(size.height) * scale_factor, - // }; + unsafe { + let scale_factor = window_state_borrow.scale_factor() as f64; + let size = window_state_borrow.content_size(); + let drawable_size: NSSize = NSSize { + width: f64::from(size.width) * scale_factor, + height: f64::from(size.height) * scale_factor, + }; - // // let _: () = msg_send![ - // // window_state_borrow.renderer.layer(), - // // setContentsScale: scale_factor - // // ]; - // // let _: () = msg_send![ - // // window_state_borrow.renderer.layer(), - // // setDrawableSize: drawable_size - // // ]; - // } + let _: () = msg_send![ + window_state_borrow.renderer.layer(), + setContentsScale: scale_factor + ]; + let _: () = msg_send![ + window_state_borrow.renderer.layer(), + setDrawableSize: drawable_size + ]; + } if let Some(mut callback) = window_state_borrow.resize_callback.take() { drop(window_state_borrow); @@ -1319,18 +1321,18 @@ extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { let _: () = msg_send![super(this, class!(NSView)), setFrameSize: size]; } - // let scale_factor = window_state_borrow.scale_factor() as f64; - // let drawable_size: NSSize = NSSize { - // width: size.width * scale_factor, - // height: size.height * scale_factor, - // }; - // - // unsafe { - // let _: () = msg_send![ - // window_state_borrow.renderer.layer(), - // setDrawableSize: drawable_size - // ]; - // } + let scale_factor = window_state_borrow.scale_factor() as f64; + let drawable_size: NSSize = NSSize { + width: size.width * scale_factor, + height: size.height * scale_factor, + }; + + unsafe { + let _: () = msg_send![ + window_state_borrow.renderer.layer(), + setDrawableSize: drawable_size + ]; + } drop(window_state_borrow); let mut window_state_borrow = window_state.lock(); @@ -1341,14 +1343,32 @@ extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { }; } -extern "C" fn display_layer(_this: &Object, _: Sel, _: id) { - // unsafe { - // let window_state = get_window_state(this); - // let mut window_state = window_state.as_ref().lock(); - // if let Some(scene) = window_state.scene_to_render.take() { - // window_state.renderer.render(&scene); - // }; - // } +extern "C" fn display_layer(this: &Object, _: Sel, _: id) { + unsafe { + let window_state = get_window_state(this); + let mut window_state = window_state.as_ref().lock(); + + let mut scene = crate::Scene::new(); + scene.insert(crate::Quad { + order: 0, + bounds: Bounds { + origin: point(10., 10.).map(px), + size: size(100., 100.).map(px), + }, + clip_bounds: Bounds { + origin: point(10., 10.).map(px), + size: size(100., 100.).map(px), + }, + clip_corner_radii: Default::default(), + background: crate::rgb(0x00ff00).into(), + border_color: Default::default(), + corner_radii: Default::default(), + border_widths: Default::default(), + }); + dbg!("!!!!!!!!!"); + let scale_factor = window_state.scale_factor(); + window_state.renderer.draw(&scene, scale_factor); + } } extern "C" fn valid_attributes_for_marked_text(_: &Object, _: Sel) -> id { @@ -1544,7 +1564,7 @@ extern "C" fn accepts_first_mouse(this: &Object, _: Sel, _: id) -> BOOL { } async fn synthetic_drag( - window_state: Weak>, + window_state: Weak>, drag_id: usize, event: MouseMovedEvent, ) { diff --git a/crates/gpui3/src/scene.rs b/crates/gpui3/src/scene.rs index 1844b94937..a029cfd5d7 100644 --- a/crates/gpui3/src/scene.rs +++ b/crates/gpui3/src/scene.rs @@ -25,19 +25,13 @@ impl Scene { } } - pub fn insert(&mut self, primitive: impl Into, is_transparent: bool) { + pub fn insert(&mut self, primitive: impl Into) { let primitive = primitive.into(); self.max_order = cmp::max(self.max_order, primitive.order()); - if is_transparent { - self.transparent_primitives.insert(primitive); - } else { - match primitive { - Primitive::Quad(quad) => self.opaque_primitives.quads.push(quad), - Primitive::Glyph(glyph) => self.opaque_primitives.glyphs.push(glyph), - Primitive::Underline(underline) => { - self.opaque_primitives.underlines.push(underline) - } - } + match primitive { + Primitive::Quad(quad) => self.opaque_primitives.quads.push(quad), + Primitive::Glyph(glyph) => self.opaque_primitives.glyphs.push(glyph), + Primitive::Underline(underline) => self.opaque_primitives.underlines.push(underline), } } diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index 35b9555e78..b0e84048cd 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -26,25 +26,18 @@ pub struct Window { } impl Window { - pub fn new( - handle: AnyWindowHandle, - options: WindowOptions, - platform: &dyn Platform, - ) -> impl Future + 'static { + pub fn new(handle: AnyWindowHandle, options: WindowOptions, platform: &dyn Platform) -> Self { let platform_window = platform.open_window(handle, options); let mouse_position = platform_window.mouse_position(); let platform_window = MainThreadOnly::new(Arc::new(platform_window), platform.dispatcher()); - - async move { - Window { - handle, - platform_window, - rem_size: px(16.), - layout_engine: TaffyLayoutEngine::new(), - text_style_stack: Vec::new(), - root_view: None, - mouse_position, - } + Window { + handle, + platform_window, + rem_size: px(16.), + layout_engine: TaffyLayoutEngine::new(), + text_style_stack: Vec::new(), + root_view: None, + mouse_position, } } }