#[repr(u32)]pub enum CpuAccess {
None = 0,
Read = 1,
Write = 2,
ReadWrite = 3,
}Expand description
Declared CPU involvement for a tensor, chosen at allocation.
The declaration covers all CPU access to the buffer: the caller’s maps, pins and sync brackets, and the HAL’s own CPU work (the CPU image backend’s converts and draws, codec decodes, decoder reads and writes). Hardware access (ISP, codec, GPU, NPU, G2D, a compositor) needs no declaration and is always allowed.
The HAL enforces it. A CPU map, pin or sync whose direction the
declaration does not cover fails with Error::CpuAccessDenied on
every backend, before the memory is touched. The HAL’s own CPU passes
go through the same check, so, for example, a CPU draw that would
blend over a Write image, or a CPU convert that would read a None
source, is refused instead of running.
| Level | CPU may | Memory selected |
|---|---|---|
None | nothing | Linux DMA-BUF: uncached CMA where available. Android: no CPU usage bits, so tile compression stays possible. |
Read | read | cached; read-direction syncs only |
Write | write whole passes | Linux DMA-BUF: uncached CMA where available, written write-combined |
ReadWrite (default) | read and write | cached |
Why uncached. A device that maps a cached buffer has to clean and
invalidate the CPU cache over all of it on every access: a compositor
blitting a client’s buffer every frame pays that for the whole buffer
each time. An uncached buffer needs no cache maintenance. CPU reads
of uncached memory are slow, which is why only declarations that
exclude CPU reads select it; with the declaration enforced, nothing
reads such a buffer on the CPU. On Linux a None or Write DMA-BUF
comes from /dev/dma_heap/linux,cma-uncached when the system has it,
and from the cached heaps otherwise. A write-only pass must write the
whole buffer (see TensorTrait::map_for_write).
On Android the ReadWrite default asks gralloc for
CPU_READ_OFTEN | CPU_WRITE_OFTEN, which may give linear, CPU-cached
memory. Pass None for a buffer that is never mapped on the CPU, so
gralloc can keep a tiled or compressed allocation.
§Examples
A CPU-drawn overlay: written whole every frame, never read back.
use edgefirst_tensor::{
CpuAccess, Error, PixelFormat, Tensor, TensorMapTrait, TensorMemory, TensorTrait,
};
let overlay = Tensor::<u8>::image(
640,
480,
PixelFormat::Rgba,
Some(TensorMemory::DmaBuf),
CpuAccess::Write,
)?;
overlay.map_for_write()?.as_mut_slice().fill(0);
assert!(matches!(overlay.map_read(), Err(Error::CpuAccessDenied { .. })));CpuAccess::code is the wire code the C header’s ef_cpu_access
enumerators are asserted against.
Variants§
None = 0
Hardware-only buffer: no CPU access. Required for vendor tile compression on platforms with compressed layouts; uncached CMA for a Linux DMA-BUF where available.
Read = 1
CPU reads only (verification, CPU consumers) — cached mapping.
Write = 2
CPU writes only, whole-buffer passes (decode targets, CPU-drawn overlays) — write-combined mapping; uncached CMA for a Linux DMA-BUF where available.
ReadWrite = 3
CPU reads and writes (the default).
Implementations§
Source§impl CpuAccess
impl CpuAccess
Sourcepub const fn code(self) -> u32
pub const fn code(self) -> u32
The shared code for this variant. Identical on every surface.
const, deliberately: a downstream binding that cannot
write Variant = OtherEnum::Variant.code() in a #[pyclass]
discriminant position (PyO3 requires a literal there) can
still pin that literal to this value with a
const _: () = assert!(...) – a build-time check instead
of a hand-synced comment. See PyTensorMemory/PyPixelFormat
in crates/python-common/src/tensor.rs for the consumer.
Sourcepub fn from_code(code: u32) -> Option<Self>
pub fn from_code(code: u32) -> Option<Self>
Reject an unknown code rather than guessing at one.
Sourcepub fn from_str_code(s: &str) -> Option<Self>
pub fn from_str_code(s: &str) -> Option<Self>
Reject an unknown string rather than guessing at one.
Source§impl CpuAccess
impl CpuAccess
Sourcepub fn covers(self, requested: CpuAccess) -> bool
pub fn covers(self, requested: CpuAccess) -> bool
Whether this declaration covers requested (every direction the
request needs is declared).
Sourcepub fn union(self, other: CpuAccess) -> CpuAccess
pub fn union(self, other: CpuAccess) -> CpuAccess
The declaration covering every direction of both self and other.
use edgefirst_tensor::CpuAccess;
assert_eq!(CpuAccess::Read.union(CpuAccess::Write), CpuAccess::ReadWrite);
assert_eq!(CpuAccess::None.union(CpuAccess::Write), CpuAccess::Write);Sourcepub fn intersection(self, other: CpuAccess) -> CpuAccess
pub fn intersection(self, other: CpuAccess) -> CpuAccess
The declaration covering only the directions both self and other
cover.
use edgefirst_tensor::CpuAccess;
assert_eq!(CpuAccess::ReadWrite.intersection(CpuAccess::Write), CpuAccess::Write);
assert_eq!(CpuAccess::Read.intersection(CpuAccess::Write), CpuAccess::None);Sourcepub fn require(self, requested: CpuAccess) -> Result<()>
pub fn require(self, requested: CpuAccess) -> Result<()>
Ok when this declaration covers requested, otherwise
Error::CpuAccessDenied naming both.
use edgefirst_tensor::{CpuAccess, Error};
assert!(CpuAccess::ReadWrite.require(CpuAccess::Write).is_ok());
assert!(matches!(
CpuAccess::Read.require(CpuAccess::Write),
Err(Error::CpuAccessDenied { .. })
));Trait Implementations§
impl Copy for CpuAccess
impl Eq for CpuAccess
impl StructuralPartialEq for CpuAccess
Auto Trait Implementations§
impl Freeze for CpuAccess
impl RefUnwindSafe for CpuAccess
impl Send for CpuAccess
impl Sync for CpuAccess
impl Unpin for CpuAccess
impl UnsafeUnpin for CpuAccess
impl UnwindSafe for CpuAccess
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