Renderer Configuration#
The renderer owns ovrtx’s GPU resources, stream-ordered work queue, and rendering pipeline. In standalone mode it also owns a runtime stage that you load USD into. In attached mode (ovrtx 0.4+) it renders scene state managed by an external ovstage instance instead. Create one renderer before loading USD or stepping RenderProducts.
Creating a Renderer#
# Create the Renderer and attach the stage that owns scene data.
print("Creating renderer. The first run of the application will take some time as shaders are compiled and cached...", file=sys.stderr)
renderer = ovrtx.Renderer()
stage = ovstage.Stage("ovrtx.example.minimal")
renderer.attach_ovstage(stage)
print("Renderer created.", file=sys.stderr)
Configuration entries are passed through RendererConfig:
config = ovrtx.RendererConfig(
sync_mode=True,
log_file_path=str(output_dir / "config-test.log"),
log_level="info",
sensors_allowed_deprecation_base="0.6.0",
aftermath_mode=ovrtx.AftermathMode.AUTO,
)
renderer = ovrtx.Renderer(config=config)
assert any(component > 0 for component in renderer.version)
assert renderer.config.sync_mode is True
assert renderer.config.log_level == "info"
assert renderer.config.log_file_path == str(output_dir / "config-test.log")
assert renderer.config.sensors_allowed_deprecation_base == "0.6.0"
assert renderer.config.aftermath_mode is ovrtx.AftermathMode.AUTO
// Create the renderer, providing configuration settings.
//
ovrtx_config_t config {};
#ifdef OVRTX_EXAMPLE_STATIC_LOADERS
// The static loader needs the package root linked beside the executable.
ovx_string_t ovrtx_package_root = {
OVX_CONFIG_EXECUTABLE_DIR_TOKEN "/ovrtx",
sizeof(OVX_CONFIG_EXECUTABLE_DIR_TOKEN "/ovrtx") - 1};
ovrtx_config_entry_t config_entries[] = {
ovrtx_config_entry_binary_package_root_path(ovrtx_package_root),
};
config.entries = config_entries;
config.entry_count = sizeof(config_entries) / sizeof(config_entries[0]);
#endif
// Publish ovrtx's schema paths before either runtime can initialize OpenUSD.
result = ovrtx_register_schema_paths(&config);
if (check_and_print_error(result, "register_schema_paths")) {
return 1;
}
std::cerr << "Creating renderer. The first run of the application will take some time as shaders are compiled and cached..." << std::endl;
result = ovrtx_create_renderer(&config, &renderer);
if (check_and_print_error(result, "create_renderer")) {
return 1;
}
std::cerr << "Renderer created." << std::endl;
Version and config-entry setup use ovrtx_config_t:
uint32_t major = 0;
uint32_t minor = 0;
uint32_t patch = 0;
ovrtx_get_version(&major, &minor, &patch);
std::string log_level = "info";
ovrtx_config_entry_t entries[] = {
ovrtx_config_entry_log_level({ log_level.data(), log_level.size() }),
ovrtx_config_entry_sync_mode(true),
};
ovrtx_config_t config{entries, 2};
ovrtx_renderer_t* configured_renderer = nullptr;
ovrtx_result_t create_result = ovrtx_create_renderer(&config, &configured_renderer);
ASSERT_API_SUCCESS(create_result.status);
ASSERT_NE(configured_renderer, nullptr);
Python’s renderer.config returns a detached RendererConfig copy. In C,
ovrtx_get_config() returns a borrowed view whose entry and payload
storage remains valid until the renderer is destroyed. Both surfaces report
only entries explicitly supplied at creation; omitted defaults and derived
internal settings are not included.
Configuration Entries#
Common configuration entries include:
|
Description |
|---|---|
|
Write renderer logs to a file. |
|
Set log verbosity. |
|
Suppress Python and native runtime warnings from deprecated APIs. Compile-time C/C++ diagnostics are unaffected. |
|
Keep shared graphics resources alive after the last renderer. |
|
Enable or disable Minimal at startup. Default: |
|
Enable or disable real-time path tracing (RT2) at startup. Default: |
|
Enable or disable PathTracing at startup. Default: |
|
Enable MDL material displacement. Disabled when omitted or |
|
Do not start the ovrtx crash reporter, for hosts that own crash handling.
Enabled when omitted or |
|
Restrict renderer-level CUDA-visible devices. |
|
Configure the UJITSO datastore cache. |
|
Choose an absolute directory for writable caches. See Cache Locations. |
|
Use the platform cache directory. Enabled by default. See Cache Locations. |
|
Opt in to geometry streaming. Disabled by default when omitted or |
|
Motion BVH mode: |
|
Texture streaming mode: |
Config-entry helper |
Description |
|---|---|
Write renderer logs to a file. |
|
Set log verbosity. |
|
Suppress native runtime warnings from deprecated APIs. Compile-time deprecation diagnostics are unaffected. |
|
Point to a custom binary package root. May include
|
|
Keep shared graphics resources alive after the last renderer. |
|
Enable or disable Minimal at startup. Omitted by default. |
|
Enable or disable real-time path tracing (RT2) at startup. Omitted by default. |
|
Enable or disable PathTracing at startup. Omitted by default. |
|
Enable MDL material displacement. Disabled when omitted. |
|
Do not start the ovrtx crash reporter when |
|
Restrict renderer-level CUDA-visible devices. |
|
Configure the UJITSO datastore cache with |
|
Choose an absolute directory for writable caches. See Cache Locations. |
|
Use the platform cache directory. Enabled by default. See Cache Locations. |
|
Opt in to geometry streaming. Disabled by default when omitted. |
|
Motion BVH mode: |
|
Texture streaming mode: |
Deprecation warnings remain enabled by default. Suppression is intended for phased migrations where deprecated compatibility APIs must remain temporarily; it does not change their behavior or removal schedule.
Texture streaming mode is process-global and applies to every active renderer instance. Synchronous mode processes texture feedback synchronously; it does not make every texture loading operation synchronous.
MDL material displacement is backed by the process-wide Carb setting
/rtx/material/enableMDLDisplacement. Renderer creation writes the configured
value, or False when the option is omitted, so it does not inherit stale
process state.
Renderer-level active_cuda_gpus must be compatible with any per-RenderProduct
deviceIds allow-list. Refer to RenderProduct Device Pinning.
Cache Locations#
ovrtx caches compiled shaders and processed assets on disk so later runs can reuse them. By default, writable caches use a directory for the current user and ovrtx version:
Platform |
Default cache directory |
|---|---|
Linux |
|
Windows |
|
<version> is the ovrtx runtime’s major.minor.patch version, for example
0.7.0. On Windows, %LOCALAPPDATA% normally points to
C:\Users\<username>\AppData\Local.
Choosing a Cache Directory#
Set cache_root_path in RendererConfig, or use
ovrtx_config_entry_cache_root_path() in C. Choose an absolute path
to a directory your application can write to. ovrtx creates cache directories
as needed. The supplied root is used directly: ovrtx does not append
ovrtx or a version directory.
Configure the cache root before creating the first renderer. The location
applies to all renderers in the process. If you supply a cache root to both
ovrtx_initialize() and ovrtx_create_renderer(), use the
same path string in both calls. To change the location, restart the application
with the new configuration. Existing caches are not moved to the new location.
The following snippets choose a cache directory before creating a renderer. Replace the example path with a writable location for your application.
import os
import ovrtx
cache_root = "C:/ovrtx-cache" if os.name == "nt" else "/tmp/ovrtx-cache"
# Configure the process-wide location before the first renderer.
config = ovrtx.RendererConfig(cache_root_path=cache_root)
renderer = ovrtx.Renderer(config=config)
# Load your scene and render here.
renderer.destroy()
#include <ovrtx/ovrtx.h>
#include <ovrtx/ovrtx_config.h>
int main(void)
{
#ifdef _WIN32
const char cache_root[] = "C:/ovrtx-cache";
#else
const char cache_root[] = "/tmp/ovrtx-cache";
#endif
// Keep the path alive until renderer creation returns.
ovx_string_t path = {cache_root, sizeof(cache_root) - 1};
ovrtx_config_entry_t entries[] = {
ovrtx_config_entry_cache_root_path(path),
};
ovrtx_config_t config = {entries, 1};
ovrtx_renderer_t* renderer = NULL;
ovrtx_result_t result = ovrtx_create_renderer(&config, &renderer);
if (result.status == OVRTX_API_ERROR) {
// Report ovrtx_get_last_error() in your application's error handler.
return 1;
}
// Load your scene and render here.
ovrtx_destroy_renderer(renderer);
return 0;
}
Changing the Linux Cache Base Directory#
On Linux, set XDG_CACHE_HOME to an absolute path before starting the
application to choose a different base directory for the default cache.
ovrtx appends ovrtx/<version> to this path. An explicit cache_root_path
takes precedence over XDG_CACHE_HOME.
XDG_CACHE_HOME has no effect on Windows. Use cache_root_path to
choose a different cache directory there.
Clearing Caches#
Stop applications using the cache before deleting its directory. ovrtx recreates writable caches on subsequent runs. The next run can take longer while shaders and assets are processed again.
Preserving the Previous Cache Location#
If you want to preserve the previous behavior of putting caches next to the
ovrtx library, set enable_global_cache_root=False in Python, or use
ovrtx_config_entry_enable_global_cache_root() with false in C.
This disables selection of the per-user cache directory. Existing custom
cache locations are preserved if already configured.
This option defaults to enabled when omitted (None in Python). An explicit
cache_root_path takes precedence over this option. In C, if either
ovrtx_initialize() or ovrtx_create_renderer() explicitly
enables it, that takes precedence over false in the other call.
Startup Render Mode Availability#
An ovrtx renderer instance is an ovrtx.Renderer object in Python or
an ovrtx_renderer_t* handle returned by ovrtx_create_renderer() in C.
The first ovrtx renderer instance initializes graphics resources shared by all
ovrtx renderer instances in the process. Configure their available rendering modes through
RendererConfig in Python, or pass the corresponding entries to
ovrtx_create_renderer() in C. These entries are not applied by
ovrtx_initialize(), which initializes the library separately.
For each option, True enables the mode and False disables it. Omission
(None in Python) leaves that rendering mode’s availability unchanged.
By default, all three rendering modes are enabled. At least one mode must remain
enabled; a configuration that disables every mode fails ovrtx renderer instance creation.
The following examples create an ovrtx renderer instance with only Minimal available. Disabling PathTracing and RT2 allows ovrtx to avoid allocating resources needed only by those modes.
config = ovrtx.RendererConfig(
enable_minimal=True,
enable_realtimepathtracing=False,
enable_pathtracing=False,
# Retain shared graphics resources even after this instance is destroyed.
keep_system_alive=True,
)
renderer = ovrtx.Renderer(config=config)
Initialize the library with ovrtx_initialize() before this code,
and call ovrtx_destroy_renderer() when finished with the renderer.
ovrtx_config_entry_t entries[] = {
ovrtx_config_entry_enable_minimal(true),
ovrtx_config_entry_enable_realtimepathtracing(false),
ovrtx_config_entry_enable_pathtracing(false),
// Retain shared graphics resources even after this instance is destroyed.
ovrtx_config_entry_keep_system_alive(true),
};
ovrtx_config_t config = {entries, sizeof(entries) / sizeof(entries[0])};
ovrtx_renderer_t* renderer = nullptr;
ovrtx_result_t result = ovrtx_create_renderer(&config, &renderer);
Each additional ovrtx renderer instance shares the initialized rendering mode availability. Omitted
options inherit it; an explicit conflicting value fails creation of the new
instance. For example, after the Minimal-only creation above, another ovrtx renderer instance
cannot enable RT2. The failed request does not change an existing ovrtx renderer instance,
release its memory, or trigger shader recompilation. renderer.config reports
the supplied entries rather than inherited values.
The choice remains fixed while any ovrtx renderer instance uses the shared graphics
resources, or while keep_system_alive=True retains them after the last instance
is destroyed. If every instance is created with keep_system_alive=False, destroying
all instances releases the shared graphics resources. The next instance can enable RT2/PathTracing.
If an earlier instance used keep_system_alive=True (the default), first create a
temporary ovrtx renderer instance with keep_system_alive=False and omit all
enable_* options. Its creation inherits the current rendering mode availability
and clears the keep-alive reference. Then destroy every ovrtx renderer instance,
including the temporary instance. Do not create another instance with
keep_system_alive=True during teardown, as that would retain the resources again.
These examples continue from the Minimal-only instance above, clear retention, destroy all instances, and create a new instance with Minimal, RT2, and PathTracing available. The new instance performs graphics initialization again; this is not an in-place configuration change.
# Omit enable_* so this instance inherits Minimal-only availability.
# Creating it clears retention left by keep_system_alive=True.
release_retention = ovrtx.Renderer(config=ovrtx.RendererConfig(keep_system_alive=False))
renderer.destroy()
# Destroy any other ovrtx renderer instances before this final destroy.
release_retention.destroy()
# No instance or keep-alive reference remains: initialize graphics again.
renderer = ovrtx.Renderer(
config=ovrtx.RendererConfig(
enable_minimal=True,
enable_realtimepathtracing=True,
enable_pathtracing=True,
keep_system_alive=False,
)
)
// Omit enable_* to inherit Minimal-only availability and clear keep-alive retention.
ovrtx_config_entry_t releaseEntry = ovrtx_config_entry_keep_system_alive(false);
ovrtx_config_t releaseConfig = {&releaseEntry, 1};
ovrtx_renderer_t* releaseRetention = nullptr;
result = ovrtx_create_renderer(&releaseConfig, &releaseRetention);
if (result.status != OVRTX_API_SUCCESS)
{
return 1;
}
result = ovrtx_destroy_renderer(renderer);
if (result.status != OVRTX_API_SUCCESS)
{
return 1;
}
// Destroy any other ovrtx renderer instances before this final destroy.
result = ovrtx_destroy_renderer(releaseRetention);
if (result.status != OVRTX_API_SUCCESS)
{
return 1;
}
// No instance or keep-alive reference remains: initialize graphics again.
ovrtx_config_entry_t allModesEntries[] = {
ovrtx_config_entry_enable_minimal(true),
ovrtx_config_entry_enable_realtimepathtracing(true),
ovrtx_config_entry_enable_pathtracing(true),
ovrtx_config_entry_keep_system_alive(false),
};
ovrtx_config_t allModesConfig = {allModesEntries, sizeof(allModesEntries) / sizeof(allModesEntries[0])};
result = ovrtx_create_renderer(&allModesConfig, &renderer);
if (result.status != OVRTX_API_SUCCESS)
{
return 1;
}
Destroy the new instance when finished. A C application can also release retained
graphics resources by calling ovrtx_shutdown() after destroying its ovrtx
renderer instances and matching every ovrtx_initialize() call with a shutdown call.
RenderProduct mode selection is separate: it chooses among the available modes. If both Minimal and RT2 are enabled at startup, different RenderProducts can use either mode. Selecting Minimal on a RenderProduct alone does not provide the same memory savings as disabling PathTracing and RT2 at startup.
If a RenderProduct requests a disabled rendering mode, ovrtx logs a warning and selects the first enabled rendering mode in RT2, PathTracing, then Minimal order. With only Minimal available, an unavailable PathTracing or RT2 request renders in Minimal.
Supported Minimal sensor outputs and motion features remain available.
Backend Support#
ovrtx 0.5 public packages use Vulkan on Windows and Linux. The former
use_vulkan Python field, OVRTX_CONFIG_USE_VULKAN C key, and
ovrtx_config_entry_use_vulkan() C helper have been removed. Passing the
retired C key from a pre-0.5 binary returns OVRTX_API_ERROR with a migration
diagnostic; recompile the application against the 0.5 headers and remove the
backend selection entry.
Runtime Package Layout#
With the shared-loader model, ovrtx expects the binary package bin layout to stay
together next to libovrtx-dynamic.so or ovrtx-dynamic.dll. The runtime
package includes directories such as cache, library, libs, mdl,
plugins, rendering-data, and usd_plugins.
In C, set binary_package_root_path through
ovrtx_config_entry_binary_package_root_path() only when static linking
ovrtx or when a custom deployment layout separates the loader library from the
package directories.
When the package bin/ directory lives next to your executable, pass
OVX_CONFIG_EXECUTABLE_DIR_TOKEN ("${executable_dir}") instead of
resolving the executable directory in client code.
Multi-Renderer Processes#
For processes that create and destroy multiple renderers, initialize ovrtx once up front when using the C API, then shut it down once all renderers are gone.
// The STATIC ovrtx loader resolves the ${executable_dir} token to the running
// executable's directory; ovrtx_setup_runtime() links the package bin beside
// the exe as "ovrtx/", which we hand the loader as the binary package root.
ovx_string_t ovrtx_package_root = {
OVX_CONFIG_EXECUTABLE_DIR_TOKEN "/ovrtx",
sizeof(OVX_CONFIG_EXECUTABLE_DIR_TOKEN "/ovrtx") - 1};
ovx_string_t active_cuda_gpus = {ACTIVE_CUDA_GPUS, sizeof(ACTIVE_CUDA_GPUS) - 1};
ovrtx_config_entry_t ovrtx_config_entries[] = {
ovrtx_config_entry_binary_package_root_path(ovrtx_package_root),
ovrtx_config_entry_active_cuda_gpus(active_cuda_gpus),
ovrtx_config_entry_selection_outline_enabled(true),
ovrtx_config_entry_selection_outline_width(4),
ovrtx_config_entry_selection_fill_mode(OVRTX_SELECTION_FILL_MODE_GROUP_FILL_COLOR),
};
ovrtx_config_t ovrtx_config = {};
ovrtx_config.entries = ovrtx_config_entries;
ovrtx_config.entry_count =
sizeof(ovrtx_config_entries) / sizeof(ovrtx_config_entries[0]);
// Publish OVRTX's USD plugin paths before ovstage initializes the shared USD
// runtime. The process-wide USD schema registry only discovers plugins once.
ovrtx_result_t result = ovrtx_register_schema_paths(&ovrtx_config);
if (check_and_print_error(result, "register_schema_paths")) {
return 1;
}
// The STATIC ovstage loader resolves ${executable_dir} the same way ovrtx does.
// ovstage_setup_runtime() links the package bin beside the exe as "ovstage/"
// (next to "ovrtx/").
ovx_string_t ovstage_package_root = {
OVX_CONFIG_EXECUTABLE_DIR_TOKEN "/ovstage",
sizeof(OVX_CONFIG_EXECUTABLE_DIR_TOKEN "/ovstage") - 1};
ovstage_config_entry_t stage_config_entries[] = {
ovstage_config_entry_binary_package_root_path(ovstage_package_root),
};
ovstage_config_t stage_config {};
stage_config.entries = stage_config_entries;
stage_config.entry_count = sizeof(stage_config_entries) / sizeof(stage_config_entries[0]);
ovstage_api_status_t stage_init_status = ovstage_initialize(&stage_config);
if (stage_init_status != OVSTAGE_OK) {
print_ovstage_error(nullptr, stage_init_status, "initialize");
return 1;
}
result = ovrtx_create_renderer(&ovrtx_config, &renderer);
if (check_and_print_error(result, "create_renderer")) {
ovstage_shutdown();
return 1;
}
auto cleanup = [&](int exit_code) {
int result_code = exit_code;
if (camera_query != OVSTAGE_INVALID_QUERY_HANDLE) {
if (wait_ovstage_op(stage,
ovstage_release_query(stage, camera_query),
"release_query")) {
result_code = 1;
}
camera_query = OVSTAGE_INVALID_QUERY_HANDLE;
}
if (stage_attached) {
result = ovrtx_detach_ovstage(renderer);
if (check_and_print_error(result, "detach_ovstage")) {
result_code = 1;
}
stage_attached = false;
}
// After a detach failure, only renderer destruction is supported.
if (renderer) {
result = ovrtx_destroy_renderer(renderer);
if (check_and_print_error(result, "destroy_renderer")) {
result_code = 1;
} else {
renderer = nullptr;
}
}
if (stage) {
ovstage_api_status_t stage_result = ovstage_destroy_instance(stage);
if (stage_result != OVSTAGE_OK) {
print_ovstage_error(stage, stage_result, "destroy_instance");
result_code = 1;
}
stage = nullptr;
}
// Release the ovstage static loader (unloads ovstage.dll). Safe even if
// ovstage_initialize failed or was never reached.
ovstage_shutdown();
return result_code;
};
// Register the per-group outline/fill style before any picking happens.
if (!configure_selection_style(renderer)) {
return cleanup(1);
}
On Linux headless systems, repeatedly creating and destroying renderers can
force shared graphics resources to unload and reload. If that causes native
driver crashes, configure keep_system_alive=True and initialize ovrtx before
creating renderers. If the issue persists, set
VK_LOADER_DISABLE_DYNAMIC_LIBRARY_UNLOADING=1 in the process environment.
Cleanup#
Python releases renderer resources when the Renderer object is destroyed.
In C, cleanup is explicit:
// Unmap output
ovrtx_cuda_sync_t no_sync = {};
result = ovrtx_unmap_render_var_output(
renderer, rendered_output.map_handle, no_sync);
if (check_and_print_error(result, "unmap_render_var_output")) {
ovrtx_destroy_results(renderer, step_result_handle);
return cleanup(1);
}
// Clean up resources (ovrtx will warn if results are leaked)
result = ovrtx_destroy_results(renderer, step_result_handle);
if (check_and_print_error(result, "destroy_results")) {
return cleanup(1);
}
Spectral Startup Configuration#
Python RendererConfig.enable_spectral_rendering and C
ovrtx_config_entry_enable_spectral_rendering() prepare spectral shaders,
materials, and physical illuminants when the first renderer is created.
Spectral rendering defaults to off. The choice persists for the process lifetime;
conflicting later values fail.
See Spectral Rendering for
RenderProduct authoring and limitations.
Embedding in a Host Application#
ovrtx reports initialization failures, such as a missing GPU Foundation or CUDA runtime, as errors from renderer creation; it never ends the host process.
By default the first renderer starts the ovrtx crash reporter, which installs
process-wide crash handlers and uploads crash dumps. A host application that
owns crash handling should disable it with Python
RendererConfig(enable_crash_reporter=False) or C
ovrtx_config_entry_enable_crash_reporter() on the first renderer. The
choice persists for the process lifetime; conflicting later values fail.
ovstage never starts a crash reporter.