#[path = "../../tensor/tests/support/outcome.rs"]
#[allow(dead_code)]
mod outcome;
#[allow(unused_imports)]
pub(crate) use outcome::{allocated, current_test, report_skip, Expect};
#[path = "../../tensor/tests/support/dma_require.rs"]
#[allow(dead_code)]
mod dma_require;
pub(crate) fn is_dma_available() -> bool {
dma_require::decide(
edgefirst_tensor::is_dma_available(),
dma_require::required(),
¤t_test(),
"no usable DMA heap (no /dev/dma_heap node, or it is not openable by this user)",
)
}
#[cfg_attr(not(feature = "opengl"), allow(dead_code))]
pub(crate) fn is_gpu_buffer_available() -> bool {
#[cfg(target_os = "linux")]
return is_dma_available();
#[cfg(not(target_os = "linux"))]
edgefirst_tensor::is_gpu_buffer_available()
}
pub(crate) fn dma_allocated<T, E: std::fmt::Debug>(result: Result<T, E>, what: &str) -> Option<T> {
match result {
Ok(value) => Some(value),
Err(e) => allocated(Err(e), what, outcome::expect_dma(is_dma_available())),
}
}
#[cfg_attr(not(feature = "opengl"), allow(dead_code))]
pub(crate) fn gpu_buffer_allocated<T, E: std::fmt::Debug>(
result: Result<T, E>,
what: &str,
) -> Option<T> {
match result {
Ok(value) => Some(value),
Err(e) => {
let expect = if is_gpu_buffer_available() {
Expect::Succeeds
} else {
Expect::MayFail("no zero-copy GPU buffer backing on this host")
};
allocated(Err(e), what, expect)
}
}
}
#[cfg_attr(not(target_os = "linux"), allow(dead_code))]
pub(crate) fn g2d_required_or(available: bool) -> bool {
let required = std::env::var("HAL_TEST_REQUIRE_G2D").as_deref() == Ok("1");
g2d_decide(available, required, ¤t_test())
}
fn g2d_decide(available: bool, required: bool, what: &str) -> bool {
assert!(
available || !required,
"HAL_TEST_REQUIRE_G2D=1 but {what} would have skipped while reporting success: \
libg2d.so.2 did not load or G2D failed to initialize"
);
available
}
#[test]
fn g2d_policy_skips_unless_required() {
assert!(g2d_decide(true, true, "t"));
assert!(g2d_decide(true, false, "t"));
assert!(!g2d_decide(false, false, "t"));
let required_but_missing = std::panic::catch_unwind(|| g2d_decide(false, true, "t"));
assert!(required_but_missing.is_err());
}
pub(crate) const BOX_BG: [u8; 4] = [10, 20, 30, 200];
pub(crate) const BOX_DIM: usize = 32;
pub(crate) fn draw_box_fixture(
processor: &mut dyn crate::ImageProcessorTrait,
color: [u8; 4],
width: Option<u32>,
opacity: f32,
) -> Vec<u8> {
use edgefirst_tensor::{CpuAccess, DType, PixelFormat, TensorDyn, TensorMapTrait, TensorTrait};
let image = || {
TensorDyn::image(
BOX_DIM,
BOX_DIM,
PixelFormat::Rgba,
DType::U8,
None,
CpuAccess::ReadWrite,
)
.unwrap()
};
let bg = image();
{
let bg_u8 = bg.as_typed::<u8>().unwrap();
let mut map = bg_u8.map_mut().unwrap();
for px in map.as_mut_slice().chunks_exact_mut(4) {
px.copy_from_slice(&BOX_BG);
}
}
let mut dst = image();
processor.set_class_colors(&[color]).unwrap();
if let Some(width) = width {
processor.set_box_line_width(width).unwrap();
}
let detect = edgefirst_tensor::DetectBox {
bbox: [0.25, 0.25, 0.75, 0.75].into(),
score: 0.9,
label: 0,
};
processor
.draw_decoded_masks(
&mut dst,
&[detect],
&[],
crate::MaskOverlay::new()
.with_background(&bg)
.with_opacity(opacity),
)
.unwrap();
let dst_u8 = dst.as_typed::<u8>().unwrap();
let mut flat = vec![0u8; BOX_DIM * BOX_DIM * 4];
dst_u8.copy_to_flat(&mut flat).unwrap();
flat
}
pub(crate) fn box_px(flat: &[u8], x: usize, y: usize) -> [u8; 4] {
let o = (y * BOX_DIM + x) * 4;
flat[o..o + 4].try_into().unwrap()
}
pub(crate) fn box_drawn_columns(flat: &[u8], y: usize) -> Vec<usize> {
(0..BOX_DIM)
.filter(|&x| box_px(flat, x, y) != BOX_BG)
.collect()
}
pub(crate) fn box_drawn_rows(flat: &[u8], x: usize) -> Vec<usize> {
(0..BOX_DIM)
.filter(|&y| box_px(flat, x, y) != BOX_BG)
.collect()
}
pub(crate) fn box_blend(color: [u8; 4], alpha: u16) -> [u8; 4] {
let mix = |c: u8, d: u8| ((c as u16 * alpha + d as u16 * (255 - alpha)) / 255) as u8;
[
mix(color[0], BOX_BG[0]),
mix(color[1], BOX_BG[1]),
mix(color[2], BOX_BG[2]),
BOX_BG[3],
]
}
pub(crate) fn box_expected_span(width: usize) -> Vec<usize> {
let (lo, hi) = (BOX_DIM / 4, BOX_DIM * 3 / 4);
(lo.saturating_sub(width)..lo)
.chain(hi..(hi + width).min(BOX_DIM))
.collect()
}