pub enum IdentityKind {
DmaBuf,
Shm,
IoSurface,
AHardwareBufferId,
AHardwareBufferPtr,
D3d11Texture,
HostPtr,
Pbo,
}Expand description
What kind of system key an identity was derived from. Participates in the id so that, say, inode 7 and IOSurfaceID 7 cannot collide.
Invariant every variant must uphold: the key passed to
BufferIdentity::derived is unique among live buffers of that kind
that own an allocation. There is no “no identity” case — where no
system-wide key exists a process-local one does (a pointer, a GL name),
and a process-local key is exactly as sound as a system-wide one:
pointer/name reuse after free is the same ABA hazard as inode reuse, and
is mitigated the same way, by the retaining cache (see the design spec’s
Task 6).
The allocation qualifier is load-bearing, not a hedge. A zero-element
tensor ([0, num_protos], the tracker’s “no detections this frame”
sentinel — see [crate::mem]) owns no allocation, so its Vec yields the
dangling well-aligned pointer align_of::<T>(). Every zero-element
Tensor<f32> in a process therefore shares one identity, and can even
collide across kinds with a small integer key from another variant.
That is safe rather than tolerated: an identity exists to answer “are
these the same bytes?”, and buffers with no bytes have nothing to alias.
Nor can they reach an import cache. There are four GPU import paths —
a dma-buf fd on Linux, an IOSurface ref on macOS, an AHardwareBuffer on
Android, and an ID3D11Texture2D on Windows — and each takes only its own
object, so a tensor with no allocation reaches none of them. The Windows
path additionally keys on the texture the import itself holds a reference
to, and edgefirst-image refuses any texture whose identity is not
D3d11Texture over that same pointer — in every build, and on every
import including one served from its cache
(GlPlatform::validate_import_identity). That refusal exists because the
rule was once only written
down: the dynamic backend handed the image crate HostPtr identities over
recyclable handle addresses, and converts silently rendered into dropped
textures. Do not “fix” the zero-element case by minting a distinct id per
empty tensor: that reintroduces a counter, which is the state this whole
design exists to remove.
Variants§
DmaBuf
(st_dev, st_ino) of a dma-buf or memfd. Survives dup, and is the
same value in every process that holds the buffer.
Shm
IoSurface
IOSurfaceGetID.
AHardwareBufferId
AHardwareBuffer_getId, API 31+.
AHardwareBufferPtr
The AHardwareBuffer* pointer, pre-API-31 where no id exists.
Process-local: unique among live buffers here, meaningless elsewhere.
D3d11Texture
An ID3D11Texture2D*. Process-local, like AHardwareBufferPtr, and
the same pointer for every kind of texture tensor: one the HAL
allocated, one wrapped from a caller’s pointer, and one opened from a
shared NT handle all key on the texture object they hold.
Both backends derive it from the same pointer, so their ids are
equal byte for byte. The static backend reads the ComPtr it owns
(d3d11::texture::tex_key); the dynamic backend reads the same
pointer back across the ABI with ef_tensor_d3d11_texture
(TensorDyn::derive_identity). That equality is the point, not a
coincidence: BufferIdentity::derived exists so two independently
linked copies of this crate name one buffer identically, and
edgefirst-image links the dynamic backend inside every -capi leaf
while its own tests link the static one.
An ef_tensor handle’s address must never be the key. It is not a
buffer at all, nothing the cache holds keeps it alive, and this
library’s allocator hands a freed handle’s address to the very next
one it mints — measured at 400 texture handles over 4 distinct
addresses. The dynamic backend did exactly that on Windows until
2026-09-04, and a convert whose destination key collided rendered into
the dropped texture while returning success.
A handle import therefore does not compare equal to the tensor it
was exported from, nor to a second import of the same handle:
OpenSharedResource1 mints a fresh ID3D11Texture2D per open. Keying
on a handle value would make those compare equal, and would be unsound:
Windows recycles a closed handle value straight into the next
DuplicateHandle, so a consumer that caches on this id past the
producing tensor’s lifetime – as the image crate’s EGLImage cache
does – could serve one texture’s entry for a later, unrelated import.
A COM object’s address cannot be recycled that way: a cache that holds
a reference to the texture keeps the address taken for as long as its
entry can be found. The cost is a cache miss per re-import instead of
a wrong image.
HostPtr
A host mapping address. Process-local.
Pbo
A GL buffer name. Valid only in the context that created it.
Trait Implementations§
Source§impl Clone for IdentityKind
impl Clone for IdentityKind
Source§fn clone(&self) -> IdentityKind
fn clone(&self) -> IdentityKind
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreimpl Copy for IdentityKind
Source§impl Debug for IdentityKind
impl Debug for IdentityKind
impl Eq for IdentityKind
Source§impl PartialEq for IdentityKind
impl PartialEq for IdentityKind
impl StructuralPartialEq for IdentityKind
Auto Trait Implementations§
impl Freeze for IdentityKind
impl RefUnwindSafe for IdentityKind
impl Send for IdentityKind
impl Sync for IdentityKind
impl Unpin for IdentityKind
impl UnsafeUnpin for IdentityKind
impl UnwindSafe for IdentityKind
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more