Native fused FAST and BRIEF
Contract
ops::fast_brief::check_inference() admits packed, contiguous UInt8 images of
rank 3–6 with trailing H,W,1. With the default OutputEncoding::Separate,
output roles are described below. Height is 31–4096; width is 31–2048. The first
three outputs are the native FAST points, scores and count,
with the same preserved outer axes and capacity K in 1–65536. A fourth output
is required: contiguous UInt8 descriptors shaped [outer...,K,32].
Descriptor i belongs to point and score i in the same image.
OutputEncoding::Packed requires two contiguous INT32 outputs:
[outer...,1+3*K] count-prefixed (x,y,score) records and [outer...,K,8]
descriptor words. Word w contains comparisons 32*w through 32*w+31, least
significant bit first. Words are stored little-endian: these are the same 32
bytes per feature as the separate UInt8 output, not a numerical cast. Consumers
on a different-endian host must decode the words explicitly. The EV compact
stage writes both representations directly; no CPU packing is required.
Only count and valid records/descriptors are written; unused capacity is preserved.
Parameters
Params::output_encoding defaults to OutputEncoding::Separate. The cold named
request accepts output_encoding = "separate" or "packed".
Params::threshold is an integer in [0,255], default 30. Params::grid accepts
the shared optional GridSelection{columns, rows, minimum_distance} contract
described in FAST grid selection.
Columns are in 1..W, rows in 1..H, and minimum distance in 0..65535 pixels.
The grid covers the full image, not only the descriptor-valid rectangle.
The cold named fields are grid_columns, grid_rows, minimum_distance;
supplying any enables the grid, with unspecified fields defaulting to 1, 1, 0.
Absent grid configuration preserves the existing raster-first mode.
There are no configurable pattern, orientation or smoothing parameters.
Numerical behavior
Detection, contrast scores and equal-score NMS follow native FAST. Feature
centers require a complete 31×31 descriptor patch: 15 <= x < W-15 and
15 <= y < H-15. NMS still compares the surrounding FAST scores, including
neighbors outside that center rectangle. Filtering an already capacity-limited
plain FAST list is therefore not an equivalent implementation.
The fixed descriptor pattern starts from unsigned 32-bit state 0x9E3779B9.
For each of 1024 coordinates, update in order:
state ^= state << 13, state ^= state >> 17, state ^= state << 5, with
32-bit wraparound. Convert the remainder to a signed integer before subtracting:
int32_t(state % 31u) - 15. Each consecutive four coordinates gives
(xa,ya,xb,yb) relative to the feature center. The first comparison uses
(-1,1) and (-9,-10); these offsets are a quick pattern-generation check.
For comparison k in 0–255, set bit k % 8 in byte k / 8 exactly when
image[y+ya,x+xa] < image[y+yb,x+xb]. Equality gives zero. This byte order is
explicit and does not depend on host INT32 serialization. There is no patch
smoothing or orientation rotation; do not assume arbitrary OpenCV BRIEF or ORB
compatibility. Default selection is raster-first K, not score-ranked. Optional
grid selection retains each cell's strongest quota, globally orders winners by
descending score and raster ties, and applies greedy cross-cell minimum spacing
without borrowing or refill. These steps happen before descriptor publication;
descriptor i always follows selected point i. Unused points,
scores and descriptor bytes remain untouched; consume only the published count.
Ring and patch geometry
Ring indices run clockwise from (0,-3); X increases rightward and Y downward.
The descriptor panel shows eligible centers, not padded pixels. Require the full
31×31 patch and apply NMS before the configured feature selection. The panel
is schematic, not to scale.
C++ call
The call below constructs all four output specs using installed public headers.
Place the includes and namespace aliases at file scope; the remaining statements
belong in a simaai::kernels::Status-returning caller function. It checks metadata and
encodes a relocatable descriptor, not EV74 computation. Runtime must map actual
buffers, bind addresses and retain inputs, outputs and any workspace until
confirmed device completion.
#include <array>
#include <simaai/kernels/ev74/fast_brief.h>
namespace k = simaai::kernels;
namespace op = k::ops::fast_brief;
namespace ev = k::ev74::fast_brief;
const std::array inputs{k::TensorSpec{{2, 480, 640, 1}, k::DType::UInt8}};
const std::array outputs{k::TensorSpec{{2, 1024, 2}, k::DType::Int32},
k::TensorSpec{{2, 1024}, k::DType::Int32},
k::TensorSpec{{2, 1}, k::DType::Int32},
k::TensorSpec{{2, 1024, 32}, k::DType::UInt8}};
op::Params params{};
params.threshold = 30;
params.grid = k::GridSelection{8, 6, 16}; // Omit for default raster-first selection.
auto admitted = op::check_inference({inputs, outputs, params});
if (auto *error = std::get_if<k::Error>(&admitted)) return *error;
const auto &plan = std::get<op::Plan>(admitted);
auto encoded = ev::encode_relocatable(plan);
if (auto *error = std::get_if<k::Error>(&encoded)) return *error;
// Encoding leaves device addresses unbound; no device work has run.
return {};
See the host contract tests (EV74/fast_brief/tests/correctness.cpp) and
device fixture (EV74/fast_brief/tests/runtime_e2e.cpp) for binding and execution coverage.
Memory and lifecycle
Default workspace is batch * 4 * (1 + 11*K) * sizeof(INT32) bytes. Four-byte-aligned
partial records contain count, coordinates, score and eight descriptor words;
these are private workspace, not the public output format. Input and descriptor
bytes need alignment one; the INT32 outputs and workspace need alignment four.
Admission rejects overflowing storage; binding rejects undersized, overlapping,
misaligned or unrepresentable address spans. Concurrent in-flight operations
need distinct writable outputs and workspace.
Grid selection uses the same score-map/frontier/spacing workspace formula as FAST, not descriptor-sized worker records. Descriptors are generated only after final selection. The plan reports the exact mode-dependent size; do not allocate using the default formula when a grid is present.
Native entry simaai_kernels_ev74_fast_brief_v3 consumes a 256-byte version-three
wire packet, not a C++ object. Relocation slots are input 16,
outputs 24/32/40/48, workspace 56. Entry validation precedes dispatch. Firmware
registration and capability verification are explicit platform responsibilities.
Implementation notes
In the default mode, FAST and BRIEF share a 31-row VCCM image ring, avoiding a second patch fetch per feature. Row DMA overlaps score computation after preload. Vector detection and NMS reject empty blocks; retained features receive descriptors before band-ordered compaction. Workers partition the flattened batch of legal center rows, retaining frame-local patch and NMS halos. Positive-row flags skip empty NMS scans; a full retained prefix stops further descriptor work in that band. The active count is chosen once from useful center rows and available workers, limited to four; raster truncation does not depend on this count. Each worker buffers 32 complete records locally before DMA to its band workspace. Compaction reads bounded record blocks and deinterleaves coordinates, scores and 32 descriptor bytes locally before bulk writes. Partial blocks retain exact lengths; output capacity suffixes remain untouched. Preload uses bounded batches of eight row events, and native calls reuse the two dispatcher handles under the serialized firmware-entry lifecycle. The canonical BRIEF pair sequence is stored as a read-only signed-byte table and copied once into each worker's local storage per invocation. This removes pattern generation from the hot call without changing any coordinate or descriptor bit. The score primitive is shared privately with FAST, but their DMA schedules and public operations stay distinct. This structure is not a measured speed claim.
Workspace bands and output prefixes can end inside a 16-byte DMA granule. Transfers therefore use only aligned complete granules; exact volatile byte stores handle each head and tail. Pending record writes retire before count publication, and no DMA touches another band's count or an output suffix.
The grid route has three EV dispatches: complete detection/NMS into a byte score map, shared grid selection/spacing and point publication, then description of the final retained points. It uses FAST+BRIEF's legal center/halo rules throughout, so it is not filtering a truncated plain FAST output. Selection uses the same bounded DMA/VCCM score-row processing as FAST, with exact scalar edge accesses for narrow or unaligned spans. The descriptor stage reuses a bounded row ring for selected points, writes descriptors in their public point order, and does not describe discarded candidates. This trades additional selected-patch reads for avoiding work on rejected descriptors; it does not imply a measured win over the default fused path. All sorting and spacing remain on EV; Runtime sees one ordinary operation submission and no CPU readback.
Tests and qualification
EV74/fast_brief/tests/correctness.cpp uses the shared independent scalar oracle
and, when Clang is available, the actual OpenCL source host model. Tests compare
all descriptor bytes, counts, coordinates, scores and preserved tails across
1–4 workers and both immediate/deferred DMA. Admission and malformed-wire cases
are separate from numerical evidence.
Grid tests additionally check strong-score quotas, deterministic ties, uneven
boundaries, cross-cell spacing, exact-distance equality, no quota refill,
maximum distance, and packed/separate point-to-descriptor correspondence.
EV74/fast_brief/tests/e2e/ is the standalone public Runtime/device fixture.
Default execution includes correctness and latency; --list-cases reports
stable case IDs. The fixture verifies dirty reuse and changed counts before
measuring reused-buffer completion latency. Host-model checks and private
MetaWare compilation do not establish device correctness. No baseline-qualified
performance is claimed without a fresh, matched device run.
Grid VGA/HD cases provide completion-latency measurements, not gains against
older firmware that cannot execute these semantics.
Wire compatibility
This operation uses descriptor ABI 3. The packet remains 256 bytes: output count is at byte 12; grid columns/rows/minimum distance occupy bytes 136/140/144; the 27 reserved words from byte 148 must be zero. Zero grid fields mean default selection. Both output modes require matching host codecs and firmware. The versioned capability probe rejects older firmware before dispatch; rebuild the composed firmware and consuming packages together. Output encoding does not change detection, selection, scores or descriptor mathematics.