Pass CVImageBuffers into GPUI instead of IOSurfaces

Nathan Sobo created

Change summary

Cargo.lock                               | 22 ++++----
crates/capture/Cargo.toml                |  2 
crates/capture/src/main.rs               | 71 ++++---------------------
crates/gpui/Cargo.toml                   |  2 
crates/gpui/src/platform/mac/renderer.rs |  3 
crates/io_surface/src/io_surface.rs      | 21 -------
crates/media/Cargo.toml                  |  4 
crates/media/src/media.rs                | 66 ++++++++++++++++++++++++
8 files changed, 95 insertions(+), 96 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -763,8 +763,8 @@ dependencies = [
  "foreign-types",
  "futures",
  "gpui",
- "io_surface",
  "log",
+ "media",
  "objc",
  "parking_lot 0.11.2",
  "postage",
@@ -2232,9 +2232,9 @@ dependencies = [
  "futures",
  "gpui_macros",
  "image",
- "io_surface",
  "lazy_static",
  "log",
+ "media",
  "metal",
  "num_cpus",
  "objc",
@@ -2601,15 +2601,6 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
-[[package]]
-name = "io_surface"
-version = "0.1.0"
-dependencies = [
- "block",
- "core-foundation",
- "objc",
-]
-
 [[package]]
 name = "iovec"
 version = "0.1.4"
@@ -3039,6 +3030,15 @@ dependencies = [
  "digest 0.10.3",
 ]
 
+[[package]]
+name = "media"
+version = "0.1.0"
+dependencies = [
+ "block",
+ "core-foundation",
+ "objc",
+]
+
 [[package]]
 name = "memchr"
 version = "2.5.0"

crates/capture/Cargo.toml 🔗

@@ -10,7 +10,7 @@ identifier = "dev.zed.Capture"
 
 [dependencies]
 gpui = { path = "../gpui" }
-io_surface = { path = "../io_surface" }
+media = { path = "../media" }
 
 block = "0.1"
 cocoa = "0.24"

crates/capture/src/main.rs 🔗

@@ -16,8 +16,8 @@ use gpui::{
     platform::current::Surface,
     Menu, MenuItem, ViewContext,
 };
-use io_surface::IOSurface;
 use log::LevelFilter;
+use media::core_video::{self, CVImageBuffer};
 use objc::{
     class,
     declare::ClassDecl,
@@ -55,7 +55,7 @@ fn main() {
 }
 
 struct ScreenCaptureView {
-    surface: Option<io_surface::IOSurface>,
+    image_buffer: Option<core_video::CVImageBuffer>,
 }
 
 impl gpui::Entity for ScreenCaptureView {
@@ -64,8 +64,9 @@ impl gpui::Entity for ScreenCaptureView {
 
 impl ScreenCaptureView {
     pub fn new(cx: &mut ViewContext<Self>) -> Self {
-        let (surface_tx, mut surface_rx) = postage::watch::channel::<Option<IOSurface>>();
-        let surface_tx = Arc::new(Mutex::new(surface_tx));
+        let (image_buffer_tx, mut image_buffer_rx) =
+            postage::watch::channel::<Option<CVImageBuffer>>();
+        let image_buffer_tx = Arc::new(Mutex::new(image_buffer_tx));
 
         unsafe {
             let block = ConcreteBlock::new(move |content: id, error: id| {
@@ -93,7 +94,7 @@ impl ScreenCaptureView {
 
                 let output: id = msg_send![capture_output_class, alloc];
                 let output: id = msg_send![output, init];
-                let surface_tx = surface_tx.clone();
+                let surface_tx = image_buffer_tx.clone();
 
                 let callback = Box::new(move |buffer: CMSampleBufferRef| {
                     let buffer = CMSampleBuffer::wrap_under_get_rule(buffer);
@@ -112,8 +113,7 @@ impl ScreenCaptureView {
                     }
 
                     let image_buffer = buffer.image_buffer();
-                    let io_surface = image_buffer.io_surface();
-                    *surface_tx.lock().borrow_mut() = Some(io_surface);
+                    *surface_tx.lock().borrow_mut() = Some(image_buffer);
                 }) as Box<dyn FnMut(CMSampleBufferRef)>;
                 let callback = Box::into_raw(Box::new(callback));
                 (*output).set_ivar("callback", callback as *mut c_void);
@@ -169,10 +169,10 @@ impl ScreenCaptureView {
         }
 
         cx.spawn_weak(|this, mut cx| async move {
-            while let Some(surface) = surface_rx.next().await {
+            while let Some(image_buffer) = image_buffer_rx.next().await {
                 if let Some(this) = this.upgrade(&cx) {
                     this.update(&mut cx, |this, cx| {
-                        this.surface = surface;
+                        this.image_buffer = image_buffer;
                         println!("NEW SURFACE!");
                         cx.notify();
                     })
@@ -183,7 +183,7 @@ impl ScreenCaptureView {
         })
         .detach();
 
-        Self { surface: None }
+        Self { image_buffer: None }
     }
 }
 
@@ -193,12 +193,12 @@ impl gpui::View for ScreenCaptureView {
     }
 
     fn render(&mut self, _: &mut gpui::RenderContext<Self>) -> gpui::ElementBox {
-        let surface = self.surface.clone();
+        let image_buffer = self.image_buffer.clone();
         Canvas::new(move |bounds, _, cx| {
-            if let Some(native_surface) = surface.clone() {
+            if let Some(image_buffer) = image_buffer.clone() {
                 cx.scene.push_surface(Surface {
                     bounds,
-                    native_surface,
+                    image_buffer,
                 });
             }
         })
@@ -291,48 +291,3 @@ mod core_media {
         fn CMSampleBufferGetImageBuffer(buffer: CMSampleBufferRef) -> CVImageBufferRef;
     }
 }
-
-mod core_video {
-    #![allow(non_snake_case)]
-
-    use core_foundation::{
-        base::{CFTypeID, TCFType},
-        declare_TCFType, impl_CFTypeDescription, impl_TCFType,
-    };
-    use io_surface::{IOSurface, IOSurfaceRef};
-    use std::ffi::c_void;
-
-    #[repr(C)]
-    pub struct __CVImageBuffer(c_void);
-    // The ref type must be a pointer to the underlying struct.
-    pub type CVImageBufferRef = *const __CVImageBuffer;
-
-    declare_TCFType!(CVImageBuffer, CVImageBufferRef);
-    impl_TCFType!(CVImageBuffer, CVImageBufferRef, CVImageBufferGetTypeID);
-    impl_CFTypeDescription!(CVImageBuffer);
-
-    impl CVImageBuffer {
-        pub fn io_surface(&self) -> IOSurface {
-            unsafe {
-                IOSurface::wrap_under_get_rule(CVPixelBufferGetIOSurface(
-                    self.as_concrete_TypeRef(),
-                ))
-            }
-        }
-
-        pub fn width(&self) -> usize {
-            unsafe { CVPixelBufferGetWidth(self.as_concrete_TypeRef()) }
-        }
-
-        pub fn height(&self) -> usize {
-            unsafe { CVPixelBufferGetHeight(self.as_concrete_TypeRef()) }
-        }
-    }
-
-    extern "C" {
-        fn CVImageBufferGetTypeID() -> CFTypeID;
-        fn CVPixelBufferGetIOSurface(buffer: CVImageBufferRef) -> IOSurfaceRef;
-        fn CVPixelBufferGetWidth(buffer: CVImageBufferRef) -> usize;
-        fn CVPixelBufferGetHeight(buffer: CVImageBufferRef) -> usize;
-    }
-}

crates/gpui/Cargo.toml 🔗

@@ -60,7 +60,7 @@ png = "0.16"
 simplelog = "0.9"
 
 [target.'cfg(target_os = "macos")'.dependencies]
-io_surface = { path = "../io_surface" }
+media = { path = "../media" }
 anyhow = "1"
 block = "0.1"
 cocoa = "0.24"

crates/gpui/src/platform/mac/renderer.rs 🔗

@@ -39,7 +39,7 @@ struct PathSprite {
 
 pub struct Surface {
     pub bounds: RectF,
-    pub native_surface: io_surface::IOSurface,
+    pub image_buffer: media::core_video::CVImageBuffer,
 }
 
 impl Renderer {
@@ -790,7 +790,6 @@ impl Renderer {
             let target_size = surface.bounds.size() * scale_factor;
             // let corner_radius = surface.corner_radius * scale_factor;
             // let border_width = surface.border.width * scale_factor;
-            // let (alloc_id, atlas_bounds) = self.image_cache.render(&surface.native_surface);
         }
 
         // command_encoder.set_render_pipeline_state(&self.image_pipeline_state);

crates/io_surface/src/io_surface.rs 🔗

@@ -1,21 +0,0 @@
-#![allow(non_snake_case)]
-
-use core_foundation::{
-    base::{CFTypeID, TCFType},
-    declare_TCFType, impl_CFTypeDescription, impl_TCFType,
-};
-use std::ffi::c_void;
-
-#[repr(C)]
-pub struct __IOSurface(c_void);
-// The ref type must be a pointer to the underlying struct.
-pub type IOSurfaceRef = *const __IOSurface;
-
-declare_TCFType!(IOSurface, IOSurfaceRef);
-impl_TCFType!(IOSurface, IOSurfaceRef, IOSurfaceGetTypeID);
-impl_CFTypeDescription!(IOSurface);
-
-#[link(name = "IOSurface", kind = "framework")]
-extern "C" {
-    fn IOSurfaceGetTypeID() -> CFTypeID;
-}

crates/io_surface/Cargo.toml → crates/media/Cargo.toml 🔗

@@ -1,10 +1,10 @@
 [package]
-name = "io_surface"
+name = "media"
 version = "0.1.0"
 edition = "2021"
 
 [lib]
-path = "src/io_surface.rs"
+path = "src/media.rs"
 doctest = false
 
 [dependencies]

crates/media/src/media.rs 🔗

@@ -0,0 +1,66 @@
+#![allow(non_snake_case)]
+
+use core_foundation::{
+    base::{CFTypeID, TCFType},
+    declare_TCFType, impl_CFTypeDescription, impl_TCFType,
+};
+use std::ffi::c_void;
+
+pub mod io_surface {
+    use super::*;
+
+    #[repr(C)]
+    pub struct __IOSurface(c_void);
+    // The ref type must be a pointer to the underlying struct.
+    pub type IOSurfaceRef = *const __IOSurface;
+
+    declare_TCFType!(IOSurface, IOSurfaceRef);
+    impl_TCFType!(IOSurface, IOSurfaceRef, IOSurfaceGetTypeID);
+    impl_CFTypeDescription!(IOSurface);
+
+    #[link(name = "IOSurface", kind = "framework")]
+    extern "C" {
+        fn IOSurfaceGetTypeID() -> CFTypeID;
+    }
+}
+
+pub mod core_video {
+    #![allow(non_snake_case)]
+
+    use super::*;
+    use io_surface::{IOSurface, IOSurfaceRef};
+
+    #[repr(C)]
+    pub struct __CVImageBuffer(c_void);
+    // The ref type must be a pointer to the underlying struct.
+    pub type CVImageBufferRef = *const __CVImageBuffer;
+
+    declare_TCFType!(CVImageBuffer, CVImageBufferRef);
+    impl_TCFType!(CVImageBuffer, CVImageBufferRef, CVImageBufferGetTypeID);
+    impl_CFTypeDescription!(CVImageBuffer);
+
+    impl CVImageBuffer {
+        pub fn io_surface(&self) -> IOSurface {
+            unsafe {
+                IOSurface::wrap_under_get_rule(CVPixelBufferGetIOSurface(
+                    self.as_concrete_TypeRef(),
+                ))
+            }
+        }
+
+        pub fn width(&self) -> usize {
+            unsafe { CVPixelBufferGetWidth(self.as_concrete_TypeRef()) }
+        }
+
+        pub fn height(&self) -> usize {
+            unsafe { CVPixelBufferGetHeight(self.as_concrete_TypeRef()) }
+        }
+    }
+
+    extern "C" {
+        fn CVImageBufferGetTypeID() -> CFTypeID;
+        fn CVPixelBufferGetIOSurface(buffer: CVImageBufferRef) -> IOSurfaceRef;
+        fn CVPixelBufferGetWidth(buffer: CVImageBufferRef) -> usize;
+        fn CVPixelBufferGetHeight(buffer: CVImageBufferRef) -> usize;
+    }
+}