Skip to main content

runtime-loop

Headless load -> populate -> read -> update -> read loop with no renderer attached: open a USD scene into the ovstage runtime table, read prims back to confirm, then update the live stage two ways — write straight into the ovstage table (e.g. animate a transform), or edit the USD source and propagate it through. Use when the user wants to drive an ovstage scene headlessly, populate USD into the runtime stage, or see runtime-table vs USD-source edits reflected in reads.

Source facts

Repository
NVIDIA-Omniverse/ovstage
Last source activity
October 15, 2026 at 05:21
Detected SKILL.md language
English
Stars
22
Forks
5

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
runtime-loop
description
Headless load -> populate -> read -> update -> read loop with no renderer attached: open a USD scene into the ovstage runtime table, read prims back to confirm, then update the live stage two ways — write straight into the ovstage table (e.g. animate a transform), or edit the USD source and propagate it through. Use when the user wants to drive an ovstage scene headlessly, populate USD into the runtime stage, or see runtime-table vs USD-source edits reflected in reads.
license
LicenseRef-NvidiaProprietary
version
0.1.0
author
NVIDIA ovstage
tags
["ovstage","population","usd","runtime"]
tools
["Read","Grep"]
# Runtime Loop (Populate, Read, Update) ## When to Use Use this skill when the user wants to work an ovstage scene **headlessly** (no renderer): load a USD scene and populate it into the runtime table, read prims back, and update the live stage. It covers the **two update paths** a client has once a scene is live: 1. **Directly in the ovstage runtime table** — `write_attribute` at a new ordinal (e.g. animate a prim's `omni:xform` transform over frames). The fast GPU-side edit; no USD round-trip. 2. **Through the USD source** — `add_usd_reference` / `apply_usd_changes` (or `update_from_usd_time` for time samples), so USD-side edits propagate into the runtime table. Do **not** use it for rendering a scene (that stays in ovrtx), or for the mechanics of a single call — route those to the focused skills (`application-flow`, `dlpack-tensor-exchange`, etc.). ## Inputs Resolve inputs in this order: existing repository files and referenced snippets, explicit user request, then broader agent context. - The scene: a USD file path (`open_usd`) or inline USDA string (`open_usd_from_string`). - The prims to query and the attribute(s) to read/write (as interned tokens or strings). - The caller-owned **ordinals**: under strict admission, use newer ordinals for repeated changes to a cell; disjoint producers may share an ordinal above their applicable floors. - Which update path(s) the request needs: direct runtime-table write, USD-source edit, or both. - Target API surface: C, Python, or both. - The shipped headers and the referenced example snippets are the authoritative contract. ## Prerequisites - Population entry points: `ovstage_population_*` in C, `ovstage.population` in Python. - Read the relevant `> **Source:**` snippet before writing or explaining API usage. - Understand the async **submit/observe** model (`cpu-ahead-gpu-async`): populate and write are enqueues that return an `op_index`; nothing is visible until you await and **advance the write floor**. Population has its own wait (`ovstage_population_wait_op`), parallel to the data-plane `ovstage_wait_op`. - The **application owns the ordinal lifecycle** — population never opens or seals an ordinal; you pass the current one to each call and advance the write floor per tick. ## Instructions 1. **Populate.** `open_usd` (file) or `open_usd_from_string` (inline) at ordinal 1 with a `PopulationDomain`, then `advance_write_floor` to seal it so reads can see it. 2. **Read to confirm.** Read the reserved `usd-prim-type` metadata (auto-maintained for every populated prim) over a path-list query — the guaranteed proof the populate landed. 3. **Update path 1 — runtime table.** `write_attribute` at a new ordinal (e.g. a prim's `omni:xform` transform, `is_array=false`, `semantic=MATRIX`), advancing the write floor each step; read the column back to confirm. 4. **Update path 2 — USD source.** `add_usd_reference` (or `_from_string`) edits only USD; `apply_usd_changes` at a fresh ordinal propagates it into the runtime table. Advance the floor, then re-read to see the change. 5. **Own the ordinals.** Clear applicable floors and satisfy the configured admission policy for affected cells and prim lifecycle. Under the `STRICTLY_INCREASING` policy, disjoint cells may share an ordinal; rewriting a cell needs a newer ordinal even before sealing. See [Ordinal Admission Policies](../../docs/scene/writing_attributes.rst) for options. ## Output Format - For explanations, cite the API names, the source snippet(s), and the key caveats (population support, ordinal ownership, which update path, transform recipe). - For code changes, summarize the files touched, snippets affected, and validation run. ## Scripts This skill has no scripts. ## Limitations - The referenced snippets remain the source of truth; update or add tested snippets before documenting new API usage. - **Transform layout: `omni:xform` is one 16-lane element per prim.** The canonical 4×4 double tensor uses `dtype.lanes = 16`, `shape = [1]` (`semantic = MATRIX`, row-vector convention, translation in row `[3][0..2]`). A compact `shape = [1, 4, 4]`, `lanes = 1` copy-in is also accepted. The input dimensions are folded into storage; raw reads and maps reconstruct `shape = [1, 4, 4]`, `lanes = 1`. Their strides count scalar elements. - **Transform scope.** This loop reads back only the local `omni:xform` value **it wrote itself**. It does not validate hierarchy-derived world-transform reads. Derived world rows may be absent or stale until their owning workflow materializes them and runs hierarchy computation; follow `docs/scene/transforms.rst` for the authoring and freshness contract. - **Inline USDA for `add_usd_reference` must be multi-line.** A single-line layer-metadata + prim body does not parse through the anonymous-layer import path. - **`apply_usd_time` / structural edits.** For the RENDERING domain, `apply_usd_changes` / `apply_usd_time` also reflect structural USD edits; other domains apply structural edits only via `apply_usd_changes`. - **Latest-snapshot build** — data becomes visible at/below the write floor once you advance it; don't design around reading historical ordinals. ## Overview ovstage is a headless, GPU-native runtime stage for USD data. The **population** bridge (`ovstage_population.h`) reads USD (a file or inline USDA) and mirrors it into an ovstage instance; the **data plane** (`ovstage.h`) then reads and writes columns against the populated prims. This skill ties them into one loop: populate → read → update (table and/or USD) → read, with the application owning the ordinal lifecycle and sealing each tick with `advance_write_floor`. ## C Populate a USD file and seal the ordinal (population has its own enqueue/wait; the `waitPop` helper mirrors the data-plane `waitOp`): > **Source:** `examples/c/runtime-loop/main.cpp` snippet `populate` Confirm the populate by reading the reserved `usd-prim-type` metadata and resolving the tokens: > **Source:** `examples/c/runtime-loop/main.cpp` snippet `read-populated` Update path 1 — write the transform straight into the runtime table over frames: > **Source:** `examples/c/runtime-loop/main.cpp` snippet `update-table` Update path 2 — edit the USD source and propagate it through: > **Source:** `examples/c/runtime-loop/main.cpp` snippet `update-usd` ## Python The Python population surface is `ovstage.population.*` (blocking `foo(...)` plus async `foo_async(...)`). Imports: > **Source:** `examples/python/runtime-loop/main.py` snippet `setup` Populate and seal: > **Source:** `examples/python/runtime-loop/main.py` snippet `populate` Read the reserved `usd-prim-type` metadata to confirm the populate: > **Source:** `examples/python/runtime-loop/main.py` snippet `read-populated` Update path 1 — animate the transform straight into the runtime table: > **Source:** `examples/python/runtime-loop/main.py` snippet `update-table` Update path 2 — edit the USD source and propagate it through: > **Source:** `examples/python/runtime-loop/main.py` snippet `update-usd` ## Key Types / Functions | Python | C | |--------|---| | `population.open_usd(stage, path, ordinal, ...)` / `open_usd_from_string` | `ovstage_population_open_usd_from_file` / `_from_string` | | `population.apply_usd_changes(stage, ordinal)` | `ovstage_population_apply_usd_changes` | | `population.add_usd_reference_from_string(stage, usda, target)` | `ovstage_population_add_usd_reference_from_string` | | `Stage.write_attribute(query, attr, ordinal, tensors, is_array=, semantic=)` | `ovstage_write_attribute` (+ `ovstage_write_data_t`) | | `Stage.read_attributes(query, attrs, OrdinalRange)` → `Read` | `ovstage_read_attributes` (+ `ovstage_fetch_read_next`) | | `Stage.advance_write_floor(ordinal)` | `ovstage_advance_write_floor` | ## Troubleshooting - **Read fails with `OVSTAGE_ERROR_WRITE_FLOOR_VIOLATION` after populate** — advance the write floor to the populate ordinal; reads only see sealed data at/below the floor. - **`OVSTAGE_ERROR_WRITE_FLOOR_VIOLATION`** — the ordinal conflicts with a floor or the configured admission policy for affected cells or prim lifecycle. Use a newer ordinal for overlapping updates in this default-policy loop (for example, populate 1 → write 2 → USD edit 3). - **USD edit didn't show up in reads** — `add_usd_reference` only edits USD; you must call `apply_usd_changes` at a fresh ordinal and advance the floor before re-reading. - **Transform read looks wrong / empty** — confirm the `omni:xform` recipe and that the query reads a column written or populated for the selected prims. For derived world rows, see **Transform scope** under Limitations and `docs/scene/transforms.rst`. ## References - Use the `> **Source:**` directives in this skill to locate tested snippets before reusing API patterns. - `application-flow` — the create → write → seal → read lifecycle this loop instantiates. - `cpu-ahead-gpu-async` — the async submit/observe model and ordinal/write-floor semantics. - `dlpack-tensor-exchange` — tensor interchange for the read/write payloads (matrices, columns). - `error-handling` — status checks and per-op error reporting for enqueues and waits. - `path-dictionary` / `string-handling` — interning prim paths and attribute names (`ovx_string_t`). - Keep related skills, docs, and snippets synchronized when changing the workflow.
View on GitHub