Start on using CVMetalTextureCache
This commit is contained in:
parent
531ffc01c9
commit
37da841716
4 changed files with 129 additions and 5 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3036,6 +3036,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block",
|
"block",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
|
"metal",
|
||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue