#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub(super) enum FloatRenderPath {
None,
PboF16Nchw,
PboF32Nhwc,
PboF32Nchw,
PboF16Nhwc,
ZeroCopyF16Nchw,
ZeroCopyF32Nchw,
ZeroCopyFloatNhwc,
ZeroCopyFloatRgba,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub(super) enum ZeroCopyFloatSet {
PlanarF16,
All,
}
pub(super) fn classify_float_render(
src: edgefirst_tensor::PixelFormat,
dst: edgefirst_tensor::PixelFormat,
dtype: edgefirst_tensor::DType,
dst_mem: edgefirst_tensor::TensorMemory,
support: crate::RenderDtypeSupport,
zero_copy: ZeroCopyFloatSet,
) -> FloatRenderPath {
use edgefirst_tensor::{DType, PixelFormat::*, TensorMemory};
let all = zero_copy == ZeroCopyFloatSet::All;
match (src, dst, dtype, dst_mem) {
(Rgba, PlanarRgb, DType::F16, TensorMemory::Pbo) if support.f16 => {
FloatRenderPath::PboF16Nchw
}
(Rgba, PlanarRgb, DType::F16, TensorMemory::DmaBuf) if support.f16 => {
FloatRenderPath::ZeroCopyF16Nchw
}
(Rgba, PlanarRgba, DType::F16, TensorMemory::DmaBuf) if all && support.f16 => {
FloatRenderPath::ZeroCopyF16Nchw
}
(Rgba, PlanarRgb | PlanarRgba, DType::F32, TensorMemory::DmaBuf) if all && support.f32 => {
FloatRenderPath::ZeroCopyF32Nchw
}
(Rgba, Rgb, DType::F16, TensorMemory::DmaBuf) if all && support.f16 => {
FloatRenderPath::ZeroCopyFloatNhwc
}
(Rgba, Rgb, DType::F32, TensorMemory::DmaBuf) if all && support.f32 => {
FloatRenderPath::ZeroCopyFloatNhwc
}
(Rgba, Rgba, DType::F16, TensorMemory::DmaBuf) if all && support.f16 => {
FloatRenderPath::ZeroCopyFloatRgba
}
(Rgba, Rgba, DType::F32, TensorMemory::DmaBuf) if all && support.f32 => {
FloatRenderPath::ZeroCopyFloatRgba
}
(Rgba, Rgb, DType::F32, TensorMemory::Pbo) if support.f32 => FloatRenderPath::PboF32Nhwc,
(Rgba, PlanarRgb, DType::F32, TensorMemory::Pbo) if support.f32 => {
FloatRenderPath::PboF32Nchw
}
(Rgba, Rgb, DType::F16, TensorMemory::Pbo) if support.f16 => FloatRenderPath::PboF16Nhwc,
_ => FloatRenderPath::None,
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::{classify_float_render, FloatRenderPath, ZeroCopyFloatSet};
use crate::RenderDtypeSupport;
use edgefirst_tensor::{DType, PixelFormat, TensorMemory};
const YES: RenderDtypeSupport = RenderDtypeSupport {
f32: true,
f16: true,
};
const NO: RenderDtypeSupport = RenderDtypeSupport {
f32: false,
f16: false,
};
const PLANAR: ZeroCopyFloatSet = ZeroCopyFloatSet::PlanarF16;
const ALL: ZeroCopyFloatSet = ZeroCopyFloatSet::All;
#[test]
fn pbo_paths_do_not_depend_on_the_zero_copy_set() {
for set in [PLANAR, ALL] {
assert_eq!(
classify_float_render(
PixelFormat::Rgba,
PixelFormat::PlanarRgb,
DType::F16,
TensorMemory::Pbo,
YES,
set,
),
FloatRenderPath::PboF16Nchw
);
assert_eq!(
classify_float_render(
PixelFormat::Rgba,
PixelFormat::Rgb,
DType::F32,
TensorMemory::Pbo,
YES,
set,
),
FloatRenderPath::PboF32Nhwc
);
}
}
#[test]
fn the_planar_f16_render_is_live_in_both_capability_sets() {
for set in [PLANAR, ALL] {
assert_eq!(
classify_float_render(
PixelFormat::Rgba,
PixelFormat::PlanarRgb,
DType::F16,
TensorMemory::DmaBuf,
YES,
set,
),
FloatRenderPath::ZeroCopyF16Nchw
);
}
}
#[test]
fn no_path_when_capability_absent() {
assert_eq!(
classify_float_render(
PixelFormat::Rgba,
PixelFormat::PlanarRgb,
DType::F16,
TensorMemory::Pbo,
NO,
ALL,
),
FloatRenderPath::None
);
assert_eq!(
classify_float_render(
PixelFormat::Rgba,
PixelFormat::Rgb,
DType::F32,
TensorMemory::Pbo,
NO,
ALL,
),
FloatRenderPath::None
);
}
#[test]
fn no_path_for_unhandled_tuples() {
let c = |src, dst, dt, mem| classify_float_render(src, dst, dt, mem, YES, ALL);
assert_eq!(
c(
PixelFormat::Bgra,
PixelFormat::PlanarRgb,
DType::F16,
TensorMemory::Pbo
),
FloatRenderPath::None
);
assert_eq!(
c(
PixelFormat::Rgba,
PixelFormat::PlanarRgb,
DType::U8,
TensorMemory::Pbo
),
FloatRenderPath::None
);
assert_eq!(
c(
PixelFormat::Rgba,
PixelFormat::PlanarRgb,
DType::F16,
TensorMemory::Mem
),
FloatRenderPath::None
);
}
#[test]
fn the_full_set_covers_every_float_layout() {
use FloatRenderPath::*;
let c = |dst, dt| {
classify_float_render(PixelFormat::Rgba, dst, dt, TensorMemory::DmaBuf, YES, ALL)
};
assert_eq!(c(PixelFormat::PlanarRgb, DType::F16), ZeroCopyF16Nchw);
assert_eq!(c(PixelFormat::PlanarRgba, DType::F16), ZeroCopyF16Nchw);
assert_eq!(c(PixelFormat::PlanarRgb, DType::F32), ZeroCopyF32Nchw);
assert_eq!(c(PixelFormat::PlanarRgba, DType::F32), ZeroCopyF32Nchw);
assert_eq!(c(PixelFormat::Rgb, DType::F16), ZeroCopyFloatNhwc);
assert_eq!(c(PixelFormat::Rgb, DType::F32), ZeroCopyFloatNhwc);
assert_eq!(c(PixelFormat::Rgba, DType::F16), ZeroCopyFloatRgba);
assert_eq!(c(PixelFormat::Rgba, DType::F32), ZeroCopyFloatRgba);
assert_eq!(
classify_float_render(
PixelFormat::Rgba,
PixelFormat::Rgb,
DType::F32,
TensorMemory::DmaBuf,
NO,
ALL,
),
None
);
assert_eq!(
classify_float_render(
PixelFormat::Rgba,
PixelFormat::Rgb,
DType::F32,
TensorMemory::Mem,
YES,
ALL,
),
None
);
}
#[test]
fn the_planar_set_leaves_the_windows_only_shaders_unreachable() {
let c = |dst, dt| {
classify_float_render(
PixelFormat::Rgba,
dst,
dt,
TensorMemory::DmaBuf,
YES,
PLANAR,
)
};
for (dst, dt) in [
(PixelFormat::PlanarRgba, DType::F16),
(PixelFormat::PlanarRgb, DType::F32),
(PixelFormat::PlanarRgba, DType::F32),
(PixelFormat::Rgb, DType::F16),
(PixelFormat::Rgb, DType::F32),
(PixelFormat::Rgba, DType::F16),
(PixelFormat::Rgba, DType::F32),
] {
assert_eq!(
c(dst, dt),
FloatRenderPath::None,
"{dst:?}/{dt:?} must stay on the CPU converter here"
);
}
}
}