diff --git a/Cargo.lock b/Cargo.lock index 7b4fbdaaa3..46abc68765 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3036,6 +3036,7 @@ version = "0.1.0" dependencies = [ "block", "core-foundation", + "metal", "objc", ] diff --git a/crates/gpui/src/platform/mac/renderer.rs b/crates/gpui/src/platform/mac/renderer.rs index 6c1d3cef21..1023d5a5ef 100644 --- a/crates/gpui/src/platform/mac/renderer.rs +++ b/crates/gpui/src/platform/mac/renderer.rs @@ -9,10 +9,13 @@ use crate::{ scene::{Glyph, Icon, Image, ImageGlyph, Layer, Quad, Scene, Shadow, Underline}, }; use cocoa::foundation::NSUInteger; +use core_foundation::base::TCFType; +use foreign_types::ForeignTypeRef; use log::warn; +use media::core_video::{self, CVMetalTextureCache}; use metal::{MTLPixelFormat, MTLResourceOptions, NSRange}; use shaders::ToFloat2 as _; -use std::{collections::HashMap, ffi::c_void, iter::Peekable, mem, sync::Arc, vec}; +use std::{collections::HashMap, ffi::c_void, iter::Peekable, mem, ptr, sync::Arc, vec}; 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. @@ -29,6 +32,7 @@ pub struct Renderer { underline_pipeline_state: metal::RenderPipelineState, unit_vertices: metal::Buffer, instances: metal::Buffer, + cv_texture_cache: core_video::CVMetalTextureCache, } struct PathSprite { @@ -39,7 +43,7 @@ struct PathSprite { pub struct Surface { pub bounds: RectF, - pub image_buffer: media::core_video::CVImageBuffer, + pub image_buffer: core_video::CVImageBuffer, } impl Renderer { @@ -128,6 +132,7 @@ impl Renderer { "underline_fragment", pixel_format, ); + let cv_texture_cache = CVMetalTextureCache::new(device.as_ptr()); Self { sprite_cache, image_cache, @@ -140,6 +145,7 @@ impl Renderer { underline_pipeline_state, unit_vertices, instances, + cv_texture_cache, } } @@ -786,10 +792,26 @@ impl Renderer { } for surface in surfaces { - let origin = surface.bounds.origin() * scale_factor; - let target_size = surface.bounds.size() * scale_factor; + // let origin = surface.bounds.origin() * scale_factor; + // 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 width = surface.image_buffer.width(); + let height = surface.image_buffer.height(); + + // We should add this method, but this return CVPixelFormatType and we need MTLPixelFormat + // I found at least one code example that manually maps them. Not sure what other options we have. + let pixel_format = surface.image_buffer.pixel_format_type(); + + let texture = self.cv_texture_cache.create_texture_from_image( + surface.image_buffer.as_concrete_TypeRef(), + ptr::null(), + pixel_format, + width, + height, + 0, + ); } // command_encoder.set_render_pipeline_state(&self.image_pipeline_state); diff --git a/crates/media/Cargo.toml b/crates/media/Cargo.toml index ff472fe352..06f73caaf5 100644 --- a/crates/media/Cargo.toml +++ b/crates/media/Cargo.toml @@ -10,4 +10,5 @@ doctest = false [dependencies] block = "0.1" core-foundation = "0.9.3" -objc = "0.2" \ No newline at end of file +metal = "0.21.0" +objc = "0.2" diff --git a/crates/media/src/media.rs b/crates/media/src/media.rs index 435c03e936..855435359c 100644 --- a/crates/media/src/media.rs +++ b/crates/media/src/media.rs @@ -1,11 +1,15 @@ #![allow(non_snake_case)] +#![allow(non_camel_case_types)] use core_foundation::{ base::{CFTypeID, TCFType}, declare_TCFType, impl_CFTypeDescription, impl_TCFType, }; +use objc::runtime; use std::ffi::c_void; +pub type id = *mut runtime::Object; + pub mod io_surface { use super::*; @@ -27,8 +31,14 @@ pub mod io_surface { pub mod core_video { #![allow(non_snake_case)] + use std::ptr; + use super::*; + use core_foundation::{ + base::kCFAllocatorDefault, dictionary::CFDictionaryRef, mach_port::CFAllocatorRef, + }; use io_surface::{IOSurface, IOSurfaceRef}; + use metal::{MTLDevice, MTLPixelFormat}; #[repr(C)] pub struct __CVImageBuffer(c_void); @@ -63,4 +73,94 @@ pub mod core_video { fn CVPixelBufferGetWidth(buffer: CVImageBufferRef) -> usize; fn CVPixelBufferGetHeight(buffer: CVImageBufferRef) -> usize; } + + #[repr(C)] + pub struct __CVMetalTextureCache(c_void); + pub type CVMetalTextureCacheRef = *const __CVMetalTextureCache; + + declare_TCFType!(CVMetalTextureCache, CVMetalTextureCacheRef); + impl_TCFType!( + CVMetalTextureCache, + CVMetalTextureCacheRef, + CVMetalTextureCacheGetTypeID + ); + impl_CFTypeDescription!(CVMetalTextureCache); + + impl CVMetalTextureCache { + pub fn new(metal_device: *mut MTLDevice) -> Self { + unsafe { + let mut this = ptr::null(); + let result = CVMetalTextureCacheCreate( + kCFAllocatorDefault, + ptr::null_mut(), + metal_device, + ptr::null_mut(), + &mut this, + ); + // TODO: Check result + CVMetalTextureCache::wrap_under_create_rule(this) + } + } + + pub fn create_texture_from_image( + &self, + source: CVImageBufferRef, + texture_attributes: CFDictionaryRef, + pixel_format: MTLPixelFormat, + width: usize, + height: usize, + plane_index: usize, + ) -> CVMetalTexture { + unsafe { + let mut this = ptr::null(); + let result = CVMetalTextureCacheCreateTextureFromImage( + kCFAllocatorDefault, + self.as_concrete_TypeRef(), + source, + texture_attributes, + pixel_format, + width, + height, + plane_index, + &mut this, + ); + // TODO: Check result + CVMetalTexture::wrap_under_create_rule(this) + } + } + } + + extern "C" { + fn CVMetalTextureCacheGetTypeID() -> CFTypeID; + fn CVMetalTextureCacheCreate( + allocator: CFAllocatorRef, + cache_attributes: CFDictionaryRef, + metal_device: *const MTLDevice, + texture_attributes: CFDictionaryRef, + cache_out: *mut CVMetalTextureCacheRef, + ) -> i32; // TODO: This should be a CVReturn enum + fn CVMetalTextureCacheCreateTextureFromImage( + allocator: CFAllocatorRef, + texture_cache: CVMetalTextureCacheRef, + source_image: CVImageBufferRef, + texture_attributes: CFDictionaryRef, + pixel_format: MTLPixelFormat, + width: usize, + height: usize, + plane_index: usize, + texture_out: *mut CVMetalTextureRef, + ) -> i32; + } + + #[repr(C)] + pub struct __CVMetalTexture(c_void); + pub type CVMetalTextureRef = *const __CVMetalTexture; + + declare_TCFType!(CVMetalTexture, CVMetalTextureRef); + impl_TCFType!(CVMetalTexture, CVMetalTextureRef, CVMetalTextureGetTypeID); + impl_CFTypeDescription!(CVMetalTexture); + + extern "C" { + fn CVMetalTextureGetTypeID() -> CFTypeID; + } }