Skip to content

Commit d4a1df7

Browse files
committed
imgproc: AVX2 paths for the chamfer L2 distance transform
8-wide row kernels for the vertical/diagonal/knight propagation steps, dispatched before the SSE fallback; the bit-for-bit reference test covers them on any AVX2 host (CI runners included).
1 parent 3bc7bac commit d4a1df7

1 file changed

Lines changed: 120 additions & 9 deletions

File tree

crates/yscv-imgproc/src/ops/features.rs

Lines changed: 120 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,9 +1068,15 @@ fn dt_l2_vertical3(dist: &mut [f32], src: usize, cur: usize, w: usize, a: f32, b
10681068
x = unsafe { dt_l2_vertical3_neon(dist, src, cur, w, a, b) };
10691069
}
10701070
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1071-
if yscv_cpu::host_cpu().features.sse {
1072-
// SAFETY: ISA guard (feature detection) above.
1073-
x = unsafe { dt_l2_vertical3_sse(dist, src, cur, w, a, b) };
1071+
{
1072+
let features = yscv_cpu::host_cpu().features;
1073+
if features.avx2 {
1074+
// SAFETY: ISA guard (feature detection) above.
1075+
x = unsafe { dt_l2_vertical3_avx2(dist, src, cur, w, a, b) };
1076+
} else if features.sse {
1077+
// SAFETY: ISA guard (feature detection) above.
1078+
x = unsafe { dt_l2_vertical3_sse(dist, src, cur, w, a, b) };
1079+
}
10741080
}
10751081

10761082
// Scalar interior tail.
@@ -1213,9 +1219,15 @@ fn dt_l2_vertical5(dist: &mut [f32], src: usize, cur: usize, w: usize, a: f32, b
12131219
x = unsafe { dt_l2_vertical5_neon(dist, src, cur, w, a, b, c) };
12141220
}
12151221
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1216-
if yscv_cpu::host_cpu().features.sse {
1217-
// SAFETY: ISA guard (feature detection) above.
1218-
x = unsafe { dt_l2_vertical5_sse(dist, src, cur, w, a, b, c) };
1222+
{
1223+
let features = yscv_cpu::host_cpu().features;
1224+
if features.avx2 {
1225+
// SAFETY: ISA guard (feature detection) above.
1226+
x = unsafe { dt_l2_vertical5_avx2(dist, src, cur, w, a, b, c) };
1227+
} else if features.sse {
1228+
// SAFETY: ISA guard (feature detection) above.
1229+
x = unsafe { dt_l2_vertical5_sse(dist, src, cur, w, a, b, c) };
1230+
}
12191231
}
12201232

12211233
while x < w - 2 {
@@ -1320,9 +1332,15 @@ fn dt_l2_knight(dist: &mut [f32], src2: usize, cur: usize, w: usize, c: f32) {
13201332
x = unsafe { dt_l2_knight_neon(dist, src2, cur, w, c) };
13211333
}
13221334
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1323-
if yscv_cpu::host_cpu().features.sse {
1324-
// SAFETY: ISA guard (feature detection) above.
1325-
x = unsafe { dt_l2_knight_sse(dist, src2, cur, w, c) };
1335+
{
1336+
let features = yscv_cpu::host_cpu().features;
1337+
if features.avx2 {
1338+
// SAFETY: ISA guard (feature detection) above.
1339+
x = unsafe { dt_l2_knight_avx2(dist, src2, cur, w, c) };
1340+
} else if features.sse {
1341+
// SAFETY: ISA guard (feature detection) above.
1342+
x = unsafe { dt_l2_knight_sse(dist, src2, cur, w, c) };
1343+
}
13261344
}
13271345

13281346
while x < w - 1 {
@@ -1376,6 +1394,99 @@ unsafe fn dt_l2_knight_sse(dist: &mut [f32], src2: usize, cur: usize, w: usize,
13761394
x
13771395
}
13781396

1397+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1398+
#[allow(unsafe_code, unsafe_op_in_unsafe_fn)]
1399+
#[target_feature(enable = "avx2")]
1400+
unsafe fn dt_l2_vertical3_avx2(
1401+
dist: &mut [f32],
1402+
src: usize,
1403+
cur: usize,
1404+
w: usize,
1405+
a: f32,
1406+
b: f32,
1407+
) -> usize {
1408+
#[cfg(target_arch = "x86")]
1409+
use std::arch::x86::*;
1410+
#[cfg(target_arch = "x86_64")]
1411+
use std::arch::x86_64::*;
1412+
1413+
let av = _mm256_set1_ps(a);
1414+
let bv = _mm256_set1_ps(b);
1415+
let ptr = dist.as_mut_ptr();
1416+
let mut x = 1usize;
1417+
while x + 8 < w {
1418+
let center = _mm256_add_ps(_mm256_loadu_ps(ptr.add(src + x)), av);
1419+
let left = _mm256_add_ps(_mm256_loadu_ps(ptr.add(src + x - 1)), bv);
1420+
let right = _mm256_add_ps(_mm256_loadu_ps(ptr.add(src + x + 1)), bv);
1421+
let cur_v = _mm256_loadu_ps(ptr.add(cur + x));
1422+
let m = _mm256_min_ps(_mm256_min_ps(cur_v, center), _mm256_min_ps(left, right));
1423+
_mm256_storeu_ps(ptr.add(cur + x), m);
1424+
x += 8;
1425+
}
1426+
x
1427+
}
1428+
1429+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1430+
#[allow(unsafe_code, unsafe_op_in_unsafe_fn)]
1431+
#[target_feature(enable = "avx2")]
1432+
unsafe fn dt_l2_vertical5_avx2(
1433+
dist: &mut [f32],
1434+
src: usize,
1435+
cur: usize,
1436+
w: usize,
1437+
a: f32,
1438+
b: f32,
1439+
c: f32,
1440+
) -> usize {
1441+
#[cfg(target_arch = "x86")]
1442+
use std::arch::x86::*;
1443+
#[cfg(target_arch = "x86_64")]
1444+
use std::arch::x86_64::*;
1445+
1446+
let av = _mm256_set1_ps(a);
1447+
let bv = _mm256_set1_ps(b);
1448+
let cv = _mm256_set1_ps(c);
1449+
let ptr = dist.as_mut_ptr();
1450+
let mut x = 2usize;
1451+
while x + 10 <= w {
1452+
let center = _mm256_add_ps(_mm256_loadu_ps(ptr.add(src + x)), av);
1453+
let b_lo = _mm256_add_ps(_mm256_loadu_ps(ptr.add(src + x - 1)), bv);
1454+
let b_hi = _mm256_add_ps(_mm256_loadu_ps(ptr.add(src + x + 1)), bv);
1455+
let c_lo = _mm256_add_ps(_mm256_loadu_ps(ptr.add(src + x - 2)), cv);
1456+
let c_hi = _mm256_add_ps(_mm256_loadu_ps(ptr.add(src + x + 2)), cv);
1457+
let cur_v = _mm256_loadu_ps(ptr.add(cur + x));
1458+
let m = _mm256_min_ps(
1459+
_mm256_min_ps(cur_v, center),
1460+
_mm256_min_ps(_mm256_min_ps(b_lo, b_hi), _mm256_min_ps(c_lo, c_hi)),
1461+
);
1462+
_mm256_storeu_ps(ptr.add(cur + x), m);
1463+
x += 8;
1464+
}
1465+
x
1466+
}
1467+
1468+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1469+
#[allow(unsafe_code, unsafe_op_in_unsafe_fn)]
1470+
#[target_feature(enable = "avx2")]
1471+
unsafe fn dt_l2_knight_avx2(dist: &mut [f32], src2: usize, cur: usize, w: usize, c: f32) -> usize {
1472+
#[cfg(target_arch = "x86")]
1473+
use std::arch::x86::*;
1474+
#[cfg(target_arch = "x86_64")]
1475+
use std::arch::x86_64::*;
1476+
1477+
let cv = _mm256_set1_ps(c);
1478+
let ptr = dist.as_mut_ptr();
1479+
let mut x = 1usize;
1480+
while x + 8 < w {
1481+
let lo = _mm256_add_ps(_mm256_loadu_ps(ptr.add(src2 + x - 1)), cv);
1482+
let hi = _mm256_add_ps(_mm256_loadu_ps(ptr.add(src2 + x + 1)), cv);
1483+
let m = _mm256_min_ps(_mm256_loadu_ps(ptr.add(cur + x)), _mm256_min_ps(lo, hi));
1484+
_mm256_storeu_ps(ptr.add(cur + x), m);
1485+
x += 8;
1486+
}
1487+
x
1488+
}
1489+
13791490
// ── ORB feature descriptors ────────────────────────────────────────
13801491

13811492
/// ORB descriptor: 256-bit binary descriptor stored as 32 bytes.

0 commit comments

Comments
 (0)