Renderer Configuration#

The renderer owns ovrtx’s GPU resources, runtime stage, stream-ordered work queue, and rendering pipeline. Create one renderer before loading USD or stepping RenderProducts.

Creating a Renderer#

# Create the Renderer and load a USD layer into it
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()
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",
)
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")
// Create the renderer, optionally providing configuration settings.
// In this case we need no configuration.
ovrtx_config_t config {};
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);

ovrtx_config_entry_t entries[] = {
    ovrtx_config_entry_log_level(ovx_str("info")),
    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);
ovrtx_destroy_renderer(configured_renderer);

Configuration Entries#

Common configuration entries include:

RendererConfig entry

Description

log_file_path=...

Write renderer logs to a file.

log_level=...

Set log verbosity.

binary_package_root_path=...

Point to a custom binary package root.

keep_system_alive=True

Keep shared graphics resources alive after the last renderer.

active_cuda_gpus="0,1"

Restrict renderer-level CUDA-visible devices.

use_vulkan=True

Select the Vulkan backend where supported.

Config-entry helper

Description

ovrtx_config_entry_log_file_path()

Write renderer logs to a file.

ovrtx_config_entry_log_level()

Set log verbosity.

ovrtx_config_entry_binary_package_root_path()

Point to a custom binary package root.

ovrtx_config_entry_keep_system_alive()

Keep shared graphics resources alive after the last renderer.

ovrtx_config_entry_active_cuda_gpus()

Restrict renderer-level CUDA-visible devices.

ovrtx_config_entry_use_vulkan()

Select the Vulkan backend where supported.

Renderer-level active_cuda_gpus must be compatible with any per-RenderProduct deviceIds allow-list. See RenderProduct Device Pinning.

Runtime Package Layout#

With dynamic linking, 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.

Set binary_package_root_path only when static linking ovrtx or when a custom deployment layout separates the loader library from the package directories.

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.

ovrtx_config_entry_t ovrtx_config_entries[] = {
    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]);
ovrtx_result_t result = ovrtx_create_renderer(&ovrtx_config, &renderer);
if (check_and_print_error(result, "create_renderer")) {
    return 1;
}
if (!configure_selection_style(renderer)) {
    ovrtx_destroy_renderer(renderer);
    return 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);
    ovrtx_destroy_renderer(renderer);
    return 1;
}

// Clean up resources (ovrtx will warn if results are leaked)
result = ovrtx_destroy_results(renderer, step_result_handle);
result = ovrtx_destroy_renderer(renderer);
if (check_and_print_error(result, "destroy_renderer")) {
    return 1;
}