From e5ffe43bb612784861f744df82b734b89f40e66f Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 20 Mar 2021 22:15:04 -0600 Subject: [PATCH] Get basic graphics rendering via Metal Also, handle window resize. --- .gitignore | 3 +- gpui/src/app.rs | 30 ++- gpui/src/platform/mac/app.rs | 4 +- gpui/src/platform/mac/renderer.rs | 153 ++++++++++++++- gpui/src/platform/mac/shaders/shaders.h | 2 +- gpui/src/platform/mac/shaders/shaders.metal | 13 +- gpui/src/platform/mac/window.rs | 206 +++++++++++--------- gpui/src/platform/mod.rs | 11 +- gpui/src/scene.rs | 26 ++- 9 files changed, 328 insertions(+), 120 deletions(-) diff --git a/.gitignore b/.gitignore index 212de442f4..9a0348bfce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target -.DS_Store \ No newline at end of file +/zed.xcworkspace +.DS_Store diff --git a/gpui/src/app.rs b/gpui/src/app.rs index 03dd695130..14d4aa3c7c 100644 --- a/gpui/src/app.rs +++ b/gpui/src/app.rs @@ -13,7 +13,6 @@ use pathfinder_geometry::{rect::RectF, vector::vec2f}; use smol::{channel, prelude::*}; use std::{ any::{type_name, Any, TypeId}, - borrow, cell::RefCell, collections::{HashMap, HashSet, VecDeque}, fmt::{self, Debug}, @@ -292,6 +291,7 @@ type ActionCallback = type GlobalActionCallback = dyn FnMut(&dyn Any, &mut MutableAppContext); pub struct MutableAppContext { + weak_self: Option>>, platform: Arc, fonts: Arc, assets: Arc, @@ -302,7 +302,6 @@ pub struct MutableAppContext { next_entity_id: usize, next_window_id: usize, next_task_id: usize, - weak_self: Option>>, subscriptions: HashMap>, observations: HashMap>, window_invalidations: HashMap, @@ -325,6 +324,7 @@ impl MutableAppContext { asset_source: impl AssetSource, ) -> Self { Self { + weak_self: None, platform, fonts: Arc::new(FontCache::new()), assets: Arc::new(AssetCache::new(asset_source)), @@ -339,7 +339,6 @@ impl MutableAppContext { next_entity_id: 0, next_window_id: 0, next_task_id: 0, - weak_self: None, subscriptions: HashMap::new(), observations: HashMap::new(), window_invalidations: HashMap::new(), @@ -355,6 +354,10 @@ impl MutableAppContext { } } + pub fn upgrade(&self) -> App { + App(self.weak_self.as_ref().unwrap().upgrade().unwrap()) + } + pub fn downgrade(&self) -> &AppContext { &self.ctx } @@ -624,7 +627,7 @@ impl MutableAppContext { self.foreground.clone(), ) { Err(e) => log::error!("error opening window: {}", e), - Ok(window) => { + Ok(mut window) => { let presenter = Rc::new(RefCell::new(Presenter::new( window_id, self.fonts.clone(), @@ -632,11 +635,26 @@ impl MutableAppContext { self, ))); + { + let mut app = self.upgrade(); + let presenter = presenter.clone(); + window.on_resize(Box::new(move |window| { + app.update(|ctx| { + let scene = presenter.borrow_mut().build_scene( + window.size(), + window.scale_factor(), + ctx, + ); + window.present_scene(scene); + }) + })); + } + self.on_window_invalidated(window_id, move |invalidation, ctx| { let mut presenter = presenter.borrow_mut(); presenter.invalidate(invalidation, ctx.downgrade()); let scene = presenter.build_scene(window.size(), window.scale_factor(), ctx); - window.render_scene(scene); + window.present_scene(scene); }); } } @@ -1909,7 +1927,7 @@ impl Hash for ModelHandle { } } -impl borrow::Borrow for ModelHandle { +impl std::borrow::Borrow for ModelHandle { fn borrow(&self) -> &usize { &self.model_id } diff --git a/gpui/src/platform/mac/app.rs b/gpui/src/platform/mac/app.rs index 11805a5db3..58c184d81f 100644 --- a/gpui/src/platform/mac/app.rs +++ b/gpui/src/platform/mac/app.rs @@ -33,7 +33,7 @@ impl platform::App for App { &self, options: platform::WindowOptions, executor: Rc, - ) -> Result> { - Ok(Rc::new(Window::open(options, executor)?)) + ) -> Result> { + Ok(Box::new(Window::open(options, executor)?)) } } diff --git a/gpui/src/platform/mac/renderer.rs b/gpui/src/platform/mac/renderer.rs index 72948f3ee0..6a2e4573b4 100644 --- a/gpui/src/platform/mac/renderer.rs +++ b/gpui/src/platform/mac/renderer.rs @@ -1,14 +1,21 @@ -use anyhow::{anyhow, Result}; +use std::{ffi::c_void, mem}; -use crate::Scene; +use self::shaders::ToUchar4; use super::window::RenderContext; +use crate::{color::ColorU, scene::Layer, Scene}; +use anyhow::{anyhow, Result}; +use metal::{MTLResourceOptions, NSRange}; +use shaders::ToFloat2 as _; const SHADERS_METALLIB: &'static [u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib")); +const INSTANCE_BUFFER_SIZE: u64 = 1024 * 1024; pub struct Renderer { quad_pipeline_state: metal::RenderPipelineState, + quad_vertices: metal::Buffer, + instances: metal::Buffer, } impl Renderer { @@ -17,6 +24,22 @@ impl Renderer { .new_library_with_data(SHADERS_METALLIB) .map_err(|message| anyhow!("error building metal library: {}", message))?; + let quad_vertices = [ + (0., 0.).to_float2(), + (1., 0.).to_float2(), + (0., 1.).to_float2(), + (0., 1.).to_float2(), + (1., 0.).to_float2(), + (1., 1.).to_float2(), + ]; + let quad_vertices = device.new_buffer_with_data( + quad_vertices.as_ptr() as *const c_void, + (quad_vertices.len() * mem::size_of::()) as u64, + MTLResourceOptions::StorageModeManaged, + ); + let instances = + device.new_buffer(INSTANCE_BUFFER_SIZE, MTLResourceOptions::StorageModeManaged); + Ok(Self { quad_pipeline_state: build_pipeline_state( device, @@ -26,10 +49,78 @@ impl Renderer { "quad_fragment", pixel_format, )?, + quad_vertices, + instances, }) } - pub fn render(&mut self, scene: &Scene, ctx: RenderContext) {} + pub fn render(&mut self, scene: &Scene, ctx: &RenderContext) { + ctx.command_encoder.set_viewport(metal::MTLViewport { + originX: 0.0, + originY: 0.0, + width: ctx.drawable_size.x() as f64, + height: ctx.drawable_size.y() as f64, + znear: 0.0, + zfar: 1.0, + }); + + for layer in scene.layers() { + self.render_quads(layer, ctx); + } + } + + fn render_quads(&mut self, layer: &Layer, ctx: &RenderContext) { + ctx.command_encoder + .set_render_pipeline_state(&self.quad_pipeline_state); + ctx.command_encoder.set_vertex_buffer( + shaders::GPUIQuadInputIndex_GPUIQuadInputIndexVertices as u64, + Some(&self.quad_vertices), + 0, + ); + ctx.command_encoder.set_vertex_buffer( + shaders::GPUIQuadInputIndex_GPUIQuadInputIndexQuads as u64, + Some(&self.instances), + 0, + ); + ctx.command_encoder.set_vertex_bytes( + shaders::GPUIQuadInputIndex_GPUIQuadInputIndexUniforms as u64, + mem::size_of::() as u64, + [shaders::GPUIQuadUniforms { + viewport_size: ctx.drawable_size.to_float2(), + }] + .as_ptr() as *const c_void, + ); + + let batch_size = self.instances.length() as usize / mem::size_of::(); + + let buffer_contents = self.instances.contents() as *mut shaders::GPUIQuad; + for quad_batch in layer.quads().chunks(batch_size) { + for (ix, quad) in quad_batch.iter().enumerate() { + log::info!("render {} {:?}", ix, quad); + unsafe { + *(buffer_contents.offset(ix as isize)) = shaders::GPUIQuad { + origin: quad.bounds.origin().to_float2(), + size: quad.bounds.size().to_float2(), + background_color: quad + .background + .unwrap_or(ColorU::transparent_black()) + .to_uchar4(), + }; + } + } + self.instances.did_modify_range(NSRange { + location: 0, + length: (quad_batch.len() * mem::size_of::()) as u64, + }); + + ctx.command_encoder.draw_primitives_instanced( + metal::MTLPrimitiveType::Triangle, + 0, + 6, + quad_batch.len() as u64, + ); + } + } } fn build_pipeline_state( @@ -47,7 +138,7 @@ fn build_pipeline_state( .get_function(fragment_fn_name, None) .map_err(|message| anyhow!("error locating fragment function: {}", message))?; - let mut descriptor = metal::RenderPipelineDescriptor::new(); + let descriptor = metal::RenderPipelineDescriptor::new(); descriptor.set_label(label); descriptor.set_vertex_function(Some(vertex_fn.as_ref())); descriptor.set_fragment_function(Some(fragment_fn.as_ref())); @@ -61,3 +152,57 @@ fn build_pipeline_state( .new_render_pipeline_state(&descriptor) .map_err(|message| anyhow!("could not create render pipeline state: {}", message)) } + +mod shaders { + #![allow(non_upper_case_globals)] + #![allow(non_camel_case_types)] + #![allow(non_snake_case)] + + use crate::{color::ColorU, geometry::vector::Vector2F}; + use std::mem; + + include!(concat!(env!("OUT_DIR"), "/shaders.rs")); + + pub trait ToFloat2 { + fn to_float2(&self) -> vector_float2; + } + + pub trait ToUchar4 { + fn to_uchar4(&self) -> vector_uchar4; + } + + impl ToFloat2 for (f32, f32) { + fn to_float2(&self) -> vector_float2 { + unsafe { + let mut output = mem::transmute::<_, u32>(self.1.to_bits()) as vector_float2; + output <<= 32; + output |= mem::transmute::<_, u32>(self.0.to_bits()) as vector_float2; + output + } + } + } + + impl ToFloat2 for Vector2F { + fn to_float2(&self) -> vector_float2 { + unsafe { + let mut output = mem::transmute::<_, u32>(self.y().to_bits()) as vector_float2; + output <<= 32; + output |= mem::transmute::<_, u32>(self.x().to_bits()) as vector_float2; + output + } + } + } + + impl ToUchar4 for ColorU { + fn to_uchar4(&self) -> vector_uchar4 { + let mut vec = self.a as vector_uchar4; + vec <<= 8; + vec |= self.b as vector_uchar4; + vec <<= 8; + vec |= self.g as vector_uchar4; + vec <<= 8; + vec |= self.r as vector_uchar4; + vec + } + } +} diff --git a/gpui/src/platform/mac/shaders/shaders.h b/gpui/src/platform/mac/shaders/shaders.h index 374ecebc5a..797e55378a 100644 --- a/gpui/src/platform/mac/shaders/shaders.h +++ b/gpui/src/platform/mac/shaders/shaders.h @@ -9,7 +9,7 @@ typedef enum { typedef struct { vector_float2 origin; vector_float2 size; - vector_float4 background_color; + vector_uchar4 background_color; } GPUIQuad; typedef struct { diff --git a/gpui/src/platform/mac/shaders/shaders.metal b/gpui/src/platform/mac/shaders/shaders.metal index e508c7ac66..60b26ac216 100644 --- a/gpui/src/platform/mac/shaders/shaders.metal +++ b/gpui/src/platform/mac/shaders/shaders.metal @@ -3,6 +3,10 @@ using namespace metal; +float4 coloru_to_colorf(uchar4 coloru) { + return float4(coloru) / float4(0xff, 0xff, 0xff, 0xff); +} + struct QuadFragmentInput { float4 position [[position]]; GPUIQuad quad; @@ -17,14 +21,15 @@ vertex QuadFragmentInput quad_vertex( ) { float2 unit_vertex = unit_vertices[unit_vertex_id]; GPUIQuad quad = quads[quad_id]; - float4 position = float4((unit_vertex * quad.size + quad.origin) / (uniforms->viewport_size / 2.0), 0.0, 1.0); + float2 position = (unit_vertex * quad.size + quad.origin) / (uniforms->viewport_size / 2.0); + float4 device_position = float4(position * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); return QuadFragmentInput { - position, + device_position, quad, }; } fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]]) { - return input.quad.background_color; -} \ No newline at end of file + return coloru_to_colorf(input.quad.background_color); +} diff --git a/gpui/src/platform/mac/window.rs b/gpui/src/platform/mac/window.rs index b5af664408..a4a74ada42 100644 --- a/gpui/src/platform/mac/window.rs +++ b/gpui/src/platform/mac/window.rs @@ -1,7 +1,8 @@ use crate::{ executor, geometry::vector::Vector2F, - platform::{self, Event}, + platform::{self, Event, WindowContext}, + util::post_inc, Scene, }; use anyhow::{anyhow, Result}; @@ -27,7 +28,7 @@ use objc::{ use pathfinder_geometry::vector::vec2f; use smol::Timer; use std::{ - cell::{Cell, RefCell}, + cell::RefCell, ffi::c_void, mem, ptr, rc::Rc, @@ -111,16 +112,16 @@ unsafe fn build_classes() { }; } -pub struct Window(Rc); +pub struct Window(Rc>); struct WindowState { native_window: id, - event_callback: RefCell bool>>>, - resize_callback: RefCell>>, - synthetic_drag_counter: Cell, + event_callback: Option>, + resize_callback: Option>, + synthetic_drag_counter: usize, executor: Rc, - scene_to_render: RefCell>, - renderer: RefCell, + scene_to_render: Option, + renderer: Renderer, command_queue: metal::CommandQueue, device: metal::Device, layer: id, @@ -181,18 +182,18 @@ impl Window { return Err(anyhow!("view return nil from initializer")); } - let window = Self(Rc::new(WindowState { + let window = Self(Rc::new(RefCell::new(WindowState { native_window, - event_callback: RefCell::new(None), - resize_callback: RefCell::new(None), - synthetic_drag_counter: Cell::new(0), + event_callback: None, + resize_callback: None, + synthetic_drag_counter: 0, executor, scene_to_render: Default::default(), - renderer: RefCell::new(Renderer::new(&device, PIXEL_FORMAT)?), + renderer: Renderer::new(&device, PIXEL_FORMAT)?, command_queue: device.new_command_queue(), device, layer, - })); + }))); (*native_window).set_ivar( WINDOW_STATE_IVAR, @@ -236,46 +237,44 @@ impl Window { pub fn zoom(&self) { unsafe { - self.0.native_window.performZoom_(nil); + self.0.as_ref().borrow().native_window.performZoom_(nil); } } - - pub fn on_event bool>(&mut self, callback: F) { - *self.0.event_callback.borrow_mut() = Some(Box::new(callback)); - } - - pub fn on_resize(&mut self, callback: F) { - *self.0.resize_callback.borrow_mut() = Some(Box::new(callback)); - } } impl Drop for Window { fn drop(&mut self) { unsafe { - self.0.native_window.close(); - let _: () = msg_send![self.0.native_window.delegate(), release]; + self.0.as_ref().borrow().native_window.close(); } } } impl platform::Window for Window { - fn size(&self) -> Vector2F { - self.0.size() + fn on_event(&mut self, callback: Box) { + self.0.as_ref().borrow_mut().event_callback = Some(callback); } - fn scale_factor(&self) -> f32 { - self.0.scale_factor() - } - - fn render_scene(&self, scene: Scene) { - *self.0.scene_to_render.borrow_mut() = Some(scene); - unsafe { - let _: () = msg_send![self.0.native_window.contentView(), setNeedsDisplay: YES]; - } + fn on_resize(&mut self, callback: Box) { + self.0.as_ref().borrow_mut().resize_callback = Some(callback); } } -impl WindowState { +impl platform::WindowContext for Window { + fn size(&self) -> Vector2F { + self.0.as_ref().borrow().size() + } + + fn scale_factor(&self) -> f32 { + self.0.as_ref().borrow().scale_factor() + } + + fn present_scene(&mut self, scene: Scene) { + self.0.as_ref().borrow_mut().present_scene(scene); + } +} + +impl platform::WindowContext for WindowState { fn size(&self) -> Vector2F { let NSSize { width, height, .. } = unsafe { NSView::frame(self.native_window.contentView()) }.size; @@ -289,16 +288,17 @@ impl WindowState { } } - fn next_synthetic_drag_id(&self) -> usize { - let next_id = self.synthetic_drag_counter.get() + 1; - self.synthetic_drag_counter.set(next_id); - next_id + fn present_scene(&mut self, scene: Scene) { + self.scene_to_render = Some(scene); + unsafe { + let _: () = msg_send![self.native_window.contentView(), setNeedsDisplay: YES]; + } } } -unsafe fn window_state(object: &Object) -> Rc { +unsafe fn get_window_state(object: &Object) -> Rc> { let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR); - let rc1 = Rc::from_raw(raw as *mut WindowState); + let rc1 = Rc::from_raw(raw as *mut RefCell); let rc2 = rc1.clone(); mem::forget(rc1); rc2 @@ -328,23 +328,25 @@ extern "C" fn dealloc_view(this: &Object, _: Sel) { } extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { - let window = unsafe { window_state(this) }; + let window_state = unsafe { get_window_state(this) }; + let mut window_state_borrow = window_state.as_ref().borrow_mut(); - let event = unsafe { Event::from_native(native_event, Some(window.size().y())) }; + let event = unsafe { Event::from_native(native_event, Some(window_state_borrow.size().y())) }; if let Some(event) = event { match event { - Event::LeftMouseDragged { position } => schedule_synthetic_drag(&window, position), + Event::LeftMouseDragged { position } => { + schedule_synthetic_drag(&&window_state, position) + } Event::LeftMouseUp { .. } => { - window.next_synthetic_drag_id(); + post_inc(&mut window_state_borrow.synthetic_drag_counter); } _ => {} } - if let Some(callback) = window.event_callback.borrow_mut().as_mut() { - if callback(event) { - return; - } + if let Some(mut callback) = window_state_borrow.event_callback.take() { + callback(event, &mut *window_state_borrow); + window_state_borrow.event_callback = Some(callback); } } } @@ -356,55 +358,62 @@ extern "C" fn send_event(this: &Object, _: Sel, native_event: id) { } extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id { - let window = unsafe { window_state(this) }; - window.layer + let window_state = unsafe { get_window_state(this) }; + let window_state = window_state.as_ref().borrow(); + window_state.layer } extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) { - let window; + let window_state = unsafe { get_window_state(this) }; + let mut window_state = window_state.as_ref().borrow_mut(); + unsafe { - window = window_state(this); - let _: () = msg_send![window.layer, setContentsScale: window.scale_factor() as f64]; + let _: () = + msg_send![window_state.layer, setContentsScale: window_state.scale_factor() as f64]; } - if let Some(callback) = window.resize_callback.borrow_mut().as_mut() { - let size = window.size(); - let scale_factor = window.scale_factor(); - callback(size, scale_factor); + if let Some(mut callback) = window_state.resize_callback.take() { + callback(&mut *window_state); + window_state.resize_callback = Some(callback); }; } extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { - let window; - unsafe { - window = window_state(this); - if window.size() == vec2f(size.width as f32, size.height as f32) { - return; - } + let window_state = unsafe { get_window_state(this) }; + let mut window_state = window_state.as_ref().borrow_mut(); - let _: () = msg_send![super(this, class!(NSView)), setFrameSize: size]; - - let scale_factor = window.scale_factor() as f64; - let drawable_size: NSSize = NSSize { - width: size.width * scale_factor, - height: size.height * scale_factor, - }; - let _: () = msg_send![window.layer, setDrawableSize: drawable_size]; + if window_state.size() == vec2f(size.width as f32, size.height as f32) { + return; } - if let Some(callback) = window.resize_callback.borrow_mut().as_mut() { - let size = window.size(); - let scale_factor = window.scale_factor(); - callback(size, scale_factor); + unsafe { + let _: () = msg_send![super(this, class!(NSView)), setFrameSize: size]; + } + + let scale_factor = window_state.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.layer, setDrawableSize: drawable_size]; + } + + if let Some(mut callback) = window_state.resize_callback.take() { + callback(&mut *window_state); + window_state.resize_callback = Some(callback); }; } extern "C" fn display_layer(this: &Object, _: Sel, _: id) { + log::info!("display layer"); unsafe { - let window = window_state(this); + let window_state = get_window_state(this); + let mut window_state = window_state.as_ref().borrow_mut(); - if let Some(scene) = window.scene_to_render.borrow_mut().take() { - let drawable: &metal::MetalDrawableRef = msg_send![window.layer, nextDrawable]; + if let Some(scene) = window_state.scene_to_render.take() { + let drawable: &metal::MetalDrawableRef = msg_send![window_state.layer, nextDrawable]; let render_pass_descriptor = metal::RenderPassDescriptor::new(); let color_attachment = render_pass_descriptor @@ -416,14 +425,19 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) { color_attachment.set_store_action(MTLStoreAction::Store); color_attachment.set_clear_color(MTLClearColor::new(0., 0., 0., 1.)); - let command_buffer = window.command_queue.new_command_buffer(); + let command_queue = window_state.command_queue.clone(); + let command_buffer = command_queue.new_command_buffer(); let command_encoder = command_buffer.new_render_command_encoder(render_pass_descriptor); - window.renderer.borrow_mut().render( + let size = window_state.size(); + let scale_factor = window_state.scale_factor(); + let device = window_state.device.clone(); + + window_state.renderer.render( &scene, - RenderContext { - drawable_size: window.size() * window.scale_factor(), - device: &window.device, + &RenderContext { + drawable_size: size * scale_factor, + device: &device, command_encoder, }, ); @@ -432,23 +446,33 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) { command_buffer.commit(); command_buffer.wait_until_completed(); drawable.present(); + + log::info!("present"); }; } } -fn schedule_synthetic_drag(window_state: &Rc, position: Vector2F) { - let drag_id = window_state.next_synthetic_drag_id(); +fn schedule_synthetic_drag(window_state: &Rc>, position: Vector2F) { let weak_window_state = Rc::downgrade(window_state); + let mut window_state = window_state.as_ref().borrow_mut(); + + let drag_id = post_inc(&mut window_state.synthetic_drag_counter); let instant = Instant::now() + Duration::from_millis(16); + window_state .executor .spawn(async move { Timer::at(instant).await; if let Some(window_state) = weak_window_state.upgrade() { - if window_state.synthetic_drag_counter.get() == drag_id { - if let Some(callback) = window_state.event_callback.borrow_mut().as_mut() { + let mut window_state_borrow = window_state.as_ref().borrow_mut(); + if window_state_borrow.synthetic_drag_counter == drag_id { + if let Some(mut callback) = window_state_borrow.event_callback.take() { schedule_synthetic_drag(&window_state, position); - callback(Event::LeftMouseDragged { position }); + callback( + Event::LeftMouseDragged { position }, + &mut *window_state_borrow, + ); + window_state_borrow.event_callback = Some(callback); } } } diff --git a/gpui/src/platform/mod.rs b/gpui/src/platform/mod.rs index 868ab9f413..cc69be5f70 100644 --- a/gpui/src/platform/mod.rs +++ b/gpui/src/platform/mod.rs @@ -32,7 +32,7 @@ pub trait App { &self, options: WindowOptions, executor: Rc, - ) -> Result>; + ) -> Result>; } pub trait Dispatcher: Send + Sync { @@ -40,10 +40,15 @@ pub trait Dispatcher: Send + Sync { fn run_on_main_thread(&self, task: Runnable); } -pub trait Window { +pub trait Window: WindowContext { + fn on_event(&mut self, callback: Box); + fn on_resize(&mut self, callback: Box); +} + +pub trait WindowContext { fn size(&self) -> Vector2F; fn scale_factor(&self) -> f32; - fn render_scene(&self, scene: Scene); + fn present_scene(&mut self, scene: Scene); } pub struct WindowOptions<'a> { diff --git a/gpui/src/scene.rs b/gpui/src/scene.rs index 85e1f788d4..6f5daaf750 100644 --- a/gpui/src/scene.rs +++ b/gpui/src/scene.rs @@ -6,12 +6,12 @@ pub struct Scene { } #[derive(Default)] -struct Layer { +pub struct Layer { clip_bounds: Option, quads: Vec, } -#[derive(Default)] +#[derive(Default, Debug)] pub struct Quad { pub bounds: RectF, pub background: Option, @@ -19,7 +19,7 @@ pub struct Quad { pub corder_radius: f32, } -#[derive(Clone, Copy, Default)] +#[derive(Clone, Copy, Default, Debug)] pub struct Border { pub width: f32, pub color: Option, @@ -38,13 +38,19 @@ impl Scene { } } - pub fn push_layer(&mut self, clip_bounds: Option) {} - - pub fn pop_layer(&mut self) { - assert!(self.active_layer_stack.len() > 1); - self.active_layer_stack.pop(); + pub fn layers(&self) -> &[Layer] { + self.layers.as_slice() } + // pub fn push_layer(&mut self, clip_bounds: Option) { + + // } + + // pub fn pop_layer(&mut self) { + // assert!(self.active_layer_stack.len() > 1); + // self.active_layer_stack.pop(); + // } + pub fn push_quad(&mut self, quad: Quad) { self.active_layer().push_quad(quad) } @@ -58,6 +64,10 @@ impl Layer { fn push_quad(&mut self, quad: Quad) { self.quads.push(quad); } + + pub fn quads(&self) -> &[Quad] { + self.quads.as_slice() + } } impl Border {