use core::ffi::c_void;
use core::fmt;
use std::sync::Arc;
#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
use std::os::fd::OwnedFd;
#[cfg(any(target_os = "linux", target_os = "android"))]
use smallvec::SmallVec;
#[cfg(windows)]
use std::os::windows::io::OwnedHandle;
use crate::PixelFormat;
pub trait ResourceKeepAlive: crate::MaybeSendSync + fmt::Debug + 'static {
fn mark_consumed(&self) {}
fn as_any(&self) -> Option<&(dyn core::any::Any + 'static)> {
None
}
}
impl ResourceKeepAlive for () {}
pub type KeepAlive = Arc<dyn ResourceKeepAlive>;
#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum InvalidHandleError {
#[error("null handle: {0}")]
NullHandle(&'static str),
#[error("null pointer: {0}")]
NullPointer(&'static str),
#[error("zero size: {0}")]
ZeroSize(&'static str),
#[error("invalid value: {field}")]
InvalidValue { field: &'static str },
}
#[cfg(target_vendor = "apple")]
#[link(name = "CoreFoundation", kind = "framework")]
unsafe extern "C" {
fn CFRetain(cf: *const c_void) -> *const c_void;
fn CFRelease(cf: *const c_void);
}
#[cfg(target_vendor = "apple")]
#[link(name = "CoreVideo", kind = "framework")]
unsafe extern "C" {
fn CVBufferRetain(buffer: *const c_void) -> *const c_void;
fn CVBufferRelease(buffer: *const c_void);
}
#[cfg(target_vendor = "apple")]
pub struct IoSurfaceRetain {
handle: *mut c_void,
}
#[cfg(target_vendor = "apple")]
impl IoSurfaceRetain {
pub unsafe fn new(handle: *mut c_void) -> Self {
unsafe { CFRetain(handle) };
Self { handle }
}
}
#[cfg(target_vendor = "apple")]
impl Drop for IoSurfaceRetain {
fn drop(&mut self) {
unsafe { CFRelease(self.handle) };
}
}
#[cfg(target_vendor = "apple")]
impl fmt::Debug for IoSurfaceRetain {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IoSurfaceRetain").finish_non_exhaustive()
}
}
#[cfg(target_vendor = "apple")]
unsafe impl Send for IoSurfaceRetain {}
#[cfg(target_vendor = "apple")]
unsafe impl Sync for IoSurfaceRetain {}
#[cfg(target_vendor = "apple")]
pub struct CvBufferRetain {
pixel_buffer: *mut c_void,
}
#[cfg(target_vendor = "apple")]
impl CvBufferRetain {
pub unsafe fn new(pixel_buffer: *mut c_void) -> Self {
unsafe { CVBufferRetain(pixel_buffer) };
Self { pixel_buffer }
}
}
#[cfg(target_vendor = "apple")]
impl Drop for CvBufferRetain {
fn drop(&mut self) {
unsafe { CVBufferRelease(self.pixel_buffer) };
}
}
#[cfg(target_vendor = "apple")]
impl fmt::Debug for CvBufferRetain {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CvBufferRetain").finish_non_exhaustive()
}
}
#[cfg(target_vendor = "apple")]
unsafe impl Send for CvBufferRetain {}
#[cfg(target_vendor = "apple")]
unsafe impl Sync for CvBufferRetain {}
#[cfg(target_os = "android")]
pub struct AHbInner {
handle: core::ptr::NonNull<ndk_sys::AHardwareBuffer>,
}
#[cfg(target_os = "android")]
impl AHbInner {
pub unsafe fn acquire(handle: *mut ndk_sys::AHardwareBuffer) -> Result<Self, InvalidHandleError> {
let nn = core::ptr::NonNull::new(handle).ok_or(InvalidHandleError::NullHandle("AHardwareBuffer"))?;
unsafe { ndk_sys::AHardwareBuffer_acquire(handle) };
Ok(Self { handle: nn })
}
pub unsafe fn from_acquired(handle: *mut ndk_sys::AHardwareBuffer) -> Result<Self, InvalidHandleError> {
let nn = core::ptr::NonNull::new(handle).ok_or(InvalidHandleError::NullHandle("AHardwareBuffer"))?;
Ok(Self { handle: nn })
}
pub fn as_ptr(&self) -> *mut ndk_sys::AHardwareBuffer {
self.handle.as_ptr()
}
}
#[cfg(target_os = "android")]
impl Drop for AHbInner {
fn drop(&mut self) {
unsafe { ndk_sys::AHardwareBuffer_release(self.handle.as_ptr()) };
}
}
#[cfg(target_os = "android")]
impl fmt::Debug for AHbInner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AHbInner").field("handle", &self.handle.as_ptr()).finish()
}
}
#[cfg(target_os = "android")]
unsafe impl Send for AHbInner {}
#[cfg(target_os = "android")]
unsafe impl Sync for AHbInner {}
#[derive(Clone)]
pub struct VkImage {
image: u64,
device: *mut c_void,
instance: *mut c_void,
phys_dev: *mut c_void,
uuid: Option<[u8; 16]>,
row_pitch: u32,
keep_alive: Option<KeepAlive>,
width: u32,
height: u32,
format: Option<crate::PixelFormat>,
plane_format: Option<crate::PlaneFormat>,
pub acquire_release: Option<VkSlotRelease>,
}
impl VkImage {
pub unsafe fn try_from_raw(
image: u64,
device: *mut c_void,
instance: *mut c_void,
phys_dev: *mut c_void,
uuid: Option<[u8; 16]>,
row_pitch: u32,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if image == 0 {
return Err(InvalidHandleError::NullHandle("VkImage"));
}
Ok(Self {
image,
device,
instance,
phys_dev,
uuid,
row_pitch,
keep_alive,
width: 0,
height: 0,
format: None,
plane_format: None,
acquire_release: None,
})
}
#[inline]
pub fn with_plane_format(mut self, plane_format: crate::PlaneFormat) -> Self {
self.plane_format = Some(plane_format);
self
}
#[inline]
pub fn with_acquire_release(mut self, release: VkSlotRelease) -> Self {
self.acquire_release = Some(release);
self
}
#[inline]
pub fn acquire_release(&self) -> Option<&VkSlotRelease> {
self.acquire_release.as_ref()
}
#[inline]
pub fn with_dimensions(mut self, width: u32, height: u32) -> Self {
self.width = width;
self.height = height;
self
}
#[inline]
pub fn with_format(mut self, format: crate::PixelFormat) -> Self {
self.format = Some(format);
self
}
#[inline]
pub fn image(&self) -> u64 {
self.image
}
#[inline]
pub fn device(&self) -> *mut c_void {
self.device
}
#[inline]
pub fn instance(&self) -> *mut c_void {
self.instance
}
#[inline]
pub fn phys_dev(&self) -> *mut c_void {
self.phys_dev
}
#[inline]
pub fn uuid(&self) -> Option<[u8; 16]> {
self.uuid
}
#[inline]
pub fn row_pitch(&self) -> u32 {
self.row_pitch
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
#[inline]
pub fn width(&self) -> u32 {
self.width
}
#[inline]
pub fn height(&self) -> u32 {
self.height
}
#[inline]
pub fn format(&self) -> Option<crate::PixelFormat> {
self.format
}
#[inline]
pub fn plane_format(&self) -> Option<crate::PlaneFormat> {
self.plane_format
}
}
impl fmt::Debug for VkImage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("VkImage")
.field("image", &self.image)
.field("uuid", &self.uuid)
.field("row_pitch", &self.row_pitch)
.finish()
}
}
unsafe impl Send for VkImage {}
unsafe impl Sync for VkImage {}
#[derive(Clone)]
pub struct VkBufferHandle {
buffer: u64,
device: *mut c_void,
uuid: Option<[u8; 16]>,
size: u64,
keep_alive: Option<KeepAlive>,
}
impl VkBufferHandle {
pub unsafe fn try_from_raw(
buffer: u64,
device: *mut c_void,
uuid: Option<[u8; 16]>,
size: u64,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if buffer == 0 {
return Err(InvalidHandleError::NullHandle("VkBuffer"));
}
if size == 0 {
return Err(InvalidHandleError::ZeroSize("VkBuffer"));
}
Ok(Self { buffer, device, uuid, size, keep_alive })
}
#[inline]
pub fn buffer(&self) -> u64 {
self.buffer
}
#[inline]
pub fn device(&self) -> *mut c_void {
self.device
}
#[inline]
pub fn uuid(&self) -> Option<[u8; 16]> {
self.uuid
}
#[inline]
pub fn size(&self) -> u64 {
self.size
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
impl fmt::Debug for VkBufferHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("VkBufferHandle")
.field("buffer", &self.buffer)
.field("uuid", &self.uuid)
.field("size", &self.size)
.finish()
}
}
unsafe impl Send for VkBufferHandle {}
unsafe impl Sync for VkBufferHandle {}
#[cfg(any(windows, unix, target_os = "wasi", target_os = "hermit"))]
#[derive(Clone)]
pub struct VkAcquireTimeline {
#[cfg(windows)]
handle: Arc<OwnedHandle>,
#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
fd: Arc<OwnedFd>,
#[cfg(windows)]
d3d12_handle: Option<Arc<OwnedHandle>>,
value: u64,
ack: Option<Arc<core::sync::atomic::AtomicBool>>,
needs_binary_fallback: Option<Arc<core::sync::atomic::AtomicBool>>,
}
#[cfg(any(windows, unix, target_os = "wasi", target_os = "hermit"))]
impl VkAcquireTimeline {
#[cfg(windows)]
#[inline]
pub fn new_win32(handle: Arc<OwnedHandle>, value: u64) -> Self {
Self { handle, d3d12_handle: None, value, ack: None, needs_binary_fallback: None }
}
#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
#[inline]
pub fn new_fd(fd: Arc<OwnedFd>, value: u64) -> Self {
Self { fd, value, ack: None, needs_binary_fallback: None }
}
#[cfg(windows)]
#[inline]
pub fn with_d3d12_handle(mut self, h: Arc<OwnedHandle>) -> Self {
self.d3d12_handle = Some(h);
self
}
#[inline]
pub fn with_wait_capability_ack(mut self, ack: Arc<core::sync::atomic::AtomicBool>) -> Self {
self.ack = Some(ack);
self
}
#[inline]
pub fn ack_wait_capability(&self) {
if let Some(a) = &self.ack {
a.store(true, core::sync::atomic::Ordering::Release);
}
}
#[cfg(windows)]
#[inline]
pub fn handle(&self) -> &Arc<OwnedHandle> {
&self.handle
}
#[cfg(windows)]
#[inline]
pub fn d3d12_handle(&self) -> Option<&Arc<OwnedHandle>> {
self.d3d12_handle.as_ref()
}
#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
#[inline]
pub fn fd(&self) -> &Arc<OwnedFd> {
&self.fd
}
#[inline]
pub fn value(&self) -> u64 {
self.value
}
#[inline]
pub fn with_needs_binary_fallback_ack(mut self, ack: Arc<core::sync::atomic::AtomicBool>) -> Self {
self.needs_binary_fallback = Some(ack);
self
}
#[inline]
pub fn signal_needs_binary_fallback(&self) {
if let Some(a) = &self.needs_binary_fallback {
a.store(true, core::sync::atomic::Ordering::Release);
}
}
}
#[cfg(any(windows, unix, target_os = "wasi", target_os = "hermit"))]
#[derive(Clone)]
pub struct VkAcquireBinary {
#[cfg(windows)]
handle: Arc<OwnedHandle>,
#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
fd: Arc<OwnedFd>,
ack: Option<Arc<core::sync::atomic::AtomicBool>>,
unstable: Option<Arc<core::sync::atomic::AtomicBool>>,
}
#[cfg(any(windows, unix, target_os = "wasi", target_os = "hermit"))]
impl VkAcquireBinary {
#[cfg(windows)]
#[inline]
pub fn new_win32(handle: Arc<OwnedHandle>) -> Self {
Self { handle, ack: None, unstable: None }
}
#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
#[inline]
pub fn new_fd(fd: Arc<OwnedFd>) -> Self {
Self { fd, ack: None, unstable: None }
}
#[inline]
pub fn with_wait_capability_ack(mut self, ack: Arc<core::sync::atomic::AtomicBool>) -> Self {
self.ack = Some(ack);
self
}
#[inline]
pub fn ack_wait_capability(&self) {
if let Some(a) = &self.ack {
a.store(true, core::sync::atomic::Ordering::Release);
}
}
#[inline]
pub fn with_unstable_ack(mut self, unstable: Arc<core::sync::atomic::AtomicBool>) -> Self {
self.unstable = Some(unstable);
self
}
#[inline]
pub fn signal_unstable(&self) {
if let Some(a) = &self.unstable {
a.store(true, core::sync::atomic::Ordering::Release);
}
}
#[cfg(windows)]
#[inline]
pub fn handle(&self) -> &Arc<OwnedHandle> {
&self.handle
}
#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
#[inline]
pub fn fd(&self) -> &Arc<OwnedFd> {
&self.fd
}
}
#[cfg(any(windows, unix, target_os = "wasi", target_os = "hermit"))]
impl fmt::Debug for VkAcquireBinary {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(windows)]
{
f.debug_struct("VkAcquireBinary").finish_non_exhaustive()
}
#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
{
use std::os::fd::AsRawFd;
f.debug_struct("VkAcquireBinary").field("fd", &self.fd.as_raw_fd()).finish()
}
}
}
#[cfg(any(windows, unix, target_os = "wasi", target_os = "hermit"))]
impl fmt::Debug for VkAcquireTimeline {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(windows)]
{
f.debug_struct("VkAcquireTimeline")
.field("value", &self.value)
.field("d3d12_handle", &self.d3d12_handle.is_some())
.finish()
}
#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
{
use std::os::fd::AsRawFd;
f.debug_struct("VkAcquireTimeline").field("fd", &self.fd.as_raw_fd()).field("value", &self.value).finish()
}
}
}
#[derive(Clone, Debug)]
pub struct VkSlotRelease {
gate: Arc<core::sync::atomic::AtomicU64>,
value: u64,
}
impl VkSlotRelease {
#[inline]
pub fn new(gate: Arc<core::sync::atomic::AtomicU64>, value: u64) -> Self {
Self { gate, value }
}
#[inline]
pub fn gate(&self) -> &Arc<core::sync::atomic::AtomicU64> {
&self.gate
}
#[inline]
pub fn value(&self) -> u64 {
self.value
}
#[inline]
pub fn release_now(&self) {
self.gate.store(self.value, core::sync::atomic::Ordering::Release);
}
}
#[cfg(any(unix, target_os = "wasi", target_os = "hermit", windows))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct VkOpaqueExportDesc {
pub size: u64,
pub memory_type_index: u32,
pub offset: u64,
pub dedicated: bool,
pub width: u32,
pub height: u32,
pub format: PixelFormat,
pub uuid: [u8; 16],
}
#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
#[derive(Clone)]
pub struct VkOpaqueFd {
fd: Arc<OwnedFd>,
desc: VkOpaqueExportDesc,
plane_format: Option<crate::PlaneFormat>,
vk_image_usage: Option<u32>,
acquire_timeline: Option<VkAcquireTimeline>,
acquire_binary: Option<VkAcquireBinary>,
acquire_release: Option<VkSlotRelease>,
}
#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
impl VkOpaqueFd {
#[inline]
pub fn new(fd: OwnedFd, desc: VkOpaqueExportDesc) -> Result<Self, InvalidHandleError> {
Self::from_shared_fd(Arc::new(fd), desc)
}
pub fn from_shared_fd(fd: Arc<OwnedFd>, desc: VkOpaqueExportDesc) -> Result<Self, InvalidHandleError> {
if desc.size == 0 {
return Err(InvalidHandleError::ZeroSize("VkOpaqueFd"));
}
if desc.width == 0 || desc.height == 0 {
return Err(InvalidHandleError::InvalidValue { field: "extent" });
}
Ok(Self {
fd,
desc,
plane_format: None,
vk_image_usage: None,
acquire_timeline: None,
acquire_binary: None,
acquire_release: None,
})
}
#[inline]
pub fn with_plane_format(mut self, plane_format: crate::PlaneFormat) -> Self {
self.plane_format = Some(plane_format);
self
}
#[inline]
pub fn with_vk_image_usage(mut self, usage: u32) -> Self {
self.vk_image_usage = Some(usage);
self
}
#[inline]
pub fn with_acquire_timeline(mut self, timeline: VkAcquireTimeline) -> Self {
self.acquire_timeline = Some(timeline);
self
}
#[inline]
pub fn with_acquire_binary(mut self, binary: VkAcquireBinary) -> Self {
self.acquire_binary = Some(binary);
self
}
#[inline]
pub fn with_acquire_release(mut self, release: VkSlotRelease) -> Self {
self.acquire_release = Some(release);
self
}
#[inline]
pub fn fd(&self) -> &Arc<OwnedFd> {
&self.fd
}
#[inline]
pub fn desc(&self) -> &VkOpaqueExportDesc {
&self.desc
}
#[inline]
pub fn size(&self) -> u64 {
self.desc.size
}
#[inline]
pub fn memory_type_index(&self) -> u32 {
self.desc.memory_type_index
}
#[inline]
pub fn offset(&self) -> u64 {
self.desc.offset
}
#[inline]
pub fn dedicated(&self) -> bool {
self.desc.dedicated
}
#[inline]
pub fn width(&self) -> u32 {
self.desc.width
}
#[inline]
pub fn height(&self) -> u32 {
self.desc.height
}
#[inline]
pub fn format(&self) -> PixelFormat {
self.desc.format
}
#[inline]
pub fn plane_format(&self) -> Option<crate::PlaneFormat> {
self.plane_format
}
#[inline]
pub fn vk_image_usage(&self) -> Option<u32> {
self.vk_image_usage
}
#[inline]
pub fn acquire_timeline(&self) -> Option<&VkAcquireTimeline> {
self.acquire_timeline.as_ref()
}
#[inline]
pub fn acquire_binary(&self) -> Option<&VkAcquireBinary> {
self.acquire_binary.as_ref()
}
#[inline]
pub fn acquire_release(&self) -> Option<&VkSlotRelease> {
self.acquire_release.as_ref()
}
#[inline]
pub fn uuid(&self) -> [u8; 16] {
self.desc.uuid
}
}
#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
impl fmt::Debug for VkOpaqueFd {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use std::os::fd::AsRawFd;
f.debug_struct("VkOpaqueFd").field("fd", &self.fd.as_raw_fd()).field("desc", &self.desc).finish()
}
}
#[cfg(windows)]
#[derive(Clone)]
pub struct VkOpaqueWin32 {
handle: Arc<OwnedHandle>,
desc: VkOpaqueExportDesc,
plane_format: Option<crate::PlaneFormat>,
vk_image_usage: Option<u32>,
acquire_timeline: Option<VkAcquireTimeline>,
acquire_binary: Option<VkAcquireBinary>,
acquire_release: Option<VkSlotRelease>,
}
#[cfg(windows)]
impl VkOpaqueWin32 {
#[inline]
pub fn new(handle: OwnedHandle, desc: VkOpaqueExportDesc) -> Result<Self, InvalidHandleError> {
Self::from_shared_handle(Arc::new(handle), desc)
}
pub fn from_shared_handle(handle: Arc<OwnedHandle>, desc: VkOpaqueExportDesc) -> Result<Self, InvalidHandleError> {
if desc.size == 0 {
return Err(InvalidHandleError::ZeroSize("VkOpaqueWin32"));
}
if desc.width == 0 || desc.height == 0 {
return Err(InvalidHandleError::InvalidValue { field: "extent" });
}
Ok(Self {
handle,
desc,
plane_format: None,
vk_image_usage: None,
acquire_timeline: None,
acquire_binary: None,
acquire_release: None,
})
}
#[inline]
pub fn with_plane_format(mut self, plane_format: crate::PlaneFormat) -> Self {
self.plane_format = Some(plane_format);
self
}
#[inline]
pub fn with_vk_image_usage(mut self, usage: u32) -> Self {
self.vk_image_usage = Some(usage);
self
}
#[inline]
pub fn with_acquire_timeline(mut self, timeline: VkAcquireTimeline) -> Self {
self.acquire_timeline = Some(timeline);
self
}
#[inline]
pub fn with_acquire_binary(mut self, binary: VkAcquireBinary) -> Self {
self.acquire_binary = Some(binary);
self
}
#[inline]
pub fn with_acquire_release(mut self, release: VkSlotRelease) -> Self {
self.acquire_release = Some(release);
self
}
#[inline]
pub fn handle(&self) -> &Arc<OwnedHandle> {
&self.handle
}
#[inline]
pub fn desc(&self) -> &VkOpaqueExportDesc {
&self.desc
}
#[inline]
pub fn size(&self) -> u64 {
self.desc.size
}
#[inline]
pub fn memory_type_index(&self) -> u32 {
self.desc.memory_type_index
}
#[inline]
pub fn offset(&self) -> u64 {
self.desc.offset
}
#[inline]
pub fn dedicated(&self) -> bool {
self.desc.dedicated
}
#[inline]
pub fn width(&self) -> u32 {
self.desc.width
}
#[inline]
pub fn height(&self) -> u32 {
self.desc.height
}
#[inline]
pub fn format(&self) -> PixelFormat {
self.desc.format
}
#[inline]
pub fn plane_format(&self) -> Option<crate::PlaneFormat> {
self.plane_format
}
#[inline]
pub fn vk_image_usage(&self) -> Option<u32> {
self.vk_image_usage
}
#[inline]
pub fn acquire_timeline(&self) -> Option<&VkAcquireTimeline> {
self.acquire_timeline.as_ref()
}
#[inline]
pub fn acquire_binary(&self) -> Option<&VkAcquireBinary> {
self.acquire_binary.as_ref()
}
#[inline]
pub fn acquire_release(&self) -> Option<&VkSlotRelease> {
self.acquire_release.as_ref()
}
#[inline]
pub fn uuid(&self) -> [u8; 16] {
self.desc.uuid
}
}
#[cfg(windows)]
impl fmt::Debug for VkOpaqueWin32 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("VkOpaqueWin32").field("desc", &self.desc).finish()
}
}
#[derive(Clone)]
pub struct D3D11Texture {
texture: *mut c_void,
luid: Option<(i32, u32)>,
row_pitch: u32,
array_slice: u32,
keep_alive: Option<KeepAlive>,
}
impl D3D11Texture {
pub unsafe fn try_from_raw(
texture: *mut c_void,
luid: Option<(i32, u32)>,
row_pitch: u32,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if texture.is_null() {
return Err(InvalidHandleError::NullPointer("ID3D11Texture2D"));
}
Ok(Self { texture, luid, row_pitch, array_slice: 0, keep_alive })
}
#[inline]
pub fn with_array_slice(mut self, slice: u32) -> Self {
self.array_slice = slice;
self
}
#[inline]
pub fn texture(&self) -> *mut c_void {
self.texture
}
#[inline]
pub fn luid(&self) -> Option<(i32, u32)> {
self.luid
}
#[inline]
pub fn row_pitch(&self) -> u32 {
self.row_pitch
}
#[inline]
pub fn array_slice(&self) -> u32 {
self.array_slice
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
impl fmt::Debug for D3D11Texture {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("D3D11Texture")
.field("luid", &self.luid)
.field("row_pitch", &self.row_pitch)
.field("array_slice", &self.array_slice)
.finish()
}
}
unsafe impl Send for D3D11Texture {}
unsafe impl Sync for D3D11Texture {}
#[derive(Clone)]
pub struct D3D12Resource {
resource: *mut c_void,
luid: Option<(i32, u32)>,
row_pitch: u32,
keep_alive: Option<KeepAlive>,
}
impl D3D12Resource {
pub unsafe fn try_from_raw(
resource: *mut c_void,
luid: Option<(i32, u32)>,
row_pitch: u32,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if resource.is_null() {
return Err(InvalidHandleError::NullPointer("ID3D12Resource"));
}
Ok(Self { resource, luid, row_pitch, keep_alive })
}
#[inline]
pub fn resource(&self) -> *mut c_void {
self.resource
}
#[inline]
pub fn luid(&self) -> Option<(i32, u32)> {
self.luid
}
#[inline]
pub fn row_pitch(&self) -> u32 {
self.row_pitch
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
impl fmt::Debug for D3D12Resource {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("D3D12Resource").field("luid", &self.luid).field("row_pitch", &self.row_pitch).finish()
}
}
unsafe impl Send for D3D12Resource {}
unsafe impl Sync for D3D12Resource {}
#[derive(Clone)]
pub struct D3D12BufferHandle {
resource: *mut c_void,
luid: Option<(i32, u32)>,
size: u64,
keep_alive: Option<KeepAlive>,
}
impl D3D12BufferHandle {
pub unsafe fn try_from_raw(
resource: *mut c_void,
luid: Option<(i32, u32)>,
size: u64,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if resource.is_null() {
return Err(InvalidHandleError::NullPointer("ID3D12Resource"));
}
if size == 0 {
return Err(InvalidHandleError::ZeroSize("D3D12 buffer"));
}
Ok(Self { resource, luid, size, keep_alive })
}
#[inline]
pub fn resource(&self) -> *mut c_void {
self.resource
}
#[inline]
pub fn luid(&self) -> Option<(i32, u32)> {
self.luid
}
#[inline]
pub fn size(&self) -> u64 {
self.size
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
impl fmt::Debug for D3D12BufferHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("D3D12BufferHandle").field("luid", &self.luid).field("size", &self.size).finish()
}
}
unsafe impl Send for D3D12BufferHandle {}
unsafe impl Sync for D3D12BufferHandle {}
#[cfg(windows)]
#[derive(Clone)]
pub struct NtHandle {
handle: Arc<OwnedHandle>,
}
#[cfg(windows)]
impl NtHandle {
pub fn new(handle: OwnedHandle) -> Self {
Self { handle: Arc::new(handle) }
}
#[inline]
pub fn handle(&self) -> &Arc<OwnedHandle> {
&self.handle
}
}
#[cfg(windows)]
impl fmt::Debug for NtHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NtHandle").finish_non_exhaustive()
}
}
#[cfg(windows)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct KmtToken(u32);
#[cfg(windows)]
impl KmtToken {
pub fn new(value: u32) -> Result<Self, InvalidHandleError> {
if value == 0 {
return Err(InvalidHandleError::InvalidValue { field: "KMT token" });
}
Ok(Self(value))
}
#[inline]
pub fn value(self) -> u32 {
self.0
}
}
#[derive(Clone)]
pub struct CudaPtr2D {
ptr: u64,
row_pitch: u32,
plane_byte_offsets: Option<[u32; 3]>,
plane_row_pitches: Option<[u32; 3]>,
size: Option<(u32, u32)>,
format: Option<PixelFormat>,
uuid: Option<[u8; 16]>,
keep_alive: Option<KeepAlive>,
}
impl CudaPtr2D {
pub unsafe fn try_from_raw(
ptr: u64,
row_pitch: u32,
uuid: Option<[u8; 16]>,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if ptr == 0 {
return Err(InvalidHandleError::NullHandle("CUdeviceptr"));
}
Ok(Self {
ptr,
row_pitch,
plane_byte_offsets: None,
plane_row_pitches: None,
size: None,
format: None,
uuid,
keep_alive,
})
}
#[inline]
pub fn with_plane_byte_offsets(mut self, offsets: [u32; 3]) -> Self {
self.plane_byte_offsets = Some(offsets);
self
}
#[inline]
pub fn with_plane_row_pitches(mut self, pitches: [u32; 3]) -> Self {
self.plane_row_pitches = Some(pitches);
self
}
#[inline]
pub fn with_size(mut self, width: u32, height: u32) -> Self {
self.size = Some((width, height));
self
}
#[inline]
pub fn with_format(mut self, format: PixelFormat) -> Self {
self.format = Some(format);
self
}
#[inline]
pub fn ptr(&self) -> u64 {
self.ptr
}
#[inline]
pub fn row_pitch(&self) -> u32 {
self.row_pitch
}
#[inline]
pub fn plane_byte_offsets(&self) -> Option<[u32; 3]> {
self.plane_byte_offsets
}
#[inline]
pub fn plane_row_pitches(&self) -> Option<[u32; 3]> {
self.plane_row_pitches
}
#[inline]
pub fn plane_row_pitch(&self, index: u8) -> u32 {
match index {
1..=3 => self
.plane_row_pitches
.and_then(|p| p.get((index - 1) as usize).copied())
.filter(|&pitch| pitch != 0)
.unwrap_or(self.row_pitch),
_ => self.row_pitch,
}
}
#[inline]
pub fn size(&self) -> Option<(u32, u32)> {
self.size
}
#[inline]
pub fn format(&self) -> Option<PixelFormat> {
self.format
}
#[inline]
pub fn uuid(&self) -> Option<[u8; 16]> {
self.uuid
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
impl fmt::Debug for CudaPtr2D {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CudaPtr2D")
.field("row_pitch", &self.row_pitch)
.field("plane_byte_offsets", &self.plane_byte_offsets)
.field("plane_row_pitches", &self.plane_row_pitches)
.field("size", &self.size)
.field("format", &self.format)
.field("uuid", &self.uuid)
.finish()
}
}
unsafe impl Send for CudaPtr2D {}
unsafe impl Sync for CudaPtr2D {}
#[derive(Clone)]
pub struct CudaBufferHandle {
ptr: u64,
size: u64,
uuid: Option<[u8; 16]>,
keep_alive: Option<KeepAlive>,
}
impl CudaBufferHandle {
pub unsafe fn try_from_raw(
ptr: u64,
size: u64,
uuid: Option<[u8; 16]>,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if ptr == 0 {
return Err(InvalidHandleError::NullHandle("CUdeviceptr"));
}
if size == 0 {
return Err(InvalidHandleError::ZeroSize("CUDA buffer"));
}
Ok(Self { ptr, size, uuid, keep_alive })
}
#[inline]
pub fn ptr(&self) -> u64 {
self.ptr
}
#[inline]
pub fn size(&self) -> u64 {
self.size
}
#[inline]
pub fn uuid(&self) -> Option<[u8; 16]> {
self.uuid
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
impl fmt::Debug for CudaBufferHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CudaBufferHandle").field("size", &self.size).field("uuid", &self.uuid).finish()
}
}
unsafe impl Send for CudaBufferHandle {}
unsafe impl Sync for CudaBufferHandle {}
#[cfg(feature = "wgpu")]
#[derive(Clone)]
pub struct CudaSurface {
surf: u64,
width: u32,
height: u32,
format: wgpu::TextureFormat,
uuid: Option<[u8; 16]>,
keep_alive: Option<KeepAlive>,
}
#[cfg(feature = "wgpu")]
impl CudaSurface {
pub unsafe fn try_from_raw(
surf: u64,
width: u32,
height: u32,
format: wgpu::TextureFormat,
uuid: Option<[u8; 16]>,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if surf == 0 {
return Err(InvalidHandleError::NullHandle("CUsurfObject"));
}
if width == 0 || height == 0 {
return Err(InvalidHandleError::InvalidValue { field: "extent" });
}
Ok(Self { surf, width, height, format, uuid, keep_alive })
}
#[inline]
pub fn surf(&self) -> u64 {
self.surf
}
#[inline]
pub fn width(&self) -> u32 {
self.width
}
#[inline]
pub fn height(&self) -> u32 {
self.height
}
#[inline]
pub fn format(&self) -> wgpu::TextureFormat {
self.format
}
#[inline]
pub fn uuid(&self) -> Option<[u8; 16]> {
self.uuid
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
#[cfg(feature = "wgpu")]
impl fmt::Debug for CudaSurface {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CudaSurface")
.field("width", &self.width)
.field("height", &self.height)
.field("format", &self.format)
.field("uuid", &self.uuid)
.finish()
}
}
#[cfg(feature = "wgpu")]
unsafe impl Send for CudaSurface {}
#[cfg(feature = "wgpu")]
unsafe impl Sync for CudaSurface {}
#[cfg(feature = "wgpu")]
#[derive(Clone)]
pub struct WgpuTexture {
texture: wgpu::Texture,
keep_alive: Option<KeepAlive>,
}
#[cfg(feature = "wgpu")]
impl WgpuTexture {
#[inline]
pub fn new(texture: wgpu::Texture) -> Self {
Self { texture, keep_alive: None }
}
#[inline]
pub fn with_keep_alive(mut self, keep_alive: KeepAlive) -> Self {
self.keep_alive = Some(keep_alive);
self
}
#[inline]
pub fn texture(&self) -> &wgpu::Texture {
&self.texture
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
#[inline]
pub fn into_texture(self) -> wgpu::Texture {
self.texture
}
}
#[cfg(feature = "wgpu")]
impl fmt::Debug for WgpuTexture {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WgpuTexture")
.field("width", &self.texture.width())
.field("height", &self.texture.height())
.field("format", &self.texture.format())
.field("keep_alive", &self.keep_alive.is_some())
.finish()
}
}
#[derive(Clone)]
pub struct OpenClMem {
mem: *mut c_void,
queue: *mut c_void,
row_pitch: u32,
keep_alive: Option<KeepAlive>,
}
impl OpenClMem {
pub unsafe fn try_from_raw(
mem: *mut c_void,
queue: *mut c_void,
row_pitch: u32,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if mem.is_null() {
return Err(InvalidHandleError::NullPointer("cl_mem"));
}
if queue.is_null() {
return Err(InvalidHandleError::NullPointer("cl_command_queue"));
}
Ok(Self { mem, queue, row_pitch, keep_alive })
}
#[inline]
pub fn mem(&self) -> *mut c_void {
self.mem
}
#[inline]
pub fn queue(&self) -> *mut c_void {
self.queue
}
#[inline]
pub fn row_pitch(&self) -> u32 {
self.row_pitch
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
impl fmt::Debug for OpenClMem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OpenClMem").field("row_pitch", &self.row_pitch).finish()
}
}
unsafe impl Send for OpenClMem {}
unsafe impl Sync for OpenClMem {}
#[derive(Clone)]
pub struct MetalTextureHandle {
tex: *mut c_void,
registry_id: Option<u64>,
keep_alive: Option<KeepAlive>,
}
impl MetalTextureHandle {
pub unsafe fn try_from_raw(
tex: *mut c_void,
registry_id: Option<u64>,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if tex.is_null() {
return Err(InvalidHandleError::NullPointer("MTLTexture"));
}
Ok(Self { tex, registry_id, keep_alive })
}
#[inline]
pub fn texture(&self) -> *mut c_void {
self.tex
}
#[inline]
pub fn registry_id(&self) -> Option<u64> {
self.registry_id
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
impl fmt::Debug for MetalTextureHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MetalTextureHandle").field("registry_id", &self.registry_id).finish()
}
}
unsafe impl Send for MetalTextureHandle {}
unsafe impl Sync for MetalTextureHandle {}
#[derive(Clone)]
pub struct MetalBufferHandle {
buf: *mut c_void,
row_pitch: u32,
registry_id: Option<u64>,
keep_alive: Option<KeepAlive>,
}
impl MetalBufferHandle {
pub unsafe fn try_from_raw(
buf: *mut c_void,
row_pitch: u32,
registry_id: Option<u64>,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if buf.is_null() {
return Err(InvalidHandleError::NullPointer("MTLBuffer"));
}
Ok(Self { buf, row_pitch, registry_id, keep_alive })
}
#[inline]
pub fn buffer(&self) -> *mut c_void {
self.buf
}
#[inline]
pub fn row_pitch(&self) -> u32 {
self.row_pitch
}
#[inline]
pub fn registry_id(&self) -> Option<u64> {
self.registry_id
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
impl fmt::Debug for MetalBufferHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MetalBufferHandle")
.field("row_pitch", &self.row_pitch)
.field("registry_id", &self.registry_id)
.finish()
}
}
unsafe impl Send for MetalBufferHandle {}
unsafe impl Sync for MetalBufferHandle {}
#[cfg(target_vendor = "apple")]
#[derive(Clone)]
pub struct IoSurface {
handle: *mut c_void,
retain: Arc<IoSurfaceRetain>,
keep_alive: Option<KeepAlive>,
}
#[cfg(target_vendor = "apple")]
impl IoSurface {
pub unsafe fn try_from_raw(handle: *mut c_void) -> Result<Self, InvalidHandleError> {
if handle.is_null() {
return Err(InvalidHandleError::NullPointer("IOSurfaceRef"));
}
let retain = Arc::new(unsafe { IoSurfaceRetain::new(handle) });
Ok(Self { handle, retain, keep_alive: None })
}
#[inline]
#[must_use]
pub fn with_keep_alive(mut self, keep_alive: KeepAlive) -> Self {
self.keep_alive = Some(keep_alive);
self
}
#[inline]
pub fn handle(&self) -> *mut c_void {
self.handle
}
#[inline]
pub fn retain(&self) -> &Arc<IoSurfaceRetain> {
&self.retain
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
#[cfg(target_vendor = "apple")]
impl fmt::Debug for IoSurface {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IoSurface").field("keep_alive", &self.keep_alive.is_some()).finish_non_exhaustive()
}
}
#[cfg(target_vendor = "apple")]
unsafe impl Send for IoSurface {}
#[cfg(target_vendor = "apple")]
unsafe impl Sync for IoSurface {}
#[cfg(target_vendor = "apple")]
#[derive(Clone)]
pub struct VideoToolboxFrame {
pixel_buffer: *mut c_void,
retain: Arc<CvBufferRetain>,
keep_alive: Option<KeepAlive>,
}
#[cfg(target_vendor = "apple")]
impl VideoToolboxFrame {
pub unsafe fn try_from_raw(pixel_buffer: *mut c_void) -> Result<Self, InvalidHandleError> {
if pixel_buffer.is_null() {
return Err(InvalidHandleError::NullPointer("CVPixelBufferRef"));
}
let retain = Arc::new(unsafe { CvBufferRetain::new(pixel_buffer) });
Ok(Self { pixel_buffer, retain, keep_alive: None })
}
#[inline]
#[must_use]
pub fn with_keep_alive(mut self, keep_alive: KeepAlive) -> Self {
self.keep_alive = Some(keep_alive);
self
}
#[inline]
pub fn pixel_buffer(&self) -> *mut c_void {
self.pixel_buffer
}
#[inline]
pub fn retain(&self) -> &Arc<CvBufferRetain> {
&self.retain
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
#[cfg(target_vendor = "apple")]
impl fmt::Debug for VideoToolboxFrame {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("VideoToolboxFrame").field("keep_alive", &self.keep_alive.is_some()).finish_non_exhaustive()
}
}
#[cfg(target_vendor = "apple")]
unsafe impl Send for VideoToolboxFrame {}
#[cfg(target_vendor = "apple")]
unsafe impl Sync for VideoToolboxFrame {}
#[derive(Clone)]
pub struct GlTextureHandle {
name: u32,
target: super::GlTextureTarget,
format: super::GlInternalFormat,
context: *mut c_void,
share_group: Option<u64>,
keep_alive: Option<KeepAlive>,
}
impl GlTextureHandle {
pub unsafe fn try_from_raw(
name: u32,
target: super::GlTextureTarget,
format: super::GlInternalFormat,
context: *mut c_void,
share_group: Option<u64>,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if name == 0 {
return Err(InvalidHandleError::NullHandle("GL texture name"));
}
Ok(Self { name, target, format, context, share_group, keep_alive })
}
#[inline]
pub fn name(&self) -> u32 {
self.name
}
#[inline]
pub fn target(&self) -> super::GlTextureTarget {
self.target
}
#[inline]
pub fn format(&self) -> super::GlInternalFormat {
self.format
}
#[inline]
pub fn context(&self) -> *mut c_void {
self.context
}
#[inline]
pub fn share_group(&self) -> Option<u64> {
self.share_group
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
impl fmt::Debug for GlTextureHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("GlTextureHandle")
.field("name", &self.name)
.field("target", &self.target)
.field("format", &self.format)
.field("share_group", &self.share_group)
.finish()
}
}
unsafe impl Send for GlTextureHandle {}
unsafe impl Sync for GlTextureHandle {}
#[derive(Clone)]
pub struct GlBufferHandle {
name: u32,
target: super::GlBufferTarget,
size: u64,
context: *mut c_void,
share_group: Option<u64>,
keep_alive: Option<KeepAlive>,
}
impl GlBufferHandle {
pub unsafe fn try_from_raw(
name: u32,
target: super::GlBufferTarget,
size: u64,
context: *mut c_void,
share_group: Option<u64>,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if name == 0 {
return Err(InvalidHandleError::NullHandle("GL buffer name"));
}
if size == 0 {
return Err(InvalidHandleError::ZeroSize("GL buffer"));
}
Ok(Self { name, target, size, context, share_group, keep_alive })
}
#[inline]
pub fn name(&self) -> u32 {
self.name
}
#[inline]
pub fn target(&self) -> super::GlBufferTarget {
self.target
}
#[inline]
pub fn size(&self) -> u64 {
self.size
}
#[inline]
pub fn context(&self) -> *mut c_void {
self.context
}
#[inline]
pub fn share_group(&self) -> Option<u64> {
self.share_group
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
impl fmt::Debug for GlBufferHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("GlBufferHandle")
.field("name", &self.name)
.field("target", &self.target)
.field("size", &self.size)
.field("share_group", &self.share_group)
.finish()
}
}
unsafe impl Send for GlBufferHandle {}
unsafe impl Sync for GlBufferHandle {}
#[cfg(any(target_os = "linux", target_os = "android"))]
#[derive(Clone)]
pub struct DmaBufHandle {
fds: SmallVec<[Arc<OwnedFd>; 2]>,
desc: DmaBufImportDesc,
keep_alive: Option<KeepAlive>,
acquire_release: Option<VkSlotRelease>,
}
#[cfg(any(target_os = "linux", target_os = "android"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DmaBufImportDesc {
pub fourcc: u32,
pub modifier: u64,
pub width: u32,
pub height: u32,
pub num_planes: u8,
pub plane_object_index: [u8; 4],
pub plane_strides: [u32; 4],
pub plane_offsets: [u32; 4],
}
#[cfg(any(target_os = "linux", target_os = "android"))]
impl DmaBufHandle {
pub fn new(fd: OwnedFd, desc: DmaBufImportDesc) -> Result<Self, InvalidHandleError> {
let mut fds: SmallVec<[Arc<OwnedFd>; 2]> = SmallVec::new();
fds.push(Arc::new(fd));
Self::from_objects(fds, desc)
}
pub fn from_objects(fds: SmallVec<[Arc<OwnedFd>; 2]>, desc: DmaBufImportDesc) -> Result<Self, InvalidHandleError> {
if desc.width == 0 || desc.height == 0 {
return Err(InvalidHandleError::InvalidValue { field: "DMA-BUF extent" });
}
if desc.num_planes == 0 || desc.num_planes > 4 {
return Err(InvalidHandleError::InvalidValue { field: "num_planes" });
}
if fds.is_empty() || fds.len() > 4 {
return Err(InvalidHandleError::InvalidValue { field: "num_objects" });
}
for &obj in &desc.plane_object_index[..desc.num_planes as usize] {
if obj as usize >= fds.len() {
return Err(InvalidHandleError::InvalidValue { field: "plane_object_index" });
}
}
Ok(Self { fds, desc, keep_alive: None, acquire_release: None })
}
#[inline]
pub fn with_keep_alive(mut self, keep_alive: KeepAlive) -> Self {
self.keep_alive = Some(keep_alive);
self
}
#[inline]
pub fn with_acquire_release(mut self, release: VkSlotRelease) -> Self {
self.acquire_release = Some(release);
self
}
#[inline]
pub fn fd(&self) -> &Arc<OwnedFd> {
&self.fds[0]
}
#[inline]
pub fn fds(&self) -> &[Arc<OwnedFd>] {
&self.fds
}
#[inline]
pub fn desc(&self) -> &DmaBufImportDesc {
&self.desc
}
#[inline]
pub fn fourcc(&self) -> u32 {
self.desc.fourcc
}
#[inline]
pub fn modifier(&self) -> u64 {
self.desc.modifier
}
#[inline]
pub fn width(&self) -> u32 {
self.desc.width
}
#[inline]
pub fn height(&self) -> u32 {
self.desc.height
}
#[inline]
pub fn num_planes(&self) -> u8 {
self.desc.num_planes
}
#[inline]
pub fn plane_object_index(&self) -> [u8; 4] {
self.desc.plane_object_index
}
#[inline]
pub fn plane_strides(&self) -> [u32; 4] {
self.desc.plane_strides
}
#[inline]
pub fn plane_offsets(&self) -> [u32; 4] {
self.desc.plane_offsets
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
#[inline]
pub fn acquire_release(&self) -> Option<&VkSlotRelease> {
self.acquire_release.as_ref()
}
}
#[cfg(any(target_os = "linux", target_os = "android"))]
impl fmt::Debug for DmaBufHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use std::os::fd::AsRawFd;
let raw_fds: SmallVec<[i32; 2]> = self.fds.iter().map(|fd| fd.as_raw_fd()).collect();
f.debug_struct("DmaBufHandle")
.field("fds", &raw_fds)
.field("desc", &self.desc)
.field("keep_alive", &self.keep_alive.is_some())
.field("acquire_release", &self.acquire_release.is_some())
.finish()
}
}
#[cfg(target_os = "android")]
#[derive(Clone)]
pub struct AHardwareBufferHandle {
inner: Arc<AHbInner>,
}
#[cfg(target_os = "android")]
impl AHardwareBufferHandle {
pub unsafe fn acquire(handle: *mut ndk_sys::AHardwareBuffer) -> Result<Self, InvalidHandleError> {
let inner = Arc::new(unsafe { AHbInner::acquire(handle)? });
Ok(Self { inner })
}
pub unsafe fn from_acquired(handle: *mut ndk_sys::AHardwareBuffer) -> Result<Self, InvalidHandleError> {
let inner = Arc::new(unsafe { AHbInner::from_acquired(handle)? });
Ok(Self { inner })
}
#[inline]
pub fn as_ptr(&self) -> *mut ndk_sys::AHardwareBuffer {
self.inner.as_ptr()
}
#[inline]
pub fn inner(&self) -> &Arc<AHbInner> {
&self.inner
}
}
#[cfg(target_os = "android")]
impl fmt::Debug for AHardwareBufferHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AHardwareBufferHandle").field("handle", &self.inner.as_ptr()).finish()
}
}
#[cfg(target_os = "android")]
#[derive(Clone)]
pub struct MediaCodecFrame {
buffer: *mut c_void,
surface_texture: *mut c_void,
format: PixelFormat,
width: u32,
height: u32,
serial: u64,
keep_alive: Option<KeepAlive>,
}
#[cfg(target_os = "android")]
impl MediaCodecFrame {
pub unsafe fn try_from_raw(
buffer: *mut c_void,
surface_texture: *mut c_void,
format: PixelFormat,
width: u32,
height: u32,
serial: u64,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if buffer.is_null() {
return Err(InvalidHandleError::NullPointer("MediaCodec buffer"));
}
Ok(Self { buffer, surface_texture, format, width, height, serial, keep_alive })
}
#[inline]
pub fn buffer(&self) -> *mut c_void {
self.buffer
}
#[inline]
pub fn surface_texture(&self) -> *mut c_void {
self.surface_texture
}
#[inline]
pub fn format(&self) -> PixelFormat {
self.format
}
#[inline]
pub fn width(&self) -> u32 {
self.width
}
#[inline]
pub fn height(&self) -> u32 {
self.height
}
#[inline]
pub fn serial(&self) -> u64 {
self.serial
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
#[cfg(target_os = "android")]
impl fmt::Debug for MediaCodecFrame {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MediaCodecFrame")
.field("format", &self.format)
.field("width", &self.width)
.field("height", &self.height)
.field("serial", &self.serial)
.finish()
}
}
#[cfg(target_os = "android")]
unsafe impl Send for MediaCodecFrame {}
#[cfg(target_os = "android")]
unsafe impl Sync for MediaCodecFrame {}
#[cfg(target_os = "android")]
#[derive(Clone)]
pub struct AImageFrame {
image: *mut c_void,
hardware: *mut c_void,
timestamp_ns: i64,
crop: Option<(i32, i32, i32, i32)>,
format: PixelFormat,
color: Option<video_types::ColorMetadata>,
keep_alive: Option<KeepAlive>,
}
#[cfg(target_os = "android")]
impl AImageFrame {
pub unsafe fn try_from_raw(
image: *mut c_void,
hardware: *mut c_void,
timestamp_ns: i64,
crop: Option<(i32, i32, i32, i32)>,
format: PixelFormat,
color: Option<video_types::ColorMetadata>,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if image.is_null() {
return Err(InvalidHandleError::NullPointer("AImage"));
}
if hardware.is_null() {
return Err(InvalidHandleError::NullPointer("AHardwareBuffer"));
}
Ok(Self { image, hardware, timestamp_ns, crop, format, color, keep_alive })
}
#[inline]
pub fn image(&self) -> *mut c_void {
self.image
}
#[inline]
pub fn hardware(&self) -> *mut c_void {
self.hardware
}
#[inline]
pub fn timestamp_ns(&self) -> i64 {
self.timestamp_ns
}
#[inline]
pub fn crop(&self) -> Option<(i32, i32, i32, i32)> {
self.crop
}
#[inline]
pub fn format(&self) -> PixelFormat {
self.format
}
#[inline]
pub fn color(&self) -> Option<video_types::ColorMetadata> {
self.color.clone()
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
#[cfg(target_os = "android")]
impl fmt::Debug for AImageFrame {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AImageFrame")
.field("timestamp_ns", &self.timestamp_ns)
.field("crop", &self.crop)
.field("format", &self.format)
.finish()
}
}
#[cfg(target_os = "android")]
unsafe impl Send for AImageFrame {}
#[cfg(target_os = "android")]
unsafe impl Sync for AImageFrame {}
#[cfg(target_os = "android")]
#[derive(Clone)]
pub struct AndroidNativeWindowHandle {
window: *mut c_void,
keep_alive: Option<KeepAlive>,
}
#[cfg(target_os = "android")]
impl AndroidNativeWindowHandle {
pub unsafe fn try_from_raw(window: *mut c_void, keep_alive: Option<KeepAlive>) -> Result<Self, InvalidHandleError> {
if window.is_null() {
return Err(InvalidHandleError::NullPointer("ANativeWindow"));
}
Ok(Self { window, keep_alive })
}
#[inline]
pub fn window(&self) -> *mut c_void {
self.window
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
#[cfg(target_os = "android")]
impl fmt::Debug for AndroidNativeWindowHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AndroidNativeWindowHandle").finish_non_exhaustive()
}
}
#[cfg(target_os = "android")]
unsafe impl Send for AndroidNativeWindowHandle {}
#[cfg(target_os = "android")]
unsafe impl Sync for AndroidNativeWindowHandle {}
#[cfg(target_os = "android")]
#[derive(Clone)]
pub struct AndroidSurfaceControlHandle {
surface_control: *mut c_void,
keep_alive: Option<KeepAlive>,
}
#[cfg(target_os = "android")]
impl AndroidSurfaceControlHandle {
pub unsafe fn try_from_raw(
surface_control: *mut c_void,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if surface_control.is_null() {
return Err(InvalidHandleError::NullPointer("ASurfaceControl"));
}
Ok(Self { surface_control, keep_alive })
}
#[inline]
pub fn surface_control(&self) -> *mut c_void {
self.surface_control
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
#[cfg(target_os = "android")]
impl fmt::Debug for AndroidSurfaceControlHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AndroidSurfaceControlHandle").finish_non_exhaustive()
}
}
#[cfg(target_os = "android")]
unsafe impl Send for AndroidSurfaceControlHandle {}
#[cfg(target_os = "android")]
unsafe impl Sync for AndroidSurfaceControlHandle {}
#[cfg(target_os = "linux")]
#[derive(Clone)]
pub struct VaapiSurface {
surface: u32,
display: *mut c_void,
keep_alive: Option<KeepAlive>,
}
#[cfg(target_os = "linux")]
impl VaapiSurface {
pub unsafe fn try_from_raw(
surface: u32,
display: *mut c_void,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if display.is_null() {
return Err(InvalidHandleError::NullPointer("VADisplay"));
}
Ok(Self { surface, display, keep_alive })
}
#[inline]
pub fn surface(&self) -> u32 {
self.surface
}
#[inline]
pub fn display(&self) -> *mut c_void {
self.display
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
#[cfg(target_os = "linux")]
impl fmt::Debug for VaapiSurface {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("VaapiSurface").field("surface", &self.surface).finish_non_exhaustive()
}
}
#[cfg(target_os = "linux")]
unsafe impl Send for VaapiSurface {}
#[cfg(target_os = "linux")]
unsafe impl Sync for VaapiSurface {}
#[derive(Clone)]
pub struct CpuBytes {
ptr: *mut u8,
size: usize,
row_pitch: u32,
format: PixelFormat,
keep_alive: Option<KeepAlive>,
}
impl CpuBytes {
pub unsafe fn try_from_raw(
ptr: *mut u8,
size: usize,
row_pitch: u32,
format: PixelFormat,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if ptr.is_null() {
return Err(InvalidHandleError::NullPointer("CPU bytes"));
}
if size == 0 {
return Err(InvalidHandleError::ZeroSize("CPU bytes"));
}
Ok(Self { ptr, size, row_pitch, format, keep_alive })
}
#[inline]
pub fn ptr(&self) -> *mut u8 {
self.ptr
}
#[inline]
pub fn size(&self) -> usize {
self.size
}
#[inline]
pub fn row_pitch(&self) -> u32 {
self.row_pitch
}
#[inline]
pub fn format(&self) -> PixelFormat {
self.format
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
impl fmt::Debug for CpuBytes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CpuBytes")
.field("size", &self.size)
.field("row_pitch", &self.row_pitch)
.field("format", &self.format)
.finish()
}
}
unsafe impl Send for CpuBytes {}
unsafe impl Sync for CpuBytes {}
#[derive(Clone)]
pub struct CpuSharedSlot {
size: u64,
row_pitch: u32,
format: PixelFormat,
keep_alive: Option<KeepAlive>,
}
impl CpuSharedSlot {
pub fn new(
size: u64,
row_pitch: u32,
format: PixelFormat,
keep_alive: Option<KeepAlive>,
) -> Result<Self, InvalidHandleError> {
if size == 0 {
return Err(InvalidHandleError::ZeroSize("CPU shared slot"));
}
Ok(Self { size, row_pitch, format, keep_alive })
}
#[inline]
pub fn size(&self) -> u64 {
self.size
}
#[inline]
pub fn row_pitch(&self) -> u32 {
self.row_pitch
}
#[inline]
pub fn format(&self) -> PixelFormat {
self.format
}
#[inline]
pub fn keep_alive(&self) -> Option<&KeepAlive> {
self.keep_alive.as_ref()
}
}
impl fmt::Debug for CpuSharedSlot {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CpuSharedSlot")
.field("size", &self.size)
.field("row_pitch", &self.row_pitch)
.field("format", &self.format)
.finish()
}
}
#[cfg(feature = "ash")]
impl VkImage {
#[inline]
pub fn as_ash_image(&self) -> ash::vk::Image {
use ash::vk::Handle;
ash::vk::Image::from_raw(self.image)
}
}
#[cfg(feature = "ash")]
impl VkBufferHandle {
#[inline]
pub fn as_ash_buffer(&self) -> ash::vk::Buffer {
use ash::vk::Handle;
ash::vk::Buffer::from_raw(self.buffer)
}
}
#[cfg(test)]
mod inline_tests {
use super::*;
#[derive(Debug)]
struct _Marker;
#[cfg(not(target_family = "wasm"))]
#[test]
fn keep_alive_trait_object_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<Arc<dyn ResourceKeepAlive>>();
}
#[cfg(target_family = "wasm")]
static_assertions::assert_not_impl_any!(Arc<dyn ResourceKeepAlive>: Send, Sync);
}