C API Reference#

The C API provides the primary public interface to the ovstage runtime data plane. The reference below is generated from the shipped public headers under include/ovstage.

Note

These pages are generated by Doxygen + Breathe from the header comments. Building them locally requires Doxygen (refer to docs/README.md); the make html target runs Doxygen first.

Data Plane#

Instance lifecycle, cloning, and hierarchy. Writes, reads, queries, maps, and the write floor are declared in ovstage_api.h (refer to API Types and Utilities below).

OVStage instance lifecycle — creation and destruction.

The OVStage data-plane API (types, handles, operations, diagnostics) is declared in ovstage_api/ovstage_api.h as a vtable contract and exposed to callers through inline wrappers in ovstage_api/ovstage_api_utils.h (transitively included from ovstage_api.h) and sibling extension APIs.

This header adds the pieces specific to ovstage: an instance descriptor, create/destroy entry points, and instance helpers. Once an ovstage_instance_t* has been produced by ovstage_create_instance, call the generic ovstage_* wrappers declared in ovstage_api.h and the ovstage-specific entry points declared here to drive it.

Version

0.3.0

Date

2026-05-27

Functions

const ovstage_build_info_t *ovstage_get_build_info(void)#

Return the build information embedded in the OVStage API implementation.

This call is safe before ovstage_initialize() and does not initialize the OVStage runtime. The shared and static loaders report the loader build. A directly linked runtime library reports the runtime build. Loader/runtime pairs from one package are built from the same generated information, but a separately selected runtime package can report different values through its callback log and crash metadata.

Returns:

A non-NULL pointer owned by the code providing this API. The pointer and all borrowed string fields remain valid for that code’s lifetime.

ovstage_api_status_t ovstage_initialize(
const ovstage_config_t *config
)#

Acquire a reference to process-scoped ovstage state.

Reference-counted: each successful call must be balanced by one ovstage_shutdown(). Process-scoped state is set up on the first reference (0 -> 1) and torn down on the last (1 -> 0). Instances created with ovstage_create_instance also hold a reference, so process state stays alive while any instance exists.

Calling ovstage_initialize() is optional when linking the ovstage shared library directly: instance creation acquires process state on demand. Call it explicitly to (1) pin process-scoped state independent of instance lifetime — so process-level resources stay alive when no instance is live or across instance create/destroy churn — and (2) bootstrap the runtime eagerly, so a framework/plugin failure surfaces here instead of at the first create_instance.

Parameters:
  • config – Optional process configuration (see ovstage_config_t / the entry builders in ovstage_config.h). OVSTAGE_CONFIG_BINARY_PACKAGE_ROOT_PATH is consumed by the static loader and must be supplied before any other ovstage_* call when a non-default root is needed. OVSTAGE_CONFIG_RUNTIME_DEFAULT_HIERARCHY_COMPUTATION_MODEL is consumed by the runtime and controls automatic hierarchy updates and the RUNTIME_DEFAULT selector for new instances. OVSTAGE_CONFIG_RUNTIME_DEFAULT_ORDINAL_ADMISSION_POLICY selects mutation admission, defaulting to NONDECREASING. Omitted settings and their DEFAULT selectors inherit active process settings, or select defaults on the first reference. Later concrete settings must match the active settings. All settings are validated together: a rejected call changes none of them and acquires no reference. A policy can change only after all initialization and instance references are released, including retained instance handles and attachments.

Returns:

OVSTAGE_OK on success; OVSTAGE_ERROR_INVALID_ARGUMENT for malformed, duplicate, unknown, or conflicting runtime configuration.

Post:

Balance every successful call with one ovstage_shutdown().

ovstage_api_status_t ovstage_get_config(
const ovstage_instance_t *instance,
ovstage_config_t *out_config
)#

Read back the process configuration captured by an ovstage instance.

The returned config contains the explicit entries accepted when the active process state was first initialized, in their original order. It does not add omitted defaults or expose internal settings derived from those entries.

The entry array and any string or blob payloads are owned by instance and remain valid until ovstage_destroy_instance() is called. The caller must not free or modify them. The caller owns only the outer ovstage_config_t value written to out_config.

Parameters:
  • instance – Initialized ovstage instance.

  • out_config – [out] Borrowed view of the instance’s process config.

Returns:

OVSTAGE_OK on success; OVSTAGE_ERROR_INVALID_ARGUMENT if either argument is NULL.

ovstage_api_status_t ovstage_shutdown(void)#

Release one reference acquired by ovstage_initialize().

On the last outstanding reference (explicit initializations and live instances both count), process-scoped state is torn down.

Returns:

OVSTAGE_OK on success; OVSTAGE_ERROR_INVALID_ARGUMENT if called without a matching outstanding ovstage_initialize().

ovstage_api_status_t ovstage_set_log_callback(
ovstage_log_severity_t severity,
const ovx_string_t *channel_filter,
ovstage_log_callback_t callback,
void *user_data
)#

Install a process-global log callback.

Routes ovstage’s log messages (and messages from its USD support layer) to callback. Process-global: one callback for the whole process, replacing any previous one. Pass callback = NULL to disable delivery.

Messages are delivered asynchronously on a dedicated dispatcher thread, so the callback never runs on the logging hot path and invocations are serialized. Use ovstage_flush_log to force pending messages through before a checkpoint.

The dispatcher thread and runtime log hook are created lazily on the first non-null callback and torn down when the callback is cleared, so a client that never installs a callback pays nothing. Passing callback = NULL flushes any pending messages to the current callback and then disables delivery.

When ovstage runs standalone (the shipped package used directly), this callback is the only diagnostics sink: with no callback installed the runtime prints nothing to stdout/stderr — except a final sanitized message when a fatal error aborts the process — and operation failures are reported through status codes and the error string accessors regardless of logging. When ovstage is embedded in a host application that configures its own logging, console behavior follows the host’s configuration. USD-support-layer messages carry the diagnostic text only (statuses at OVSTAGE_LOG_INFO, warnings and USD coding errors at OVSTAGE_LOG_WARNING, other errors at OVSTAGE_LOG_ERROR), never call-site file/line details.

Requires the ovstage runtime to be bootstrapped (an ovstage_initialize() or a live instance); otherwise returns OVSTAGE_ERROR_OP_FAILED. Keep a process reference (or clear the callback) before releasing the last one — the last ovstage_shutdown / instance destroy flushes and tears the bridge down.

Parameters:
  • severity – Default severity threshold for channels not matched by a rule in channel_filter. Messages below it are dropped. OVSTAGE_LOG_NONE drops all by default.

  • channel_filter – Optional comma-separated <channel>=<level> list (e.g. “omni.ovstage=verbose”). NULL applies severity uniformly. Levels: verbose|debug|info|warn| warning|error|fatal|none.

  • callback – Callback to receive messages, or NULL to disable.

  • user_data – Context passed to each callback invocation.

Returns:

OVSTAGE_OK on success; OVSTAGE_ERROR_INVALID_ARGUMENT if the filter string fails to parse; OVSTAGE_ERROR_OP_FAILED if the runtime is not bootstrapped.

ovstage_api_status_t ovstage_flush_log(ovstage_timeout_ns_t timeout)#

Block until all log messages emitted before this call have been delivered through the callback.

Point-in-time barrier: messages produced concurrently with or after this call are not guaranteed to be included. Returns OVSTAGE_OK immediately if no callback is installed (nothing is buffered).

Parameters:
  • timeout – Max time to wait. OVSTAGE_TIMEOUT_INFINITE blocks; 0 polls.

Returns:

OVSTAGE_OK if drained (or no callback installed); OVSTAGE_ERROR_TIMEOUT if not drained within timeout.

ovstage_api_status_t ovstage_create_instance(
const ovstage_instance_desc_t *desc,
ovstage_instance_t **out_instance
)#

Create an ovstage instance.

Parameters:
  • desc – Configuration descriptor.

  • out_instance – [out] Receives the new instance (vtable + context bundle).

Returns:

OVSTAGE_OK on success.

Post:

Caller owns the instance; destroy via ovstage_destroy_instance.

ovstage_api_status_t ovstage_destroy_instance(
ovstage_instance_t *instance
)#

Release an ovstage instance handle.

Another component may retain a distinct handle to the same stage. In that case the shared stage state and resources remain alive until the final retained handle is released. In-flight work remains valid and must be completed and released through a surviving handle.

Parameters:
  • instance – Instance handle to release. May be NULL (no-op).

Pre:

If this is the final handle retaining the stage, all operations, handles, and result payloads associated with the stage must be released first.

Pre:

No other thread may invoke any ovstage_* wrapper, vtable slot, or internal accessor on this instance while or after destroy runs. The supplied bundle is deallocated before this call returns; any concurrent or post-destroy use of that handle is a use-after-free.

ovstage_api_status_t ovstage_get_usd_stage_id(
ovstage_instance_t *instance,
uint64_t *out_usd_stage_id
)#

Get the source USD stage id backing this ovstage instance.

TEMPORARY: this accessor is a stopgap and is expected to be removed. Consumers should read stage data (units, attributes, relationships) through the ovstage query/read API rather than reaching back to the USD stage; do not build a lasting dependency on this entry point.

An ovstage instance with USD population support mirrors a USD stage (populated by ovpopulation or the host). This returns the runtime identifier of that source stage.

Parameters:
  • instance – The ovstage instance.

  • out_usd_stage_id – [out] Receives the USD stage id.

Returns:

OVSTAGE_OK on success.

Returns:

OVSTAGE_ERROR_INVALID_ARGUMENT if instance or out_usd_stage_id is NULL.

Returns:

OVSTAGE_ERROR_NOT_SUPPORTED if the instance has no associated USD stage.

ovstage_enqueue_result_t ovstage_clone(
ovstage_instance_t *instance,
ovx_string_t source_path,
const ovx_string_t *target_paths,
size_t num_target_paths,
ovstage_ordinal_t ordinal
)#

Enqueue an asynchronous operation to clone the subtree under the source path to one or more target paths in the runtime stage representation.

The source path must exist in the stage; a missing source is rejected with OVSTAGE_ERROR_NOT_FOUND (surfaced through wait_op). The target paths must not already exist; a target that does is rejected with OVSTAGE_ERROR_PRIM_NOT_FOUND (the create-only convention shared with INSERT-mode writes), before any prim is created, so a batch mixing fresh and existing targets clones nothing. A prim that already exists below an absent target root is merged into, unless it holds a cloned attribute with a different type, carries a prim type other than that of its typed source prim, or lacks a cloned attribute connection that has no value column, which fails the clone with OVSTAGE_ERROR_OP_FAILED before any prim is created. The per-op error string (ovstage_get_last_op_error) names the missing source or the targets that already exist, e.g. ovstage_clone: target prim already exists at /World/Tile3’`, so a large batch can be corrected in one round-trip.

Data-plane peer of ovrtx’s ovrtx_clone_usd (the _usd postfix is dropped), but — like write_attribute / delete_attributes — clone is an ordinal-keyed write: it carries an ordinal and is rejected with OVSTAGE_ERROR_WRITE_FLOOR_VIOLATION when ordinal is at or below an applicable seal or conflicts with retained target cell/lifecycle history under the configured ordinal admission policy. Each copied attribute records a change at ordinal. The STRICTLY_INCREASING policy requires a newer ordinal for later customization even before sealing; NONDECREASING allows customization at the same unsealed ordinal but rejects older intersecting history. FLOOR_ONLY skips retained-history and separate prim-lifecycle admission. Every policy preserves the applicable global, source and destination attribute floors. Disjoint target cells may share an ordinal. The call returns immediately with an ovstage_enqueue_result_t (status + op_index); await completion through the vtable wait_op (and release it with release_op) like any other data-plane operation. An asynchronous failure makes wait_op return OVSTAGE_ERROR_OP_FAILED; fetch_clone_result returns the underlying error, and get_last_op_error describes it. A synchronous rejection is returned in the enqueue status. The clone’s completion report includes the targets’ scene hierarchy subtree sizes after cloning, summed over all targets (see ovstage_clone_result_t). It is available through ovstage_fetch_clone_result from completion until release_op.

Path-bearing values that target the source subtree are rebased to the corresponding target subtree. This includes relationship targets (e.g. material:binding, skel:skeleton), scalar/array path values, and USD attribute connections. Paths outside the source subtree are copied unchanged, so clones can continue to reference shared materials and other shared resources. Every cloned column is ordinal-change-tracked: attribute values, relationship targets, an attribute connection that has no value column, prim type / applied schema / ancestor type metadata, and each typed identity of an attribute name that has different types on different source prims. Scene hierarchy changes, such as the source/target parents’ child lists, are not.

Remark

Target paths are expected to be disjoint and outside the source subtree. A target nested under another target of the same batch is not rejected today; its prims are counted as enumerated in the completion report. A target that is also a prim the clone creates under another target (e.g. /World/T and /World/T/Inner for a source with a child Inner) fails with OVSTAGE_ERROR_OP_FAILED and clones nothing. A target path with a property part (e.g. /World/T.attr) cannot hold the source’s child prims; if the source has any, the clone fails with OVSTAGE_ERROR_OP_FAILED and clones nothing.

Remark

Merging into a prim that already exists below an absent target root is partial. The existing prim keeps the attributes it has that the source prim lacks, its applied schemas and ancestor types become the union of its own and the source prim’s, and if the source prim has no prim type it keeps its own. For an attribute name that the source prim holds both as a value and as a connection, the value is merged, but the connection is copied (and rebased) only when the existing prim already has a connection under that name; otherwise it is not cloned and the clone still succeeds. A newly created target receives both. Either way such a name is change-tracked under its value type only, and an existing prim that holds only the connection under that name fails the clone with OVSTAGE_ERROR_OP_FAILED. Delete such a prim before cloning onto it to get an exact copy.

Remark

Before its merge and ordinal checks on the target prims, a clone interns the path of every prim it would create or merge into (each source subtree prim under each target root). Interned paths are not released individually, so a clone that fails after that point keeps them: each such clone that uses new target names keeps memory proportional to source prims times target roots. Reusing the same names avoids new path entries, but repeated registration can extend their lifetime. Interned paths can stay allocated after the instance is destroyed.

Parameters:
  • instance – The ovstage instance.

  • source_path – Path to the source subtree to clone.

  • target_paths – Array of target paths to clone to.

  • num_target_paths – Number of target paths to clone to.

  • ordinal – Ordinal for this clone. Must exceed the global write floor and the effective seals of the source subtree’s attributes. For nonempty targets, it must also exceed the effective seals of all reproduced destination attributes, including copied prim type, applied schema and ancestor type metadata. Independently, the configured history policy checks retained destination-cell changes and every derived target prim’s lifecycle, including the effective usd-path floor. FLOOR_ONLY skips retained-history and separate lifecycle admission. All checks run at execution time. With no targets, only the global and source-attribute floor checks apply.

Returns:

Enqueue result with status + op_index.

  • status == OVSTAGE_OK if the operation was enqueued successfully.

  • OVSTAGE_ERROR_INVALID_ARGUMENT if a target path is empty or is not a valid path, or appears more than once in target_paths (rejected at enqueue; the offending path is reported through ovstage_get_last_error).

  • a non-OK status if the enqueue was rejected (e.g. invalid arguments, or the required runtime capability is unavailable). Per-op execution errors — including OVSTAGE_ERROR_WRITE_FLOOR_VIOLATION, OVSTAGE_ERROR_NOT_FOUND (missing source), OVSTAGE_ERROR_PRIM_NOT_FOUND (a target already exists), and OVSTAGE_ERROR_OP_FAILED (a merge conflict) — are surfaced through wait_op (as OVSTAGE_ERROR_OP_FAILED plus the message) and with their own code through ovstage_fetch_clone_result.

ovstage_api_status_t ovstage_fetch_clone_result(
ovstage_instance_t *instance,
ovstage_op_id_t op_id,
ovstage_timeout_ns_t timeout,
ovstage_clone_result_t *out_result
)#

Fetch the completion report of a clone operation.

Waits up to timeout (0 polls, OVSTAGE_TIMEOUT_INFINITE blocks — the ovstage_fetch_* convention) for the clone identified by op_id (the op_index returned by ovstage_clone) to complete, then copies its report. The report is per-op completion state like the op’s error string: available from completion until release_op. Fetching does not release the op; call release_op afterwards as for any other operation.

Remark

Like wait_op, an infinite-timeout fetch may execute the still-pending clone inline on the calling thread.

Parameters:
  • instance – The ovstage instance.

  • op_id – The clone’s op id.

  • timeout – Maximum time to wait for completion, in nanoseconds.

  • out_result – [out] Receives the report on OVSTAGE_OK; zeroed otherwise.

Returns:

OVSTAGE_OK and the report on success.

Returns:

OVSTAGE_ERROR_INVALID_ARGUMENT if instance or out_result is NULL.

Returns:

OVSTAGE_ERROR_INVALID_HANDLE if op_id is not a live clone operation of this instance: OVSTAGE_INVALID_OP_ID, an id of another kind of operation, or a clone whose op has already been released.

Returns:

OVSTAGE_ERROR_TIMEOUT if the clone has not completed within timeout; the op stays waitable.

Returns:

the clone’s own failure status — OVSTAGE_ERROR_NOT_FOUND (missing source), OVSTAGE_ERROR_PRIM_NOT_FOUND (a target already existed), OVSTAGE_ERROR_WRITE_FLOOR_VIOLATION, OVSTAGE_ERROR_OUT_OF_MEMORY or OVSTAGE_ERROR_INTERNAL (an internal failure, which can also be reported after the clone was applied, so the targets may exist), otherwise OVSTAGE_ERROR_OP_FAILED — if the clone ran and failed, with the message available through ovstage_get_last_op_error(op_id).

ovstage_enqueue_result_t ovstage_get_hierarchy(
ovstage_instance_t *instance,
ovx_primpath_list_t prim_paths,
ovstage_ordinal_t ordinal,
ovstage_hierarchy_relation_t relation,
ovstage_hierarchy_handle_t *out_hierarchy_handle
)#

Enqueue a hierarchy lookup for a batch of prims.

prim_paths is an immutable ordered ovx_primpath_list_t. The list is copied during enqueue; callers may destroy their user-owned list after this call returns OVSTAGE_OK. The operation returns parent, child or sibling relations for each input prim. Fetch the per-input results with ovstage_fetch_hierarchy_result.

Hierarchy lookups read the current committed hierarchy when the operation executes. They do not select a historical snapshot.

Parameters:
  • instance – The ovstage instance.

  • prim_paths – Ordered prim path list to inspect.

  • ordinal – Echoed as a caller-supplied tag; it does not select a historical hierarchy snapshot.

  • relation – Hierarchy direction to return for each input prim.

  • out_hierarchy_handle – [out] Receives the lookup handle.

Returns:

Enqueue result with status + op_index. Per-op execution failures are surfaced through ovstage_wait_op + ovstage_get_last_op_error.

ovstage_api_status_t ovstage_fetch_hierarchy_result(
ovstage_instance_t *instance,
ovstage_hierarchy_handle_t hierarchy_handle,
ovstage_hierarchy_result_t *out_result
)#

Fetch the result of a completed hierarchy lookup batch.

Use ovstage_wait_op with the op_index returned by ovstage_get_hierarchy to wait for completion before fetching. This function does not block.

Returns:

OVSTAGE_OK on success, OVSTAGE_ERROR_TIMEOUT if the producer op has not completed, OVSTAGE_ERROR_OP_FAILED if the underlying enqueue failed.

Post:

On OVSTAGE_OK, pointers in *out_result remain valid until ovstage_release_hierarchy_result.

ovstage_api_status_t ovstage_release_hierarchy_result(
ovstage_instance_t *instance,
const ovstage_hierarchy_result_t *result
)#

Release a fetched hierarchy result payload.

After this call, pointers in *result are invalid.

ovstage_enqueue_result_t ovstage_release_hierarchy(
ovstage_instance_t *instance,
ovstage_hierarchy_handle_t handle
)#

Enqueue release of a hierarchy handle.

Per-handle ordered: the release waits for any in-flight fetch on the same handle to complete before reclaiming resources.

ovstage_api_status_t ovstage_get_hierarchy_computation_models(
ovstage_instance_t *instance,
const ovstage_hierarchy_computation_model_desc_t **out_models,
size_t *out_model_count
)#

Return the hierarchy computation models supported by this runtime.

The descriptor array lists the ovstage_hierarchy_computation_model_id_t concrete values and selectors supported by this instance. Names and descriptions are implementation-owned and valid for the lifetime of the instance.

Parameters:
  • instance – The ovstage instance.

  • out_models – [out] Receives the implementation-owned descriptor array.

  • out_model_count – [out] Receives the number of descriptors.

Returns:

OVSTAGE_OK on success.

ovstage_enqueue_result_t ovstage_compute_hierarchy(
ovstage_instance_t *instance,
ovstage_hierarchy_computation_model_id_t computation_model_id,
ovstage_ordinal_t input_ordinal,
ovstage_ordinal_t output_ordinal
)#

Enqueue hierarchy computation using a runtime computation model.

This computes hierarchy-derived world transforms with the selected runtime model. It does not update derived visibility.

The caller supplies the output ordinal assigned to hierarchy-derived results. The computation records an omni:fabric:worldMatrix change at output_ordinal for every world-matrix row it rewrote. The write floor of that column does not limit output_ordinal: a record can land at a sealed ordinal. A consumer that read that ordinal before the computation does not see those rows. Compute before you seal the ordinal when consumers need a complete snapshot at it. A write-floor advance that covers the column runs the runtime default model when the hierarchy is dirty, and records the rewritten rows at the advance ordinal, before the floor moves. Only rows a computation rewrote are recorded this way. A direct write to the column is recorded by the write itself. Ordinal-range reads of the column select the recorded prims.

Remark

The current implementation ignores input_ordinal and computes from the latest committed inputs. Inputs committed after input_ordinal are part of the computation.

Parameters:
  • instance – The ovstage instance.

  • computation_model_id – Public model enum value: a concrete model, a DEFAULT_* alias, or RUNTIME_DEFAULT to use the process default captured when the instance was created.

  • input_ordinal – Ordinal of the hierarchy inputs. See the remark above on how the current implementation handles it.

  • output_ordinal – Ordinal assigned to hierarchy-derived outputs.

Returns:

Enqueue result with status + op_index. Per-op execution failures are surfaced through ovstage_wait_op + ovstage_get_last_op_error.

Types#

Backend-owned enums, handles, and result structures.

ovstage-specific data-plane types.

This header contains the type surface that is specific to ovstage. The generic vtable runtime types remain in ovstage_api/ovstage_api_types.h.

Version

0.3.0

Date

2026-06-17

Defines

OVSTAGE_INVALID_HIERARCHY_HANDLE#
OVSTAGE_INVALID_HIERARCHY_RESULT_ID#
OVSTAGE_INVALID_HIERARCHY_COMPUTATION_MODEL_ID#

Typedefs

typedef void (*ovstage_log_callback_t)(ovstage_log_severity_t severity, double timestamp, ovx_string_t message, void *user_data)#

Callback for receiving ovstage log messages.

Process-global (see ovstage_set_log_callback) and may be invoked from any thread; the implementation serializes invocations, so the callback body needs no mutex of its own for its own state. message is valid only for the duration of the call — copy it to retain.

Param severity:

Severity of the message.

Param timestamp:

Wall-clock seconds since the epoch.

Param message:

Message text (valid only during the call).

Param user_data:

Context passed to ovstage_set_log_callback.

typedef uint64_t ovstage_hierarchy_handle_t#

Hierarchy handle - identifies an enqueued hierarchy lookup batch.

typedef uint64_t ovstage_hierarchy_result_id_t#

Opaque identity for a fetched hierarchy result payload.

Enums

enum ovstage_ordinal_admission_policy_t#

Admission of mutations against retained value and prim-lifecycle history.

The policy is process-scoped and captured by each new instance. All modes enforce the operation’s write floors and retain successful change history; they do not enable historical payload storage or relax type/INSERT checks. History comparisons apply to affected cells and prim lifecycles; disjoint cells may share an ordinal.

NONDECREASING remains the default. STRICTLY_INCREASING is experimental and represents the intended direction for a future default; FLOOR_ONLY is retained for backward compatibility.

Values:

enumerator OVSTAGE_ORDINAL_ADMISSION_DEFAULT#

No override: inherit active process state; a fresh lifetime uses NONDECREASING.

enumerator OVSTAGE_ORDINAL_ADMISSION_FLOOR_ONLY#

Check write floors without rejecting retained value or lifecycle conflicts.

enumerator OVSTAGE_ORDINAL_ADMISSION_NONDECREASING#

Reject ordinals older than intersecting retained changes; equal ordinals are allowed (the default).

enumerator OVSTAGE_ORDINAL_ADMISSION_STRICTLY_INCREASING#

Reject ordinals older than or equal to intersecting retained changes.

enum ovstage_config_key_type_t#

Key-type tag for ovstage_config_entry_t; selects the valid key/value union members.

Values:

enumerator OVSTAGE_CONFIG_KEY_TYPE_BOOL#
enumerator OVSTAGE_CONFIG_KEY_TYPE_INT64#
enumerator OVSTAGE_CONFIG_KEY_TYPE_UINT64#
enumerator OVSTAGE_CONFIG_KEY_TYPE_DOUBLE#
enumerator OVSTAGE_CONFIG_KEY_TYPE_STRING#
enumerator OVSTAGE_CONFIG_KEY_TYPE_BLOB#
enumerator OVSTAGE_CONFIG_KEY_TYPE_COUNT#
enum ovstage_config_bool_t#

Boolean config keys.

Value type: bool. (None defined yet.)

Values:

enumerator OVSTAGE_CONFIG_BOOL_COUNT#
enum ovstage_config_int64_t#

Int64 config keys.

Value type: int64_t. (None defined yet.)

Values:

enumerator OVSTAGE_CONFIG_INT64_COUNT#
enum ovstage_config_uint64_t#

Uint64 config keys.

Value type: uint64_t.

Values:

enumerator OVSTAGE_CONFIG_RUNTIME_DEFAULT_HIERARCHY_COMPUTATION_MODEL#

ovstage_hierarchy_computation_model_id_t override used for automatic hierarchy-derived transform updates and by OVSTAGE_HIERARCHY_COMPUTATION_MODEL_RUNTIME_DEFAULT.

Defaults to OVSTAGE_HIERARCHY_COMPUTATION_MODEL_CPU_INCREMENTAL. An entry whose value is RUNTIME_DEFAULT is ignored.

enumerator OVSTAGE_CONFIG_RUNTIME_DEFAULT_ORDINAL_ADMISSION_POLICY#

ovstage_ordinal_admission_policy_t for data-plane mutation admission.

Defaults to NONDECREASING on a fresh process-state lifetime. DEFAULT means no override, including while another policy is active.

enumerator OVSTAGE_CONFIG_UINT64_COUNT#
enum ovstage_config_double_t#

Double config keys.

Value type: double. (None defined yet.)

Values:

enumerator OVSTAGE_CONFIG_DOUBLE_COUNT#
enum ovstage_config_string_t#

String config keys.

Value type: ovx_string_t.

Values:

enumerator OVSTAGE_CONFIG_BINARY_PACKAGE_ROOT_PATH#

Directory of the ovstage binary package (the package bin/).

The static loader (ovstage-static) loads the ovstage shared library from here and ovstage resolves its bundled plugins/USD schemas relative to it. When absent, the loader defaults to its own module directory. Ignored by the ovstage shared library’s own ovstage_initialize.

enumerator OVSTAGE_CONFIG_STRING_COUNT#
enum ovstage_config_blob_t#

Blob config keys.

Value type: ptr + size. (None defined yet.)

Values:

enumerator OVSTAGE_CONFIG_BLOB_COUNT#
enum ovstage_log_severity_t#

Log severity levels.

Values follow the underlying log-level ordering.

Values:

enumerator OVSTAGE_LOG_VERBOSE#

Most verbose (debug/trace).

enumerator OVSTAGE_LOG_INFO#

Informational.

enumerator OVSTAGE_LOG_WARNING#

Warning; operation continues.

enumerator OVSTAGE_LOG_ERROR#

Error; operation may have failed (fatal is reported here too).

enumerator OVSTAGE_LOG_NONE#

Threshold sentinel: as a filter level, disables all logging.

Never delivered to the callback.

enum ovstage_hierarchy_computation_model_id_t#

Public hierarchy computation model identifiers.

Hierarchy computation models update hierarchy-derived world transforms owned by the backing runtime. An explicit ovstage_compute_hierarchy call does not update derived visibility. The enum values are stable API inputs for ovstage_compute_hierarchy.

Not every implementation, platform, or build supports every concrete model below. Call ovstage_get_hierarchy_computation_models to discover the concrete models and selectors advertised by the current ovstage instance, along with their display names and descriptions.

The DEFAULT_* aliases are semantic convenience choices for callers that only care about CPU vs GPU placement. They intentionally alias concrete entries instead of introducing extra model IDs, so catalog discovery remains stable and duplicate-free.

Values:

enumerator OVSTAGE_HIERARCHY_COMPUTATION_MODEL_INVALID#

Invalid/sentinel value; never accepted by ovstage_compute_hierarchy.

enumerator OVSTAGE_HIERARCHY_COMPUTATION_MODEL_CPU_INCREMENTAL#

Incrementally update hierarchy-derived stage data on CPU.

enumerator OVSTAGE_HIERARCHY_COMPUTATION_MODEL_GPU_INCREMENTAL#

Incrementally update hierarchy-derived stage data on GPU.

enumerator OVSTAGE_HIERARCHY_COMPUTATION_MODEL_GPU_GLOBAL#

Globally recompute hierarchy-derived stage data on GPU.

enumerator OVSTAGE_HIERARCHY_COMPUTATION_MODEL_RUNTIME_DEFAULT#

Use the runtime default captured when this ovstage instance was created.

The process default is configured through OVSTAGE_CONFIG_RUNTIME_DEFAULT_HIERARCHY_COMPUTATION_MODEL and defaults to CPU_INCREMENTAL.

enumerator OVSTAGE_HIERARCHY_COMPUTATION_MODEL_DEFAULT_CPU#

Default CPU hierarchy computation model for this API revision.

enumerator OVSTAGE_HIERARCHY_COMPUTATION_MODEL_DEFAULT_GPU#

Default GPU hierarchy computation model for this API revision.

enum ovstage_hierarchy_relation_t#

Hierarchy relation to inspect for each input prim.

Values:

enumerator OVSTAGE_HIERARCHY_PARENT#

Parent prim path; result count is 0 or 1.

enumerator OVSTAGE_HIERARCHY_CHILDREN#

Direct child prim paths.

enumerator OVSTAGE_HIERARCHY_SIBLINGS#

Other prims with the same direct parent.

struct ovstage_instance_desc_t#
#include <ovstage_types.h>

Configuration for creating an ovstage instance.

Note

GPU device configuration is intentionally omitted; see “Deferred Design

Items” in

ovstage.h.

Public Members

const char *name#

Optional instance name for debugging.

May be NULL.

struct ovstage_build_info_t#
#include <ovstage_types.h>

Build information embedded in an OVStage native library.

String fields are borrowed UTF-8 views. Their lengths exclude the trailing NUL terminator, and their storage remains valid for the lifetime of the loaded library. Future versions may append fields; use struct_size to determine which fields are present.

Public Members

uint32_t struct_size#

Size of this struct in bytes.

uint32_t build_number#

Numeric CI/local build number.

ovx_string_t build_string#

Full version, build number, and source revision.

ovx_string_t git_branch#

Source branch used for the build.

ovx_string_t git_hash#

Source revision used for the build.

ovx_string_t build_location#

Build-system/location identifier.

struct ovstage_config_entry_t#
#include <ovstage_types.h>

A single config entry.

key_type selects the valid key/value union members.

Public Members

ovstage_config_key_type_t key_type#
ovstage_config_bool_t bool_key#
ovstage_config_int64_t int64_key#
ovstage_config_uint64_t uint64_key#
ovstage_config_double_t double_key#
ovstage_config_string_t string_key#
ovstage_config_blob_t blob_key#
union ovstage_config_entry_t key#
bool bool_value#
int64_t int_value#
uint64_t uint_value#
double double_value#
ovx_string_t string_value#
const void *data#
size_t size#
struct ovstage_config_entry_t blob_value#
union ovstage_config_entry_t value#
struct ovstage_config_t#
#include <ovstage_types.h>

Process configuration passed to ovstage_initialize().

NULL, or entry_count 0, uses defaults on the first process reference and inherits active settings on subsequent initializations.

Public Members

const ovstage_config_entry_t *entries#
size_t entry_count#
struct ovstage_clone_result_t#
#include <ovstage_types.h>

Completion report of a finished ovstage_clone operation.

Plain values copied out by ovstage_fetch_clone_result; nothing to release. prims_cloned sums the sizes of the targets’ scene hierarchy subtrees after cloning, including each target root. It counts prims created or merged into and any prims already attached beneath them. A prim whose path lies beneath a target but remains detached from its scene hierarchy is not counted. For disjoint targets that merge into no existing prims, it equals source_prim_count * target_count. A zero-target clone reports {ordinal, 0, source_prim_count, 0}.

Remark

Target paths are expected to be disjoint and outside the source subtree; a target nested under another target is counted as enumerated.

Public Members

ovstage_ordinal_t ordinal#

Ordinal the clone was recorded at.

size_t target_count#

num_target_paths as submitted.

size_t source_prim_count#

Prims in the source subtree, root inclusive.

size_t prims_cloned#

Prims in all target scene hierarchy subtrees after cloning.

struct ovstage_hierarchy_item_t#
#include <ovstage_types.h>

Per-input hierarchy result metadata.

path_offset and path_count select this input’s relation paths from the flattened ovstage_hierarchy_result_t::paths array. Empty relations return OVSTAGE_OK with path_count 0. Missing input prims report OVSTAGE_ERROR_NOT_FOUND in the item status without failing the whole fetched batch.

Public Members

ovstage_api_status_t status#
size_t path_offset#
size_t path_count#
struct ovstage_hierarchy_result_t#
#include <ovstage_types.h>

Result of a fetched hierarchy lookup batch.

items has one entry for each input path in the submitted ovx_primpath_list_t, in the same order. paths is a flattened array of ovstage-owned string-or-token views referenced by item offsets/counts. ordinal echoes the caller-supplied value from ovstage_get_hierarchy; it tags the result but does not identify a selected historical hierarchy snapshot. Both arrays remain valid until ovstage_release_hierarchy_result.

Public Members

ovstage_hierarchy_result_id_t hierarchy_result_id#
ovstage_ordinal_t ordinal#
const ovstage_hierarchy_item_t *items#
size_t input_count#
const ovx_string_or_token_t *paths#
size_t path_count#
struct ovstage_hierarchy_computation_model_desc_t#
#include <ovstage_types.h>

Description of a runtime-supported hierarchy computation model.

model_id is one of ovstage_hierarchy_computation_model_id_t. name is stable enough for logs/config files owned by the implementation; description is human-readable guidance.

Public Members

ovstage_hierarchy_computation_model_id_t model_id#
ovx_string_t name#
ovx_string_t description#

Population (USD → ovstage)#

Per-stage population state is created lazily on first use of any populate entry point and released automatically when the ovstage instance is destroyed via ovstage_destroy_instance.

Reserved prim attributes.

Every populated prim with a USD type name, other than an instance root (below), carries it as usd-prim-type, whatever put the prim in scope and whatever its properties are. A prim to which USD gives no type name is still populated but carries no usd-prim-type.

Every populated prim carries usd-schemas with the prim’s applied API schema names; a prim with none carries an empty set. A HAS predicate on it therefore matches every populated prim; use CONTAINS to select prims by a schema. An instance of a multiple-apply schema, such as CollectionAPI:lightLink, also adds the schema’s bare name, CollectionAPI.

Every populated prim with a known USD type carries the types it derives from as usd-ancestor-types, excluding its own type. A typeless prim, or a type no loaded schema declares, carries none. Use CONTAINS to select prims by a base type, such as every Boundable prim.

An instance root is the exception, in every domain. Its usd-prim-type is XformInstance, or ScopeInstance when it is a Scope, whatever its authored type. Its usd-schemas also carries GeomInstanceAPI, and GeomInstanceRootAPI when it is outside a prototype; no USD schema applies these names. Its usd-ancestor-types is Xformable alone. Where PHYSICS or a selector populates it, its authored type is usd-metadata:typeName. This does not apply when PHYSICS or a selector populates an instanceable prim authored below a PointInstancer, such as one inside its prototypes scope: it keeps its authored type and applied schemas, even alongside RENDERING, and carries neither instance tag. Without RENDERING it receives its normal USD ancestors; with RENDERING, population does not synthesize usd-ancestor-types at these authored paths. It still links its prototype, so the instancing queries list it as an instance root. RENDERING renders a PointInstancer’s prototypes from copies it makes under the instancer and populates no instance data at the authored path.

None of these depends on the selector’s property predicate. A selector that selects no properties at all still yields them.

What a USD value becomes in ovstage is fixed by its USD value type: the type USD reports for the attribute, which for a schema-declared attribute is the declared type. The rules below give the whole mapping; the per-type table is in the population documentation.

Remark

The RENDERING domain currently differs in a few ways. Prims it populates carry usd-schemas only when they have applied API schemas; a prim there with none, such as a typeless container, carries neither usd-prim-type nor usd-schemas. When RENDERING is selected, it provides usd-ancestor-types for every prim, and its sets differ in a few cases, such as Imageable on a typeless prim. Its usd-schemas carries further names no USD schema applies, such as PrimvarsAPI. With RENDERING alone, a Scope and a non-Scope instance root sharing a prototype may both carry the instance type of the first one encountered. The population documentation lists these cases. These are temporary limitations. Populated value types.

  • Numeric types keep their bytes. The dtype’s element type and bit width come from the USD scalar type and its lane count from the number of components, so float is {float, 32, 1}, double3 is {float, 64, 3}, int4 is {int, 32, 4}, and matrix4d is {float, 64, 16}.

  • A USD array populates with the same dtype as its element type and is_array = true. Everything else populates flat, one fixed-size value per prim.

  • String-like types normally do not populate as text. token, string, pathExpression and the halves of an asset are interned through the path dictionary and populate as {uint, 64, 1} ids, which a consumer resolves back through the dictionary. An asset is the exception in width: it carries the (authored, resolved) pair as {uint, 64, 2}. Schema-pinned exceptions are listed in the population guide.

  • An empty token, string, path expression, or asset half normally populates as id 0. It is a value USD authors and reads back, so it is populated rather than dropped: absence means the property was not authored, not that it was empty. A string pinned to the byte representation below instead populates as an empty OVSTAGE_SEMANTIC_STRING byte row.

  • The semantic records what the bytes mean. It comes from the USD type’s role where it has one (point3f to OVSTAGE_SEMANTIC_POINT, color3f to ..._COLOR, frame4d to ..._FRAME), and otherwise from the type itself (matrix4d to ..._MATRIX, quatf to ..._QUATERNION, timecode to ..._TIME_CODE, token to ..._TOKEN_ID, asset to ..._ASSET_PATH_ID, pathExpression to ..._PATH_EXPRESSION_STRING). A relationship’s targets populate as interned path ids with ..._RELATIONSHIP_PATH_ID.

  • **opaque** carries no value by definition, so nothing is populated for it and nothing is reported.

Some properties populate in a type their USD type does not predict, because the OVSTAGE_POPULATION_DOMAIN_RENDERING domain populates them in a fixed one and both domains must agree on a shared stage. The population guide lists them, with the schema or prim type each pin is gated on. A value that cannot be represented in the pinned type is skipped with a warning; the attribute keeps its required type and its last written value. This mismatch does not fail population.

A value authored in another numeric type than its schema declares is converted to the declared type as USD converts numeric values:

  • Conversion keeps the shape: scalar to scalar, array to array, vector to vector of the same dimension, over the bool, uchar, int, uint, int64, uint64, half, float and double scalars and the int, half, float and double vectors of 2, 3 and 4 components, in any role. Each scalar, element and component converts on its own.

  • To an integer or bool: an integer or bool value converts if it is in the declared type’s range (0 or 1 for bool); a floating-point value is truncated toward zero and converts if that is in range, and an infinity or NaN does not convert.

  • To floating point: every value converts, rounded to the declared type. A value beyond the declared type’s range becomes an infinity, and a nonzero value too small for it becomes zero. Infinities and NaN convert unchanged.

  • Every element and component must convert, or the whole value is skipped with a warning. The attribute keeps its declared type and its last written value.

  • Shape mismatches and nonnumeric type mismatches (token, string, asset and so on) also skip the value with a warning rather than failing population.

  • Re-authoring the property’s declared type or role replaces its column using FORCE attribute replacement; an unconvertible value does not replace it.

  • An attribute without a schema declaration uses its authored type, subject to the representation rules above.

Export reads the populated state rather than the USD source, so everything above carries over into exported USD; see ovstage_population_export.h. Path predicates.

OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_PATH and ..._IS_UNDER_PATH take an absolute prim path, or /. A property, target, or variant-selection path is rejected at enqueue.

Neither matches a prim inside a native instance. Populated ancestors.

A prim that OVSTAGE_POPULATION_DOMAIN_PHYSICS or a desc’s selectors put in scope is populated together with every one of its ancestor prims, so a consumer can walk the prim tree down to it however sparse the selection is.

An ancestor that no selector matches on its own merit carries none of the data a selected prim does — no attributes, relationships, or metadata — only the reserved ones above. It does carry the derived local-transform attributes below when it is xformable, which is what lets world-transform composition run the whole chain.

Populated USD metadata attributes.

Besides attribute and relationship values, population can surface USD metadata as attributes, under a reserved usd-metadata: prefix:

  • Prim metadata -> usd-metadata:<field>

  • Property (attribute/relationship) metadata -> <property>:usd-metadata:<field>

A metadatum inside a dictionary field (e.g. customData) extends <field> with the :-joined key path — the same separator USD itself uses to address subdictionary elements. Example attribute names:

  • usd-metadata:inactiveIds

  • usd-metadata:customData:physics:localSpaceVelocities

  • points:usd-metadata:interpolation

A path with an empty component — a leading, trailing or doubled : — names neither a field nor a key, and is rejected wherever one is taken.

The value uses the same type mapping as attribute values.

Defines

OVSTAGE_POPULATION_INVALID_OP_ID#
OVSTAGE_POPULATION_INVALID_USD_REFERENCE_HANDLE#
OVSTAGE_POPULATION_DEFAULT_TIME#

The time value that selects USD’s default time code rather than a numeric one.

Every population entry point taking a time takes it in seconds. Passing this instead evaluates each property at USD’s default time code.

The value is a NaN.

Never compare a time against it with . A NaN is not equal to itself, so time == OVSTAGE_POPULATION_DEFAULT_TIME is false even for the default time. Use ovstage_population_is_default_time instead.

Typedefs

typedef uint64_t ovstage_population_op_id_t#

Opaque id of an enqueued population operation, returned by the async entry points and passed to ovstage_population_wait_op.

Zero is never a live op id.

typedef uint64_t ovstage_population_usd_reference_handle_t#

Opaque handle to a USD reference added by ovstage_population_add_usd_reference_from_file / _from_string, passed to ovstage_population_remove_usd_reference to take it back out.

Reserved synchronously by the add call (so it is valid immediately, before the op runs) and freed by ovstage_population_remove_usd_reference, _reset_usd, or a fresh _open_usd_*. Zero is never a live handle.

Enums

enum ovstage_population_domain_t#

Coarse population domains for the canonical population entry points.

Bitmask — OR values together.

OVSTAGE_POPULATION_DOMAIN_NONE (0) selects no data domain: a domains argument of 0 populates nothing at all. Pass OVSTAGE_POPULATION_DOMAIN_ALL to populate all domains.

Values:

enumerator OVSTAGE_POPULATION_DOMAIN_NONE#
enumerator OVSTAGE_POPULATION_DOMAIN_RENDERING#

Meshes, lights, materials, and cameras.

enumerator OVSTAGE_POPULATION_DOMAIN_PHYSICS#

Colliders, rigid bodies, joints, articulations, and the physics schema attributes/relationships authored on them.

Every prim it populates also carries its composed USD type name as usd-metadata:typeName.

enumerator OVSTAGE_POPULATION_DOMAIN_ALL#

Functions

static inline bool ovstage_population_is_default_time(double time)#

Test whether a time selects USD’s default time code.

Use this rather than time == OVSTAGE_POPULATION_DEFAULT_TIME, which is false even for the default time.

Parameters:
  • time – A time in seconds, as passed to a population entry point.

Returns:

true if time selects the default time code, false if it names a numeric time.

ovstage_api_status_t ovstage_population_register_usd_schemas(
const ovx_string_t *paths,
size_t path_count
)#

Transform attributes.

For every prim that OVSTAGE_POPULATION_DOMAIN_PHYSICS or a desc’s selectors put in scope, and that is USD-xformable, population also derives the prim’s local transform. The attributes and their types are a contract consumers can rely on:

  • omni:xform — float64, 16 lanes, OVSTAGE_SEMANTIC_MATRIX. The 4x4 row-major local transform: the prim’s USD transform ops composed into a single matrix. This is the input ovstage_compute_hierarchy reads to derive world transforms.

  • omni:resetXformStack — bool. True when the prim resets the inherited parent transform stack, which world-transform composition honors.

  • omni:fabric:worldMatrix — float64, 16 lanes, OVSTAGE_SEMANTIC_MATRIX. Created, not maintained, and only when OVSTAGE_POPULATION_DOMAIN_RENDERING is not among the selected domains. ovstage_compute_hierarchy updates this value but does not create it, so population creates it for a qualifying prim that has none and thereafter leaves it alone: the value is written once, at creation, as the local transform, and later derived values come from hierarchy computation. Treat this provisional implementation-named attribute as read-only output; author transforms through omni:xform and omni:resetXformStack instead. A prim that stops being xformable loses it. With ..._RENDERING selected that domain owns it outright and population neither creates nor writes it.

A prim that is not xformable gets none of these. Being xformable does not by itself put a prim in scope: the derivation only ever applies to prims population already includes.

These names belong to population. A USD property named omni:xform, omni:resetXformStack or omni:fabric:worldMatrix, or omni:fabric:localMatrix / omni:fabric:resetXformStack (how the stage stores the first two), is never published, even when a selector names or matches it, on any prim. Register USD schema definitions with the USD runtime population reads through.

Population registers only what its USD build provides (the core Usd* schemas). Register any additional family your stages use, so population resolves each prim’s full schema-declared property set rather than only its authored properties.

Registering does not load schema code, so a family that ships a C++ library or Python module is usable for its definitions alone.

Remark

Only the paths themselves are checked here. What a descriptor contains is USD’s to validate: a malformed one, or an Includes pattern matching nothing, raises a USD diagnostic, contributes no plugins, and still returns OVSTAGE_OK — surfacing later as schema properties that never resolve.

Remark

Register before the first ovstage call that reads USD schema definitions — population and export both do. USD assembles its schema definitions once, on first read, and ignores plugins registered after that — a late family registers cleanly and contributes nothing. Such a call reports OVSTAGE_ERROR_OP_FAILED, and the plugins it registered cannot be taken back. If another USD consumer in the process reads schemas first, that cannot be detected and the call still reports success.

Remark

Process-scoped, thread-safe and irreversible: USD offers no counterpart removal. Re-registering a family is a no-op, not an error.

Remark

Callable on its own: it requires no prior ovstage_initialize() and no live ovstage instance.

Remark

Registering a family makes its definitions resolvable. It does not change which prims a population domain claims.

Parameters:
  • paths – Array of path_count paths, each a USD plugin descriptor (plugInfo.json) or a directory containing one. A descriptor’s Includes are followed. Symbolic links (and directory junctions on Windows) are followed, but a linked descriptor’s relative Root, ResourcePath and Includes resolve beside the link, not beside its target. Link the directory holding a descriptor, or link the descriptor together with the files it refers to; otherwise the call succeeds but the definitions those paths lead to never resolve. Each ovx_string_t must remain valid until this call returns.

  • path_count – Number of entries in paths. Zero is a no-op.

Returns:

OVSTAGE_OK on success; OVSTAGE_ERROR_INVALID_ARGUMENT for a NULL paths with a non-zero path_count or an empty entry; OVSTAGE_ERROR_NOT_FOUND if an entry names no readable descriptor; OVSTAGE_ERROR_OP_FAILED if the call came too late (see below). Detail in ovstage_population_get_last_error. Both argument failures are checked before anything registers, so a rejected call leaves the process untouched and can be corrected and retried.

ovstage_population_enqueue_result_t ovstage_population_open_usd_from_file(
ovstage_instance_t *stage,
ovx_string_t path,
ovstage_ordinal_t ordinal,
double time,
uint32_t domains
)#

Enqueue an asynchronous operation to populate an ovstage instance from a USD file.

Loads path as this instance’s USD source, replacing whatever source was loaded before, and populates from it in one operation. Replacing the source does not remove what an earlier populate wrote: see “Repopulating an instance” above. Initial population is one-shot; live edits made afterwards are picked up by ovstage_population_apply_usd_changes / ovstage_population_apply_usd_time.

Per-stage population state is created lazily on first use and released automatically when stage is destroyed.

Remark

A rejected enqueue leaves ordinal and the previously populated content untouched, so the caller may retry at the same ordinal. A failure reported by ovstage_population_wait_op carries no such guarantee: repopulate at a higher ordinal.

Parameters:
  • stage – ovstage instance to populate into.

  • path – Filesystem path to a .usda / .usdc / .usd file, or an Omniverse Nucleus URL (omniverse://<server>/<path>.usd), as an ovx_string_t view.

  • ordinal – Accumulating ordinal owned by the caller. Must be greater than the effective write floor at execution time; a new instance’s floor is 0, so initial population starts at 1.

  • time – Time in seconds at which to evaluate attributes; converted to a USD time code via the stage’s timeCodesPerSecond. OVSTAGE_POPULATION_DEFAULT_TIME evaluates at USD’s default time code instead.

  • domains – Bitmask of ovstage_population_domain_t selecting which data domains to populate. 0 (DOMAIN_NONE) populates nothing; pass OVSTAGE_POPULATION_DOMAIN_ALL for everything.

Returns:

Enqueue result (see ovstage_population_enqueue_result_t). A rejected enqueue is reported in status; failures while the op runs — the stage cannot be populated, the file cannot be opened, or population failed — are surfaced by ovstage_population_wait_op, with detail in ovstage_population_get_last_error.

ovstage_population_enqueue_result_t ovstage_population_open_usd_from_string(
ovstage_instance_t *stage,
ovx_string_t usda,
ovstage_ordinal_t ordinal,
double time,
uint32_t domains
)#

Enqueue an asynchronous operation to populate an ovstage instance from an inline USDA string.

Same semantics as ovstage_population_open_usd_from_file but the USD content is provided directly as text instead of loaded from disk.

Remark

A rejected enqueue leaves ordinal and the previously populated content untouched, so the caller may retry at the same ordinal. A failure reported by ovstage_population_wait_op carries no such guarantee: repopulate at a higher ordinal.

Parameters:
  • stage – ovstage instance to populate into.

  • usda – USDA content (e.g. “#usda 1.0\n…”) as an ovx_string_t view.

  • ordinal – Accumulating ordinal owned by the caller. Must be greater than the effective write floor at execution time; a new instance’s floor is 0, so initial population starts at 1.

  • time – Time in seconds; converted to a USD time code via the stage’s timeCodesPerSecond. OVSTAGE_POPULATION_DEFAULT_TIME evaluates at USD’s default time code instead.

  • domains – Bitmask of ovstage_population_domain_t selecting which data domains to populate. 0 (DOMAIN_NONE) populates nothing; pass OVSTAGE_POPULATION_DOMAIN_ALL for everything.

Returns:

Enqueue result (see ovstage_population_enqueue_result_t). A rejected enqueue is reported in status; failures while the op runs — the stage cannot be populated, the USDA content fails to parse, or population failed — are surfaced by ovstage_population_wait_op, with detail in ovstage_population_get_last_error.

ovstage_population_enqueue_result_t ovstage_population_open_usd_from_file_with_desc(
ovstage_instance_t *stage,
ovx_string_t path,
ovstage_ordinal_t ordinal,
double time,
const ovstage_population_desc_t *descs,
size_t desc_count
)#

Enqueue an asynchronous operation to populate an ovstage instance from a USD file, with an explicit population description.

Identical to ovstage_population_open_usd_from_file except that what to populate is given as an array of ovstage_population_desc_t rather than a bare domains bitmask. A single desc that carries only domains is exactly the shorter entry point.

Remark

A rejected enqueue leaves ordinal and the previously populated content untouched, so the caller may retry at the same ordinal. A failure reported by ovstage_population_wait_op carries no such guarantee: repopulate at a higher ordinal.

Parameters:
  • stage – ovstage instance to populate into.

  • path – Filesystem path to a .usda / .usdc / .usd file, or an Omniverse Nucleus URL (omniverse://<server>/<path>.usd), as an ovx_string_t view.

  • ordinal – Accumulating ordinal owned by the caller. Must be greater than the effective write floor at execution time; a new instance’s floor is 0, so initial population starts at 1.

  • time – Time in seconds at which to evaluate attributes; converted to a USD time code via the stage’s timeCodesPerSecond. OVSTAGE_POPULATION_DEFAULT_TIME evaluates at USD’s default time code instead.

  • descs – Array of descriptions selecting what to populate; their domains are OR-ed together and their selectors combined. Must stay valid only until this call returns. May be NULL when desc_count is 0.

  • desc_count – Number of entries in descs. 0 (or a NULL descs) selects nothing, as OVSTAGE_POPULATION_DOMAIN_NONE does.

Returns:

Enqueue result (see ovstage_population_enqueue_result_t). A rejected enqueue is reported in status; failures while the op runs — the stage cannot be populated, the file cannot be opened, or population failed — are surfaced by ovstage_population_wait_op, with detail in ovstage_population_get_last_error.

ovstage_population_enqueue_result_t ovstage_population_open_usd_from_string_with_desc(
ovstage_instance_t *stage,
ovx_string_t usda,
ovstage_ordinal_t ordinal,
double time,
const ovstage_population_desc_t *descs,
size_t desc_count
)#

Enqueue an asynchronous operation to populate an ovstage instance from an inline USDA string, with an explicit population description.

Same semantics as ovstage_population_open_usd_from_file_with_desc but the USD content is provided directly as text instead of loaded from disk.

Remark

A rejected enqueue leaves ordinal and the previously populated content untouched, so the caller may retry at the same ordinal. A failure reported by ovstage_population_wait_op carries no such guarantee: repopulate at a higher ordinal.

Parameters:
  • stage – ovstage instance to populate into.

  • usda – USDA content (e.g. “#usda 1.0\n…”) as an ovx_string_t view.

  • ordinal – Accumulating ordinal owned by the caller. Must be greater than the effective write floor at execution time; a new instance’s floor is 0, so initial population starts at 1.

  • time – Time in seconds; converted to a USD time code via the stage’s timeCodesPerSecond. OVSTAGE_POPULATION_DEFAULT_TIME evaluates at USD’s default time code instead.

  • descs – Array of descriptions selecting what to populate; their domains are OR-ed together and their selectors combined. Must stay valid only until this call returns. May be NULL when desc_count is 0.

  • desc_count – Number of entries in descs. 0 (or a NULL descs) selects nothing, as OVSTAGE_POPULATION_DOMAIN_NONE does.

Returns:

Enqueue result (see ovstage_population_enqueue_result_t). A rejected enqueue is reported in status; failures while the op runs — the stage cannot be populated, the USDA content fails to parse, or population failed — are surfaced by ovstage_population_wait_op, with detail in ovstage_population_get_last_error.

ovstage_population_enqueue_result_t ovstage_population_repopulate_usd_with_desc(
ovstage_instance_t *stage,
ovstage_ordinal_t ordinal,
double time,
const ovstage_population_desc_t *descs,
size_t desc_count
)#

Enqueue a wholesale population from the stage’s current USD source, without replacing or editing that source.

Retains the same USD stage, root and session layers, authored edits, composition state, and handles returned by the add-reference operations. It does not reopen files, reload layers, change the edit target, or adopt another USD stage. Every attribute the supplied descriptions select is written again from USD at time, replacing any value written directly into the ovstage since. Like an open, it removes nothing: prims and attributes the descriptions do not populate, including ones absent from USD, remain; delete them when they must not survive it. The supplied descriptions replace the population scope used by subsequent changes/time operations; they are not combined with the previous scope.

Parameters:
  • stage – Instance with an existing population source.

  • ordinal – Caller-owned accumulating ordinal; must be greater than the effective write floor at execution time.

  • time – Seconds, converted using the retained stage’s timeCodesPerSecond, or OVSTAGE_POPULATION_DEFAULT_TIME.

  • descs – Population descriptions, copied before the call returns. May be NULL when desc_count is zero (selects nothing).

  • desc_count – Number of descriptions.

Returns:

Enqueue status and op_index. No population state is rejected with OVSTAGE_ERROR_NOT_FOUND; malformed arguments are rejected with OVSTAGE_ERROR_INVALID_ARGUMENT. Await an accepted operation using ovstage_population_wait_op.

ovstage_population_enqueue_result_t ovstage_population_add_usd_reference_from_file(
ovstage_instance_t *stage,
ovx_string_t ref_file_path,
ovx_string_t target_path,
ovstage_population_usd_reference_handle_t *out_handle
)#

Enqueue an asynchronous operation to add a USD file as a reference at target_path.

This edits only the USD source, additively — existing USD content is left untouched. The shape of the merge depends on target_path (see below): a new prim is defined and ref_file_path referenced on it, the reference is added onto an existing prim, or — for the root “/” — the content is merged in at the top level. Like ovstage_population_reset_usd, it does not itself touch the ovstage; call ovstage_population_apply_usd_changes afterwards to propagate the added subtree into the ovstage (at the time and domains already in effect from the initial _open_usd_*).

Requires existing population state: call one of the _open_usd_* entry points first. The enqueue is rejected (status) if this stage has never been populated.

The subtree that ovstage_population_apply_usd_changes republishes depends on target_path. For a not-yet-existing prim path it is only the new prim and the content beneath it. For an existing prim path it is that prim and every prim beneath it, including prims the reference does not add or change; for the root “/” it is the whole stage. Every selected attribute of a republished prim is written at the apply ordinal even when its value is unchanged, so a read of that ordinal range reports it as changed, and the written value replaces any value written directly into the ovstage since. To add content without republishing existing prims, target a not-yet-existing prim path.

Parameters:
  • stage – ovstage instance.

  • ref_file_path – Filesystem path to a .usda / .usdc / .usd file, or an Omniverse Nucleus URL (omniverse://<server>/<path>.usd), as an ovx_string_t view — the layer to reference.

  • target_path – Absolute path (starting with ‘/’) selecting how the content is merged, additively in every case:

    • the root “/” — the content is merged in at the top level (its top-level prims are added to the stage without clobbering the existing stage’s units/upAxis/defaultPrim);

    • an existing prim path — the reference is added onto that prim and the referenced subtree composes in beneath it; the prim and its prior content are left in place;

    • a not-yet-existing prim path — a new prim is defined there (any missing ancestors are defined) and the layer referenced on it.

  • out_handle – [out, optional] Receives a handle for the added reference, reserved synchronously (valid before the op runs) for a later ovstage_population_remove_usd_reference. Set to OVSTAGE_POPULATION_INVALID_USD_REFERENCE_HANDLE if the enqueue is rejected. A non-invalid handle does not by itself mean the reference was added — await the op to confirm.

Returns:

Enqueue result (see ovstage_population_enqueue_result_t). A rejected enqueue is reported in status; failures while the op runs — the file cannot be opened, or the target path is not a valid absolute path — are surfaced by ovstage_population_wait_op, with detail in ovstage_population_get_last_error.

ovstage_population_enqueue_result_t ovstage_population_add_usd_reference_from_string(
ovstage_instance_t *stage,
ovx_string_t ref_str,
ovx_string_t target_path,
ovstage_population_usd_reference_handle_t *out_handle
)#

Enqueue an asynchronous operation to add inline USDA content as a reference at target_path.

Same semantics as ovstage_population_add_usd_reference_from_file but the USD content is provided directly as text instead of loaded from disk. The inline layer is held alive for as long as the reference exists (until ovstage_population_remove_usd_reference / _reset_usd / a fresh _open_usd_*).

Parameters:
  • stage – ovstage instance.

  • ref_str – USDA content (e.g. “#usda 1.0\n…”) as an ovx_string_t view — the layer to reference.

  • target_path – Absolute path (starting with ‘/’) selecting how the content is merged, additively in every case — the root “/” merges the content at the top level, an existing prim path adds the reference onto that prim, a not-yet-existing prim path defines a new prim there. See ovstage_population_add_usd_reference_from_file.

  • out_handle – [out, optional] Receives a handle for the added reference, reserved synchronously, for a later ovstage_population_remove_usd_reference. See ovstage_population_add_usd_reference_from_file.

Returns:

Enqueue result (see ovstage_population_enqueue_result_t). A rejected enqueue is reported in status; failures while the op runs — the USDA content fails to parse, or the target path is not a valid absolute path — are surfaced by ovstage_population_wait_op, with detail in ovstage_population_get_last_error.

ovstage_population_enqueue_result_t ovstage_population_remove_usd_reference(
ovstage_instance_t *stage,
ovstage_population_usd_reference_handle_t handle
)#

Enqueue an asynchronous operation to remove a USD reference previously added by ovstage_population_add_usd_reference_from_file / _from_string.

This edits only the USD source, undoing exactly what the matching add introduced: a prim the add defined is removed whole (with its referenced subtree); a reference the add placed onto a pre-existing prim is removed on its own, leaving that prim and its prior content in place; a root “/” merge removes just the sublayer the add inserted. Like the add, it does not itself touch the ovstage; call ovstage_population_apply_usd_changes afterwards to propagate the removal (the affected prims are tombstoned out of the ovstage). For an inline (_from_string) reference this also releases the held layer. Carries no ordinal.

Parameters:
  • stage – ovstage instance.

  • handle – Handle returned by an add-reference call. Removing the same handle twice, or a handle whose add never completed, fails when the op runs.

Returns:

Enqueue result (see ovstage_population_enqueue_result_t). A rejected enqueue (invalid handle, or no population state) is reported in status; a run-time failure (unknown/already-removed handle, or the prim could not be removed) is surfaced by ovstage_population_wait_op.

ovstage_population_enqueue_result_t ovstage_population_reset_usd(
ovstage_instance_t *stage
)#

Enqueue an asynchronous operation to reset (clear) all USD source content from this stage.

Unlike the open entry points, which load and populate in one step, this edits only the USD source. Call ovstage_population_apply_usd_changes afterwards to propagate the cleared state into the ovstage: until something does, what was populated from the old source is still there, and a later open merges into it rather than replacing it. Carries no ordinal.

Remark

Only USD source content is cleared. With the RENDERING domain populated, the few prims the runtime currently maintains for its own stage-level bookkeeping are not USD content and remain, so a query with no path restriction still counts them afterwards; scope by usd-path prefix to observe the emptied scene. This is a temporary, RENDERING-specific limitation.

Parameters:
  • stage – ovstage instance.

Returns:

Enqueue result (see ovstage_population_enqueue_result_t). A rejected enqueue (no population state) is reported in status; a run-time failure is surfaced by ovstage_population_wait_op.

ovstage_population_enqueue_result_t ovstage_population_apply_usd_time(
ovstage_instance_t *stage,
ovstage_ordinal_t ordinal,
double time
)#

Enqueue an asynchronous operation to advance the time and propagate time-sampled attribute changes into the ovstage.

Call once per simulation tick when playing back time-sampled USD content.

Samples time-sampled attributes from the latest USD state at time: their values are re-sampled from the current USD, so edits to an attribute’s time samples are reflected at the new time even if ovstage_population_apply_usd_changes has not been called since they were made.

Re-samples whatever the initial _open_usd_* put in scope, not only the domains it selected: a _with_desc open puts prims in scope through its selectors as well, so a description carrying selectors and domains == 0 is advanced like any other. Nothing outside that scope is written.

**Every in-scope time-sampled property is overwritten, whether or not time differs from the previous call.** Re-applying the same time is not a no-op: the values are re-read from USD and re-written at ordinal, so a property changed through the write API since the last advance is overwritten with what USD resolves at time.

Passing OVSTAGE_POPULATION_DEFAULT_TIME as time advances to USD’s default time code.

RENDERING — additional behavior: for the RENDERING domain this call also reflects pending structural USD edits (prim add/remove, and attribute or relationship changes that are not time samples) at the new time, even if ovstage_population_apply_usd_changes has not been called. Other domains advance time for time-sampled values only and leave such structural edits to be applied by ovstage_population_apply_usd_changes. This RENDERING-specific behavior is expected to converge with the other domains over time.

Parameters:
  • stage – ovstage instance.

  • ordinal – Accumulating ordinal owned by the caller. Must be greater than the effective write floor at execution time.

  • time – New time in seconds; converted to a USD time code via the stage’s timeCodesPerSecond. OVSTAGE_POPULATION_DEFAULT_TIME advances to USD’s default time code instead.

Returns:

Enqueue result (see ovstage_population_enqueue_result_t). A rejected enqueue (no population state) is reported in status; a run-time failure is surfaced by ovstage_population_wait_op.

ovstage_population_enqueue_result_t ovstage_population_apply_usd_changes(
ovstage_instance_t *stage,
ovstage_ordinal_t ordinal
)#

Enqueue an asynchronous operation to propagate any USD edits accumulated since the last call (including content emptied by ovstage_population_reset_usd) into the ovstage.

Intended for frame-coordinator pre-commit hooks: call once per tick before consumers read from the ovstage so any pending USD-side edits are visible. A no-op (returns success) when nothing has changed.

Honors the data domains selected by the initial _open_usd_*: only those domains’ edits are propagated.

Parameters:
  • stage – ovstage instance.

  • ordinal – Accumulating ordinal owned by the caller. Must be greater than the effective write floor at execution time.

Returns:

Enqueue result (see ovstage_population_enqueue_result_t). A rejected enqueue (no population state) is reported in status; a run-time failure is surfaced by ovstage_population_wait_op. A no-op (nothing changed) returns OVSTAGE_OK.

ovstage_api_status_t ovstage_population_wait_op(
ovstage_instance_t *stage,
ovstage_population_op_id_t op_id,
ovstage_timeout_ns_t timeout_ns,
ovstage_population_op_wait_result_t *out_wait_result
)#

Wait for completion of all operations up to and including op_id, or until timeout_ns elapses.

Because the wait covers earlier operations too, any of them may be the one that failed — see out_wait_result.

timeout_ns = 0 polls; OVSTAGE_TIMEOUT_INFINITE blocks indefinitely.

Parameters:
  • stage – ovstage instance.

  • op_id – Operation id from a population enqueue result.

  • timeout_ns – Nanoseconds to wait; OVSTAGE_TIMEOUT_INFINITE blocks.

  • out_wait_result – [out, optional] Receives the ids of every op that failed within the awaited range and, on timeout, the lowest still-pending op id. May be NULL if the caller only needs the return code. See ovstage_population_op_wait_result_t.

Returns:

  • OVSTAGE_OK if the awaited op (and all ops before it) completed successfully.

  • OVSTAGE_ERROR_TIMEOUT if the range did not complete within timeout_ns.

  • OVSTAGE_ERROR_OP_FAILED if any op in the range failed; the failing ids are reported in out_wait_result, with per-op detail available from ovstage_population_get_last_op_error and the primary failure mirrored into ovstage_population_get_last_error.

  • OVSTAGE_ERROR_INVALID_HANDLE for an op id this instance’s operation stream never issued: zero, never enqueued, issued by a different instance, or issued by a stream this instance has since replaced.

  • OVSTAGE_ERROR_NOT_FOUND if stage has no population state (no _open_usd_* has run on it).

ovx_string_t ovstage_population_get_last_error(void)#

Returns the thread-local error string for the latest population call on this thread, regardless of which ovstage instance produced it.

For an op that failed asynchronously, this holds the primary failure only after ovstage_population_wait_op has observed it on this thread; for a rejected enqueue it is set on return. Valid until the next population call on the same thread. Returns {NULL, 0} when no error has been recorded.

ovx_string_t ovstage_population_get_last_op_error(
ovstage_population_op_id_t op_id
)#

Returns the human-readable error string for op_id, as reported by the last ovstage_population_wait_op call on this thread (i.e.

an op id listed in that call’s ovstage_population_op_wait_result_t::error_op_ids). Valid until the next ovstage_population_wait_op call on the same thread. Returns {NULL, 0} if op_id is not known to have failed on this thread.

struct ovstage_population_selector_t#
#include <ovstage_population.h>

One population selector: which prims are populated, and which of their properties and metadata.

Public Members

ovstage_population_prim_predicate_t prim_predicate#

Which prims this selector populates.

ovstage_population_property_predicate_t property_predicate#

Which properties of those prims are populated.

const ovx_string_t *prim_metadata_paths#

Metadata to populate for each selected prim, as paths: a metadata field name, extended with a :-joined key path to reach inside a dictionary field.

A path naming a dictionary rather than a single value populates every value beneath it, one attribute each. Populated as usd-metadata:<path>.

size_t prim_metadata_path_count#
const ovx_string_t *property_metadata_paths#

Metadata to populate for each selected property, as paths &#8212; same addressing and dictionary flattening as prim_metadata_paths.

Applies to every property property_predicate selects; use a further selector to populate a field for some properties only. Populated as <property>:usd-metadata:<path>.

size_t property_metadata_path_count#
struct ovstage_population_desc_t#
#include <ovstage_population.h>

A complete description of what to populate.

Zero-initialize, then set the fields you need. A desc with no selectors and domains set is exactly equivalent to passing that domains to the entry point without a desc; a desc with neither populates nothing.

Descs are supplied as an array and compose: domains is OR-ed across every desc, and their selectors are combined in array order.

The array, and everything it points at, must stay valid only until the call returns: the description is copied as the operation is enqueued.

Public Members

uint32_t domains#

Bitmask of ovstage_population_domain_t — built-in domains to populate alongside this desc’s selectors.

0 for selectors only.

const ovstage_population_selector_t *selectors#

The selectors that make up this description.

May be NULL when domains alone is wanted.

size_t selector_count#
const ovx_string_t *stage_metadata_paths#

Stage metadata to populate onto the root prim, as paths: a stage metadata field name, extended with a :-joined key path to reach inside a dictionary field — customLayerData:myTool:version.

A path naming a dictionary rather than a single value populates every value beneath it, one attribute each. A path that does not resolve populates nothing.

size_t stage_metadata_path_count#
struct ovstage_population_enqueue_result_t#
#include <ovstage_population.h>

Result of enqueuing a population operation.

Population runs asynchronously: status reports only that the operation was accepted (OVSTAGE_OK) and the work runs on a background worker — call ovstage_population_wait_op(op_id) to await completion and obtain the outcome (with detail via ovstage_population_get_last_error). op_index identifies the operation for ovstage_population_wait_op, or is OVSTAGE_POPULATION_INVALID_OP_ID if nothing was enqueued.

Public Members

ovstage_api_status_t status#
ovstage_population_op_id_t op_index#
struct ovstage_population_op_wait_result_t#
#include <ovstage_population.h>

Output of ovstage_population_wait_op.

Because a single wait covers all operations up to and including the awaited op, more than one op can have failed within that range. error_op_ids lists those failed op ids. Each failure is reported exactly once — by the first ovstage_population_wait_op call (on any thread) whose range covers it — so a later wait does not re-report it. For each id, retrieve the human-readable detail with ovstage_population_get_last_op_error.

The array (and the strings from ovstage_population_get_last_op_error) live in the calling thread’s storage and stay valid only until that same thread’s next ovstage_population_wait_op call, which overwrites them; copy anything you need to keep before calling again. Calls on different threads use independent buffers and do not clobber each other.

lowest_pending_op_id is meaningful only when the wait returns OVSTAGE_ERROR_TIMEOUT: it is the lowest op id in the awaited range that had not completed when the timeout elapsed (useful for partial-progress reporting). It is OVSTAGE_POPULATION_INVALID_OP_ID otherwise.

Public Members

const ovstage_population_op_id_t *error_op_ids#
size_t error_op_id_count#
ovstage_population_op_id_t lowest_pending_op_id#

Enums

enum ovstage_population_prim_predicate_kind_t#

How an ovstage_population_prim_predicate_t matches, and which member of its values union carries the value_count values it matches against.

A kind that takes values matches when any one of them matches: the values of a single predicate are a disjunction, never a conjunction. Requiring more than one condition is what OVSTAGE_POPULATION_PRIM_PREDICATE_AND is for.

Values:

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_NONE#

Matches no prim.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_ALL#

Matches every prim.

Takes no values.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_AND#

values.subpredicates: matches when every subpredicate matches.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_OR#

values.subpredicates: matches when any subpredicate matches.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_NOT#

values.subpredicates, exactly one: matches when it does not.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_PARENT#

values.subpredicates, exactly one: matches when the prim’s parent does.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_ANCESTOR#

values.subpredicates, exactly one: matches when any ancestor does.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_PROPERTY#

values.property_predicate, exactly one: matches when any property of the prim matches it.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_TYPE#

values.strings: the prim’s type name, matched exactly.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_IS_A_TYPE#

values.strings: the prim’s type name, or any type it derives from.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_SCHEMA#

values.strings: a schema the prim conforms to, matched exactly — its type name or one of its applied API schemas.

The form to use when a list of schema names mixes the two, which a schema family generally does.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_APPLIED_SCHEMA#

values.strings: an API schema applied to the prim, matched exactly — including the :instance suffix a multiple-apply schema carries.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_APPLIED_SCHEMA_IN_NAMESPACE#

values.strings: a namespace an applied API schema name is in, matched at : boundaries — PhysxJointAxisAPI matches every instance of it, such as PhysxJointAxisAPI:linear.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_PATH#

values.strings: the prim’s absolute path, matched exactly.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_IS_UNDER_PATH#

values.strings: an absolute prim path the prim’s own path is at or beneath.

Matched at path-component boundaries, so /World/Env does not match /World/Environment. Does not match a prim inside a native instance.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_KIND#

values.strings: the prim’s model kind, matched exactly — a kind’s ancestors in the kind hierarchy are not considered.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_PURPOSE#

values.strings: the prim’s purpose, as inherited down the tree — a prim under a guide scope has purpose guide.

A prim that is not imageable has no purpose and matches nothing.

enumerator OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_METADATA#

values.strings: a metadata path the prim resolves, in the same form prim_metadata_paths takes — a field name, extended with a :-joined key path to reach inside a dictionary field.

Presence, not value: a path resolving to false or 0 matches as much as one resolving to true.

Name a key, not a whole dictionary field. A field matches whenever anything resolves beneath it, including what a schema registers rather than the prim authoring it; customData:myTool:export selects the prims that carry that key.

enum ovstage_population_property_predicate_kind_t#

How an ovstage_population_property_predicate_t matches, and which member of its values union carries the value_count values it matches against.

A kind that takes values matches when any one of them matches: the values of a single predicate are a disjunction, never a conjunction. Requiring more than one condition is what OVSTAGE_POPULATION_PROPERTY_PREDICATE_AND is for.

Values:

enumerator OVSTAGE_POPULATION_PROPERTY_PREDICATE_NONE#

Matches no property.

enumerator OVSTAGE_POPULATION_PROPERTY_PREDICATE_ALL#

Matches every property of an in-scope prim.

Takes no values.

enumerator OVSTAGE_POPULATION_PROPERTY_PREDICATE_AND#

values.subpredicates: matches when every subpredicate matches.

enumerator OVSTAGE_POPULATION_PROPERTY_PREDICATE_OR#

values.subpredicates: matches when any subpredicate matches.

enumerator OVSTAGE_POPULATION_PROPERTY_PREDICATE_NOT#

values.subpredicates, exactly one: matches when it does not.

enumerator OVSTAGE_POPULATION_PROPERTY_PREDICATE_DECLARED_BY_SCHEMA#

values.strings: the property’s name is declared by one of the named schemas.

Whether the prim carrying the property has that schema applied is not considered.

enumerator OVSTAGE_POPULATION_PROPERTY_PREDICATE_HAS_NAME#

values.strings: the property’s name, matched exactly.

enumerator OVSTAGE_POPULATION_PROPERTY_PREDICATE_IN_NAMESPACE#

values.strings: a namespace the property’s name is in, matched at : boundaries — material:binding matches material:binding:physics but not material:bindingStrength.

enumerator OVSTAGE_POPULATION_PROPERTY_PREDICATE_HAS_METADATA#

values.strings: a metadata path the property resolves, in the same form property_metadata_paths takes.

Path form, presence, and the dictionary-field caveat are as for OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_METADATA.

enumerator OVSTAGE_POPULATION_PROPERTY_PREDICATE_IS_ATTRIBUTE#

Matches an attribute.

Takes no values.

enumerator OVSTAGE_POPULATION_PROPERTY_PREDICATE_IS_RELATIONSHIP#

Matches a relationship.

Takes no values.

enumerator OVSTAGE_POPULATION_PROPERTY_PREDICATE_IS_CUSTOM#

Matches a property carrying USD’s custom modifier, which marks ad hoc client data not formalized into a schema.

Takes no values.

enumerator OVSTAGE_POPULATION_PROPERTY_PREDICATE_IS_AUTHORED#

Matches a property carrying an authored opinion, as opposed to one resolving to its schema fallback.

Takes no values.

Functions

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_none(
void
)#

Predicate constructors — one per kind.

Each sets kind, the one values member that kind names, and value_count together, so no combination can be built wrongly. See the kind’s enumerator for what it matches.

A nested predicate is referenced, not copied: the object passed to _and, _or, _not, _has_parent, _has_ancestor, or _has_property must outlive the predicate built from it. OVSTAGE_POPULATION_PRIM_PREDICATE_NONE.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_all(
void
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_ALL.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_and(
const ovstage_population_prim_predicate_t *subpredicates,
size_t value_count
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_AND over value_count subpredicates.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_or(
const ovstage_population_prim_predicate_t *subpredicates,
size_t value_count
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_OR over value_count subpredicates.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_not(
const ovstage_population_prim_predicate_t *subpredicate
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_NOT over one subpredicate.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_has_parent(
const ovstage_population_prim_predicate_t *subpredicate
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_PARENT over one subpredicate.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_has_ancestor(
const ovstage_population_prim_predicate_t *subpredicate
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_ANCESTOR over one subpredicate.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_has_property(
const ovstage_population_property_predicate_t *property_predicate
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_PROPERTY over one property predicate.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_has_type(
const ovx_string_t *values,
size_t value_count
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_TYPE over value_count type names.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_is_a_type(
const ovx_string_t *values,
size_t value_count
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_IS_A_TYPE over value_count type names.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_has_schema(
const ovx_string_t *values,
size_t value_count
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_SCHEMA over value_count schema names.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_has_applied_schema(
const ovx_string_t *values,
size_t value_count
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_APPLIED_SCHEMA over value_count schema names.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_has_applied_schema_in_namespace(
const ovx_string_t *values,
size_t value_count
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_APPLIED_SCHEMA_IN_NAMESPACE over value_count namespaces.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_has_path(
const ovx_string_t *values,
size_t value_count
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_PATH over value_count paths.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_is_under_path(
const ovx_string_t *values,
size_t value_count
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_IS_UNDER_PATH over value_count paths.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_has_kind(
const ovx_string_t *values,
size_t value_count
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_KIND over value_count kinds.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_has_purpose(
const ovx_string_t *values,
size_t value_count
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_PURPOSE over value_count purposes.

static inline ovstage_population_prim_predicate_t ovstage_population_prim_predicate_has_metadata(
const ovx_string_t *paths,
size_t path_count
)#

OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_METADATA over value_count metadata paths.

static inline ovstage_population_property_predicate_t ovstage_population_property_predicate_none(
void
)#

OVSTAGE_POPULATION_PROPERTY_PREDICATE_NONE.

static inline ovstage_population_property_predicate_t ovstage_population_property_predicate_all(
void
)#

OVSTAGE_POPULATION_PROPERTY_PREDICATE_ALL.

static inline ovstage_population_property_predicate_t ovstage_population_property_predicate_and(
const ovstage_population_property_predicate_t *subpredicates,
size_t value_count
)#

OVSTAGE_POPULATION_PROPERTY_PREDICATE_AND over value_count subpredicates.

static inline ovstage_population_property_predicate_t ovstage_population_property_predicate_or(
const ovstage_population_property_predicate_t *subpredicates,
size_t value_count
)#

OVSTAGE_POPULATION_PROPERTY_PREDICATE_OR over value_count subpredicates.

static inline ovstage_population_property_predicate_t ovstage_population_property_predicate_not(
const ovstage_population_property_predicate_t *subpredicate
)#

OVSTAGE_POPULATION_PROPERTY_PREDICATE_NOT over one subpredicate.

static inline ovstage_population_property_predicate_t ovstage_population_property_predicate_declared_by_schema(
const ovx_string_t *values,
size_t value_count
)#

OVSTAGE_POPULATION_PROPERTY_PREDICATE_DECLARED_BY_SCHEMA over value_count schema names.

static inline ovstage_population_property_predicate_t ovstage_population_property_predicate_has_name(
const ovx_string_t *values,
size_t value_count
)#

OVSTAGE_POPULATION_PROPERTY_PREDICATE_HAS_NAME over value_count names.

static inline ovstage_population_property_predicate_t ovstage_population_property_predicate_in_namespace(
const ovx_string_t *values,
size_t value_count
)#

OVSTAGE_POPULATION_PROPERTY_PREDICATE_IN_NAMESPACE over value_count namespaces.

static inline ovstage_population_property_predicate_t ovstage_population_property_predicate_has_metadata(
const ovx_string_t *paths,
size_t path_count
)#

OVSTAGE_POPULATION_PROPERTY_PREDICATE_HAS_METADATA over value_count metadata paths.

static inline ovstage_population_property_predicate_t ovstage_population_property_predicate_is_attribute(
void
)#

OVSTAGE_POPULATION_PROPERTY_PREDICATE_IS_ATTRIBUTE.

static inline ovstage_population_property_predicate_t ovstage_population_property_predicate_is_relationship(
void
)#

OVSTAGE_POPULATION_PROPERTY_PREDICATE_IS_RELATIONSHIP.

static inline ovstage_population_property_predicate_t ovstage_population_property_predicate_is_custom(
void
)#

OVSTAGE_POPULATION_PROPERTY_PREDICATE_IS_CUSTOM.

static inline ovstage_population_property_predicate_t ovstage_population_property_predicate_is_authored(
void
)#

OVSTAGE_POPULATION_PROPERTY_PREDICATE_IS_AUTHORED.

struct ovstage_population_prim_predicate_t#
#include <ovstage_population_predicate.h>

Which prims a selector puts in scope.

Zero-initialize, then set kind, the values member that kind names, and value_count. Several values of one kind match if any one of them does, so a list of schema names is a single predicate; combine different kinds with AND / OR / NOT. A property predicate nests here — as OVSTAGE_POPULATION_PRIM_PREDICATE_HAS_PROPERTY — so a prim can be gated on the properties it carries.

Public Members

ovstage_population_prim_predicate_kind_t kind#
const ovx_string_t *strings#
const ovstage_population_prim_predicate_t *subpredicates#
const ovstage_population_property_predicate_t *property_predicate#
union ovstage_population_prim_predicate_t values#
size_t value_count#
struct ovstage_population_property_predicate_t#
#include <ovstage_population_predicate.h>

Which of an in-scope prim’s properties a selector includes in population.

Built the same way as ovstage_population_prim_predicate_t: kind names the live values member, and several values of one kind match if any one of them does.

Public Members

ovstage_population_property_predicate_kind_t kind#
const ovx_string_t *strings#
const ovstage_population_property_predicate_t *subpredicates#
union ovstage_population_property_predicate_t values#
size_t value_count#

Population Export (ovstage → USD)#

Selected current runtime state can be authored into a USD destination that ovstage opens and owns, without exposing OpenUSD C++ types through the C ABI. See Exporting ovstage to USD for destination ownership and persistence rules.

Defines

OVSTAGE_POPULATION_EXPORT_UNKNOWN_APPLIED_API_SCHEMAS_CUSTOM_DATA_KEY#

Custom-data key used to preserve an array of unresolved applied API schema names when unknown_metadata_policy is PRESERVE.

OVSTAGE_POPULATION_EXPORT_INVALID_DESTINATION_HANDLE#

Invalid/sentinel reusable export destination handle.

Typedefs

typedef uint64_t ovstage_population_export_destination_handle_t#

ABI-opaque handle for a reusable, source-stage-bound USD export destination.

Enums

enum ovstage_population_export_selection_t#

Selects the source-state class exported by a descriptor.

Values:

enumerator OVSTAGE_POPULATION_EXPORT_SELECTION_EXPLICIT_PREDICATE#

Export the current committed ovstage state constrained by predicates and rules.

enumerator OVSTAGE_POPULATION_EXPORT_SELECTION_CHANGED_PROPERTIES_SINCE_ORDINAL#

Export properties dirtied in the open interval (since_ordinal, ordinal], intersected with the descriptor’s prim and property predicates.

enum ovstage_population_export_layer_mode_t#

Controls the authored USD prim specifier for newly materialized prim specs.

Values:

enumerator OVSTAGE_POPULATION_EXPORT_LAYER_MODE_OVER#

Author sparse overlay opinions with SdfSpecifierOver.

enumerator OVSTAGE_POPULATION_EXPORT_LAYER_MODE_DEF#

Author durable definitions with SdfSpecifierDef.

enum ovstage_population_export_path_match_t#

How rule paths are compared against ovstage/USD prim paths.

Values:

enumerator OVSTAGE_POPULATION_EXPORT_PATH_MATCH_EXACT#

Match one exact absolute prim path.

enumerator OVSTAGE_POPULATION_EXPORT_PATH_MATCH_PREFIX#

Match the path itself and all descendants under it.

enum ovstage_population_export_name_match_t#

How rule attribute-name patterns are compared against ovstage runtime names.

Values:

enumerator OVSTAGE_POPULATION_EXPORT_NAME_MATCH_EXACT#

Match the exact attribute name.

enumerator OVSTAGE_POPULATION_EXPORT_NAME_MATCH_GLOB#

Match with simple glob wildcards accepted by the implementation.

enum ovstage_population_export_transform_policy_t#

How local transform attributes are emitted to USD.

Values:

enumerator OVSTAGE_POPULATION_EXPORT_TRANSFORM_USD_XFORM_OP#

Prefer standard xformOp opinions such as xformOp:transform where possible.

enumerator OVSTAGE_POPULATION_EXPORT_TRANSFORM_NONE#

Do not export recognized transform attributes.

enumerator OVSTAGE_POPULATION_EXPORT_TRANSFORM_USD_MATRIX_OP#

Author local matrices as an explicit USD matrix transform op.

enum ovstage_population_export_unknown_metadata_policy_t#

Policy for selected source metadata whose USD schema or type cannot be resolved.

Values:

enumerator OVSTAGE_POPULATION_EXPORT_UNKNOWN_METADATA_DROP#

Drop unknown metadata and continue.

enumerator OVSTAGE_POPULATION_EXPORT_UNKNOWN_METADATA_PRESERVE#

Preserve supported unknown metadata in a namespaced fallback where available.

enumerator OVSTAGE_POPULATION_EXPORT_UNKNOWN_METADATA_FAIL#

Fail the export when unknown selected metadata is encountered.

enum ovstage_population_export_source_api_schema_policy_t#

Controls whether effective applied API schemas recorded on source prims are authored on destination prims.

Values:

enumerator OVSTAGE_POPULATION_EXPORT_SOURCE_API_SCHEMAS_EXPLICIT_ONLY#

Author only API schemas named by explicit api_schema_rules.

enumerator OVSTAGE_POPULATION_EXPORT_SOURCE_API_SCHEMAS_APPLY_RECORDED#

Also author each selected prim’s effective usd-schemas metadata.

enum ovstage_population_export_projection_t#

Controls automatic projection of source runtime attributes.

Values:

enumerator OVSTAGE_POPULATION_EXPORT_PROJECTION_EXPLICIT_RULES#

Author only attributes named by explicit attribute_rules.

enumerator OVSTAGE_POPULATION_EXPORT_PROJECTION_SCHEMA_DECLARED#

Also author selected attributes declared by each prim’s effective USD schemas.

enum ovstage_population_export_rule_flags_t#

Per-rule behavior flags.

Flags may be ORed together.

Values:

enumerator OVSTAGE_POPULATION_EXPORT_RULE_NONE#

No special behavior.

enumerator OVSTAGE_POPULATION_EXPORT_RULE_EXPORT_DEFAULT_VALUE#

Export a selected attribute even when the value equals the USD default/fallback.

enumerator OVSTAGE_POPULATION_EXPORT_RULE_DERIVED_ALLOWED#

Allow schema-derived type resolution instead of requiring an exact explicit type.

enumerator OVSTAGE_POPULATION_EXPORT_RULE_INFER_CUSTOM_TYPE#

Infer a custom USD value type from the ovstage runtime tensor shape/type.

enumerator OVSTAGE_POPULATION_EXPORT_RULE_REQUIRED#

Treat a missing, unsupported, or non-authoring rule as an export error.

enum ovstage_population_export_property_kind_t#

USD property kind authored by a property-edge rule.

Values:

enumerator OVSTAGE_POPULATION_EXPORT_PROPERTY_INVALID#

Invalid sentinel.

Zero-initialized property rules are rejected; callers must select RELATIONSHIP, CONNECTION, or MATERIAL_BINDING explicitly.

enumerator OVSTAGE_POPULATION_EXPORT_PROPERTY_RELATIONSHIP#

Author a UsdRelationship target list.

enumerator OVSTAGE_POPULATION_EXPORT_PROPERTY_CONNECTION#

Author an attribute connection target list.

enumerator OVSTAGE_POPULATION_EXPORT_PROPERTY_MATERIAL_BINDING#

Author the material:binding relationship.

Other binding names are unsupported.

enum ovstage_population_export_metadata_kind_t#

Destination kind for a metadata rule.

Values:

enumerator OVSTAGE_POPULATION_EXPORT_METADATA_PRIM#

Author metadata on matching prim specs.

enumerator OVSTAGE_POPULATION_EXPORT_METADATA_LAYER_CUSTOM_DATA#

Author entries into layer customData.

enumerator OVSTAGE_POPULATION_EXPORT_METADATA_REFERENCES#

Author selected asset references on matching prim specs.

enumerator OVSTAGE_POPULATION_EXPORT_METADATA_LAYER_STANDARD#

Author known layer-level metadata such as defaultPrim or documentation.

enum ovstage_population_export_destination_mode_t#

Controls the initial contents of a persistent USD export destination.

Values:

enumerator OVSTAGE_POPULATION_EXPORT_DESTINATION_EMPTY#

Start from an empty in-memory USD stage.

Existing stored content is not read and is replaced only when the destination is explicitly saved.

enumerator OVSTAGE_POPULATION_EXPORT_DESTINATION_OPEN_EXISTING#

Open and preserve an existing USD layer stack.

Export opinions are authored into its root layer without flattening composed content.

Functions

ovstage_api_status_t ovstage_population_export_desc_init(
ovstage_population_export_desc_t *desc
)#

Initialize an export descriptor with conservative defaults.

The descriptor selects explicit-predicate export in OVER mode, authors recognized transforms as USD xform ops, and drops metadata whose USD type is unknown.

Parameters:
  • desc – [out] Descriptor to initialize.

Returns:

OVSTAGE_OK on success or OVSTAGE_ERROR_INVALID_ARGUMENT when desc is null.

ovstage_api_status_t ovstage_population_export_desc_init_snapshot(
ovstage_population_export_desc_t *desc,
ovstage_ordinal_t ordinal
)#

Initialize a current-snapshot descriptor for an ordinal.

Applies the defaults from ovstage_population_export_desc_init, then records the expected current ordinal. Both predicates retain their ALL defaults.

Parameters:
  • desc – [out] Descriptor to initialize.

  • ordinal – Current committed ordinal expected by the caller.

Returns:

OVSTAGE_OK on success or OVSTAGE_ERROR_INVALID_ARGUMENT when desc is null.

static inline ovstage_api_status_t ovstage_population_export_desc_init_typed_hierarchy(
ovstage_population_export_desc_t *desc,
ovstage_ordinal_t ordinal,
const ovx_string_t *root_path
)#

Initialize a typed DEF-hierarchy export descriptor rooted at one USD path.

Applies current-snapshot defaults, selects root_path and its descendants, applies recorded API schemas, and projects schema-declared attributes. Callers may refine the returned descriptor before exporting.

The caller-owned ovx_string_t object and the character bytes referenced by that view are retained by the descriptor. They must outlive a synchronous export call or, for asynchronous export, successful enqueue; the enqueue then copies them.

Parameters:
  • desc – [out] Descriptor to initialize.

  • ordinal – Current committed ordinal expected by the caller.

  • root_path – Root USD path to select, retained by the descriptor.

Returns:

OVSTAGE_OK on success or the status from ovstage_population_export_desc_init_snapshot.

ovstage_api_status_t ovstage_population_export_destination_create(
ovstage_instance_t *stage,
ovx_string_t usd_identifier,
ovstage_population_export_destination_mode_t mode,
ovstage_population_export_destination_handle_t *out_destination
)#

Create a reusable USD export destination and wait for initialization.

The destination is bound to stage, which must outlive it. Exactly one active destination may own a canonical USD identifier in this process. Creation never writes storage. EMPTY starts from an empty private stage; OPEN_EXISTING fails unless the identifier can be opened and preserves its layer stack while selecting the root layer as the edit target.

Parameters:
  • stage – Source ovstage instance and owner of destination ordering.

  • usd_identifier – Local path or resolver identifier for later save.

  • mode – Initial-content policy.

  • out_destination – [out] Receives the destination handle on success and the invalid handle on failure.

Returns:

OVSTAGE_OK on success or an ovstage_api_status_t error code.

ovstage_population_enqueue_result_t ovstage_population_export_destination_enqueue_create(
ovstage_instance_t *stage,
ovx_string_t usd_identifier,
ovstage_population_export_destination_mode_t mode,
ovstage_population_export_destination_handle_t *out_destination
)#

Enqueue creation of a reusable USD export destination.

The handle is reserved synchronously and remains usable for later operations enqueued on the same stage. Those operations execute after initialization on the per-instance population FIFO. A non-invalid handle does not mean that opening succeeded; await the returned operation to observe its outcome. The identifier is copied before this function returns.

Parameters:
  • stage – Source ovstage instance and owner of destination ordering.

  • usd_identifier – Local path or resolver identifier for later save.

  • mode – Initial-content policy.

  • out_destination – [out] Receives the reserved destination handle, or the invalid handle when enqueue is rejected.

Returns:

Enqueue result for ovstage_population_export_wait_op.

ovstage_api_status_t ovstage_population_export_to_destination(
ovstage_instance_t *stage,
ovstage_population_export_destination_handle_t destination,
const ovstage_population_export_desc_t *desc,
ovstage_population_export_report_t *report
)#

Export into a reusable destination and wait for completion.

Successful calls accumulate opinions in the destination without saving. Failure leaves the destination at its previously committed in-memory state. The handle must have been created for the same stage.

Parameters:
  • stage – Source ovstage instance that owns the destination.

  • destination – Reusable destination created for stage.

  • desc – Export descriptor. The caller retains ownership.

  • report – [out, optional] Receives counters for this export only.

Returns:

OVSTAGE_OK on success or an ovstage_api_status_t error code.

ovstage_population_enqueue_result_t ovstage_population_export_enqueue_to_destination(
ovstage_instance_t *stage,
ovstage_population_export_destination_handle_t destination,
const ovstage_population_export_desc_t *desc
)#

Enqueue export into a reusable destination.

The descriptor graph is copied before return. Work is ordered with create, prior exports, save, and destroy operations on the same source stage. Retrieve the report with ovstage_population_export_wait_op.

Parameters:
  • stage – Source ovstage instance that owns the destination.

  • destination – Reusable destination created for stage.

  • desc – Export descriptor; the complete graph is copied before return.

Returns:

Enqueue result for ovstage_population_export_wait_op.

ovstage_api_status_t ovstage_population_export_destination_save(
ovstage_instance_t *stage,
ovstage_population_export_destination_handle_t destination
)#

Persist the complete current destination and wait for completion.

A successful save replaces storage at the captured identifier and leaves the destination open for later export and save calls. .usd, .usda, .usdc, and other resolver/file-format identifiers supported by this OpenUSD build are passed through to OpenUSD. Save is explicit; export and destroy never persist implicitly. OpenUSD does not provide a portable atomic-replacement guarantee, so a failed save may have modified storage.

Parameters:
  • stage – Source ovstage instance that owns the destination.

  • destination – Reusable destination created for stage.

Returns:

OVSTAGE_OK on success or an ovstage_api_status_t error code.

ovstage_population_enqueue_result_t ovstage_population_export_destination_enqueue_save(
ovstage_instance_t *stage,
ovstage_population_export_destination_handle_t destination
)#

Enqueue explicit persistence of the complete current destination.

Parameters:
  • stage – Source ovstage instance that owns the destination.

  • destination – Reusable destination created for stage.

Returns:

Enqueue result for ovstage_population_export_wait_op.

ovstage_api_status_t ovstage_population_export_destination_destroy(
ovstage_instance_t *stage,
ovstage_population_export_destination_handle_t destination
)#

Destroy a reusable destination without saving and wait for completion.

Already-enqueued work completes first. No new work is accepted after destroy is submitted, and the handle is invalid after completion.

Parameters:
  • stage – Source ovstage instance that owns the destination.

  • destination – Reusable destination created for stage.

Returns:

OVSTAGE_OK on success or an ovstage_api_status_t error code.

ovstage_population_enqueue_result_t ovstage_population_export_destination_enqueue_destroy(
ovstage_instance_t *stage,
ovstage_population_export_destination_handle_t destination
)#

Enqueue ordered destruction of a reusable destination without saving.

Parameters:
  • stage – Source ovstage instance that owns the destination.

  • destination – Reusable destination created for stage.

Returns:

Enqueue result for ovstage_population_export_wait_op.

ovstage_api_status_t ovstage_population_export_to_usd_file(
ovstage_instance_t *stage,
ovx_string_t usd_identifier,
const ovstage_population_export_desc_t *desc,
ovstage_population_export_report_t *report
)#

Export one snapshot to durable USD storage.

Convenience equivalent to creating an EMPTY destination, exporting once, saving, and destroying it. The destination is replaced on successful save.

Parameters:
  • stage – Source ovstage instance and owner of operation ordering.

  • usd_identifier – Local path or resolver identifier to replace.

  • desc – Export descriptor. The caller retains ownership.

  • report – [out, optional] Receives counters for this export.

Returns:

OVSTAGE_OK on success or an ovstage_api_status_t error code.

ovstage_population_enqueue_result_t ovstage_population_export_enqueue_to_usd_file(
ovstage_instance_t *stage,
ovx_string_t usd_identifier,
const ovstage_population_export_desc_t *desc
)#

Enqueue the one-shot EMPTY export-and-save convenience operation.

The descriptor graph and identifier are copied before return. Retrieve the export report with ovstage_population_export_wait_op.

Parameters:
  • stage – Source ovstage instance and owner of operation ordering.

  • usd_identifier – Local path or resolver identifier to replace.

  • desc – Export descriptor; the complete graph is copied before return.

Returns:

Enqueue result for ovstage_population_export_wait_op.

ovstage_api_status_t ovstage_population_export_to_usd_layer_identifier(
ovstage_instance_t *stage,
ovx_string_t usd_layer_identifier,
const ovstage_population_export_desc_t *desc,
ovstage_population_export_report_t *report
)#

Export to a USD layer addressed by identifier.

This synchronous call authors directly in place. It bypasses the population/export FIFO, provides no rollback, and requires caller-controlled serialization of the destination. The implementation first looks for an already-open SdfLayer with this identifier, then falls back to opening it from storage. Anonymous in-memory layers are supported when they are already resident in USD’s layer registry.

Parameters:
  • stage – Source ovstage instance.

  • usd_layer_identifier – Identifier of the destination USD layer.

  • desc – Export descriptor. The caller retains ownership.

  • report – [out, optional] Receives export diagnostic counters.

Returns:

OVSTAGE_OK on success or an ovstage_api_status_t error code.

ovstage_api_status_t ovstage_population_export_to_usd_stage_identifier(
ovstage_instance_t *stage,
ovx_string_t usd_stage_root_layer_identifier,
const ovstage_population_export_desc_t *desc,
ovstage_population_export_report_t *report
)#

Export to a USD stage addressed by its root-layer identifier.

This synchronous call opens the stage and authors directly into that stage’s default edit target. It bypasses the population/export FIFO, provides no rollback, and requires caller-controlled serialization of the destination. Caller-owned custom edit-target selection is not available through this public C API.

Parameters:
  • stage – Source ovstage instance.

  • usd_stage_root_layer_identifier – Root-layer identifier of the destination stage.

  • desc – Export descriptor. The caller retains ownership.

  • report – [out, optional] Receives export diagnostic counters.

Returns:

OVSTAGE_OK on success or an ovstage_api_status_t error code.

ovstage_population_enqueue_result_t ovstage_population_export_enqueue_to_usd_layer_identifier(
ovstage_instance_t *stage,
ovx_string_t usd_layer_identifier,
const ovstage_population_export_desc_t *desc
)#

Enqueue export to a USD layer addressed by identifier.

The descriptor and every nested array/string are copied before this function returns. The destination layer is resolved and retained at enqueue time. Work runs on the same per-instance FIFO used by ovpopulation operations.

The caller must not concurrently read or author the destination layer until the operation has completed. Synchronous export is not serialized with this queue and requires the same caller-provided synchronization.

Parameters:
  • stage – ovstage instance.

  • usd_layer_identifier – Identifier of an existing USD layer.

  • desc – Export descriptor; the complete descriptor graph is copied before this function returns.

Returns:

Enqueue result (see ovstage_population_enqueue_result_t). A rejected enqueue is reported in status; execution failures are returned by ovstage_population_export_wait_op with export diagnostics available through ovstage_population_get_last_error.

ovstage_population_enqueue_result_t ovstage_population_export_enqueue_to_usd_stage_identifier(
ovstage_instance_t *stage,
ovx_string_t usd_stage_root_layer_identifier,
const ovstage_population_export_desc_t *desc
)#

Enqueue export to a USD stage addressed by its root-layer identifier.

The stage is opened and retained at enqueue time. Export authors into its default edit target. The caller must not read or author that stage or its layers concurrently with the export.

Parameters:
  • stage – ovstage instance.

  • usd_stage_root_layer_identifier – Root-layer identifier of the destination stage.

  • desc – Export descriptor; the complete descriptor graph is copied before this function returns.

Returns:

Enqueue result. Admission failures are reported immediately; execution failures are returned by ovstage_population_export_wait_op.

ovstage_api_status_t ovstage_population_export_wait_op(
ovstage_instance_t *stage,
ovstage_population_op_id_t op_id,
ovstage_timeout_ns_t timeout_ns,
ovstage_population_export_report_t *report
)#

Wait for an asynchronous export operation and consume its stored result.

The wait fences every ovpopulation operation through op_id. A timeout leaves the result available for a later wait and does not cancel work. This function accepts operations returned by async export, destination create, destination save, and destination destroy functions. A terminal wait consumes the result; a second export wait for the same id is invalid. Generic ovstage_population_wait_op may be used first as a fence without consuming this result. Every accepted operation from this header must eventually receive a terminal call to this function; abandoning it retains its result and any destination keepalive until the ovstage instance is destroyed.

Parameters:
  • stage – ovstage instance.

  • op_id – Operation id returned by an async function in this header.

  • timeout_ns – Maximum wait duration, or OVSTAGE_TIMEOUT_INFINITE.

  • report – [out, optional] Receives the final export report after terminal completion; lifecycle operations return a zeroed report. Zeroed before waiting and on timeout.

Returns:

OVSTAGE_OK on successful completion, OVSTAGE_ERROR_TIMEOUT while work remains pending, the operation failure status when execution failed, or OVSTAGE_ERROR_INVALID_HANDLE for any op id that does not resolve to a live export/destination operation on this instance — an id this instance’s operation stream never issued (zero, issued by a different instance, or by a stream this instance has since replaced), one already consumed by an earlier terminal wait, or one that never identified an export/destination operation.

struct ovstage_population_export_attribute_rule_t#
#include <ovstage_population_export.h>

Attribute export rule.

Use this rule to map one or more ovstage runtime attributes to USD attributes. Empty path means every selected prim. Empty destination_attribute_name reuses source_attribute_name. Empty usd_type_name asks the exporter to use the destination schema/existing USD attribute type, or infer a custom type when OVSTAGE_POPULATION_EXPORT_RULE_INFER_CUSTOM_TYPE is set.

Public Members

ovx_string_t path#

Prim path selector; empty means all selected prims.

ovstage_population_export_path_match_t path_match#

Exact or prefix path matching mode for path.

ovx_string_t source_attribute_name#

ovstage runtime attribute name or glob pattern to read.

ovstage_population_export_name_match_t source_attribute_name_match#

Exact/glob matching mode for source_attribute_name.

ovx_string_t destination_attribute_name#

USD attribute name to author; empty reuses source_attribute_name.

ovx_string_t usd_type_name#

USD value type name to author; empty uses schema/destination/inference.

ovx_string_t required_schema_name#

Optional required schema name used when resolving schema-defined attribute types.

uint32_t flags#

Bitmask of ovstage_population_export_rule_flags_t.

struct ovstage_population_export_prim_rule_t#
#include <ovstage_population_export.h>

Prim export rule.

Use this rule to force creation of USD prim specs and, in DEF mode, to supply or override the authored USD type name. Prefix rules author each selected runtime prim under the prefix.

Public Members

ovx_string_t path#

Prim path selector.

ovstage_population_export_path_match_t path_match#

Exact or prefix path matching mode for path.

ovx_string_t usd_type_name#

USD prim type name to author; empty preserves/infer source type where available.

ovx_string_t unknown_type_metadata_key#

Optional metadata key used to preserve unknown type names when policy permits.

struct ovstage_population_export_api_schema_rule_t#
#include <ovstage_population_export.h>

Applied API schema export rule.

Use this rule to apply a USD API schema to matching prims. Multiple-apply API schemas use instance_name; single-apply schemas leave it empty.

Public Members

ovx_string_t path#

Prim path selector.

ovstage_population_export_path_match_t path_match#

Exact or prefix path matching mode for path.

ovx_string_t schema_name#

API schema type name to apply, such as “PhysicsRigidBodyAPI”.

ovx_string_t instance_name#

Multiple-apply instance name; empty for single-apply schemas.

uint32_t flags#

Bitmask of ovstage_population_export_rule_flags_t.

struct ovstage_population_export_property_edge_rule_t#
#include <ovstage_population_export.h>

Property-target export rule.

Relationship and material-binding rules read target paths from the runtime attribute named by source_property_name. Connection rules read target paths from the companion runtime attribute named “<source_property_name>.connect”. The source attributes must use the corresponding relationship-path or connection-path semantic. Empty path means every selected prim. Empty destination_property_name reuses source_property_name.

Public Members

ovx_string_t path#

Prim path selector; empty means all selected prims.

ovstage_population_export_path_match_t path_match#

Exact or prefix path matching mode for path.

ovx_string_t source_property_name#

Runtime property name whose target-path attribute is read.

ovx_string_t destination_property_name#

USD relationship or attribute name to author; empty reuses source_property_name.

ovx_string_t usd_type_name#

USD value type for connection attributes; ignored for relationships.

ovstage_population_export_property_kind_t property_kind#

Property kind to author.

uint32_t flags#

Bitmask of ovstage_population_export_rule_flags_t.

struct ovstage_population_export_metadata_rule_t#
#include <ovstage_population_export.h>

Metadata export rule.

Use this rule to map ovstage metadata attributes to USD prim metadata, layer metadata/customData, or references. Empty path means every selected prim for prim-scoped metadata; layer-scoped metadata ignores path.

Public Members

ovx_string_t path#

Prim path selector for prim-scoped metadata; empty means all selected prims.

ovstage_population_export_path_match_t path_match#

Exact or prefix path matching mode for path.

ovx_string_t source_metadata_name#

ovstage metadata attribute name to read.

ovx_string_t destination_metadata_name#

USD metadata/customData key to author; empty reuses source_metadata_name.

ovstage_population_export_metadata_kind_t metadata_kind#

Metadata destination kind.

uint32_t flags#

Bitmask of ovstage_population_export_rule_flags_t.

struct ovstage_population_export_desc_t#
#include <ovstage_population_export.h>

USD export descriptor.

Public Members

uint32_t struct_size#

Must be sizeof(ovstage_population_export_desc_t) for this header revision.

This is not an automatic compatibility mode for old layouts.

ovstage_population_export_source_api_schema_policy_t source_api_schema_policy#

Policy for applied API schemas recorded on source prims.

ovstage_population_export_projection_t projection#

Policy for automatic projection of source runtime attributes.

ovstage_ordinal_t ordinal#

Current committed ordinal expected by the caller.

Export queries the current topology and rejects stale or future ordinals instead of silently exporting a different source state.

ovstage_ordinal_t since_ordinal#

Lower bound for CHANGED_PROPERTIES_SINCE_ORDINAL; exports the open interval (since_ordinal, ordinal].

ovstage_population_export_selection_t selection#
ovstage_population_export_layer_mode_t layer_mode#
ovstage_population_export_transform_policy_t transform_policy#
ovstage_population_export_unknown_metadata_policy_t unknown_metadata_policy#
ovstage_population_prim_predicate_t prim_predicate#

Which runtime prims are candidates for export.

Defaults to ALL.

Export supports NONE, ALL, AND, OR, NOT, HAS_TYPE, IS_A_TYPE, HAS_SCHEMA, HAS_APPLIED_SCHEMA, HAS_APPLIED_SCHEMA_IN_NAMESPACE, HAS_PATH, and IS_UNDER_PATH. Other declared kinds require USD semantics not preserved by the public runtime representation and are rejected atomically with OVSTAGE_ERROR_NOT_SUPPORTED.

ovstage_population_property_predicate_t property_predicate#

Which runtime properties are candidates for property-scoped export rules and schema-declared projection.

Defaults to ALL. Prim rules, applied-schema rules, and prim/layer metadata rules are governed only by prim_predicate.

Export supports NONE, ALL, AND, OR, NOT, DECLARED_BY_SCHEMA, HAS_NAME, IN_NAMESPACE, IS_ATTRIBUTE, and IS_RELATIONSHIP. Other declared kinds are rejected atomically with OVSTAGE_ERROR_NOT_SUPPORTED.

const ovstage_population_export_prim_rule_t *prim_rules#

Each descriptor array below is limited to 4096 entries.

Counts above that limit are rejected before an array is read or retained.

size_t prim_rule_count#
const ovstage_population_export_api_schema_rule_t *api_schema_rules#
size_t api_schema_rule_count#
const ovstage_population_export_attribute_rule_t *attribute_rules#
size_t attribute_rule_count#
const ovstage_population_export_property_edge_rule_t *property_rules#
size_t property_rule_count#
const ovstage_population_export_metadata_rule_t *metadata_rules#
size_t metadata_rule_count#
struct ovstage_population_export_report_t#
#include <ovstage_population_export.h>

Export diagnostic counters.

Counters are best-effort progress diagnostics, not a stable ABI for behavioral decisions.

Public Members

size_t prims_examined#
size_t prims_exported#
size_t prims_skipped#
size_t attributes_examined#
size_t attributes_exported#
size_t attributes_skipped#
size_t attributes_unsupported#
size_t api_schemas_examined#
size_t api_schemas_applied#
size_t api_schemas_skipped#
size_t custom_attributes_inferred#
size_t unknown_metadata_preserved#
size_t transforms_examined#
size_t transforms_exported#
size_t property_edges_examined#
size_t property_edges_exported#
size_t property_edges_skipped#
size_t property_edges_unsupported#
size_t metadata_examined#
size_t metadata_exported#
size_t metadata_skipped#
size_t metadata_unsupported#
size_t source_states_unavailable#

Export could not read the requested current source ordinal.

Instancing#

High-level instancing queries.

Functions

ovstage_api_status_t ovstage_instancing_get_instance_roots(
ovstage_instance_t *instance,
ovx_primpath_t prototype_root,
ovx_primpath_list_t *out_instance_roots
)#

Return all instance-root prim paths that reference prototype_root.

Parameters:
  • instance – ovstage instance.

  • prototype_root – Prototype-root prim path.

  • out_instance_roots – Receives a path-list handle. The list may be empty when no instance roots reference prototype_root.

Returns:

OVSTAGE_OK on success.

ovstage_api_status_t ovstage_instancing_get_prototype_root(
ovstage_instance_t *instance,
ovx_primpath_t instance_root,
ovx_primpath_t *out_prototype_root
)#

Return the prototype root referenced by instance_root.

Parameters:
  • instance – ovstage instance.

  • instance_root – Instance-root prim path.

  • out_prototype_root – Receives the prototype-root prim path.

Returns:

OVSTAGE_OK on success, OVSTAGE_ERROR_NOT_FOUND when the prim is not an instance root.

ovstage_api_status_t ovstage_instancing_get_prototype_roots(
ovstage_instance_t *instance,
ovx_primpath_list_t *out_prototype_roots
)#

Return all prototype-root prim paths.

Parameters:
  • instance – ovstage instance.

  • out_prototype_roots – Receives a path-list handle. The list may be empty when the stage contains no scene-graph instancing prototypes.

Returns:

OVSTAGE_OK on success.

API Types and Utilities#

ovstage_api — vtable-based contract for asynchronous, ordinal-keyed zero-copy simulation data access.

ovstage_api provides a unified C API for reading, writing, and managing simulation data (transforms, velocities, materials, metadata) across CPU and GPU memory. It is the abstract contract that various stage implementations can provide.

Consumers receive an ovstage_instance_t* (vtable + context) and invoke functions either directly through the vtable, via the core convenience wrappers in ovstage_api_utils.h, or via sibling extension APIs such as ovstage_instancing.h.

Functions

ovx_string_t ovstage_get_last_error(void)#

Get the error string for the latest synchronous API call on the calling thread.

Free function (no instance), because the error state is thread-local rather than per-instance: each thread observes its own most-recent synchronous error, regardless of which ovstage_instance_t produced it. If two instances are driven from the same thread, the most recent failure wins. Crucially, this can be called when ovstage_create_instance itself failed and no instance exists. Valid until the next API call on the same thread. Returns {NULL, 0} when no error has been recorded.

Mirrors ovstage_population_get_last_error(void).

struct ovstage_vtable_t#
#include <ovstage_api.h>

Vtable defined in ovstage_api.h.

Public Members

ovstage_api_status_t (*wait_op)(ovstage_context_t *instance, ovstage_op_id_t op_id, ovstage_timeout_ns_t timeout, ovstage_op_wait_result_t *out_wait_result)#

Wait for completion of an enqueued operation, with timeout.

Blocks until the operation identified by op_id (and any operations it transitively depends on under the ordinal-keyed ordering rules) has completed, or until timeout elapses. timeout = 0 makes this a non-blocking poll. OVSTAGE_TIMEOUT_INFINITE blocks indefinitely. Operations in unrelated ordinal buckets may still be in flight when this call returns OVSTAGE_OK.

On return, out_wait_result->error_op_ids lists ops observed to have failed since the previous wait_op call on this thread. For each id, the error string can be retrieved via get_last_op_error. The list and strings are transient thread-local data, invalidated by the next wait_op call on the same thread.

ovstage_api_status_t (*release_op)(ovstage_context_t *instance, ovstage_op_id_t op_id)#

Release tracking state associated with an op id (synchronous).

Safe to call once the op is known to have completed. After this call the op id may not be used again with wait_op or get_last_op_error.

ovstage_enqueue_result_t (*advance_write_floor)(ovstage_context_t *instance, const ovstage_write_floor_desc_t *desc)#

Enqueue a write-floor advance with scope control.

desc->scope selects the attributes affected:

  • SCOPE_ALL: advance the global write floor and every known attribute.

  • SCOPE_INCLUDE: advance only the listed attributes.

  • SCOPE_EXCLUDE: advance every known attribute EXCEPT the listed ones. With an empty attribute list, SCOPE_EXCLUDE behaves like SCOPE_ALL.

Advances clamp to the current value (max), so they never regress and a non-monotonic ordinal is a no-op rather than an error.

Param instance:

Implementation context.

Param desc:

Write-floor advance descriptor.

Return:

Enqueue result with status + op_index.

ovstage_enqueue_result_t (*get_oldest_preserved_ordinal)(ovstage_context_t *instance, ovstage_ordinal_query_handle_t *out_handle)#

Enqueue a query for the inclusive retained-history frontier.

Ordinal queries at or above the returned frontier are exact. Older history may have been coalesced or discarded.

Remark

In the current implementation, this is the exact change-membership frontier. Payload reads store only current values: they return the current payload or tombstone, or OVSTAGE_ERROR_OUT_OF_RANGE when a selected path changed after a requested end below UINT64_MAX.

ovstage_enqueue_result_t (*get_attribute_write_floor)(ovstage_context_t *instance, ovx_string_or_token_t attribute, ovstage_ordinal_query_handle_t *out_handle)#

Enqueue a query for the write floor of a specific attribute.

Pass an empty attribute ({.token = 0, .string = {NULL, 0}}) to query the global write floor (minimum across all known attributes).

ovstage_api_status_t (*fetch_ordinal)(ovstage_context_t *instance, ovstage_ordinal_query_handle_t handle, ovstage_timeout_ns_t timeout, ovstage_ordinal_t *out_ordinal)#

Fetch the scalar result of any enqueued ordinal query.

Return:

OVSTAGE_OK on success, OVSTAGE_ERROR_TIMEOUT if not ready within timeout, OVSTAGE_ERROR_OP_FAILED if the underlying enqueue failed.

ovstage_enqueue_result_t (*release_ordinal_query)(ovstage_context_t *instance, ovstage_ordinal_query_handle_t handle)#

Enqueue release of an ordinal-query handle.

Per-handle ordered: the release waits for any in-flight fetch on the same handle to complete before reclaiming resources.

ovstage_enqueue_result_t (*query)(ovstage_context_t *instance, const ovstage_filter_t *filter, const ovx_token_t *attrs, size_t attr_count, ovstage_query_handle_t *out_query_handle)#

Enqueue a query of prims matching a filter, optionally discovering attributes for the matched set.

The returned query handle is reserved synchronously. Reading the discovered attribute list and total prim count requires a subsequent fetch_query_result call.

ovstage_api_status_t (*query_from_path_list)(ovstage_context_t *instance, ovx_primpath_list_t path_list, ovstage_query_handle_t *out_handle)#

Create a query handle from an explicit prim path list.

Synchronous.

The returned handle wraps a caller-owned, interned prim path list and does not require evaluation against the stage. It may be used immediately as input to any enqueue.

ovstage_api_status_t (*fetch_query_result)(ovstage_context_t *instance, ovstage_query_handle_t query_handle, ovstage_timeout_ns_t timeout, ovstage_query_result_t *out_result)#

Fetch the result (discovered attributes + summary) of a prior query enqueue.

Pointers in *out_result are valid until release_query_result.

Return:

OVSTAGE_OK on success, OVSTAGE_ERROR_TIMEOUT if not ready within timeout, OVSTAGE_ERROR_OP_FAILED if the underlying enqueue failed.

ovstage_api_status_t (*release_query_result)(ovstage_context_t *instance, const ovstage_query_result_t *result)#

Release a query result payload (synchronous).

After this call, the attributes array in *result is invalid. The query handle itself remains valid and must be released separately via release_query.

ovstage_enqueue_result_t (*release_query)(ovstage_context_t *instance, ovstage_query_handle_t handle)#

Enqueue release of a query handle.

Per-handle ordered: the release waits for any in-flight read/write/ map/delete enqueued against the same handle to complete before reclaiming resources.

ovstage_enqueue_result_t (*read_attributes)(ovstage_context_t *instance, ovstage_query_handle_t handle, const ovx_token_t *attrs, size_t attr_count, ovstage_ordinal_range_t range, ovstage_read_handle_t *out_read_handle)#

Enqueue a multi-attribute read.

Remark

This implementation stores only current values. Later recorded changes can make a requested snapshot or change range unavailable; see ovstage_ordinal_range_t for the checks and limitations.

ovstage_api_status_t (*fetch_read_next)(ovstage_context_t *instance, ovstage_read_handle_t read_handle, ovstage_timeout_ns_t timeout, ovstage_read_group_t *out_group)#

Fetch the next read result group, with timeout.

Return:

OVSTAGE_OK on success, OVSTAGE_ERROR_END_OF_ITERATION when no more groups, OVSTAGE_ERROR_TIMEOUT if the next group is not ready within timeout, OVSTAGE_ERROR_OP_FAILED if the underlying enqueue failed. When a deferred read is rejected, the producer’s own status (for example OVSTAGE_ERROR_WRITE_FLOOR_VIOLATION or OVSTAGE_ERROR_OUT_OF_RANGE) is reported once that producer has completed; a fetch that is itself waiting on the producer reports OVSTAGE_ERROR_OP_FAILED instead. Ready queries are validated at enqueue and report the typed status from read_attributes.

Post:

On OVSTAGE_OK, the group is independently valid until release_group.

ovstage_api_status_t (*release_group)(ovstage_context_t *instance, const ovstage_read_group_t *group)#

Release a read group’s pinned storage (synchronous).

Thread-safe; groups can be released in any order from any thread.

ovstage_enqueue_result_t (*release_read)(ovstage_context_t *instance, ovstage_read_handle_t read_handle)#

Enqueue release of a read handle.

Per-handle ordered: the release waits for any in-flight fetch_read_next call on the same handle to complete before reclaiming resources.

ovstage_enqueue_result_t (*write_attribute)(ovstage_context_t *instance, ovstage_query_handle_t handle, ovx_string_or_token_t attribute, ovstage_ordinal_t ordinal, ovstage_write_data_t data, ovstage_prim_mode_t prim_mode)#

Enqueue a write of attribute values for prims identified by a query handle.

This call follows the non-transactional write_attributes contract for a single entry. A successfully applied entry commits its values, any new prims or attributes, and their change records at the submitted ordinal. A failed entry is not recorded as a completed write, although changes made before the failure can remain visible to an attribute-presence (HAS) query. Because this operation has only one entry, a failed application leaves the submitted ordinal available; a corrected same-ordinal retry remains admissible subject to current stage state. The exception is a forcing write that ended a prim’s previous schema before failing: that end stays recorded, so a retry for that prim needs a later ordinal (see OVSTAGE_ATTRIBUTE_MODE_FORCE above). A prim left by a failed write counts as an existing target for INSERT and can make that retry fail with OVSTAGE_ERROR_PRIM_NOT_FOUND; UPSERT can repair it. This call also shares the recoverable-error and partial-failure behavior documented for write_attributes. Write-entry, tensor-layout, and attribute-schema errors that can be proven during common preflight are therefore returned synchronously with an invalid op_index; failures that require pending-query resolution or execution remain observable through wait_op. A successful enqueue can still fail ordinal admission during execution, before this operation changes stage data. When multiple inputs are independently invalid, callers must not rely on error precedence; common preflight currently validates prim_mode before query-handle readiness and enqueue-time ordinal checks.

Param instance:

Implementation context.

Param handle:

Query handle identifying target prims.

Param attribute:

Attribute to write.

Param ordinal:

Must exceed applicable floors and satisfy the configured ordinal admission policy for affected cells and prim lifecycles at execution. The STRICTLY_INCREASING policy rejects equality with retained changes; NONDECREASING allows equality. Disjoint writes may share an ordinal and execute in submission order.

Param data:

Write payload (tensors + cuda_sync + mask/index_map).

Param prim_mode:

UPSERT (default) or INSERT.

Return:

Enqueue result with status + op_index. A synchronous preflight failure has an invalid op_index. After a successful enqueue, failures discovered only during pending-query resolution, state-race revalidation, or execution are surfaced through wait_op + get_last_op_error.

ovstage_enqueue_result_t (*map_attribute)(ovstage_context_t *instance, ovstage_query_handle_t handle, const ovstage_map_desc_t *desc, ovstage_ordinal_t ordinal, const size_t *element_sizes, size_t element_count, ovstage_map_handle_t *out_map_handle)#

Enqueue a map session for writing an attribute.

The returned map handle is reserved synchronously and may immediately be used with subsequent fetch_map_next / unmap_* calls. A successful enqueue can still fail ordinal admission during setup, before writable groups are made available. Observe setup failure through wait_op or fetch_map_next. Successful setup does not guarantee a later commit: unmap rechecks the current layout, type/semantic compatibility, prim creation policy, ordinal admission and read overlap before committing remaining data.

Remark

Mapped buffers need not alias final backing storage; the current implementation may copy or scatter them during unmap.

Remark

This slot maps on the host: ovstage_map_desc_t carries no device field; map_attribute_on_device, in the experimental placement extension, is the counterpart that names one. unmap_group and unmap_attribute are shared by both, and their write_done_sync is inbound &#8212;

the caller’s “my kernel has finished

filling the buffer”, which ovstage waits on before committing. It is accepted only where there is device-side work to wait for: a fixed-size session mapped on a CUDA device consumes it, while a host-mapped session and any ragged payload commit reject a non-zero

stream or wait_event. Because that rejection is an accepted failure it is terminal for the session. For a session from this slot, pass a zeroed ovstage_cuda_sync_t. A cleanup-only close of unmap_attribute &#8212; every group already committed by unmap_group &#8212; has no payload and never inspects the sync, so this is not a general argument check.

Remark

above. Pass NULL for fixed-size (scalar / fixed-tuple) attributes, whose per-element footprint comes from the existing column type, or from desc.dtype when the column is being created.

Param instance:

Implementation context.

Param handle:

Query handle identifying target prims.

Param desc:

Map descriptor (attribute, dtype, semantic, prim_mode). See ovstage_map_desc_t.

Param ordinal:

Ordinal for this map session. Setup and publication must exceed applicable floors and satisfy the configured ordinal admission policy for affected cells and prim lifecycles. Disjoint maps may share an ordinal.

Param element_sizes:

For array (variable-size) attributes, the per-prim element count: element_sizes[i] is the number of array elements to allocate for the i-th prim in handle’s prim set. This sizes the per-prim writable staging handed back in the group; the final ragged backing storage is allocated at commit, per the

Param element_count:

Number of entries in element_sizes. When element_sizes is non-NULL it must equal the number of prims in handle’s prim set; pass 0 when element_sizes is NULL.

Param out_map_handle:

Receives the reserved map handle.

Return:

Enqueue result with status + op_index.

ovstage_api_status_t (*fetch_map_next)(ovstage_context_t *instance, ovstage_map_handle_t map_handle, ovstage_timeout_ns_t timeout, ovstage_map_group_t *out_group)#

Fetch the next writable map group, with timeout.

out_group and its pointers borrow map-owned storage. Do not access the group’s buffers after submitting its commit or finalizing the session.

ovstage_enqueue_result_t (*unmap_group)(ovstage_context_t *instance, ovstage_map_handle_t map_handle, const ovstage_map_group_t *group, ovstage_cuda_sync_t write_done_sync)#

Enqueue commit of a single map group (streaming commit).

Executes in the session’s ordinal bucket; ordered relative to other writes/deletes/map commits at the session’s ordinal.

A successful operation commits this group’s values, any prim or attribute creation, schema or hierarchy changes, and ordinal change records once. A failed operation does not record these as completed changes and does not undo groups committed earlier.

Map commits are not transactional. A failed commit is not undone: the implementation may have changed some or all of the group’s stored rows. Those changes can remain observable despite the failed operation; no rollback or atomicity is guaranteed.

If an accepted group commit fails during execution, the session becomes terminal. Its groups cannot be retried. Call unmap_attribute to release the session; it reports the retained failure without committing more data. Recovery requires a new map session or another write operation. The exception is a placed session whose availability event cannot be recorded: that failure is reported after the commit, whose changes stay recorded, and the session stays open (see ovstage_placement_t in experimental/ovstage_placement_extension.h).

ovstage_enqueue_result_t (*unmap_attribute)(ovstage_context_t *instance, ovstage_map_handle_t map_handle, ovstage_cuda_sync_t write_done_sync)#

Enqueue commit of all remaining groups and release of the map handle.

After the enqueued op executes, the map handle is no longer valid.

Successful finalization commits only groups not committed by earlier unmap_group calls. If all groups were committed, finalization only releases the session; it neither reapplies changes nor repeats commit admission checks. If an earlier accepted group commit failed, it releases the session and reports that failure without committing remaining data.

An accepted finalization consumes the handle even if it fails during execution, including when only its availability event cannot be recorded. The failure and non-transactional rules of unmap_group also apply to remaining groups committed here.

ovstage_enqueue_result_t (*delete_attributes)(ovstage_context_t *instance, ovstage_query_handle_t handle, const ovx_string_or_token_t *attributes, size_t attribute_count, ovstage_ordinal_t ordinal)#

Enqueue a delete (tombstone) of attributes on prims at a given ordinal.

Param instance:

Implementation context.

Param handle:

Query handle identifying target prims.

Param attributes:

List of attributes to delete. Empty list = delete entire prims (all attributes).

Param attribute_count:

Number of attributes. 0 = delete entire prims.

Param ordinal:

Ordinal of the deletion. Must exceed applicable floors and satisfy the configured ordinal admission policy for deleted cells and, for whole-prim deletion, the affected prim lifecycles.

Return:

Enqueue result with status + op_index.

void (*get_version)(ovstage_context_t *instance, uint32_t *out_major, uint32_t *out_minor, uint32_t *out_patch)#

Get the implementation’s version (SemVer 2.0).

Returns the same values as the compile-time OVSTAGE_VERSION_MAJOR / OVSTAGE_VERSION_MINOR / OVSTAGE_VERSION_PATCH macros, so a runtime query and a compile-time #if check always agree.

const char *(*get_error_string)(ovstage_context_t *instance, ovstage_api_status_t error)#

Get a human-readable string for an error code.

Return:

Static string. Never NULL.

ovx_string_t (*get_last_op_error)(ovstage_context_t *instance, ovstage_op_id_t op_id)#

Get the human-readable error string for a failed op id reported by the last wait_op call on this thread.

The returned string is valid until the next wait_op call on the same thread. Returns {NULL, 0} if the op id is not known or did not fail.

path_dictionary_instance_t *(*get_path_dictionary)(ovstage_context_t *instance)#

Get the path dictionary obtained from this ovstage instance.

Returns a path_dictionary_instance_t* owned by the ovstage subsystem. See <ovx/path_dictionary/path_dictionary.h> for the full vtable contract, handle-lifetime regimes, refcount rules and thread safety; the points below are ovstage-specific.

ovstage_enqueue_result_t (*write_attributes)(ovstage_context_t *instance, ovstage_query_handle_t handle, const ovstage_attribute_write_t *writes, size_t write_count, ovstage_ordinal_t ordinal, ovstage_prim_mode_t prim_mode)#

Enqueue one operation that writes multiple attributes to the prims identified by a query handle.

The write array undergoes common preflight before the operation is queued. Errors established there, including invalid descriptors and known write-floor violations, are returned synchronously. Successful enqueue can still fail ordinal admission during execution. Admission is checked for the complete batch before any entry changes stage data; rejection is reported through wait_op and get_last_op_error. Ordinary value columns and the reserved usd-prim-type/usd-schemas entries participate in the same operation, including any prim or attribute creation. Attribute kind is declared by each entry’s data.is_array with exactly the same rules as write_attribute.

One op_index groups completion and pending-write coverage; it does not make the entries an atomic multi-attribute transaction or establish a global snapshot barrier. Entries may be applied incrementally, descriptor order does not define execution order, and operations that do not overlap the batch may interleave before completion. Pending coverage rejects read_attributes calls overlapping any batch entry until the operation finishes.

Non-reserved entries that resolve to the same canonical storage column may appear together only when their selected prim coverage is disjoint; repeating a concrete (prim, canonical-column) target is invalid. Such entries must also declare compatible column identities: the same dtype, row layout, array kind, and semantic.

Every DLManagedTensorVersioned pointer across the complete write array must be non-NULL and unique. Ownership of all supplied managed tensors transfers at call entry; every unique pointer is released exactly once, including when synchronous validation rejects the batch.

If the query has no target prims, batch-level names, aliases, ordinal admission, and managed-pointer uniqueness are still validated, but tensor payload shape/device/type validation is skipped because no payload is accessed. Transferred managed tensors are still released exactly once. The placed form’s check that an availability event on a default stream does not span CUDA sources on two devices still applies (see ovstage_placement_t in experimental/ovstage_placement_extension.h).

A successful enqueue does not promise transactional rollback. If execution returns a failure after storage mutation begins, wait_op still reports failure and get_last_op_error supplies its diagnostic. Entries whose application completed successfully before that failure remain committed, including any new prims or attributes and their change records at the submitted ordinal. The failed entry is not recorded as a completed write, although changes made before the failure can remain visible to an attribute-presence (HAS) query. Preparing storage alone does not count as a completed write or record changes at the submitted ordinal. Reserved metadata may complete before ordinary attribute values; it remains committed if a later entry fails.

The operation still has one failure result and does not expose a per-entry completion mask. Repair a whole batch that may have completed an entry with a newer ordinal: the STRICTLY_INCREASING policy rejects rewriting completed entries at their recorded ordinal. If no entry completed, including when the sole entry of a one-entry call did not complete, the ordinal remains available. A corrected same-ordinal retry remains admissible subject to current stage state, except for a prim whose previous schema a forcing entry ended before the failure: that end stays recorded, so its retry needs a later ordinal. Allocation or size failures follow normal error reporting only while the runtime can keep the stage and its ordinal change records consistent with every previously completed entry.

Remark

Current implementation: a failed write can leave a prim visible to queries without recording its creation at the submitted ordinal. INSERT treats that prim as an existing target and rejects it with OVSTAGE_ERROR_PRIM_NOT_FOUND. A later successful UPSERT commits its attribute changes and their ordinal records but does not record a prim-creation event for that already-present prim.

Remark

Current implementation: after an entry is applied successfully, failure to record its prim, attribute and ordinal changes terminates the process rather than return an inconsistent instance. This condition is not surfaced through wait_op.

Param instance:

Implementation context.

Param handle:

Query handle identifying target prims.

Param writes:

Array of named attribute writes.

Param write_count:

Number of entries in writes.

Param ordinal:

Ordinal shared by the operation.

Param prim_mode:

UPSERT (default) or INSERT.

Return:

Enqueue result with status and one op_index for the complete group.

ovstage_api_status_t (*query_extension)(ovstage_context_t *instance, const char *name, const void **out_extension)#

Query an optional implementation-specific extension table.

Extension names are UTF-8, NUL-terminated identifiers. On success, *out_extension receives a pointer to an immutable function table owned by the implementation and valid for the lifetime of the process. The table layout is defined by the extension owner.

Returns OVSTAGE_OK when the extension exists, OVSTAGE_ERROR_NOT_FOUND when it does not, and OVSTAGE_ERROR_INVALID_ARGUMENT for NULL arguments.

struct ovstage_extension_header_t#
#include <ovstage_api.h>

Header that begins every ovstage extension table.

struct_size is the size in bytes of the table the implementation provides, and version its revision. Check both before using a field: a table smaller than the struct a caller was compiled against does not have that struct’s trailing fields, and they must not be read. Size alone does not establish compatibility; each extension’s header states which versions it accepts.

Public Members

uint32_t struct_size#
uint32_t version#

ovstage_api — shared types, handles, and instance bundle.

ovstage_api is a vtable-based contract for asynchronous, ordinal-keyed zero-copy simulation data access. It is the abstract API that various stage implementations can provide.

This header defines the data types (handles, error codes, enums, payload structs), the forward declarations for the vtable and context, and the ovstage_instance_t bundle that pairs them.

The vtable itself is defined in ovstage_api.h. Convenience static inline wrappers around the core data-plane slots live in ovstage_api_utils.h; higher-level extension APIs may live in sibling headers.

Defines

OVSTAGE_VERSION_MAJOR#
OVSTAGE_VERSION_MINOR#
OVSTAGE_VERSION_PATCH#
OVSTAGE_DEPRECATED(msg)#
OVSTAGE_ORDINAL_T_DECLARED#

Application/simulation ordinal used as the API’s ordering key.

The ordinal is not necessarily physical simulation time in nanoseconds. It is the scalar key used for write ordering, sealing/write floors, point/range change-membership reads, and retention frontiers. Applications that need physical time should carry an explicit ordinal-to-time mapping outside this scalar or in metadata.

Valid range: any uint64_t value. There is no sentinel; see ovstage_ordinal_range_t for how “latest” reads are expressed.

OVSTAGE_TIMEOUT_INFINITE#
OVSTAGE_INVALID_OP_ID#
OVSTAGE_INVALID_QUERY_HANDLE#
OVSTAGE_INVALID_READ_HANDLE#
OVSTAGE_INVALID_MAP_HANDLE#
OVSTAGE_INVALID_ORDINAL_QUERY_HANDLE#
OVSTAGE_INVALID_READ_GROUP_ID#
OVSTAGE_INVALID_QUERY_RESULT_ID#
OVSTAGE_INSTANCE_T_DECLARED#

Typedefs

typedef struct ovstage_context_t ovstage_context_t#

Opaque per-implementation context, stored in ovstage_instance_t.

typedef uint64_t ovstage_ordinal_t#
typedef const uint64_t *ovstage_mask_t#

Bitmask pointer.

NULL = all valid. Bit i set = element i is valid.

Element i is bit i % 64 of word i / 64, least significant bit first. A non-NULL mask spans at least ceil(count / 64) uint64_t words, where count is the logical element count of the structure carrying it; exactly that many words are read. Any bits above count in the final word are ignored.

typedef uint64_t ovstage_timeout_ns_t#

Timeout for fetch/wait calls, in nanoseconds.

  • 0 : non-blocking poll.

  • OVSTAGE_TIMEOUT_INFINITE : block until the result is ready.

  • any other value : block for up to that many nanoseconds before returning OVSTAGE_ERROR_TIMEOUT.

typedef uint64_t ovstage_op_id_t#

Monotonic per-instance operation identifier.

typedef uint64_t ovstage_query_handle_t#

Query handle — identifies a logical set of prims.

typedef uint64_t ovstage_read_handle_t#

Read handle — identifies an enqueued multi-attribute read.

typedef uint64_t ovstage_map_handle_t#

Map handle — identifies an enqueued mapped-write session.

typedef uint64_t ovstage_ordinal_query_handle_t#

Ordinal-query handle — identifies an enqueued read of an ordinal scalar, such as the global or per-attribute write floor.

typedef uint64_t ovstage_read_group_id_t#

Opaque identity for a fetched read group payload.

typedef uint64_t ovstage_query_result_id_t#

Opaque identity for a fetched query result payload.

Enums

enum ovstage_api_status_t#

API status / error code returned by ovstage calls (synchronous returns and the status field of enqueue results).

A typed enum rather than a bare integer: the fine-grained codes are retained, and a human-readable detail string for the most recent failure is available via ovstage_get_last_error() (or ovstage_get_last_op_error() for a failed op). The numeric values are stable ABI.

Values:

enumerator OVSTAGE_OK#
enumerator OVSTAGE_ERROR_INVALID_ARGUMENT#
enumerator OVSTAGE_ERROR_INVALID_HANDLE#

Stale/invalid handle of any kind.

enumerator OVSTAGE_ERROR_NOT_FOUND#
enumerator OVSTAGE_ERROR_PRIM_NOT_FOUND#

INSERT mode and prim already exists.

enumerator OVSTAGE_ERROR_WRITE_FLOOR_VIOLATION#

Mutation blocked by an effective floor or retained value/prim-lifecycle change; read selects an unsealed change at/before its end.

enumerator OVSTAGE_ERROR_NOT_SUPPORTED#
enumerator OVSTAGE_ERROR_QUEUE_FULL#

Backpressure: submit queue full.

enumerator OVSTAGE_ERROR_END_OF_ITERATION#

No more groups to iterate.

enumerator OVSTAGE_ERROR_OUT_OF_MEMORY#
enumerator OVSTAGE_ERROR_LAYOUT_CHANGED#

Layout changed during map.

enumerator OVSTAGE_ERROR_TIMEOUT#

Fetch/wait did not complete within timeout.

enumerator OVSTAGE_ERROR_OP_FAILED#

An enqueued op failed; see get_last_op_error.

enumerator OVSTAGE_ERROR_OUT_OF_RANGE#

Values needed for the requested snapshot or change range are no longer available.

enumerator OVSTAGE_ERROR_INTERNAL#
enum ovstage_filter_op_t#

Filter predicate operators for query matching.

Notes:

  • CONTAINS tests whether a composite value (array, string) contains at least one of the provided match values. For “contains all”, use multiple CONTAINS predicates (one per required value).

  • CONTAINS works on string attributes (substring match), array attributes (element membership), and any other composite data types.

  • Comparison operators (LT, LE, GT, GE) work on numeric and string attributes. String comparison is binary (byte-wise).

Values:

enumerator OVSTAGE_FILTER_OP_HAS#

Attribute exists on prim (no value test).

enumerator OVSTAGE_FILTER_OP_IN#

Attribute value ∈ {values} (single value = equals).

enumerator OVSTAGE_FILTER_OP_CONTAINS#

Composite attribute contains one of {values}.

enumerator OVSTAGE_FILTER_OP_PREFIX#

String attribute starts with one of {values}.

enumerator OVSTAGE_FILTER_OP_LT#

Attribute value < value.

enumerator OVSTAGE_FILTER_OP_LE#

Attribute value <= value.

enumerator OVSTAGE_FILTER_OP_GT#

Attribute value > value.

enumerator OVSTAGE_FILTER_OP_GE#

Attribute value >= value.

enum ovstage_prim_mode_t#

Write prim creation mode.

  • UPSERT (default): Create prims that don’t exist; update prims that do.

  • INSERT: Only create new prims; error if prim already exists.

Values:

enumerator OVSTAGE_PRIM_MODE_UPSERT#

Create if absent, update if present (default).

enumerator OVSTAGE_PRIM_MODE_INSERT#

Create only; OVSTAGE_ERROR_PRIM_NOT_FOUND if exists.

enum ovstage_attribute_mode_t#

What a write or map does when a target prim already has the attribute with a different schema.

An attribute’s schema is its storage &#8212; dtype, row layout, and fixed versus array kind &#8212; and its authored semantic.

  • REJECT (default): the write or map fails.

  • FORCE: the target prim’s existing schema is replaced by the written one.

See write_attribute and map_attribute for how a replacement is applied.

Values:

enumerator OVSTAGE_ATTRIBUTE_MODE_REJECT#

A differing existing schema fails the write or map (default).

enumerator OVSTAGE_ATTRIBUTE_MODE_FORCE#

A differing existing schema is replaced by the written one.

enum ovstage_scope_t#

Write-floor advance scope.

Values:

enumerator OVSTAGE_SCOPE_ALL#

Advance all attributes (and the global write floor).

enumerator OVSTAGE_SCOPE_INCLUDE#

Advance only listed attributes.

enumerator OVSTAGE_SCOPE_EXCLUDE#

Advance all EXCEPT listed attributes.

enum ovstage_attribute_semantic_t#

Per-attribute USD semantic — the authored interpretation of a column’s bytes, orthogonal to its DLDataType storage shape.

ovpopulation derives this from the USD SdfValueTypeName (role + scalar type) and carries it through writes; consumers (e.g. runtime→USD export) use it to recover the authored USD type (point3f vs float3, asset vs string, etc.). It is NOT part of the bucket key — float3 and point3f share bytes and a column. Tuple width comes from dtype.lanes, precision from dtype.bits; these roles deliberately do not encode dimensional suffixes such as 3f or 4d.

The semantic round-trips through the attribute column: write records it on the column at creation, read recovers it by decoding the column.

  • Geometric semantics (POINT, VECTOR, NORMAL, COLOR, QUATERNION, MATRIX, FRAME, TEXTURE_COORDINATE) record a geometric role on the column. Storage stays in the requested numeric dtype.

  • TIME_CODE marks a time code — a unitless time value — again with storage in the requested numeric dtype. Only the plain numeric value is carried: sentinel time codes have no portable numeric encoding, so they are not representable.

  • ID semantics select the corresponding ID storage type and require pre-interned id payloads (producers — e.g. ovpopulation — must intern via the path or token dictionary before writing; ovstage does not stringify or resolve):

    • TOKEN_ID → dtype = {kDLUInt, 64, 1} (one 64-bit token id per row; id 0 is the empty token)

    • RELATIONSHIP_PATH_ID → dtype = {kDLUInt, 64, 1} (one 64-bit path id per element; is_array = true is a relationship’s target list, is_array = false holds exactly one path per row)

    • CONNECTION_PATH_ID → dtype = {kDLUInt, 64, 2} (one (path_id, token_id) pair per row, using one 16-byte element per row)

    • ASSET_PATH_ID → dtype = {kDLUInt, 64, 2} (one (authored_token, resolved_token) pair per row, using one 16-byte element per row)

    An asset has two paths: the path as authored, and the path after resolution. ASSET_PATH_ID carries both as token ids. A token id of 0 means no path, so an unresolved asset has a resolved token id of 0. CONNECTION_PATH_ID writes are singular: they require exactly one pair per target prim. Extra pairs are rejected.

  • PATH_EXPRESSION_STRING carries the expression text as one interned token id, dtype {kDLUInt, 64, 1}. is_array = false is a scalar pathExpression; true is pathExpression[], one id per element. Other layouts return OVSTAGE_ERROR_INVALID_ARGUMENT. A token id of 0 means no expression. ovstage does not evaluate the expression; it stores the id of the authored text.

  • STRING carries a plain USD string value as raw UTF-8 bytes. The payload is a ragged kDLUInt,8,1 byte array (one string per row, is_array = true) — NOT a pre-interned token id. It stamps the USD-string role on the column, so the resulting column is the canonical USD-string representation. Read recovers the semantic by decoding that role. The row is length-delimited: every byte, including a trailing NUL, is part of the value, so do not append a C-style terminator. USD cannot persist a NUL byte inside a string, so export refuses a STRING row that contains one and reports it as unsupported. Only an untyped (SEMANTIC_NONE) byte row keeps the legacy reading where one trailing NUL is an optional terminator.

Either way, borrow and replicate modes converge on the same authored interpretation because they consult the same attribute column.

Values:

enumerator OVSTAGE_SEMANTIC_NONE#
enumerator OVSTAGE_SEMANTIC_ASSET_PATH_ID#
enumerator OVSTAGE_SEMANTIC_TOKEN_ID#
enumerator OVSTAGE_SEMANTIC_PATH_EXPRESSION_STRING#
enumerator OVSTAGE_SEMANTIC_RELATIONSHIP_PATH_ID#
enumerator OVSTAGE_SEMANTIC_POINT#
enumerator OVSTAGE_SEMANTIC_VECTOR#
enumerator OVSTAGE_SEMANTIC_NORMAL#
enumerator OVSTAGE_SEMANTIC_COLOR#
enumerator OVSTAGE_SEMANTIC_QUATERNION#

Four floating-point lanes in (x, y, z, w) order: imaginary part first, real part last.

enumerator OVSTAGE_SEMANTIC_MATRIX#
enumerator OVSTAGE_SEMANTIC_TEXTURE_COORDINATE#
enumerator OVSTAGE_SEMANTIC_CONNECTION_PATH_ID#
enumerator OVSTAGE_SEMANTIC_STRING#
enumerator OVSTAGE_SEMANTIC_TIME_CODE#
enumerator OVSTAGE_SEMANTIC_FRAME#
struct ovstage_cuda_sync_t#
#include <ovstage_api_types.h>

CUDA synchronization for a GPU data handoff.

The two fields are independent knobs — set either, both, or neither. Each non-zero field adds its own synchronization before the op:

  • stream — 0 = none; 1 = the default stream; >1 = a specific cudaStream_t. When set, all work currently queued on that stream is drained.

  • wait_event — 0 = none; otherwise a cudaEvent_t to wait on.

So { 0, event } waits on the event only, { stream, 0 } drains the stream only, { stream, event } does both, and { 0, 0 } is no synchronization (CPU-resident or already-synced data).

Public Members

uintptr_t stream#

CUDA stream to synchronize: 0 = none, 1 = default stream, >1 = a specific cudaStream_t.

uintptr_t wait_event#

CUDA event to wait on: 0 = none, else a cudaEvent_t.

struct ovstage_enqueue_result_t#
#include <ovstage_api_types.h>

Result of an asynchronous enqueue call.

  • status is the enqueue status. OVSTAGE_OK means the operation was accepted; the operation itself has not necessarily executed. Use the wait_op slot or a corresponding fetch_* call to observe completion/results.

  • op_index is OVSTAGE_INVALID_OP_ID when status != OVSTAGE_OK.

Public Members

ovstage_api_status_t status#
ovstage_op_id_t op_index#
struct ovstage_op_wait_result_t#
#include <ovstage_api_types.h>

Output of the wait_op slot.

  • error_op_ids lists op ids observed to have failed since the previous wait_op call on this thread. For each id, call the get_last_op_error slot to retrieve the human-readable error string. The array is transient thread-local memory and is invalidated by the next wait_op call on the same thread.

  • lowest_pending_op_id is meaningful only on OVSTAGE_ERROR_TIMEOUT: it is the lowest still-pending op id within the dependency chain of the waited op (not a global lowest across the instance). Useful for partial-progress reporting.

Public Members

const ovstage_op_id_t *error_op_ids#
size_t error_op_id_count#
ovstage_op_id_t lowest_pending_op_id#
struct ovstage_data_t#
#include <ovstage_api_types.h>

Data payload — array of tensors plus sparsity and GPU sync metadata.

Used for both read results (caller reads from tensors[i].data) and the map iterator (caller writes into tensors[i].data). The DLTensor metadata is owned by the implementation and treated as read-only by the caller.

Invariant

For value groups, tensor_count >= 1. For fixed-size attributes it is 1; for array attributes it equals the number of logical prim elements.

Invariant

A fixed-size value tensor has leading shape equal to the transported data-row count. Read and map tensors have dtype.lanes == 1 and type-aware trailing dimensions. Logical element i selects row i when index_map is NULL, or row index_map[i] otherwise.

Invariant

Every published tensor has non-NULL strides with compact row-major strides; NULL strides are never produced (DLPack v1.2+ forbids NULL strides when ndim != 0).

Invariant

For delete/tombstone read groups (is_delete == true), tensor_count == 0, tensors == NULL, and count == 0.

Invariant

index_map and mask are mutually exclusive.

Invariant

count is set (non-zero) when index_map or mask is non-NULL. When both are NULL, logical elements select data rows by identity.

Invariant

cuda_sync is {0, 0} for CPU-resident or already-synchronized data.

Public Members

const DLTensor *tensors#

Array of tensors (1 for fixed-size attrs; per-prim for array attrs).

uint32_t tensor_count#

Number of tensors in tensors.

uint32_t count#

Logical element count when index_map/mask present.

const uint32_t *index_map#

NULL = identity; non-NULL = gather/reorder/dedup.

ovstage_mask_t mask#

NULL = all valid; non-NULL = bitmask over elements.

ovstage_cuda_sync_t cuda_sync#

GPU sync applied before access; {0,0} = none.

See ovstage_cuda_sync_t.

struct ovstage_prim_group_t#
#include <ovstage_api_types.h>

Prim group — identifies which prims a group covers.

Uses four mutually exclusive representations:

  1. Full match: list == query list, offset=0, count=total, index_map=NULL

  2. Contiguous sub-range: same list, offset/count subset, index_map=NULL

  3. Sparse subset: same list, index_map non-NULL (gather indices into list)

  4. Different set: different list handle (resolve via path dictionary)

Handle comparison (list == other.list) is O(1) pointer equality.

Public Members

ovx_primpath_list_t list#

Comparable prim list handle (== for identity).

uint32_t offset#

Start index within list (0 if full match).

uint32_t count#

Number of prims in this group.

const uint32_t *index_map#

NULL = contiguous from offset; non-NULL = sparse indices.

struct ovstage_attribute_meta_t#
#include <ovstage_api_types.h>

Attribute metadata — write floor and layout generation.

Shared across read groups and map groups.

  • attribute_write_floor_ordinal: The write floor in effect for this attribute when the group was produced. Data at ordinals <= attribute_write_floor_ordinal is sealed (will never change).

  • layout_generation: Monotonically increasing counter scoped to the attribute. Bumps on structural changes (prim add/remove, index_map shape change). Stable when only values update. Enables consumers to skip re-setup on hot path.

Public Members

ovstage_ordinal_t attribute_write_floor_ordinal#

Write floor for this attribute.

uint64_t layout_generation#

Structural version (opaque).

struct ovstage_ordinal_range_t#
#include <ovstage_api_types.h>

Ordinal range for read operations.

  • Snapshot: has_start_ordinal = false, end_ordinal = N. Requests values at N for each requested attribute on all queried paths. A zero-initialized range is therefore a snapshot at ordinal 0, not a request for current values.

  • Change range [start, end]: has_start_ordinal = true, start_ordinal <= end_ordinal. Selects queried attribute/path pairs with recorded changes in [start_ordinal, end_ordinal], including both ends.

A selected change at or before the end and above the effective write floor fails with OVSTAGE_ERROR_WRITE_FLOOR_VIOLATION. If the read detects that the requested values are no longer available, it fails with OVSTAGE_ERROR_OUT_OF_RANGE. Use UINT64_MAX as the end to request current values; a selected unsealed change still fails with OVSTAGE_ERROR_WRITE_FLOOR_VIOLATION.

The requested end need not be at or below the attribute’s write floor (ovstage_get_attribute_write_floor). While the end is above the floor, changes in (floor, end] can still be admitted and, once sealed, change what the same request returns. Once the end is at or below the floor, later writes, deletes and maps cannot change the recorded values that a successful read of the same request returns for paths the query still selects. This does not cover derived attributes or query membership, which reflect current state, changes that ovstage_compute_hierarchy records at or below the floor, or history below the retention frontier (see below).

A returned group’s ordinal (ovstage_read_group_t::ordinal) is informational. It may be above or below the requested end, and it is not, by itself, proof of which state the payload represents.

A selected key whose schema was replaced in the change interval (a write or map commit with OVSTAGE_ATTRIBUTE_MODE_FORCE) returns both a tombstone for the previous schema and its payload in the written schema; see write_attribute.

Implementations may coalesce or discard history below their inclusive retention frontier. Query ovstage_get_oldest_preserved_ordinal before relying on an old snapshot or interval. Below the frontier, history may be insufficient to detect unavailable values; success does not guarantee the requested earlier state.

These checks use recorded change history. Snapshot reads of values without such history, including derived attributes such as usd-path, return current state. Queries select current paths, not the paths present at N. After an attribute’s deletion history is discarded, a snapshot from before that deletion may succeed without a row for that attribute.

Remark

This implementation stores only the current values. For each attribute, it first checks for the write-floor violation described above. Otherwise, a recorded change after end_ordinal on a selected path causes OVSTAGE_ERROR_OUT_OF_RANGE, whether that later change is sealed or not. Sealing the later change does not restore the older values. A read stops at the first attribute that fails either check. An end of UINT64_MAX skips this later-change check. Because a later change after the end makes a bounded request fail with OVSTAGE_ERROR_OUT_OF_RANGE, a bounded read is not a replay point.

0 is a valid ordinal (no sentinel values).

Remark

Under OVSTAGE_ORDINAL_ADMISSION_FLOOR_ONLY, a write or delete above the applicable floors can be admitted even when the same attribute and path already has a change at a higher ordinal. STRICTLY_INCREASING and the default NONDECREASING policy reject such older changes against retained history. Under FLOOR_ONLY, reads return the most recently applied change rather than the one at the highest ordinal, and a read whose end covers both changes can succeed with it. A group’s ordinal then need not match the change whose value is returned: depending on the operations that changed the attribute, it can be the most recently applied ordinal or the highest one recorded, and it may come from a prim outside the query. Groups of derived attributes such as usd-path report the requested end.

Remark

The current implementation retains bounded exact change membership at or above the frontier reported by ovstage_get_oldest_preserved_ordinal. Callers must query the frontier rather than assume a fixed retention depth. Ordinal ranges are therefore not a historical-payload event log. Historical-payload support must first return a retained in-range payload when one is available before reporting OVSTAGE_ERROR_OUT_OF_RANGE.

Public Members

ovstage_ordinal_t start_ordinal#

Range start (only when has_start_ordinal).

ovstage_ordinal_t end_ordinal#

Upper-bound ordinal; UINT64_MAX requests current values.

bool has_start_ordinal#

false = snapshot at end; true = changes in [start, end].

struct ovstage_read_group_t#
#include <ovstage_api_types.h>

A single read result group.

Public Members

ovstage_read_group_id_t read_group_id#

Opaque payload identity for release_group.

ovx_token_t attribute#

Which attribute this group contains.

ovstage_ordinal_t ordinal#

Informational ordinal; may differ from the requested end and does not by itself prove which state the payload represents.

See ovstage_ordinal_range_t.

bool is_delete#

true = tombstone group (deletions).

bool is_array#

true = source is a ragged (variable-length / USD-array or byte-string) column; false = fixed scalar.

The data is CSR either way, so this is the only signal that distinguishes e.g. a 1-byte string from a scalar uint8.

ovstage_attribute_semantic_t semantic#

Authored USD interpretation of the column’s bytes (point vs float3, asset vs string, …).

NONE when unspecified. Orthogonal to dtype/is_array; see ovstage_attribute_semantic_t.

ovstage_prim_group_t prims#

Which prims this group covers.

ovstage_data_t data#

Attribute data (array of tensors).

ovstage_attribute_meta_t meta#

Write floor + layout generation.

struct ovstage_map_group_t#
#include <ovstage_api_types.h>

A writable group returned by the map iterator.

Public Members

ovstage_prim_group_t prims#

Which prims this group covers.

ovstage_data_t data#

Writable tensor(s).

Caller writes values here.

ovstage_attribute_meta_t meta#

Layout generation (detect structural changes).

struct ovstage_map_desc_t#
#include <ovstage_api_types.h>

Descriptor for a map session (map_attribute).

Public Members

ovx_string_or_token_t attribute#

Attribute to map (name or interned token).

DLDataType dtype#

Requested element type.

Required to create a new mapped attribute. Leave zero-initialized only when the target prims already have one unambiguous schema for this attribute name. dtype.lanes carries the tuple width.

ovstage_attribute_semantic_t semantic#

Authored USD interpretation (point vs float3, asset vs string, …).

NONE = unspecified; adopts an unambiguous compatible existing identity. Conflicting authored roles on a target prim/name are rejected unless attribute_mode is FORCE. Takes effect only when unmap succeeds.

ovstage_prim_mode_t prim_mode#

UPSERT (create absent prims, update present) or INSERT (create-only; OVSTAGE_ERROR_PRIM_NOT_FOUND if a prim already exists).

ovstage_attribute_mode_t attribute_mode#

REJECT (default) fails setup when a target prim has the attribute with a different schema; FORCE replaces that schema when each group commits.

FORCE requires dtype. See ovstage_attribute_mode_t.

struct ovstage_predicate_t#
#include <ovstage_api_types.h>

Single filter predicate (tests one attribute).

  • HAS: attribute exists (values/value_count ignored).

  • IN: attribute value matches one of the provided values.

  • CONTAINS: composite attribute contains at least one of the values. Works on arrays (element membership), strings (substring), and composites. For “contains ALL”, use multiple CONTAINS predicates.

  • PREFIX: string attribute starts with one of the values.

  • LT/LE/GT/GE: numeric or binary (byte-wise) comparison (single value expected).

Public Members

ovx_string_or_token_t attribute#

Which attribute to test.

ovstage_filter_op_t op#

Comparison operator.

const ovx_string_t *values#

Match values (NULL for HAS).

size_t value_count#

Number of values (0 for HAS).

struct ovstage_filter_t#
#include <ovstage_api_types.h>

Query filter — conjunction (AND) of all predicates.

All predicates must match for a prim to be included.

Public Members

const ovstage_predicate_t *predicates#

Array of predicates (AND).

size_t count#

Number of predicates.

struct ovstage_query_result_t#
#include <ovstage_api_types.h>

Result of the fetch_query_result slot — discovered attributes + summary.

all_handle is the same query handle reserved by the query slot (or built by query_from_path_list). It is included for convenience so consumers receiving only this struct still have the handle in hand.

Public Members

ovstage_query_result_id_t query_result_id#

Opaque payload identity for release_query_result.

const ovx_token_t *attributes#

Discovered attribute tokens.

size_t attribute_count#

Number of distinct attributes.

ovstage_query_handle_t all_handle#

Handle covering all matched prims.

size_t total_prim_count#

Total prims matching the filter.

struct ovstage_write_floor_desc_t#
#include <ovstage_api_types.h>

Descriptor for advancing the per-attribute and/or global write floor.

Usage patterns:

  • SCOPE_ALL: advance the global write floor and every known attribute (end-of-frame signal).

  • SCOPE_INCLUDE {“transforms”}: advance only transforms after xform writer completes.

  • SCOPE_EXCLUDE {“points”, “velocities”}: advance all except physics attrs still being written. With an empty attribute list, SCOPE_EXCLUDE behaves like SCOPE_ALL.

To query the global write floor, call the get_attribute_write_floor slot with attribute = {.token = 0, .string = {NULL, 0}}.

To advance the global write floor (all attributes), use SCOPE_ALL.

Public Members

ovstage_ordinal_t ordinal#

New write-floor ordinal.

ovstage_scope_t scope#

ALL, INCLUDE, or EXCLUDE.

const ovx_token_t *attributes#

Attribute list (for INCLUDE/EXCLUDE).

size_t attribute_count#

Number of attributes in list.

struct ovstage_write_data_t#
#include <ovstage_api_types.h>

Write payload — tensor(s) plus sparsity and GPU sync metadata.

Exactly one of tensors and managed_tensors is non-NULL, selecting the lifetime model for the supplied tensors. Both arrays, when present, have length tensor_count.

Every attribute, including reserved metadata, follows this contract. usd-prim-type has the canonical fixed token-id schema (is_array == false); usd-schemas has the canonical token-id-array schema (is_array == true). A conflicting declaration is rejected. Both attributes use the normal row/count/mask/index_map coverage rules; their names do not trigger implicit broadcasting or kind correction.

Invariant

Exactly one of tensors / managed_tensors is non-NULL.

Invariant

tensor_count >= 1.

Invariant

When is_array == false, tensor_count == 1 and the tensor contains the fixed-size rows stacked along its leading dimension. The canonical input is ndim == 1, shape == {source_rows}, with the complete per-row tuple width in dtype.lanes. A compact convenience input may instead place tuple components in trailing shape dimensions (for example (N, 3) with lanes == 1, or (N, 4) with lanes == 4). Those per-row dimensions are folded into dtype.lanes; their rank and shape are not preserved. Reads and maps instead expose scalar lanes with component axes derived from the stored width and semantic: (N, 3) for a three-component tuple, (N, 4, 4) for a 4x4 MATRIX, and (N, 16) for a generic 16-component tuple. Without index_map, shape[0] must equal the logical element count. A flat (N * L,), lanes == 1 tensor is not an encoding of N rows of width L.

Invariant

When is_array == true, tensor_count == 1 selects packed uniform-row transport and tensor_count > 1 selects one tensor per source row. Neither form changes the declared logical kind. Packed transport carries no explicit row capacity &#8212; one flat tensor holds every row back to back &#8212; so its row count is inferred: the highest index_map entry plus one, or the logical element count when index_map is NULL. The uniform row width is the payload size divided by that inferred count &#8212; not by the logical element count &#8212; so an index_map declares the partition as well as selecting from it, and may declare more rows than the logical element count. A partition the payload cannot support is rejected: the payload must divide evenly across the inferred count, and the resulting row width must be a whole number of dtype elements. A packed payload cannot carry trailing rows above the highest index_map entry; they would change the inferred width of every row. Use tensor_count > 1 when rows must be described individually.

Invariant

index_map and mask are mutually exclusive.

Invariant

count is set (non-zero) when index_map or mask is non-NULL. Otherwise count == 0 means the write addresses every prim the query covers. A non-zero count addresses the leading count prims in query order and may not exceed the query’s prim count. The logical element count is count, or the query’s prim count when count == 0.

Invariant

index_map has count entries and holds source row indices, not target prim indices: logical element i reads transported row index_map[i]. Where the payload declares a transported row count &#8212; shape[0] when is_array == false, tensor_count for per-row array transport &#8212; every entry is less than it, and an out-of-range entry is rejected rather than reinterpreted. Rows no entry references are left unused, so the payload may carry more rows than the query has prims. Packed array transport declares no row count; there the map defines one, as described above.

Invariant

mask selects which of the count logical elements are written; unselected prims are left untouched. It does not change how the payload is cut into rows, so the payload still carries a row for every logical element, including the unselected ones. A non-NULL mask addresses at least ceil(count / 64) uint64_t words &#8212; the implementation reads that many &#8212; with element i at bit i % 64 of word i / 64.

Invariant

cuda_sync is {0, 0} for CPU-resident or already-synchronized data.

Public Members

const DLTensor *tensors#

Client-managed tensors (read-only to the implementation).

Must remain valid until op completes, or until the placement’s availability_event has completed when one is supplied (longer if that event could not be recorded; see ovstage_placement_t). NULL when managed_tensors is provided.

const DLManagedTensorVersioned *const *managed_tensors#

Storage-managed tensors (read-only to the implementation).

Deleter invoked once no work of the op reads them, which can be after op completion when an availability_event is supplied. NULL when tensors is provided.

uint32_t tensor_count#

Number of tensors in tensors/managed_tensors; selects transport layout, not attribute kind.

uint32_t count#

Logical element count; addresses the leading count prims in query order.

Required (non-zero) when index_map/mask present; 0 = every prim the query covers.

const uint32_t *index_map#

NULL = identity; non-NULL = gather/reorder/dedup.

count source row indices, each below the transported row count.

ovstage_mask_t mask#

NULL = all valid; non-NULL = bitmask over elements, at least ceil(count / 64) words long.

Selects target elements; it does not change how the payload is cut into rows.

ovstage_cuda_sync_t cuda_sync#

GPU sync applied before access; {0,0} = none.

See ovstage_cuda_sync_t.

ovstage_attribute_semantic_t semantic#

Authored USD interpretation for this write (NONE = unspecified).

Must match an existing prim/name unless the attribute is being created or attribute_mode is FORCE. Geometric semantics are recorded at creation and surfaced back on read; see ovstage_attribute_semantic_t.

bool is_array#

Logical attribute kind.

Sole authority for fixed (false) versus array (true) storage.

ovstage_attribute_mode_t attribute_mode#

REJECT (default) fails the write when a target prim has the attribute with a different schema; FORCE replaces that schema.

See ovstage_attribute_mode_t. Last field: the fields before it keep their earlier offsets.

struct ovstage_attribute_write_t#
#include <ovstage_api_types.h>

One named attribute write passed to write_attributes.

Attribute kind is declared by data.is_array with the same contract as write_attribute. Tensor count, tensor shape, payload width, attribute name, semantic, and existing storage never substitute for that declaration.

Public Members

ovx_string_or_token_t attribute#

Attribute to write (name or interned token).

ovstage_write_data_t data#

Write payload for this attribute.

struct ovstage_instance_t#
#include <ovstage_api_types.h>

Public Members

const ovstage_vtable_t *vtable#

Vtable pointer (see ovstage_api.h).

ovstage_context_t *context#

Implementation-specific context.

Convenience static inline wrappers around the core ovstage_api slots.

This header is included by ovstage_api.h after the vtable struct is defined. Callers should #include "ovstage_api.h" and then call the wrappers directly:

ovstage_query_handle_t qh;
ovstage_enqueue_result_t er = ovstage_query(instance, &filter,
                                            NULL, 0, &qh);
The core data-plane slots have wrappers here, including the diagnostics slots (ovstage_get_version, ovstage_get_error_string, ovstage_get_last_op_error) and the resources slot (ovstage_get_path_dictionary). Higher-level extension APIs live in sibling headers such as ovstage_instancing.h, and the wrappers for the experimental device-placement extension in experimental/ovstage_placement_extension.h.

Functions

static inline ovstage_api_status_t ovstage_wait_op(
ovstage_instance_t *instance,
ovstage_op_id_t op_id,
ovstage_timeout_ns_t timeout,
ovstage_op_wait_result_t *out_wait_result
)#
static inline ovstage_api_status_t ovstage_release_op(
ovstage_instance_t *instance,
ovstage_op_id_t op_id
)#
static inline ovstage_enqueue_result_t ovstage_advance_write_floor(
ovstage_instance_t *instance,
const ovstage_write_floor_desc_t *desc
)#
static inline ovstage_enqueue_result_t ovstage_get_oldest_preserved_ordinal(
ovstage_instance_t *instance,
ovstage_ordinal_query_handle_t *out_handle
)#
static inline ovstage_enqueue_result_t ovstage_get_attribute_write_floor(
ovstage_instance_t *instance,
ovx_string_or_token_t attribute,
ovstage_ordinal_query_handle_t *out_handle
)#
static inline ovstage_api_status_t ovstage_fetch_ordinal(
ovstage_instance_t *instance,
ovstage_ordinal_query_handle_t handle,
ovstage_timeout_ns_t timeout,
ovstage_ordinal_t *out_ordinal
)#
static inline ovstage_enqueue_result_t ovstage_release_ordinal_query(
ovstage_instance_t *instance,
ovstage_ordinal_query_handle_t handle
)#
static inline ovstage_enqueue_result_t ovstage_query(
ovstage_instance_t *instance,
const ovstage_filter_t *filter,
const ovx_token_t *attrs,
size_t attr_count,
ovstage_query_handle_t *out_query_handle
)#
static inline ovstage_api_status_t ovstage_query_from_path_list(
ovstage_instance_t *instance,
ovx_primpath_list_t path_list,
ovstage_query_handle_t *out_handle
)#
static inline ovstage_api_status_t ovstage_fetch_query_result(
ovstage_instance_t *instance,
ovstage_query_handle_t query_handle,
ovstage_timeout_ns_t timeout,
ovstage_query_result_t *out_result
)#
static inline ovstage_api_status_t ovstage_release_query_result(
ovstage_instance_t *instance,
const ovstage_query_result_t *result
)#
static inline ovstage_enqueue_result_t ovstage_release_query(
ovstage_instance_t *instance,
ovstage_query_handle_t handle
)#
static inline ovstage_enqueue_result_t ovstage_read_attributes(
ovstage_instance_t *instance,
ovstage_query_handle_t handle,
const ovx_token_t *attrs,
size_t attr_count,
ovstage_ordinal_range_t range,
ovstage_read_handle_t *out_read_handle
)#
static inline ovstage_api_status_t ovstage_fetch_read_next(
ovstage_instance_t *instance,
ovstage_read_handle_t read_handle,
ovstage_timeout_ns_t timeout,
ovstage_read_group_t *out_group
)#
static inline ovstage_api_status_t ovstage_release_group(
ovstage_instance_t *instance,
const ovstage_read_group_t *group
)#
static inline ovstage_enqueue_result_t ovstage_release_read(
ovstage_instance_t *instance,
ovstage_read_handle_t read_handle
)#
static inline ovstage_enqueue_result_t ovstage_write_attribute(
ovstage_instance_t *instance,
ovstage_query_handle_t handle,
ovx_string_or_token_t attribute,
ovstage_ordinal_t ordinal,
ovstage_write_data_t data,
ovstage_prim_mode_t prim_mode
)#
static inline ovstage_enqueue_result_t ovstage_write_attributes(
ovstage_instance_t *instance,
ovstage_query_handle_t handle,
const ovstage_attribute_write_t *writes,
size_t write_count,
ovstage_ordinal_t ordinal,
ovstage_prim_mode_t prim_mode
)#
static inline ovstage_enqueue_result_t ovstage_map_attribute(
ovstage_instance_t *instance,
ovstage_query_handle_t handle,
const ovstage_map_desc_t *desc,
ovstage_ordinal_t ordinal,
const size_t *element_sizes,
size_t element_count,
ovstage_map_handle_t *out_map_handle
)#
static inline ovstage_api_status_t ovstage_fetch_map_next(
ovstage_instance_t *instance,
ovstage_map_handle_t map_handle,
ovstage_timeout_ns_t timeout,
ovstage_map_group_t *out_group
)#
static inline ovstage_enqueue_result_t ovstage_unmap_group(
ovstage_instance_t *instance,
ovstage_map_handle_t map_handle,
const ovstage_map_group_t *group,
ovstage_cuda_sync_t write_done_sync
)#
static inline ovstage_enqueue_result_t ovstage_unmap_attribute(
ovstage_instance_t *instance,
ovstage_map_handle_t map_handle,
ovstage_cuda_sync_t write_done_sync
)#
static inline ovstage_enqueue_result_t ovstage_delete_attributes(
ovstage_instance_t *instance,
ovstage_query_handle_t handle,
const ovx_string_or_token_t *attributes,
size_t attribute_count,
ovstage_ordinal_t ordinal
)#
static inline void ovstage_get_version(
ovstage_instance_t *instance,
uint32_t *out_major,
uint32_t *out_minor,
uint32_t *out_patch
)#
static inline const char *ovstage_get_error_string(
ovstage_instance_t *instance,
ovstage_api_status_t error
)#
static inline ovx_string_t ovstage_get_last_op_error(
ovstage_instance_t *instance,
ovstage_op_id_t op_id
)#
static inline path_dictionary_instance_t *ovstage_get_path_dictionary(
ovstage_instance_t *instance
)#
static inline ovstage_api_status_t ovstage_query_extension(
ovstage_instance_t *instance,
const char *name,
const void **out_extension
)#

Functions

static inline ovstage_api_status_t ovstage_tensor_to_write(
const DLTensor *source,
DLTensor *output,
int64_t layout[2]
)#

Explicitly convert a typed read or map tensor to the lane-based array-write layout.

Only call for a tensor obtained from an OVStage read or map, whose trailing axes describe components. This does not infer types for arbitrary scalar arrays. No payload is copied. Preserve the attribute’s semantic and array kind. Copy payload AND descriptor metadata before releasing the read group if the write targets its pinned storage. Caller-owned layout[2] and payload must remain valid until the write completes. On error, output is unchanged.

Experimental Device Placement#

The ovstage.placement extension selects CPU or CUDA copies for reads, writes, and maps. Include <ovstage/ovstage_api/experimental/ovstage_placement_extension.h> explicitly; ovstage.h does not include it. Its API, ABI, and semantics may change between releases. Lookup requires the exact extension version and a sufficiently large table; unavailable or incompatible implementations return OVSTAGE_ERROR_NOT_FOUND. See Experimental Device Placement for device selection and synchronization.

Experimental device-placement extension (“ovstage.placement”): write, map and read on a specific device.

Experimental. Everything in this header &#8212; ovstage_placement_t, OVSTAGE_PLACEMENT_INIT, the extension table and its wrappers &#8212; may change between releases in source/API, ABI and semantics. Check availability at run time: ovstage_query_placement_extension() and every wrapper below return OVSTAGE_ERROR_NOT_FOUND when the implementation does not provide a table this header can use. Once stable, placement stays an extension; it does not move into ovstage_vtable_t.

Versioning: the lookup accepts only header.version equal to OVSTAGE_PLACEMENT_EXTENSION_VERSION, with header.struct_size at least sizeof(ovstage_placement_extension_v1_t). An additive change &#8212; entries appended, nothing existing changed &#8212; grows struct_size and keeps the version. Any other change, including one to ovstage_placement_t, bumps the version, so a caller built against an older header gets OVSTAGE_ERROR_NOT_FOUND instead of a table it would misuse.

Placement is reached through query_extension, not ovstage_vtable_t, and <ovstage/ovstage.h> does not include this header. Include it explicitly:

#include <ovstage/ovstage_api/experimental/ovstage_placement_extension.h>

Defines

OVSTAGE_PLACEMENT_INIT#

Initializer for ovstage_placement_t: everything unspecified.

Assign the fields you care about afterwards.

ovstage_placement_t placement = OVSTAGE_PLACEMENT_INIT;

OVSTAGE_PLACEMENT_EXTENSION_NAME#

Name to pass to query_extension for the device-placement extension.

OVSTAGE_PLACEMENT_EXTENSION_VERSION#

Version this header describes; the lookup accepts only this exact value.

Functions

static inline ovstage_api_status_t ovstage_query_placement_extension(
ovstage_instance_t *instance,
const ovstage_placement_extension_v1_t **out_extension
)#

Look up the device-placement extension (“ovstage.placement”).

Returns OVSTAGE_OK and sets *out_extension when the implementation provides the extension at exactly OVSTAGE_PLACEMENT_EXTENSION_VERSION, in a table at least as large as ovstage_placement_extension_v1_t. Returns OVSTAGE_ERROR_NOT_FOUND otherwise &#8212; an implementation that predates the extension or serves another version of it &#8212; and OVSTAGE_ERROR_INVALID_ARGUMENT for a NULL out_extension.

This is the capability check. A caller that needs placement can fail cleanly here instead of discovering its absence on the first placed call; the ovstage_*_on_device wrappers below run the same check on every call.

static inline ovstage_enqueue_result_t ovstage_write_attribute_on_device(
ovstage_instance_t *instance,
ovstage_query_handle_t handle,
ovx_string_or_token_t attribute,
ovstage_ordinal_t ordinal,
ovstage_write_data_t data,
ovstage_prim_mode_t prim_mode,
const ovstage_placement_t *placement
)#
static inline ovstage_enqueue_result_t ovstage_write_attributes_on_device(
ovstage_instance_t *instance,
ovstage_query_handle_t handle,
const ovstage_attribute_write_t *writes,
size_t write_count,
ovstage_ordinal_t ordinal,
ovstage_prim_mode_t prim_mode,
const ovstage_placement_t *placement
)#
static inline ovstage_enqueue_result_t ovstage_read_attributes_on_device(
ovstage_instance_t *instance,
ovstage_query_handle_t handle,
const ovx_token_t *attrs,
size_t attr_count,
ovstage_ordinal_range_t range,
const ovstage_placement_t *placement,
ovstage_read_handle_t *out_read_handle
)#
static inline ovstage_enqueue_result_t ovstage_map_attribute_on_device(
ovstage_instance_t *instance,
ovstage_query_handle_t handle,
const ovstage_map_desc_t *desc,
ovstage_ordinal_t ordinal,
const size_t *element_sizes,
size_t element_count,
const ovstage_placement_t *placement,
ovstage_map_handle_t *out_map_handle
)#
struct ovstage_placement_t#
#include <ovstage_placement_extension.h>

Device placement — which device’s copy of an attribute a write produces.

Destination residency. This is the counterpart of ovstage_cuda_sync_t, which describes the source handoff; the two are independent. A producer may hand over a tensor on one device while asking that the write land on another.

Placement selects a mirror; it does not pin a column to one device for its lifetime. Stage storage keeps CPU and per-device copies and tracks which are current, so a later write to the same attribute with a different placement is an ordinary mirror update, not a conflict, and never an error.

The guarantee placement buys is on the read side: after a write placed on device D completes, a read of that attribute on device D is served from the copy already current on D and performs no migration. It does not promise the data is absent from other devices.

One placement applies to an entire operation — it is a parameter of the slot, not a per-attribute field, so a single operation cannot name two devices. Placing two attributes on two devices takes two operations.

Placement reaches the API through the “ovstage.placement” extension declared below, rather than by widening the existing slots: write_attribute_on_device, write_attributes_on_device and map_attribute_on_device are the placed counterparts of write_attribute, write_attributes and map_attribute. An unplaced call is byte-for-byte the call it always was, and a NULL placement on a placed function reproduces it exactly: the write follows the source tensor’s device, the map stages on the host.

read_attributes_on_device takes a placement too, but it selects rather than places: a read asks for data that already exists somewhere, so device names which of an attribute’s copies the returned groups point at. A column already current there is pointed straight at; one current elsewhere is materialized onto the requested device rather than the read failing. stream carries that transfer, and availability_event is what makes it asynchronous. read_attributes is unchanged, and a NULL placement on the placed read is that call.

The pointer does not have to outlive the call. Everything the operation needs is copied out of the struct during the enqueue, so a caller may pass the address of a local.

Within a supplied struct, a zero-initialized device ({0, 0}) is also “unspecified” — DLPack assigns no device type 0 (kDLCPU == 1), so that field pattern is unambiguously “I did not ask”.

Every direction is staged, for fixed-size and ragged (is_array == true) payloads alike: host to CUDA, CUDA to a different CUDA device (peer), and CUDA back to the host. A ragged payload transports one tensor per row, so staging moves every row into one allocation and preserves the row structure. A strided host row is packed by its strides, so it lands with the values an unplaced write gives it; a row with a negative or zero (broadcast) stride is rejected with OVSTAGE_ERROR_NOT_SUPPORTED.

Remark

A placement that agrees with the source tensor’s device is honored directly. A host payload placed on a CUDA device is staged onto that device and scattered there, so the column becomes current on the GPU — this is the common case of producing data on the CPU for a GPU consumer. Staging currently costs a full device synchronization, because the scatter runs on the default stream and the staged buffer cannot be released until it drains; honoring stream removes that.

A staged write honors the payload’s ovstage_cuda_sync_t before it first reads the payload, on the source tensor’s device (stream == 1

is that device’s default stream).

One exception, and it is observable: a write that has to

stage (its placement names a device other than the source’s) drains that stream before releasing the staging buffer, because the buffer is scoped to the call. Such a write is therefore synchronous despite naming a stream. A placed write whose source already lives on the target device stages nothing and runs fully asynchronously.

Remark

stream carries the op’s device work for a fixed-size placed write: the scatter is launched on it. The write executes after the enqueue returns, so work enqueued on stream is ordered behind it only once ovstage_wait_op has reported the write complete &#8212; a host-side handshake, not a wait for the GPU. See the safe sequences under availability_event.

stream is ignored for ragged (is_array) writes, whose device work stays on the default stream; their payload is still staged onto the placed device, only the scatter is not stream-ordered.

It marks availability rather than this operation’s completion, and the two are not the same instant &#8212; on a placed read they are deliberately not the same instant (see below). Availability is also the one meaning that covers all three placed operations: a placed write makes its data available on the target device, a placed map’s commit makes the values it committed available, and a placed read makes the column available.

Remark

availability_event is how a caller learns that the memory the operation concerns is safe to dereference without the host waiting for the device work. It does not replace ovstage_wait_op (or a read’s successful fetch), which is still the point after which the event has been recorded. It is a cudaEvent_t the caller creates and owns; ovstage records into it and never creates, destroys or hands back a CUDA object. That matches stream and ovstage_cuda_sync_t, which are also caller-owned.

It is the one outbound field here. ovstage_cuda_sync_t describes the source handoff and ovstage waits on it; availability_event describes the destination and ovstage signals it. A write may use both: wait for the producer, then signal this when the scatter is done.

It is recorded exactly once for every accepted operation (for a placed map, every commit; see the end of this remark), on stream, after the device work is launched &#8212; and also when the operation turns out to need no device work at all, and when it fails. A caller can therefore always wait on it without risking a wait that never ends. The converse would be unusable: the caller cannot know which internal path an operation took. A call rejected synchronously &#8212; an invalid op_index &#8212; owes no record and leaves the event untouched, unless it was rejected for lack of memory.

That makes the event fire mean “stop waiting”, not “the data is

good”.

Because a failed operation records it too &#8212; so that no caller waits forever on work that will never land &#8212; the event on its own says nothing about whether the operation succeeded, and the name is not a promise that the memory holds valid data. The caller still checks the operation’s status (ovstage_wait_op, or the fetch that hands back the payload). The event bounds the wait; the status qualifies what the memory is worth.

Wait only after the submission boundary. The record is issued when the operation executes, after the enqueue has returned; a wait issued earlier, on the event or on stream, observes an old or never-recorded event and orders nothing against this operation. The safe sequences, neither of which waits on the host for the GPU:

  • Write, or map commit (unmap_group, unmap_attribute): enqueue; ovstage_wait_op returns OVSTAGE_OK for it; then wait on the event, or enqueue the downstream work on stream.

  • Read: enqueue; fetch_read_next hands back a group, which happens only after the record was issued; then make the consumer wait on the event (cudaStreamWaitEvent), or enqueue it on stream.

Event completion does not replace that status check: a failed operation records the event too. A default stream is the default stream of the device the record ran on; stream == 2 is the per-thread stream of the thread that ran the operation, not necessarily the caller’s, so there only the event orders the caller’s work.

A record that CUDA refuses is reported, not swallowed: the event is left untouched and an otherwise successful operation reports OVSTAGE_ERROR_OP_FAILED with a diagnostic naming availability_event. That failure comes after the operation’s effects and does not undo them: a write’s entries stay committed at its ordinal, so under the STRICTLY_INCREASING admission policy a retry of them needs a later one, and a map commit’s changes stay recorded (the session of an unmap_group stays open; an unmap_attribute still consumes its handle). A placed read fails instead of handing back its payload, and an operation that completes during the enqueue is rejected synchronously, after it ran. Nothing drains a write’s device work on that path, and the untouched event does not cover it, so its client-managed source stays borrowed until, after ovstage_wait_op has returned, the caller has synchronized stream if it is a specific stream, or else the device the record was due to run on (for example cudaDeviceSynchronize with that device current; stream == 2 names the per-thread stream of the thread that ran the write). A storage-managed source is still released once that work has finished.

It must be a live cudaEvent_t. ovstage probes the handle and rejects one CUDA recognizes as dead, but no API can validate an arbitrary integer as an event &#8212; querying one dereferences it. Passing a value that was never an event is undefined behaviour, as it is for any handle a C API takes.

It must also belong to the device the record runs on. With a specific stream that is the stream’s device. A default stream (0, 1, or 2 for cudaStreamPerThread) is the default stream of device when that is a CUDA device; for a write whose device is unspecified and that has CUDA source tensors, of the device they live on; otherwise, a host device included, of the device current on the calling thread when the operation is enqueued (for a map, the map_attribute_on_device call). A write whose device is unspecified and that has CUDA sources on more than one device cannot be covered by one record on a default stream and is rejected with OVSTAGE_ERROR_INVALID_ARGUMENT.

Lifetime differs from the rest of this struct. The struct itself need not outlive the call, but the event must: it is recorded when the operation executes, which is after the enqueue returns, so destroying it before the record is issued is a use-after-free. The record has been issued, or refused, once ovstage_wait_op has returned OVSTAGE_OK or OVSTAGE_ERROR_OP_FAILED for the operation, or a read’s fetch_read_next has handed back a group. A wait on the event or on stream before then establishes nothing.

Supplying one makes the operation genuinely asynchronous: ovstage otherwise drains the device work before reporting the op complete, so ovstage_wait_op alone implies the data has landed. With an availability event, ovstage_wait_op no longer implies that for the cases ovstage can leave running &#8212; wait on the event. The exceptions are the ones listed above: a write that must stage drains its call-scoped buffer regardless, and a ragged write runs on the default stream, so for those the event is already signalled by the time the op completes. It is correct in every case; it only buys asynchrony in some.

For a write, the device work left running reads the source: a client-managed source (ovstage_write_data_t::tensors) stays borrowed until this event has completed, not merely until ovstage_wait_op returns, and a storage-managed one is released only once that work has finished. If the event could not be recorded, the borrow lasts until the synchronization described above instead.

On a placed read the event is not that read’s completion, and that is deliberate. The read operation completes first: it hands back pointers, and the event marks the later moment those pointers became safe to dereference. It has to, because it covers more than the read’s own work &#8212;

both any write ovstage has already run into the columns the read touches, including device work that write left running on whatever stream ovstage issued it on, and the read’s own transfer, if one was needed. Some of what it waits for is therefore work the caller never issued, which is exactly why “when this

operation finished” is the wrong way to read it. Once a group has been fetched, waiting on it is

sufficient: a caller that then waits on the event, or enqueues its own work on stream behind it, may dereference the payload without knowing which route the read took or which stream any producing write used. ovstage orders the read behind those writes with events of its own; those are internal and are neither this event nor ever handed back.

The caveat above applies here with the most force: a read whose event has fired is a read that is done making the caller wait, not a read that returned a payload worth looking at. Check its status first.

A caller who supplies no availability event gets the same guarantee the other way round: ovstage does the waiting itself, so the operation does not report complete until both the earlier write and any transfer have landed, and the payload is ready the moment it is handed over.

The transform-hierarchy pass that ovstage runs for a read, query, seal or ovstage_compute_hierarchy first waits on the host for every write it still has in flight, so it derives transforms only from landed writes. A pass run outside ovstage on the same stage data, such as an attached renderer’s own propagation, is not ordered behind those writes: wait on their events before starting one.

A placed map records it on each commit &#8212; every unmap_group and unmap_attribute of the session &#8212; once that commit has run. Its setup records it only if cancelled before it runs, so the event covers committed values, not the staging buffers fetch_map_next hands back.

Public Members

DLDevice device#

Target mirror.

{0, 0} = unspecified (follow the source tensor).

uintptr_t stream#

0/1 = legacy default stream, 2 = per-thread default stream, else a cudaStream_t.

uintptr_t availability_event#

Caller-owned cudaEvent_t recorded when the memory is safe to use; 0 = none.

struct ovstage_placement_extension_v1_t#
#include <ovstage_placement_extension.h>

Device-placement extension: placed write, map and read.

Obtain it with ovstage_query_placement_extension(), below, or call ovstage_write_attribute_on_device() and its siblings directly: they look the table up and return OVSTAGE_ERROR_NOT_FOUND when the implementation does not provide it. The table is owned by the implementation, immutable, and valid for the lifetime of the process. Every function takes the implementation context as its first argument, exactly like a vtable slot.

Public Members

ovstage_extension_header_t header#
ovstage_enqueue_result_t (*write_attribute_on_device)(ovstage_context_t *instance, ovstage_query_handle_t handle, ovx_string_or_token_t attribute, ovstage_ordinal_t ordinal, ovstage_write_data_t data, ovstage_prim_mode_t prim_mode, const ovstage_placement_t *placement)#

Enqueue a write of attribute values, targeting a specific device.

Identical to write_attribute except that placement selects which device’s copy of the attribute the write produces, and except for the availability-event failure rule below. See ovstage_placement_t for the placement contract and for the current implementation limits.

If placement->availability_event cannot be recorded, the write still applies and reports OVSTAGE_ERROR_OP_FAILED. It has consumed its ordinal, so write_attribute’s same-ordinal retry after a failure does not apply.

Param instance:

Implementation context.

Param handle:

Query handle identifying target prims.

Param attribute:

Attribute to write.

Param ordinal:

Ordinal for this write (must be > write floor at execution time).

Param data:

Write payload (tensors + cuda_sync + mask/index_map).

Param prim_mode:

UPSERT (default) or INSERT.

Param placement:

Target device for this operation. NULL = unspecified (follow the source tensor’s device), which makes this exactly write_attribute.

Return:

Enqueue result with status + op_index. Placement errors are provable during preflight and are returned synchronously with an invalid op_index.

ovstage_enqueue_result_t (*write_attributes_on_device)(ovstage_context_t *instance, ovstage_query_handle_t handle, const ovstage_attribute_write_t *writes, size_t write_count, ovstage_ordinal_t ordinal, ovstage_prim_mode_t prim_mode, const ovstage_placement_t *placement)#

Enqueue a multi-attribute write, targeting a specific device.

Identical to write_attributes except that placement selects which device’s copy the operation produces, for every attribute in it. A single operation cannot name two devices; use two operations.

If placement->availability_event cannot be recorded, the write still applies and reports OVSTAGE_ERROR_OP_FAILED. It has consumed its ordinal, so write_attributes’ same-ordinal retry after a failure does not apply.

Param instance:

Implementation context.

Param handle:

Query handle identifying target prims.

Param writes:

Per-attribute write entries.

Param write_count:

Number of entries in writes.

Param ordinal:

Ordinal for this write (must be > write floor at execution time).

Param prim_mode:

UPSERT (default) or INSERT.

Param placement:

Target device for this operation. NULL = unspecified (follow the source tensor’s device), which makes this exactly write_attributes.

Return:

Enqueue result with status + op_index.

ovstage_enqueue_result_t (*map_attribute_on_device)(ovstage_context_t *instance, ovstage_query_handle_t handle, const ovstage_map_desc_t *desc, ovstage_ordinal_t ordinal, const size_t *element_sizes, size_t element_count, const ovstage_placement_t *placement, ovstage_map_handle_t *out_map_handle)#

Enqueue a map session whose staging buffers live on a device.

Identical to map_attribute except that placement selects where the writable staging buffers handed back by fetch_map_next are allocated, so a CUDA kernel can fill them in place.

Each unmap_group and unmap_attribute records it; one that cannot reports OVSTAGE_ERROR_OP_FAILED after its commit. An unmap_group then leaves the session open; an unmap_attribute still consumes the handle.

Remark

Staging is write-only and uninitialized; it does not contain the attribute’s current values. Fill every selected element before committing a group. To preserve existing values, read them first and explicitly copy them into staging before applying edits. Release overlapping read groups before committing the map. CUDA staging is supported only for fixed-size attributes; array-valued CUDA maps return OVSTAGE_ERROR_NOT_SUPPORTED.

Remark

A map’s own device work &#8212; the unmap scatter &#8212; still runs on the mapped device’s default stream, not on placement->stream. The stream is not inert, though: each commit &#8212; unmap_group and unmap_attribute &#8212; records placement->availability_event on it once that commit has run, so after ovstage_wait_op reports the commit complete a consumer can chain off that stream or the event. It covers the committed values, not the staging buffers fetch_map_next hands back. Because the scatter is host-drained before the mapping is released, recording there can only make the signal later than the work, never earlier.

Param instance:

Implementation context.

Param handle:

Query handle identifying target prims.

Param desc:

Map descriptor (attribute, dtype, semantic, prim_mode).

Param ordinal:

Ordinal for this map session.

Param element_sizes:

Per-prim element counts for array attributes, else NULL.

Param element_count:

Number of entries in element_sizes, else 0.

Param placement:

Device for the staging buffers. NULL = the host, which makes this exactly map_attribute.

Param out_map_handle:

Receives the reserved map handle.

Return:

Enqueue result with status + op_index.

ovstage_enqueue_result_t (*read_attributes_on_device)(ovstage_context_t *instance, ovstage_query_handle_t handle, const ovx_token_t *attrs, size_t attr_count, ovstage_ordinal_range_t range, const ovstage_placement_t *placement, ovstage_read_handle_t *out_read_handle)#

Enqueue a multi-attribute read served from a specific device.

Identical to read_attributes except that placement->device selects which of an attribute’s copies the returned groups point at. The payload DLTensors report that device, so a CUDA read yields pointers a kernel can consume without a host round-trip.

Unlike the placed write and map functions, this one is permissive: when the column is not current on the requested device it is made available there rather than the read failing. That is the difference between placing and selecting &#8212; a write chooses where data should land, while a read asks for data that already exists somewhere, and refusing it would leave the caller no recourse but to read it elsewhere and copy it themselves, which is the work this function is doing on their behalf.

Zero-copy is preserved where it is available: if the column is already current on placement->device the group points straight into that copy and nothing is transferred. Only a column that is current elsewhere is materialized onto the requested device, into storage owned by the group and released with it by release_group.

The read operation completes before the event fires, and that is deliberate. The event is not this read’s completion &#8212; it is when the payload became available. It has to be, because half of what it waits for is a write the caller never issued. A read that reports complete has therefore said nothing about its own pointers; the event is what says they are safe.

Remark

placement->availability_event is what makes a transferring read asynchronous, and the guarantee on it is that waiting on it is sufficient. fetch_read_next hands back a group only after the record was issued, so wait once a group is in hand; a wait issued earlier may observe an old or unrecorded event. Until it has been waited on &#8212; or until the caller’s own work is enqueued on placement->stream behind it &#8212; the pointers in the group are not safe to dereference. Once it has, they are, because the event covers both halves of what the data depends on: any write ovstage has already run into the columns this read touches, including device work that write left running on whatever stream ovstage issued it on, and this read’s own transfer, if one was needed. A caller therefore never has to know which route the read took, nor which stream a producing write used: a read served with no transfer at all records the event just the same, and ovstage orders the read behind those writes using events of its own, which are internal and never handed back.

And the event firing means “stop waiting”, not “the data is

good”.

It is recorded for every accepted operation including one that fails &#8212; that rule is what keeps a caller from waiting forever &#8212; so a fired event is not evidence the read succeeded. Check the operation’s status before dereferencing what it handed back. A read whose event cannot be recorded fails instead of handing back its payload.

This is what read_attributes has always promised, but it is not what it previously did. An unplaced read takes the host copy of a column, and a write that left its scatter running had already marked the host copy stale, so the download that refreshed it was issued without ordering against the stream still writing. An unplaced read now waits for that write too, which costs it a host wait it did not previously pay &#8212; and did not previously pay correctly.

Remark

A caller who supplies no availability event gets the same guarantee without doing anything: ovstage does the waiting itself &#8212; for the earlier write’s device work and for this read’s transfer &#8212; before the operation reports complete, so the payload is ready as soon as fetch_read_next hands it over.

Remark

The asynchrony is partial, and worth knowing before budgeting for it. Stage storage is pageable host memory, and a host-to-device copy out of pageable memory stages through an internal pinned buffer: that staging copy is paid synchronously, inside the call, and only the DMA that follows it overlaps. So an availability event removes the drain, not the copy. It also currently runs under the instance lock. A read already current on the requested device transfers nothing and has neither cost.

Param instance:

Implementation context.

Param handle:

Query handle identifying target prims.

Param attrs:

Attributes to read.

Param attr_count:

Number of entries in attrs.

Param range:

Ordinal range to read.

Param placement:

Device to serve the read from, the stream any transfer is issued on, and the availability event recorded when the payload becomes safe to dereference. NULL = the host, which makes this exactly read_attributes.

Param out_read_handle:

Receives the reserved read handle.

Return:

Enqueue result with status + op_index.

Configuration#

Helpers for building the ovstage_config_t entries passed to ovstage_initialize().

Helpers for building ovstage_config_t entries passed to ovstage_initialize().

Functions

static inline ovstage_config_entry_t ovstage_config_entry_string(
ovstage_config_string_t key,
ovx_string_t value
)#

Build a config entry for a string setting.

Parameters:
  • key – Config key from ovstage_config_string_t.

  • value – String value. value.ptr must remain valid until the API call that consumes the config returns.

static inline ovstage_config_entry_t ovstage_config_entry_uint64(
ovstage_config_uint64_t key,
uint64_t value
)#

Build a config entry for an unsigned 64-bit setting.

Parameters:
  • key – Config key from ovstage_config_uint64_t.

  • value – Unsigned 64-bit value.

static inline ovstage_config_entry_t ovstage_config_entry_runtime_default_hierarchy_computation_model(
ovstage_hierarchy_computation_model_id_t model
)#

Configure the hierarchy computation model used by automatic transform updates and by OVSTAGE_HIERARCHY_COMPUTATION_MODEL_RUNTIME_DEFAULT.

To override the default, use CPU_INCREMENTAL, GPU_INCREMENTAL, or GPU_GLOBAL (the DEFAULT_CPU and DEFAULT_GPU aliases are also accepted). RUNTIME_DEFAULT means “no override”; an entry with that value is ignored.

The setting is process-scoped and must be supplied when acquiring the first process reference. Existing instances retain the default captured when they were created.

static inline ovstage_config_entry_t ovstage_config_entry_runtime_default_ordinal_admission_policy(
ovstage_ordinal_admission_policy_t policy
)#

Configure ordinal admission for data-plane writes, maps, clones and deletes.

DEFAULT means no override. A fresh process-state lifetime uses NONDECREASING; later DEFAULT entries inherit the active policy. Supply a concrete policy on the first process reference. Later concrete values must match until all initialization and instance references are gone.

Parameters:
  • policy – The ordinal admission policy.

static inline ovstage_config_entry_t ovstage_config_entry_binary_package_root_path(
ovx_string_t path
)#

Configure the ovstage “binary package root” directory.

This is used by the static loader (ovstage-static) to locate the ovstage shared library and, transitively, its bundled runtime closure (plugins/), which ovstage resolves relative to the directory the shared library is loaded from. If not provided, the loader defaults to its own module directory.

Pass this entry to ovstage_initialize(). The loader loads the shared library once, from the root supplied on that first load — so static-loader consumers that need a non-default root must call ovstage_initialize() with this entry BEFORE any other ovstage_* call (ovstage_create_instance would otherwise trigger the load from the default module directory). Ignored by the dynamic ovstage shared library, so it is harmless when passed in non-static builds.

Parameters:
  • path – The package bin/ directory. path.ptr must remain valid until the ovstage_initialize() call that consumes the config returns. The path may contain the OVX_CONFIG_EXECUTABLE_DIR_TOKEN token, which the static loader substitutes with the absolute directory of the running executable (e.g. OVX_CONFIG_EXECUTABLE_DIR_TOKEN “/ovstage/bin”).

ovx_string_t ovstage_executable_dir(void)#

Absolute directory of the running executable, with no trailing separator.

Convenience for static-loader clients building the binary package root, e.g. OVX_CONFIG_EXECUTABLE_DIR_TOKEN “/ovstage”, to pass via ovstage_config_entry_binary_package_root_path() — so callers need not reimplement the platform-specific GetModuleFileName/readlink lookup.

Provided by the ovstage-static loader (link ovstage::ovstage_static); it is not exported by the dynamic ovstage shared library. The returned pointer is backed by a thread-local buffer valid until the next ovstage_executable_dir() call on the same thread. Returns {NULL, 0} if the path cannot be determined. Callable at any time, including before ovstage_initialize().

Path Dictionary (OVX)#

The shared path dictionary: interning, tokens, and prim-path lists. These headers ship under include/ovx/ and are shared with sibling OV libraries.

struct path_dictionary_vtable_t#
#include <path_dictionary_vtable.h>

Public Members

ovx_api_result_t (*create_tokens_from_strings)(path_dictionary_context_t *instance, const ovx_string_t *strings, size_t num_strings, ovx_token_t *out_tokens)#
ovx_api_result_t (*create_paths_from_tokens)(path_dictionary_context_t *instance, const ovx_token_t *tokens_per_path, const size_t *num_tokens_per_path, size_t num_paths, ovx_primpath_t *out_prim_paths)#

Intern prim paths described as concatenated token arrays.

Output handles are dict-lifetime. Equal token sequences yield equal output paths. The input tokens must have been minted from this dictionary.

Each token names a path component without a separator. Paths are absolute: tokens for World and Box produce /World/Box, with the same handle as create_paths_from_strings for that absolute path in this dictionary. A path with zero tokens represents /. Supply a non-null tokens_per_path array even when every path has zero tokens.

ovx_api_result_t (*create_paths_from_strings)(path_dictionary_context_t *instance, const ovx_string_t *path_strings, size_t num_paths, ovx_primpath_t *out_prim_paths)#
ovx_api_result_t (*create_path_list_from_paths)(path_dictionary_context_t *instance, const ovx_primpath_t *paths, size_t num_paths, ovx_primpath_list_t *out_path_list)#
ovx_api_result_t (*create_path_list_from_strings)(path_dictionary_context_t *instance, const ovx_string_t *path_strings, size_t num_paths, ovx_primpath_list_t *out_path_list)#
ovx_api_result_t (*add_path_list_reference)(path_dictionary_context_t *instance, ovx_primpath_list_t path_list)#
ovx_api_result_t (*release_path_list_reference)(path_dictionary_context_t *instance, ovx_primpath_list_t path_list)#
ovx_api_result_t (*get_strings_from_tokens)(path_dictionary_context_t *instance, const ovx_token_t *tokens, size_t num_tokens, ovx_string_t *out_strings)#
ovx_api_result_t (*get_tokens_from_paths)(path_dictionary_context_t *instance, const ovx_primpath_t *prim_paths, size_t num_paths, ovx_token_t *token_buffer, size_t token_buffer_size, ovx_token_t **out_tokens_per_path, size_t *out_num_tokens_per_path, size_t *out_num_paths_processed)#
ovx_api_result_t (*get_num_paths_from_path_list)(path_dictionary_context_t *instance, ovx_primpath_list_t path_list, size_t *out_num_paths)#
ovx_api_result_t (*get_paths_from_path_list)(path_dictionary_context_t *instance, ovx_primpath_list_t path_list, size_t start_offset, size_t max_paths, ovx_primpath_t *out_paths, size_t *out_num_paths)#
void (*release_error)(path_dictionary_context_t *context, ovx_string_t error)#

Typedefs

typedef struct path_dictionary_context_t path_dictionary_context_t#
struct path_dictionary_instance_t#
#include <path_dictionary_types.h>

Public Members

path_dictionary_vtable_t *vtable#
path_dictionary_context_t *context#

Implementation-specific data.

Functions

static inline ovx_api_result_t path_dictionary_create_tokens_from_strings(
path_dictionary_instance_t *instance,
const ovx_string_t *strings,
size_t num_strings,
ovx_token_t *out_tokens
)#
static inline ovx_api_result_t path_dictionary_create_paths_from_tokens(
path_dictionary_instance_t *instance,
const ovx_token_t *tokens_per_path,
const size_t *num_tokens_per_path,
size_t num_paths,
ovx_primpath_t *out_prim_paths
)#

Intern paths from concatenated arrays of component tokens.

See path_dictionary_vtable_t::create_paths_from_tokens for the contract, including absolute-path and zero-component root behavior.

static inline ovx_api_result_t path_dictionary_create_paths_from_strings(
path_dictionary_instance_t *instance,
const ovx_string_t *path_strings,
size_t num_paths,
ovx_primpath_t *out_prim_paths
)#
static inline ovx_api_result_t path_dictionary_create_path_list_from_paths(
path_dictionary_instance_t *instance,
const ovx_primpath_t *paths,
size_t num_paths,
ovx_primpath_list_t *out_path_list
)#
static inline ovx_api_result_t path_dictionary_create_path_list_from_strings(
path_dictionary_instance_t *instance,
const ovx_string_t *path_strings,
size_t num_paths,
ovx_primpath_list_t *out_path_list
)#
static inline ovx_api_result_t path_dictionary_add_path_list_reference(
path_dictionary_instance_t *instance,
ovx_primpath_list_t path_list
)#
static inline ovx_api_result_t path_dictionary_release_path_list_reference(
path_dictionary_instance_t *instance,
ovx_primpath_list_t path_list
)#
static inline ovx_api_result_t path_dictionary_get_strings_from_tokens(
path_dictionary_instance_t *instance,
const ovx_token_t *tokens,
size_t num_tokens,
ovx_string_t *out_strings
)#
static inline ovx_api_result_t path_dictionary_get_tokens_from_paths(
path_dictionary_instance_t *instance,
const ovx_primpath_t *prim_paths,
size_t num_paths,
ovx_token_t *token_buffer,
size_t token_buffer_size,
ovx_token_t **out_tokens_per_path,
size_t *out_num_tokens_per_path,
size_t *out_num_paths_processed
)#
static inline ovx_api_result_t path_dictionary_get_num_paths_from_path_list(
path_dictionary_instance_t *instance,
ovx_primpath_list_t path_list,
size_t *out_num_paths
)#
static inline ovx_api_result_t path_dictionary_get_paths_from_path_list(
path_dictionary_instance_t *instance,
ovx_primpath_list_t path_list,
size_t start_offset,
size_t max_paths,
ovx_primpath_t *out_paths,
size_t *out_num_paths
)#
static inline void path_dictionary_release_error(
path_dictionary_instance_t *instance,
ovx_string_t error
)#

Functions

static inline bool ovx_string_contains_embedded_nul(
const ovx_string_t *string
)#
static inline bool ovx_string_has_null_data(
const ovx_string_t *string
)#