Skip to content

Prototype: generic composite-option API for multi-param XU controls (HKR Temporal Filter DPP) - #17

Open
ev-mp wants to merge 6 commits into
devfrom
proto/structured-api-temporal-filter
Open

Prototype: generic composite-option API for multi-param XU controls (HKR Temporal Filter DPP)#17
ev-mp wants to merge 6 commits into
devfrom
proto/structured-api-temporal-filter

Conversation

@ev-mp

@ev-mp ev-mp commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Summary

Prototype of a generic, additive rs2_set_composite_option/rs2_get_composite_option API (keyed by rs2_composite_option_id, raw void* + size payload) for controls that pack multiple logical parameters into a single atomic UVC XU transaction — modeled after the HKR Depth Post-Processing "Temporal Filter" control (enabled, smooth_alpha, smooth_delta, persistency_index).

This is one of two comparative prototypes explored for this feature; the other keeps the public API limited to set_option/get_option via N+1 scalar options backed by a host-side cache + explicit commit option. This PR is the "structured/composite API" side of that comparison.

  • New public API: rs2_set_composite_option/rs2_get_composite_option, generic across any future composite-option control (not just this one) via an internal (control_id -> extension_unit/ctrl_id/wire_size) registry on the sensor.
  • Typed payload struct (rs2_temporal_filter_dpp_config) — caller casts the raw buffer to/from this struct, same contract as the generic dispatch.
  • realsense-viewer panel: populate-on-open + single "Send" button, one atomic set_xu per Send.
  • Standalone fake-transport example (examples/hkr-temporal-filter-dpp-mock) proving round-trip correctness and exactly-one-set_xu/one-get_xu atomicity without requiring physical HKR hardware (none is attached to the dev machine this was built on).

Test plan

  • realsense2 builds clean (Debug, VS 18 2026 generator, BUILD_GRAPHICAL_EXAMPLES=ON)
  • realsense-viewer builds clean
  • rs-hkr-temporal-filter-dpp-mock example builds and runs clean: round-trip correctness + exactly 1 set_xu + 1 get_xu verified
  • Not yet tested against real HKR/D555 hardware (none available on this dev machine)

@ev-mp
ev-mp force-pushed the proto/structured-api-temporal-filter branch 2 times, most recently from 9ab9703 to 9a20e4b Compare August 19, 2026 13:43
@ev-mp
ev-mp changed the base branch from dev to master August 19, 2026 13:46
@ev-mp
ev-mp changed the base branch from master to dev August 19, 2026 13:46
Evgeni Raikhel and others added 6 commits August 19, 2026 16:55
Introduces a new API surface for multi-parameter XU controls that are
exchanged as one atomic struct in a single UVC transaction, distinct
from the existing single-value rs2_option mechanism:

- C API: rs2_set/get_composite_option, rs2_get_composite_option_range,
  keyed by their own rs2_composite_option_id enum (kept separate from
  rs2_option so composite controls don't collide with the scalar
  option-numbering space), plus metadata queries (description,
  read-only, supported-options enumeration).
- C++ wrapper: rs2::options gains get_composite_option_as<T>()/
  set_composite_option_from<T>()/get_composite_option_range_as<T>(),
  casting the raw payload to/from an application-defined struct that
  matches the documented wire layout - no SDK-side per-feature struct
  header, so adding a new control doesn't require an SDK release.
- composite_xu_option implements the mechanism against a real XU
  transport; options_container gets a second, separate composite-option
  registry alongside its existing scalar one.

HKR Temporal Filter DPP is the first control built on this mechanism,
registered as its own embedded filter (not directly on the sensor),
with a realsense-viewer panel and a fake-transport example proving the
round-trip is atomic. This commit represents the API's final shape;
the design went through several rounds of rework (ownership model,
identity/enum split, casting approach) before landing here.
- A full-surface walkthrough sample exercising every composite-option
  entry point (enumeration, get, read-modify-write set, get_range,
  metadata queries) against real hardware.
- rs2_minz_control: the second composite-option consumer's struct,
  byte-aligned to the real wire layout, plus typed cast helpers and
  notes on future MinZ versioning - groundwork for registering it as an
  actual device control in the next commit.
…e scalar path

Registers RS2_COMPOSITE_OPTION_HKR_MINZ_CONTROL via composite_xu_option (ds::depth_xu,
ds::DS5_HKR_MINZ_CONTROL = 0x14, sizeof(rs2_minz_control)) across every device
constructor that used to register the scalar "Improved Close Range Depth" option:
D555 (FW-gated), rs5x5_device and rs5x5_dedicated_color_device (unconditional), and
left disabled on D585 GMSL for the same pre-existing MIPI/V4L2 backend limitation.

Retires close_range_xu_option/d500_close_range_embedded_filter/close_range_filter_feature
entirely (POC/demo PR - full consolidation onto the composite-option mechanism rather
than keeping two independent accessors on one physical XU control). Known consequence:
common/embedded-filter-model.cpp's generic RS2_OPTION_EMBEDDED_FILTER_ENABLED toggle no
longer applies to this filter - not fixed, out of scope here.

Also corrects rs_hkr_minz_control.h's ctl_id (0x0004 -> 0x0008) and flags (-> 0x01),
sourced from the former close_range_xu_option implementation and a real-hardware FW
validation tool rather than the Confluence page's stale wire-layout table.

Adds examples/composite-option-walkthrough/rs-minz-control-walkthrough.cpp - enumerate/
get_range/get/set/get one at a time against a real connected device.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- realsense-viewer panel for RS2_COMPOSITE_OPTION_HKR_MINZ_CONTROL,
  fixing an embedded-filter-model crash and quieting preset-glob noise
  surfaced along the way.
- composite_control_editor<T>: a reusable debounced-auto-commit editor
  extracted so any multi-param composite option can get the same
  touch -> fade in -> reset-on-retouch -> hard-commit-on-lapse behavior
  by holding one, instead of re-implementing the mechanism per control.
  Includes a fix for the fade animation freezing partway through, and a
  focus-loss shortcut that finishes the countdown early once focus
  genuinely leaves the group instead of making the user wait it out.
- Wires the control's `enable` field to the row header's existing
  toggle (composite-only embedded filters have no scalar
  RS2_OPTION_EMBEDDED_FILTER_ENABLED to hook into), and forces
  enable=1 on auto-commit - editing any field in the box implies the
  control is meant to be active.
- Visual polish: tint the row toggle to match the editor's own pending-
  commit fade, log every real FW GET at DEBUG verbosity, and dim the
  box while the control is disabled.
…ytes

ReadFromBuffer() capped every min/max/step/def copy at
min(sizeof(uint32_t), length) - correct for classic scalar PU/CT controls
(a value is genuinely at most a 4-byte int there), but silently truncated
composite XU controls whose real wire size exceeds 4 bytes: the
destination vector was correctly sized to the full option_range_size, yet
only its first 4 bytes were ever populated from the device's real
response, leaving every field past that offset at std::vector's zero-init
default regardless of what the device actually reported.

Confirmed against a real D555 running RS2_COMPOSITE_OPTION_HKR_MINZ_CONTROL
(38-byte rs2_minz_control): get_composite_option_range_as() previously
returned all-zero bounds for every field past ctl_id; after this fix it
returns real, sane values matching the documented ranges in
rs_hkr_minz_control.h (e.g. disparity_shift max=512, threshold max=65535,
step=1 across the board). Verified scalar option ranges (Exposure, Gain,
Laser Power, etc.) are unaffected, since length was already <=4 there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Editor UI:
- Make the disabled-state dim more pronounced.
- Disparity Shift/Threshold sliders gain a pencil-icon toggle between
  the slider and a centered, color-matched manual-entry text box
  (ImGui's native Ctrl+Click/double-click text-input proved unreliable
  here), plus Left/Right arrow-key nudging once the slider has focus.
  Both modes call touch() while active so the debounce timer freezes
  during manual edits instead of expiring mid-entry.
- Add a "Reset to Default" button reusing the same debounced-commit
  pipeline as every other field edit, later hidden behind a small "..."
  marker in the box's bottom-right corner - revealed only on hover
  nearby, and drawn on the same line as the last field rather than
  reserving a row of its own, so it may partially overlap that field
  when revealed.
- Fix: changing the Downscale Ratio radio buttons via arrow-key
  navigation didn't start the auto-commit debounce timer the way a
  mouse click did - a discrete edit's touch()+finalize() land in the
  same frame as the deadline-collapsing focus-loss shortcut, which
  couldn't yet tell a fresh discrete edit apart from focus genuinely
  leaving the group; suppressed for the one frame finalize() just ran
  on.
- Keyboard-driven edits (arrow-key slider nudges, and radio-button
  changes via keyboard/gamepad nav) now schedule their auto-commit
  0.1s out instead of the usual 1.7s, since they already land on a
  known, deliberate value one step at a time and don't need the same
  give-me-a-moment-to-change-my-mind pause a mouse edit gets. Mouse
  clicks/drags on the same controls are unaffected.

Examples:
- Generalize the composite-option walkthrough to sweep every embedded
  filter/id on the device rather than just Temporal Filter DPP, with
  dual raw-bytes + typed views and rectangular hex-grid wrapping for
  long buffers.
- Add a pure-C99 demo of the same MinZ get/set walkthrough through the
  raw C API (no exceptions, templates, or RAII), verified end-to-end on
  both Windows and Linux.
@ev-mp
ev-mp force-pushed the proto/structured-api-temporal-filter branch from 9a20e4b to 2c693fe Compare August 19, 2026 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant