Start on using CVMetalTextureCache

This commit is contained in:
Nathan Sobo 2022-08-30 21:50:41 -06:00 committed by Antonio Scandurra
parent 531ffc01c9
commit 37da841716
4 changed files with 129 additions and 5 deletions

1
Cargo.lock generated
View file

@ -3036,6 +3036,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"block", "block",
"core-foundation", "core-foundation",
"metal",
"objc", "objc",
] ]

View file

@ -9,10 +9,13 @@ use crate::{
scene::{Glyph, Icon, Image, ImageGlyph, Layer, Quad, Scene, Shadow, Underline}, scene::{Glyph, Icon, Image, ImageGlyph, Layer, Quad, Scene, Shadow, Underline},
}; };
use cocoa::foundation::NSUInteger; use cocoa::foundation::NSUInteger;
use core_foundation::base::TCFType;
use foreign_types::ForeignTypeRef;
use log::warn; use log::warn;
use media::core_video::{self, CVMetalTextureCache};
use metal::{MTLPixelFormat, MTLResourceOptions, NSRange}; use metal::{MTLPixelFormat, MTLResourceOptions, NSRange};
use shaders::ToFloat2 as _; 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 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. 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, underline_pipeline_state: metal::RenderPipelineState,
unit_vertices: metal::Buffer, unit_vertices: metal::Buffer,
instances: metal::Buffer, instances: metal::Buffer,
cv_texture_cache: core_video::CVMetalTextureCache,
} }
struct PathSprite { struct PathSprite {
@ -39,7 +43,7 @@ struct PathSprite {
pub struct Surface { pub struct Surface {
pub bounds: RectF, pub bounds: RectF,
pub image_buffer: media::core_video::CVImageBuffer, pub image_buffer: core_video::CVImageBuffer,
} }
impl Renderer { impl Renderer {
@ -128,6 +132,7 @@ impl Renderer {
"underline_fragment", "underline_fragment",
pixel_format, pixel_format,
); );
let cv_texture_cache = CVMetalTextureCache::new(device.as_ptr());
Self { Self {
sprite_cache, sprite_cache,
image_cache, image_cache,
@ -140,6 +145,7 @@ impl Renderer {
underline_pipeline_state, underline_pipeline_state,
unit_vertices, unit_vertices,
instances, instances,
cv_texture_cache,
} }
} }
@ -786,10 +792,26 @@ impl Renderer {
} }
for surface in surfaces { for surface in surfaces {
let origin = surface.bounds.origin() * scale_factor; // let origin = surface.bounds.origin() * scale_factor;
let target_size = surface.bounds.size() * scale_factor; // let target_size = surface.bounds.size() * scale_factor;
// let corner_radius = surface.corner_radius * scale_factor; // let corner_radius = surface.corner_radius * scale_factor;
// let border_width = surface.border.width * 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); // command_encoder.set_render_pipeline_state(&self.image_pipeline_state);

View file

@ -10,4 +10,5 @@ doctest = false
[dependencies] [dependencies]
block = "0.1" block = "0.1"
core-foundation = "0.9.3" core-foundation = "0.9.3"
objc = "0.2" metal = "0.21.0"
objc = "0.2"

View file

@ -1,11 +1,15 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
#![allow(non_camel_case_types)]
use core_foundation::{ use core_foundation::{
base::{CFTypeID, TCFType}, base::{CFTypeID, TCFType},
declare_TCFType, impl_CFTypeDescription, impl_TCFType, declare_TCFType, impl_CFTypeDescription, impl_TCFType,
}; };
use objc::runtime;
use std::ffi::c_void; use std::ffi::c_void;
pub type id = *mut runtime::Object;
pub mod io_surface { pub mod io_surface {
use super::*; use super::*;
@ -27,8 +31,14 @@ pub mod io_surface {
pub mod core_video { pub mod core_video {
#![allow(non_snake_case)] #![allow(non_snake_case)]
use std::ptr;
use super::*; use super::*;
use core_foundation::{
base::kCFAllocatorDefault, dictionary::CFDictionaryRef, mach_port::CFAllocatorRef,
};
use io_surface::{IOSurface, IOSurfaceRef}; use io_surface::{IOSurface, IOSurfaceRef};
use metal::{MTLDevice, MTLPixelFormat};
#[repr(C)] #[repr(C)]
pub struct __CVImageBuffer(c_void); pub struct __CVImageBuffer(c_void);
@ -63,4 +73,94 @@ pub mod core_video {
fn CVPixelBufferGetWidth(buffer: CVImageBufferRef) -> usize; fn CVPixelBufferGetWidth(buffer: CVImageBufferRef) -> usize;
fn CVPixelBufferGetHeight(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;
}
} }