use std::sync::Arc;
use objc2::rc::Retained;
use objc2::runtime::ProtocolObject;
use objc2_io_surface::IOSurfaceRef;
use objc2_metal::{
MTLDevice, MTLPixelFormat, MTLStorageMode, MTLTextureDescriptor, MTLTextureType,
MTLTextureUsage,
};
use crate::error::{Error, Result};
use super::ExportedFrame;
impl ExportedFrame {
pub fn into_wgpu_texture(mut self, device: &wgpu::Device) -> Result<wgpu::Texture> {
let (width, height) = (self.width(), self.height());
let raw_device = {
let hal_device = unsafe { device.as_hal::<wgpu_hal::api::Metal>() };
let Some(hal_device) = hal_device else {
return Err(Error::WgpuImport(
"wgpu device is not on the Metal backend".into(),
));
};
hal_device.raw_device().clone()
};
let descriptor = unsafe {
MTLTextureDescriptor::texture2DDescriptorWithPixelFormat_width_height_mipmapped(
MTLPixelFormat::BGRA8Unorm,
width as usize,
height as usize,
false,
)
};
descriptor.setUsage(MTLTextureUsage::ShaderRead);
descriptor.setStorageMode(if raw_device.hasUnifiedMemory() {
MTLStorageMode::Shared
} else {
MTLStorageMode::Managed
});
let raw_texture = unsafe {
let surface = &*self.io_surface().cast::<IOSurfaceRef>();
raw_device.newTextureWithDescriptor_iosurface_plane(&descriptor, surface, 0)
};
drop::<Retained<ProtocolObject<dyn MTLDevice>>>(raw_device);
let Some(raw_texture) = raw_texture else {
return Err(Error::WgpuImport(format!(
"newTextureWithDescriptor:iosurface:plane: failed for {width}x{height}"
)));
};
let buffer = self
.buffer
.take()
.expect("buffer present until drop/presented");
let shared = Arc::clone(&self.shared);
let drop_callback: wgpu_hal::DropCallback = Box::new(move || {
super::return_buffer(&shared, buffer);
});
let hal_texture = unsafe {
wgpu_hal::metal::Device::texture_from_raw(
raw_texture,
wgpu::TextureFormat::Bgra8Unorm,
MTLTextureType::Type2D,
1,
1,
wgpu_hal::CopyExtent {
width,
height,
depth: 1,
},
Some(drop_callback),
)
};
let desc = super::exported_texture_desc(width, height);
Ok(unsafe {
device.create_texture_from_hal::<wgpu_hal::api::Metal>(
hal_texture,
&desc,
wgpu::TextureUses::RESOURCE,
)
})
}
}