diff --git a/crates/gpui/src/platform/mac/renderer.rs b/crates/gpui/src/platform/mac/renderer.rs index dea9f0612e..f9cc6e730d 100644 --- a/crates/gpui/src/platform/mac/renderer.rs +++ b/crates/gpui/src/platform/mac/renderer.rs @@ -8,12 +8,17 @@ use crate::{ platform, scene::{Glyph, Icon, Image, ImageGlyph, Layer, Quad, Scene, Shadow, Underline}, }; -use cocoa::foundation::NSUInteger; +use cocoa::{ + base::{NO, YES}, + foundation::{NSRect, NSUInteger}, + quartzcore::AutoresizingMask, +}; use core_foundation::base::TCFType; use foreign_types::ForeignTypeRef; use log::warn; use media::core_video::{self, CVMetalTextureCache}; -use metal::{MTLPixelFormat, MTLResourceOptions, NSRange}; +use metal::{CGFloat, 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}; @@ -21,6 +26,8 @@ const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shader const INSTANCE_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, sprite_cache: SpriteCache, image_cache: ImageCache, path_atlases: AtlasAllocator, @@ -48,12 +55,30 @@ pub struct Surface { } impl Renderer { - pub fn new( - device: metal::Device, - pixel_format: metal::MTLPixelFormat, - scale_factor: f32, - fonts: Arc, - ) -> Self { + pub fn new(fonts: Arc) -> 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); + 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"); @@ -76,13 +101,8 @@ impl Renderer { MTLResourceOptions::StorageModeManaged, ); - let sprite_cache = SpriteCache::new( - device.clone(), - vec2i(1024, 768), - scale_factor, - fonts.clone(), - ); - let image_cache = ImageCache::new(device.clone(), vec2i(1024, 768), scale_factor, fonts); + let sprite_cache = SpriteCache::new(device.clone(), vec2i(1024, 768), 1., fonts.clone()); + let image_cache = ImageCache::new(device.clone(), vec2i(1024, 768), 1., fonts); let path_atlases = AtlasAllocator::new(device.clone(), build_path_atlas_texture_descriptor()); let quad_pipeline_state = build_pipeline_state( @@ -91,7 +111,7 @@ impl Renderer { "quad", "quad_vertex", "quad_fragment", - pixel_format, + PIXEL_FORMAT, ); let shadow_pipeline_state = build_pipeline_state( &device, @@ -99,7 +119,7 @@ impl Renderer { "shadow", "shadow_vertex", "shadow_fragment", - pixel_format, + PIXEL_FORMAT, ); let sprite_pipeline_state = build_pipeline_state( &device, @@ -107,7 +127,7 @@ impl Renderer { "sprite", "sprite_vertex", "sprite_fragment", - pixel_format, + PIXEL_FORMAT, ); let image_pipeline_state = build_pipeline_state( &device, @@ -115,7 +135,7 @@ impl Renderer { "image", "image_vertex", "image_fragment", - pixel_format, + PIXEL_FORMAT, ); let surface_pipeline_state = build_pipeline_state( &device, @@ -123,7 +143,7 @@ impl Renderer { "surface", "surface_vertex", "surface_fragment", - pixel_format, + PIXEL_FORMAT, ); let path_atlas_pipeline_state = build_path_atlas_pipeline_state( &device, @@ -139,10 +159,12 @@ impl Renderer { "underline", "underline_vertex", "underline_fragment", - pixel_format, + PIXEL_FORMAT, ); let cv_texture_cache = CVMetalTextureCache::new(device.as_ptr()).unwrap(); Self { + layer, + command_queue: device.new_command_queue(), sprite_cache, image_cache, path_atlases, @@ -159,13 +181,21 @@ impl Renderer { } } - pub fn render( - &mut self, - scene: &Scene, - drawable_size: Vector2F, - command_buffer: &metal::CommandBufferRef, - output: &metal::TextureRef, - ) { + pub fn layer(&self) -> &metal::MetalLayerRef { + &*self.layer + } + + pub fn render(&mut self, scene: &Scene) { + let layer = self.layer.clone(); + let drawable = layer.next_drawable().unwrap(); + let command_queue = self.command_queue.clone(); + let command_buffer = command_queue.new_command_buffer(); + + let frame: NSRect = unsafe { msg_send![self.layer(), frame] }; + let scale_factor: CGFloat = unsafe { msg_send![self.layer(), contentsScale] }; + let drawable_size = + vec2f(frame.size.width as f32, frame.size.height as f32) * scale_factor as f32; + self.sprite_cache.set_scale_factor(scene.scale_factor()); self.image_cache.set_scale_factor(scene.scale_factor()); @@ -178,13 +208,17 @@ impl Renderer { &mut offset, drawable_size, command_buffer, - output, + drawable.texture(), ); self.instances.did_modify_range(NSRange { location: 0, length: offset as NSUInteger, }); self.image_cache.finish_frame(); + + command_buffer.commit(); + command_buffer.wait_until_completed(); + drawable.present(); } fn render_path_atlases( diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index ed1231588c..822e1700f1 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -20,11 +20,10 @@ use cocoa::{ foundation::{ NSAutoreleasePool, NSInteger, NSNotFound, NSPoint, NSRect, NSSize, NSString, NSUInteger, }, - quartzcore::AutoresizingMask, }; use core_graphics::display::CGRect; use ctor::ctor; -use foreign_types::ForeignType as _; +use foreign_types::ForeignTypeRef; use objc::{ class, declare::ClassDecl, @@ -306,9 +305,7 @@ struct WindowState { executor: Rc, scene_to_render: Option, renderer: Renderer, - command_queue: metal::CommandQueue, last_fresh_keydown: Option, - layer: id, traffic_light_position: Option, previous_modifiers_changed_event: Option, //State tracking what the IME did after the last request @@ -329,8 +326,6 @@ impl Window { executor: Rc, fonts: Arc, ) -> Self { - const PIXEL_FORMAT: metal::MTLPixelFormat = metal::MTLPixelFormat::BGRA8Unorm; - unsafe { let pool = NSAutoreleasePool::new(nil); @@ -368,25 +363,6 @@ impl Window { native_window.setFrame_display_(screen.visibleFrame(), YES); } - 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: id = msg_send![class!(CAMetalLayer), layer]; - let _: () = msg_send![layer, setDevice: device.as_ptr()]; - let _: () = msg_send![layer, setPixelFormat: PIXEL_FORMAT]; - let _: () = msg_send![layer, setAllowsNextDrawableTimeout: NO]; - let _: () = msg_send![layer, setNeedsDisplayOnBoundsChange: YES]; - let _: () = msg_send![layer, setPresentsWithTransaction: YES]; - let _: () = msg_send![ - layer, - setAutoresizingMask: AutoresizingMask::WIDTH_SIZABLE - | AutoresizingMask::HEIGHT_SIZABLE - ]; - let native_view: id = msg_send![VIEW_CLASS, alloc]; let native_view = NSView::init(native_view); assert!(!native_view.is_null()); @@ -406,15 +382,8 @@ impl Window { synthetic_drag_counter: 0, executor, scene_to_render: Default::default(), - renderer: Renderer::new( - device.clone(), - PIXEL_FORMAT, - get_scale_factor(native_window), - fonts, - ), - command_queue: device.new_command_queue(), + renderer: Renderer::new(fonts), last_fresh_keydown: None, - layer, traffic_light_position: options .titlebar .as_ref() @@ -1057,7 +1026,7 @@ 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().borrow(); - window_state.layer + window_state.renderer.layer().as_ptr() as id } extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) { @@ -1072,8 +1041,14 @@ extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) { height: size.y() as f64 * scale_factor, }; - let _: () = msg_send![window_state_borrow.layer, setContentsScale: scale_factor]; - let _: () = msg_send![window_state_borrow.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() { @@ -1102,7 +1077,10 @@ extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { }; unsafe { - let _: () = msg_send![window_state_borrow.layer, setDrawableSize: drawable_size]; + let _: () = msg_send![ + window_state_borrow.renderer.layer(), + setDrawableSize: drawable_size + ]; } drop(window_state_borrow); @@ -1118,25 +1096,8 @@ 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().borrow_mut(); - if let Some(scene) = window_state.scene_to_render.take() { - let drawable: &metal::MetalDrawableRef = msg_send![window_state.layer, nextDrawable]; - let command_queue = window_state.command_queue.clone(); - let command_buffer = command_queue.new_command_buffer(); - - let size = window_state.size(); - let scale_factor = window_state.scale_factor(); - - window_state.renderer.render( - &scene, - size * scale_factor, - command_buffer, - drawable.texture(), - ); - - command_buffer.commit(); - command_buffer.wait_until_completed(); - drawable.present(); + window_state.renderer.render(&scene); }; } }