diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..6ef3714df --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,92 @@ + + + + +# IsaacTeleop — agent notes + +## CRITICAL — mandatory preflight (do not skip) + +**Hard requirement:** Do **not** edit or add code under `IsaacTeleop/` until you have **read** (e.g. with the Read tool) **every** relevant `AGENTS.md` file as defined below. This is **not** optional, **not** "only for large tasks," and **not** satisfiable by inferring from prior conversation. If you have not read those files in **this** session for **this** task, stop and read them first. + +**You must:** + +1. List the **directories** you expect to edit or create files under (e.g. `src/core/live_trackers/cpp/`, `src/core/deviceio_base/cpp/inc/…`). +2. For **each** such directory, **read** **`AGENTS.md` in that directory** if it exists. +3. Walk **up** toward the **IsaacTeleop repo root** and **read** **`AGENTS.md` in every ancestor directory** that has one (e.g. `live_trackers/` → `src/core/` → **`IsaacTeleop/AGENTS.md` (this file)**). + +**You must not** assume that reading the single "closest" `AGENTS.md` is enough. **Multiple** `AGENTS.md` files can apply to one change (e.g. both `live_trackers` and `deviceio_base`). + +**Listing every `AGENTS.md` in this repo** (no curated table here—add new files under the tree without editing this document): + +```bash +# Run from the IsaacTeleop repository root (the directory that contains this file): +find . -name AGENTS.md ! -path '*/.git/*' | sort +``` + +If you cannot run a shell, use your search/glob tools on the pattern `**/AGENTS.md` from the same root. That inventory is for orientation; you must still **read** every file that applies to the directories you will touch (steps 1–3 above). + +Optional context index: [`src/core/AGENTS.md`](src/core/AGENTS.md) (also on the ancestor walk—read it when working under `src/core/`). + +## Pre-commit — match CI before you stop + +- From the **IsaacTeleop repo root** (this directory), run pre-commit and **fix all failures** before you treat a change as finished (do not only rely on “should pass” reasoning). +- **Use the same hook set as GitHub Actions:** `.github/workflows/pre-commit.yaml` runs pre-commit with **`SKIP=check-copyright-year`**. Mirror that locally: + + ```bash + SKIP=check-copyright-year pre-commit run --all-files + ``` + +- **REUSE:** files covered by the REUSE hook need **`SPDX-FileCopyrightText`** and **`SPDX-License-Identifier`** in the form the repo already uses (for example the HTML comment block at the top of `README.md` also applies to **`AGENTS.md`** and similar docs). +- If a hook failure shows **missing or non-obvious repo policy** (not a one-off typo), you **must** add a **short** reminder under **Mandatory learning loop** rules to the right `AGENTS.md` or adjacent **`//` comments** so the next run does not repeat it—unless it is already documented. + +## Mandatory learning loop (AGENTS.md and comments) + +**Hard requirement:** When **any** of the following happens, you **must** complete steps 1–3 **before** you end the session or move on as if the work were complete: + +1. The **user** is dissatisfied or corrects your approach (wrong layer, scope, style, or a fix that does not stick). +2. **Pre-commit** or **CI** fails on something you or another agent could hit again (linters, REUSE/SPDX, formatting, policy hooks, etc.). +3. You **repeat** the same **category** of error after a correction. + +**You must:** + +1. **Distill** what went wrong into a **short, reusable pattern** (a rule or boundary, not a chat transcript). +2. **Update** the right artifact in the **same working pass** as the fix: prefer the **most local** `AGENTS.md` for package- or subtree-level rules; use the **repo root** `AGENTS.md` only for expectations that span the whole tree; put **volatile or line-specific** detail in **`//` comments** next to the code. +3. Respect **scope vs `main`** (below): only add `AGENTS.md` bullets for **this branch’s delta** to **`main`** (or the agreed base), not for behavior that already exists on the base branch. + +**You must not** skip documentation updates because the user did not say “update AGENTS.md”—failed checks and repeated mistakes **trigger** this loop automatically. + +**What belongs in `AGENTS.md`** + +- **High-level** expectations: boundaries between layers, what to avoid, naming or structural conventions, CMake/include policy at a glance, “always / never” rules that stay true across refactors. +- **Style of work**: how minimal to keep diffs, when to ask for clarification, how this subsystem should relate to OpenXR/schema/deviceio, etc. + +**What does *not* belong in `AGENTS.md`** + +- **Low-level or volatile detail**: exact call sequences, field-by-field semantics, long checklists tied to one function, anything that will go stale the next time the code moves. +- Put that in **comments in the source files** where the behavior lives (short `//` notes: intent, invariants, or “do not X because …”). + +**Scope — document what *this* branch changes, not main** + +- New or updated bullets should capture **learnings from the delta** between **this branch (or commit)** and **`main`** (or whatever long-lived base you are targeting—release branch, parent MR, etc.). +- Do **not** restate facts that already hold on **`main`** just because this branch touches nearby files. If behavior landed in the **base** history, it belongs in **code comments** next to that code or in **main’s** docs—not as “new” guidance in an `AGENTS.md` introduced only to support a smaller follow-up change. +- Example: schema- or API-level choices that merged **before** this branch are **out of scope** for `AGENTS.md` edits tied to this branch; they add churn and read like stale noise after merge. diff --git a/src/core/AGENTS.md b/src/core/AGENTS.md new file mode 100644 index 000000000..e1494b8c5 --- /dev/null +++ b/src/core/AGENTS.md @@ -0,0 +1,12 @@ + + +# Agent notes — IsaacTeleop `src/core` (index) + +**CRITICAL:** The mandatory multi-file `AGENTS.md` preflight in **[`../../AGENTS.md`](../../AGENTS.md)** applies here too. Before changing anything under `src/core/`, you must have read **this file**, **the repo root `AGENTS.md`**, and **every other `AGENTS.md` on the directory paths you will touch**. Do not skip any of them. + +To see **all** `AGENTS.md` files in the IsaacTeleop repo, use the **`find` command (or `**/AGENTS.md` glob) documented in the repo root [`AGENTS.md`](../../AGENTS.md)**—do not rely on a hand-maintained list in this file. + +If work under **`src/core/`** went wrong—**user** correction, **pre-commit/CI** failure, or **repeated** same-class mistakes—you **must** follow the repo root **[`AGENTS.md`](../../AGENTS.md)** **Mandatory learning loop**: distill a short rule and **update** the **nearest** relevant `AGENTS.md` (this file or a package file) or **source comments** in the same session (including **delta vs `main`** scope). diff --git a/src/core/deviceio_base/AGENTS.md b/src/core/deviceio_base/AGENTS.md new file mode 100644 index 000000000..e3a92a338 --- /dev/null +++ b/src/core/deviceio_base/AGENTS.md @@ -0,0 +1,21 @@ + + +# Agent notes — `deviceio_base` + +**CRITICAL (non-optional):** Before editing this package, complete the mandatory **`AGENTS.md` preflight** in [`../../../AGENTS.md`](../../../AGENTS.md) (read every applicable `AGENTS.md` on your paths, not just this file). + +## API + +- **`ITrackerImpl::update`** takes **`int64_t monotonic_time_ns`** (system monotonic clock, same domain as `core::os_monotonic_now_ns()`). +- **Do not** use `XrTime`, ``, or OpenXR link targets in this library. Keep the tracker abstraction runtime-agnostic. + +## CMake + +- **`deviceio_base`** is an **INTERFACE** library: list only what the headers actually need (e.g. `isaacteleop_schema`). Do **not** link `OpenXR::headers` or `oxr::oxr_utils` here. + +## Fallout for dependents + +- Targets that need OpenXR/oxr for compilation must declare those dependencies themselves (they are **not** implied by `deviceio_base`). See e.g. [`../live_trackers/AGENTS.md`](../live_trackers/AGENTS.md). **`deviceio_trackers`** intentionally stays OpenXR-free—see [`../deviceio_trackers/AGENTS.md`](../deviceio_trackers/AGENTS.md). diff --git a/src/core/deviceio_base/cpp/CMakeLists.txt b/src/core/deviceio_base/cpp/CMakeLists.txt index 2defe9713..c01d0ece5 100644 --- a/src/core/deviceio_base/cpp/CMakeLists.txt +++ b/src/core/deviceio_base/cpp/CMakeLists.txt @@ -14,8 +14,6 @@ target_include_directories(deviceio_base target_link_libraries(deviceio_base INTERFACE isaacteleop_schema - oxr::oxr_utils - OpenXR::headers ) add_library(deviceio::deviceio_base ALIAS deviceio_base) diff --git a/src/core/deviceio_base/cpp/inc/deviceio_base/tracker.hpp b/src/core/deviceio_base/cpp/inc/deviceio_base/tracker.hpp index 4a28cb671..dd405191f 100644 --- a/src/core/deviceio_base/cpp/inc/deviceio_base/tracker.hpp +++ b/src/core/deviceio_base/cpp/inc/deviceio_base/tracker.hpp @@ -3,8 +3,7 @@ #pragma once -#include - +#include #include #include #include @@ -12,9 +11,6 @@ namespace core { -// Forward declarations -struct OpenXRSessionHandles; - // Base interface for tracker implementations. // The actual worker objects updated each frame by DeviceIOSession. class ITrackerImpl @@ -23,13 +19,16 @@ class ITrackerImpl virtual ~ITrackerImpl() = default; /** - * @brief Updates tracker state for the specified OpenXR time. + * @brief Updates tracker state for the current frame. + * + * @param monotonic_time_ns Current time from the system monotonic clock, in nanoseconds + * (same domain as core::os_monotonic_now_ns()). * * @throws std::runtime_error On critical tracker/runtime failures. * @note A thrown exception indicates a fatal condition; the application is * expected to terminate rather than continue running. */ - virtual void update(XrTime time) = 0; + virtual void update(int64_t monotonic_time_ns) = 0; }; /** diff --git a/src/core/deviceio_session/AGENTS.md b/src/core/deviceio_session/AGENTS.md new file mode 100644 index 000000000..cfb986b0c --- /dev/null +++ b/src/core/deviceio_session/AGENTS.md @@ -0,0 +1,22 @@ + + +# Agent notes — `deviceio_session` + +**CRITICAL (non-optional):** Before editing this package, complete the mandatory **`AGENTS.md` preflight** in [`../../../AGENTS.md`](../../../AGENTS.md) (read every applicable `AGENTS.md` on your paths, not just this file). + +## Update loop + +- **`DeviceIOSession::update`** reads the clock once with **`core::os_monotonic_now_ns()`** (via `#include `) and passes that value to **`ITrackerImpl::update(int64_t)`** for every registered impl. +- **No** session-owned **`XrTimeConverter`** is required solely to drive that loop (OpenXR conversion stays inside live impls). + +## Implementation / includes + +- **`deviceio_session.cpp`**: if the TU uses **`XR_NULL_HANDLE`** or other OpenXR macros, include **``** explicitly after the session header so **`XR_NO_PROTOTYPES`** is already established by **`oxr_utils/oxr_funcs.hpp`** pulled in through **`deviceio_session.hpp`**. + +## Related docs + +- Tracker interface contract: [`../deviceio_base/AGENTS.md`](../deviceio_base/AGENTS.md) +- Live factory + impls: [`../live_trackers/AGENTS.md`](../live_trackers/AGENTS.md) diff --git a/src/core/deviceio_session/cpp/CMakeLists.txt b/src/core/deviceio_session/cpp/CMakeLists.txt index 31ecf2a04..eebac3d6f 100644 --- a/src/core/deviceio_session/cpp/CMakeLists.txt +++ b/src/core/deviceio_session/cpp/CMakeLists.txt @@ -14,12 +14,14 @@ target_include_directories(deviceio_session $ ) -# Public headers include oxr_funcs.hpp, which pulls in NVIDIA OpenXR extension -# headers (e.g. XR_NVX1_action_context.h). Propagate Teleop::openxr_extensions so -# consumers (Python bindings, apps) can compile without linking deviceio_trackers. +# Public headers include oxr_funcs.hpp and oxr_session_handles.hpp. Propagate +# oxr::oxr_utils (OpenXR headers + oxr inc/) and Teleop::openxr_extensions (NVIDIA +# extension headers) so consumers (Python bindings, apps) compile without linking +# live_trackers. target_link_libraries(deviceio_session PUBLIC deviceio::deviceio_base + oxr::oxr_utils Teleop::openxr_extensions PRIVATE deviceio::deviceio_trackers diff --git a/src/core/deviceio_session/cpp/deviceio_session.cpp b/src/core/deviceio_session/cpp/deviceio_session.cpp index 72e7549b8..f24e4f30c 100644 --- a/src/core/deviceio_session/cpp/deviceio_session.cpp +++ b/src/core/deviceio_session/cpp/deviceio_session.cpp @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include @@ -24,7 +26,7 @@ namespace core DeviceIOSession::DeviceIOSession(const std::vector>& trackers, const OpenXRSessionHandles& handles, std::optional recording_config) - : handles_(handles), time_converter_(handles) + : handles_(handles) { std::vector> tracker_names; @@ -103,11 +105,11 @@ std::unique_ptr DeviceIOSession::run(const std::vectorupdate(current_time); + kv.second->update(monotonic_ns); } } diff --git a/src/core/deviceio_session/cpp/inc/deviceio_session/deviceio_session.hpp b/src/core/deviceio_session/cpp/inc/deviceio_session/deviceio_session.hpp index 09965c8d7..67aee3100 100644 --- a/src/core/deviceio_session/cpp/inc/deviceio_session/deviceio_session.hpp +++ b/src/core/deviceio_session/cpp/inc/deviceio_session/deviceio_session.hpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -88,7 +87,6 @@ class DeviceIOSession : public ITrackerSession const OpenXRSessionHandles handles_; std::unordered_map> tracker_impls_; - XrTimeConverter time_converter_; // Owned MCAP writer; null when recording is not configured. std::unique_ptr mcap_writer_; diff --git a/src/core/deviceio_trackers/AGENTS.md b/src/core/deviceio_trackers/AGENTS.md new file mode 100644 index 000000000..9b9816352 --- /dev/null +++ b/src/core/deviceio_trackers/AGENTS.md @@ -0,0 +1,16 @@ + + +# Agent notes — `deviceio_trackers` + +**CRITICAL (non-optional):** Before editing this package, complete the mandatory **`AGENTS.md` preflight** in [`../../../AGENTS.md`](../../../AGENTS.md) (read every applicable `AGENTS.md` on your paths, not just this file). + +## No OpenXR dependency + +- **`deviceio_trackers`** must **not** link **`OpenXR::headers`**, **`oxr::oxr_utils`**, or vendor extension targets, and must **not** `#include` OpenXR headers. Public API stays schema + **`deviceio_base`** only. + +## Related docs + +- Base interface: [`../deviceio_base/AGENTS.md`](../deviceio_base/AGENTS.md) diff --git a/src/core/live_trackers/AGENTS.md b/src/core/live_trackers/AGENTS.md new file mode 100644 index 000000000..41558202c --- /dev/null +++ b/src/core/live_trackers/AGENTS.md @@ -0,0 +1,34 @@ + + +# Agent notes — `live_trackers` + +**CRITICAL (non-optional):** Before editing this package, complete the mandatory **`AGENTS.md` preflight** in [`../../../AGENTS.md`](../../../AGENTS.md) (read every applicable `AGENTS.md` on your paths, not just this file). + +## Time and OpenXR + +- Store **`last_update_time_` as `int64_t`** (monotonic ns), not **`XrTime`**. +- **Once per `update` call:** `const XrTime xr_time = time_converter_.convert_monotonic_ns_to_xrtime(monotonic_time_ns);` then use **`xr_time`** for every **`xrLocate*`** / hand / body call **and** for MCAP (see below). **Do not** call **`convert_monotonic_ns_to_xrtime`** again in the MCAP block. +- **Full-body limp mode:** if the body tracker handle is null and you **return early**, **do not** compute **`xr_time`** first—only convert after you know you will call OpenXR. + +## `DeviceDataTimestamp` (MCAP) + +- **Fields 1–2:** monotonic ns (e.g. **`last_update_time_`, `last_update_time_`**). +- **Field 3 (`sample_time_raw_device_clock`):** the **same** **`xr_time`** variable used for OpenXR this frame (not a second conversion). + +## Includes + +- In headers that need both: **`#include `** comes **before** any bare **`#include `**. `oxr_funcs.hpp` defines **`XR_NO_PROTOTYPES`** then includes OpenXR; including **`openxr.h`** first fights that policy. +- In **`.cpp`** files that construct **`DeviceDataTimestamp`**, include **`#include `** explicitly. +- **`.cpp`** files should include headers for **symbols the TU uses** (e.g. **`oxr_funcs.hpp`** for **`createReferenceSpace`**), not only what the matching **`.hpp`** happens to pull in. + +## CMake + +- **`live_trackers`** should **`PUBLIC` link `oxr::oxr_utils`** (OpenXR headers come through that INTERFACE target) because headers/sources use OpenXR / oxr types. + +## Related docs + +- Session update loop: [`../deviceio_session/AGENTS.md`](../deviceio_session/AGENTS.md) +- No OpenXR in base API: [`../deviceio_base/AGENTS.md`](../deviceio_base/AGENTS.md) diff --git a/src/core/live_trackers/cpp/CMakeLists.txt b/src/core/live_trackers/cpp/CMakeLists.txt index f562f718d..a2e429215 100644 --- a/src/core/live_trackers/cpp/CMakeLists.txt +++ b/src/core/live_trackers/cpp/CMakeLists.txt @@ -33,6 +33,7 @@ target_link_libraries(live_trackers deviceio::deviceio_base deviceio::deviceio_trackers mcap::mcap_core + oxr::oxr_utils Teleop::openxr_extensions ) diff --git a/src/core/live_trackers/cpp/live_controller_tracker_impl.cpp b/src/core/live_trackers/cpp/live_controller_tracker_impl.cpp index b6464a8a9..a2d918b7b 100644 --- a/src/core/live_trackers/cpp/live_controller_tracker_impl.cpp +++ b/src/core/live_trackers/cpp/live_controller_tracker_impl.cpp @@ -5,8 +5,8 @@ #include #include -#include #include +#include #include #include @@ -314,9 +314,10 @@ LiveControllerTrackerImpl::LiveControllerTrackerImpl(const OpenXRSessionHandles& std::cout << "ControllerTracker initialized (left + right) with action context" << std::endl; } -void LiveControllerTrackerImpl::update(XrTime time) +void LiveControllerTrackerImpl::update(int64_t monotonic_time_ns) { - last_update_time_ = time; + last_update_time_ = monotonic_time_ns; + const XrTime xr_time = time_converter_.convert_monotonic_ns_to_xrtime(monotonic_time_ns); // Sync actions via xrSyncActions2NV with our session action context XrActiveActionSet active_action_set{ action_set_.get(), XR_NULL_PATH }; @@ -352,7 +353,7 @@ void LiveControllerTrackerImpl::update(XrTime time) ControllerPose aim_pose{}; XrSpaceLocation grip_location{ XR_TYPE_SPACE_LOCATION }; - result = core_funcs_.xrLocateSpace(grip_space.get(), base_space_, time, &grip_location); + result = core_funcs_.xrLocateSpace(grip_space.get(), base_space_, xr_time, &grip_location); if (XR_FAILED(result)) { tracked.data.reset(); @@ -373,7 +374,7 @@ void LiveControllerTrackerImpl::update(XrTime time) } XrSpaceLocation aim_location{ XR_TYPE_SPACE_LOCATION }; - result = core_funcs_.xrLocateSpace(aim_space.get(), base_space_, time, &aim_location); + result = core_funcs_.xrLocateSpace(aim_space.get(), base_space_, xr_time, &aim_location); if (XR_FAILED(result)) { tracked.data.reset(); @@ -419,8 +420,7 @@ void LiveControllerTrackerImpl::update(XrTime time) if (mcap_channels_) { - int64_t monotonic_ns = time_converter_.convert_xrtime_to_monotonic_ns(last_update_time_); - DeviceDataTimestamp timestamp(monotonic_ns, monotonic_ns, last_update_time_); + DeviceDataTimestamp timestamp(last_update_time_, last_update_time_, xr_time); mcap_channels_->write(0, timestamp, left_tracked_.data); mcap_channels_->write(1, timestamp, right_tracked_.data); } diff --git a/src/core/live_trackers/cpp/live_controller_tracker_impl.hpp b/src/core/live_trackers/cpp/live_controller_tracker_impl.hpp index 66ac5c06f..986396ca9 100644 --- a/src/core/live_trackers/cpp/live_controller_tracker_impl.hpp +++ b/src/core/live_trackers/cpp/live_controller_tracker_impl.hpp @@ -5,13 +5,12 @@ #include #include -#include #include #include #include #include -#include +#include #include #include #include @@ -40,7 +39,7 @@ class LiveControllerTrackerImpl : public IControllerTrackerImpl LiveControllerTrackerImpl(LiveControllerTrackerImpl&&) = delete; LiveControllerTrackerImpl& operator=(LiveControllerTrackerImpl&&) = delete; - void update(XrTime time) override; + void update(int64_t monotonic_time_ns) override; const ControllerSnapshotTrackedT& get_left_controller() const override; const ControllerSnapshotTrackedT& get_right_controller() const override; @@ -75,7 +74,7 @@ class LiveControllerTrackerImpl : public IControllerTrackerImpl ControllerSnapshotTrackedT left_tracked_; ControllerSnapshotTrackedT right_tracked_; - XrTime last_update_time_ = 0; + int64_t last_update_time_ = 0; std::unique_ptr mcap_channels_; }; diff --git a/src/core/live_trackers/cpp/live_frame_metadata_tracker_oak_impl.cpp b/src/core/live_trackers/cpp/live_frame_metadata_tracker_oak_impl.cpp index a8bc77cb0..fa28deb80 100644 --- a/src/core/live_trackers/cpp/live_frame_metadata_tracker_oak_impl.cpp +++ b/src/core/live_trackers/cpp/live_frame_metadata_tracker_oak_impl.cpp @@ -59,7 +59,7 @@ LiveFrameMetadataTrackerOakImpl::LiveFrameMetadataTrackerOakImpl(const OpenXRSes } } -void LiveFrameMetadataTrackerOakImpl::update(XrTime /*time*/) +void LiveFrameMetadataTrackerOakImpl::update(int64_t /*monotonic_time_ns*/) { // Policy: per-stream SchemaTracker throws on critical OpenXR/tensor API failures. // Missing stream collection/no fresh sample are treated as common non-fatal cases. diff --git a/src/core/live_trackers/cpp/live_frame_metadata_tracker_oak_impl.hpp b/src/core/live_trackers/cpp/live_frame_metadata_tracker_oak_impl.hpp index 790557785..f839eca7b 100644 --- a/src/core/live_trackers/cpp/live_frame_metadata_tracker_oak_impl.hpp +++ b/src/core/live_trackers/cpp/live_frame_metadata_tracker_oak_impl.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -40,7 +41,7 @@ class LiveFrameMetadataTrackerOakImpl : public IFrameMetadataTrackerOakImpl LiveFrameMetadataTrackerOakImpl(LiveFrameMetadataTrackerOakImpl&&) = delete; LiveFrameMetadataTrackerOakImpl& operator=(LiveFrameMetadataTrackerOakImpl&&) = delete; - void update(XrTime time) override; + void update(int64_t monotonic_time_ns) override; const FrameMetadataOakTrackedT& get_stream_data(size_t stream_index) const override; private: diff --git a/src/core/live_trackers/cpp/live_full_body_tracker_pico_impl.cpp b/src/core/live_trackers/cpp/live_full_body_tracker_pico_impl.cpp index e8457f356..fcb86ec4d 100644 --- a/src/core/live_trackers/cpp/live_full_body_tracker_pico_impl.cpp +++ b/src/core/live_trackers/cpp/live_full_body_tracker_pico_impl.cpp @@ -5,8 +5,8 @@ #include #include -#include #include +#include #include #include @@ -97,9 +97,9 @@ LiveFullBodyTrackerPicoImpl::~LiveFullBodyTrackerPicoImpl() } } -void LiveFullBodyTrackerPicoImpl::update(XrTime time) +void LiveFullBodyTrackerPicoImpl::update(int64_t monotonic_time_ns) { - last_update_time_ = time; + last_update_time_ = monotonic_time_ns; if (body_tracker_ == XR_NULL_HANDLE) { @@ -108,10 +108,12 @@ void LiveFullBodyTrackerPicoImpl::update(XrTime time) return; } + const XrTime xr_time = time_converter_.convert_monotonic_ns_to_xrtime(monotonic_time_ns); + XrBodyJointsLocateInfoBD locate_info{ XR_TYPE_BODY_JOINTS_LOCATE_INFO_BD }; locate_info.next = nullptr; locate_info.baseSpace = base_space_; - locate_info.time = time; + locate_info.time = xr_time; XrBodyJointLocationBD joint_locations[XR_BODY_JOINT_COUNT_BD]; @@ -157,8 +159,7 @@ void LiveFullBodyTrackerPicoImpl::update(XrTime time) if (mcap_channels_) { - int64_t monotonic_ns = time_converter_.convert_xrtime_to_monotonic_ns(last_update_time_); - DeviceDataTimestamp timestamp(monotonic_ns, monotonic_ns, last_update_time_); + DeviceDataTimestamp timestamp(last_update_time_, last_update_time_, xr_time); mcap_channels_->write(0, timestamp, tracked_.data); } } diff --git a/src/core/live_trackers/cpp/live_full_body_tracker_pico_impl.hpp b/src/core/live_trackers/cpp/live_full_body_tracker_pico_impl.hpp index 11b033cf1..181d6b803 100644 --- a/src/core/live_trackers/cpp/live_full_body_tracker_pico_impl.hpp +++ b/src/core/live_trackers/cpp/live_full_body_tracker_pico_impl.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -40,7 +41,7 @@ class LiveFullBodyTrackerPicoImpl : public IFullBodyTrackerPicoImpl LiveFullBodyTrackerPicoImpl(LiveFullBodyTrackerPicoImpl&&) = delete; LiveFullBodyTrackerPicoImpl& operator=(LiveFullBodyTrackerPicoImpl&&) = delete; - void update(XrTime time) override; + void update(int64_t monotonic_time_ns) override; const FullBodyPosePicoTrackedT& get_body_pose() const override; private: @@ -48,7 +49,7 @@ class LiveFullBodyTrackerPicoImpl : public IFullBodyTrackerPicoImpl XrSpace base_space_; XrBodyTrackerBD body_tracker_; FullBodyPosePicoTrackedT tracked_; - XrTime last_update_time_ = 0; + int64_t last_update_time_ = 0; PFN_xrCreateBodyTrackerBD pfn_create_body_tracker_; PFN_xrDestroyBodyTrackerBD pfn_destroy_body_tracker_; diff --git a/src/core/live_trackers/cpp/live_generic_3axis_pedal_tracker_impl.cpp b/src/core/live_trackers/cpp/live_generic_3axis_pedal_tracker_impl.cpp index ecf0a5179..2d7133ed6 100644 --- a/src/core/live_trackers/cpp/live_generic_3axis_pedal_tracker_impl.cpp +++ b/src/core/live_trackers/cpp/live_generic_3axis_pedal_tracker_impl.cpp @@ -44,7 +44,7 @@ LiveGeneric3AxisPedalTrackerImpl::LiveGeneric3AxisPedalTrackerImpl(const OpenXRS { } -void LiveGeneric3AxisPedalTrackerImpl::update(XrTime /*time*/) +void LiveGeneric3AxisPedalTrackerImpl::update(int64_t /*monotonic_time_ns*/) { // Policy: SchemaTracker throws on critical OpenXR/tensor API failures. // Missing collection/no new data are treated as common non-fatal cases. diff --git a/src/core/live_trackers/cpp/live_generic_3axis_pedal_tracker_impl.hpp b/src/core/live_trackers/cpp/live_generic_3axis_pedal_tracker_impl.hpp index a7841abd5..f2d403591 100644 --- a/src/core/live_trackers/cpp/live_generic_3axis_pedal_tracker_impl.hpp +++ b/src/core/live_trackers/cpp/live_generic_3axis_pedal_tracker_impl.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -38,7 +39,7 @@ class LiveGeneric3AxisPedalTrackerImpl : public IGeneric3AxisPedalTrackerImpl LiveGeneric3AxisPedalTrackerImpl(LiveGeneric3AxisPedalTrackerImpl&&) = delete; LiveGeneric3AxisPedalTrackerImpl& operator=(LiveGeneric3AxisPedalTrackerImpl&&) = delete; - void update(XrTime time) override; + void update(int64_t monotonic_time_ns) override; const Generic3AxisPedalOutputTrackedT& get_data() const override; private: diff --git a/src/core/live_trackers/cpp/live_hand_tracker_impl.cpp b/src/core/live_trackers/cpp/live_hand_tracker_impl.cpp index f35ed0829..04da2df71 100644 --- a/src/core/live_trackers/cpp/live_hand_tracker_impl.cpp +++ b/src/core/live_trackers/cpp/live_hand_tracker_impl.cpp @@ -5,8 +5,8 @@ #include #include -#include #include +#include #include #include @@ -117,16 +117,16 @@ LiveHandTrackerImpl::~LiveHandTrackerImpl() } } -void LiveHandTrackerImpl::update(XrTime time) +void LiveHandTrackerImpl::update(int64_t monotonic_time_ns) { - last_update_time_ = time; - update_hand(left_hand_tracker_, time, left_tracked_); - update_hand(right_hand_tracker_, time, right_tracked_); + last_update_time_ = monotonic_time_ns; + const XrTime xr_time = time_converter_.convert_monotonic_ns_to_xrtime(monotonic_time_ns); + update_hand(left_hand_tracker_, xr_time, left_tracked_); + update_hand(right_hand_tracker_, xr_time, right_tracked_); if (mcap_channels_) { - int64_t monotonic_ns = time_converter_.convert_xrtime_to_monotonic_ns(last_update_time_); - DeviceDataTimestamp timestamp(monotonic_ns, monotonic_ns, last_update_time_); + DeviceDataTimestamp timestamp(last_update_time_, last_update_time_, xr_time); mcap_channels_->write(0, timestamp, left_tracked_.data); mcap_channels_->write(1, timestamp, right_tracked_.data); } diff --git a/src/core/live_trackers/cpp/live_hand_tracker_impl.hpp b/src/core/live_trackers/cpp/live_hand_tracker_impl.hpp index 961d3f84f..a946fc379 100644 --- a/src/core/live_trackers/cpp/live_hand_tracker_impl.hpp +++ b/src/core/live_trackers/cpp/live_hand_tracker_impl.hpp @@ -5,12 +5,12 @@ #include #include -#include #include #include #include #include +#include #include #include #include @@ -38,7 +38,7 @@ class LiveHandTrackerImpl : public IHandTrackerImpl LiveHandTrackerImpl(LiveHandTrackerImpl&&) = delete; LiveHandTrackerImpl& operator=(LiveHandTrackerImpl&&) = delete; - void update(XrTime time) override; + void update(int64_t monotonic_time_ns) override; const HandPoseTrackedT& get_left_hand() const override; const HandPoseTrackedT& get_right_hand() const override; @@ -53,7 +53,7 @@ class LiveHandTrackerImpl : public IHandTrackerImpl HandPoseTrackedT left_tracked_; HandPoseTrackedT right_tracked_; - XrTime last_update_time_ = 0; + int64_t last_update_time_ = 0; PFN_xrCreateHandTrackerEXT pfn_create_hand_tracker_; PFN_xrDestroyHandTrackerEXT pfn_destroy_hand_tracker_; diff --git a/src/core/live_trackers/cpp/live_head_tracker_impl.cpp b/src/core/live_trackers/cpp/live_head_tracker_impl.cpp index 6f6adbe78..dbda95fa5 100644 --- a/src/core/live_trackers/cpp/live_head_tracker_impl.cpp +++ b/src/core/live_trackers/cpp/live_head_tracker_impl.cpp @@ -4,7 +4,9 @@ #include "live_head_tracker_impl.hpp" #include +#include #include +#include #include #include @@ -40,12 +42,14 @@ LiveHeadTrackerImpl::LiveHeadTrackerImpl(const OpenXRSessionHandles& handles, { } -void LiveHeadTrackerImpl::update(XrTime time) +void LiveHeadTrackerImpl::update(int64_t monotonic_time_ns) { - last_update_time_ = time; + last_update_time_ = monotonic_time_ns; + + const XrTime xr_time = time_converter_.convert_monotonic_ns_to_xrtime(monotonic_time_ns); XrSpaceLocation location{ XR_TYPE_SPACE_LOCATION }; - XrResult result = core_funcs_.xrLocateSpace(view_space_.get(), base_space_, time, &location); + XrResult result = core_funcs_.xrLocateSpace(view_space_.get(), base_space_, xr_time, &location); if (XR_FAILED(result)) { @@ -78,8 +82,7 @@ void LiveHeadTrackerImpl::update(XrTime time) if (mcap_channels_) { - int64_t monotonic_ns = time_converter_.convert_xrtime_to_monotonic_ns(last_update_time_); - DeviceDataTimestamp timestamp(monotonic_ns, monotonic_ns, last_update_time_); + DeviceDataTimestamp timestamp(last_update_time_, last_update_time_, xr_time); mcap_channels_->write(0, timestamp, tracked_.data); } } diff --git a/src/core/live_trackers/cpp/live_head_tracker_impl.hpp b/src/core/live_trackers/cpp/live_head_tracker_impl.hpp index 5a9b525f5..a212b1875 100644 --- a/src/core/live_trackers/cpp/live_head_tracker_impl.hpp +++ b/src/core/live_trackers/cpp/live_head_tracker_impl.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -36,7 +37,7 @@ class LiveHeadTrackerImpl : public IHeadTrackerImpl LiveHeadTrackerImpl(LiveHeadTrackerImpl&&) = delete; LiveHeadTrackerImpl& operator=(LiveHeadTrackerImpl&&) = delete; - void update(XrTime time) override; + void update(int64_t monotonic_time_ns) override; const HeadPoseTrackedT& get_head() const override; private: @@ -45,7 +46,7 @@ class LiveHeadTrackerImpl : public IHeadTrackerImpl XrSpace base_space_; XrSpacePtr view_space_; HeadPoseTrackedT tracked_; - XrTime last_update_time_ = 0; + int64_t last_update_time_ = 0; std::unique_ptr mcap_channels_; }; diff --git a/src/core/oxr/cpp/inc/oxr/oxr_session.hpp b/src/core/oxr/cpp/inc/oxr/oxr_session.hpp index c95e0c4b9..9fd78d3a3 100644 --- a/src/core/oxr/cpp/inc/oxr/oxr_session.hpp +++ b/src/core/oxr/cpp/inc/oxr/oxr_session.hpp @@ -24,9 +24,10 @@ class OpenXRSession OpenXRSessionHandles get_handles() const; private: - using InstanceHandle = std::unique_ptr, decltype(&xrDestroyInstance)>; - using SessionHandle = std::unique_ptr, decltype(&xrDestroySession)>; - using SpaceHandle = std::unique_ptr, decltype(&xrDestroySpace)>; + // PFN_* deleter types work when OpenXR was already included with XR_NO_PROTOTYPES (no xrDestroy* declarations). + using InstanceHandle = std::unique_ptr, PFN_xrDestroyInstance>; + using SessionHandle = std::unique_ptr, PFN_xrDestroySession>; + using SpaceHandle = std::unique_ptr, PFN_xrDestroySpace>; // Initialization methods void create_instance(const std::string& app_name, const std::vector& extensions);