fix compile.

This commit is contained in:
Syoyo Fujita
2025-09-01 09:54:39 +09:00
parent 2ccac129ed
commit 0ec0449dde
7 changed files with 20 additions and 500 deletions

View File

@@ -1467,7 +1467,6 @@ if(TINYUSDZ_BUILD_EXAMPLES)
if (TINYUSDZ_WITH_TYDRA)
add_subdirectory(examples/tydra_api)
add_subdirectory(examples/tydra_to_renderscene)
add_subdirectory(examples/layer-to-renderscene)
add_subdirectory(examples/usddiff)
if (TINYUSDZ_WITH_MCP_SERVER)

View File

@@ -533,6 +533,7 @@ Some helper code is licensed under MIT license.
* SDL2 : zlib license. https://www.libsdl.org/index.php
* optional-lite: BSL 1.0 license. https://github.com/martinmoene/optional-lite
* expected-lite: BSL 1.0 license. https://github.com/martinmoene/expected-lite
* span-lite: BSL 1.0 license. https://github.com/martinmoene/span-lite
* string-view-lite: BSL 1.0 license. https://github.com/martinmoene/string-view-lite
* mapbox/earcut.hpp: ISC license. https://github.com/mapbox/earcut.hpp
* par_shapes.h generate parametric surfaces and other simple shapes: MIT license https://github.com/prideout/par

View File

@@ -1,70 +0,0 @@
cmake_minimum_required(VERSION 3.16)
set(BUILD_TARGET "layer_to_renderscene_example")
project(${BUILD_TARGET} CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
FORCE)
endif()
set(TINYUSDZ_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/../../src/tinyusdz.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/tinyusdz.hh
${CMAKE_CURRENT_SOURCE_DIR}/../../src/stage.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/prim-types.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/prim-types.hh
${CMAKE_CURRENT_SOURCE_DIR}/../../src/value-types.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/value-types.hh
${CMAKE_CURRENT_SOURCE_DIR}/../../src/value-pprint.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/pprinter.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/usdGeom.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/usdShade.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/usdSkel.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/usda-reader.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/usdc-reader.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/crate-reader.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/ascii-parser.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/ascii-parser-basetype.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/ascii-parser-timesamples.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/composition.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/asset-resolution.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/str-util.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/io-util.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/prim-reconstruct.cc
)
set(TYDRA_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/../../src/tydra/render-data.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/tydra/layer-to-renderscene.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/tydra/scene-access.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../src/tydra/shader-network.cc
)
add_executable(${BUILD_TARGET}
main.cc
${TINYUSDZ_SOURCES}
${TYDRA_SOURCES}
)
target_include_directories(${BUILD_TARGET} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../../src
${CMAKE_CURRENT_SOURCE_DIR}/../../src/external
)
target_compile_definitions(${BUILD_TARGET} PRIVATE
TINYUSDZ_WITH_TYDRA=1
)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(${BUILD_TARGET} PRIVATE -Wall -Wextra)
endif()
if(MSVC)
target_compile_options(${BUILD_TARGET} PRIVATE /W4)
endif()

View File

@@ -1,152 +0,0 @@
# Layer to RenderScene Direct Conversion
This example demonstrates memory-efficient direct conversion from USD Layer/PrimSpec to Tydra RenderScene, bypassing the traditional Stage/Prim construction pipeline.
## Key Features
### 1. Direct Conversion Path
- **Traditional**: USD File → Layer → PrimSpec → Stage → Prim → RenderScene
- **Optimized**: USD File → Layer → PrimSpec → RenderScene (direct)
### 2. In-Place Memory Management
- Converts data structures in-place, freeing source memory as conversion progresses
- Significantly reduces peak memory usage
- Useful for large USD files on memory-constrained systems
### 3. Memory Tracking
- Real-time memory usage reporting
- Peak memory tracking
- Memory freed notifications during in-place conversion
## Building
```bash
mkdir build
cd build
cmake ..
make
```
## Usage
```bash
# Run all conversion modes for comparison
./layer_to_renderscene_example model.usda
# Run specific conversion mode
./layer_to_renderscene_example model.usda [mode]
```
Available modes:
- `normal` - Traditional Stage→RenderScene conversion
- `direct` - Direct Layer→RenderScene conversion
- `inplace` - In-place Layer→RenderScene conversion with memory freeing
- `primspec` - Single PrimSpec conversion example
- `all` - Run all modes (default)
## Memory Optimization Strategies
### 1. Skip Intermediate Representations
The direct conversion skips creating Stage and Prim objects, which contain:
- Full composition arc evaluation
- Schema validation overhead
- Property inheritance chains
- Reference/payload resolution caches
### 2. In-Place Data Movement
Instead of copying data:
```cpp
// Traditional copy
render_mesh->points = prim_spec->points; // Copy
// In-place move
render_mesh->points = std::move(prim_spec->points); // Move
prim_spec->points.shrink_to_fit(); // Free memory
```
### 3. Progressive Memory Release
During in-place conversion:
1. Extract data from PrimSpec attribute
2. Move data to RenderMesh/RenderMaterial
3. Clear and shrink source containers immediately
4. Report freed memory for monitoring
### 4. Selective Processing
Only process attributes needed for rendering:
- Geometry: points, normals, UVs, indices
- Materials: surface shaders, textures
- Transforms: local and global matrices
Skip:
- Metadata not used in rendering
- Composition arcs (already resolved in Layer)
- Schema validation data
## Performance Comparison
Example with a 100MB USD file containing 10,000 meshes:
| Method | Peak Memory | Conversion Time | Notes |
|--------|------------|-----------------|-------|
| Traditional | 450 MB | 2500 ms | Full Stage construction |
| Direct | 280 MB | 1800 ms | Skip Stage/Prim |
| In-place | 180 MB | 1900 ms | Progressive memory release |
## API Example
```cpp
// Create converter with configuration
LayerToRenderSceneConverter converter;
DirectConversionConfig config;
config.triangulate = true;
config.enable_inplace_conversion = true;
config.max_memory_limit_mb = 512;
// Set callbacks for monitoring
config.progress_callback = [](const std::string& msg) {
std::cout << "Progress: " << msg << std::endl;
};
config.memory_freed_callback = [](size_t bytes) {
std::cout << "Freed: " << bytes << " bytes" << std::endl;
};
converter.SetConfig(config);
// Convert with in-place memory management
std::unique_ptr<Layer> layer = LoadLayer("model.usda");
RenderScene scene;
converter.ConvertLayerInPlace(std::move(layer), &scene, &warn, &err);
```
## Use Cases
1. **Memory-Constrained Environments**
- Embedded systems
- Mobile devices
- Web browsers (WASM)
2. **Large Scene Processing**
- Batch conversion pipelines
- Asset validation tools
- Preview generation
3. **Real-time Applications**
- Game engines requiring fast USD loading
- Interactive viewers
- VR/AR applications
## Limitations
- No support for complex composition (references, variants)
- Assumes Layer has already resolved basic composition
- Materials and shaders simplified compared to full Stage evaluation
- Animation/TimeSamples support is limited
## Future Improvements
- [ ] Streaming conversion for very large files
- [ ] Parallel PrimSpec processing
- [ ] Memory pool allocators for better fragmentation control
- [ ] Direct USDC binary to RenderScene without Layer
- [ ] Lazy loading of texture data

View File

@@ -1,275 +0,0 @@
#include <iostream>
#include <memory>
#include <chrono>
#include <iomanip>
#include <fstream>
#include <sstream>
#include "../../src/tinyusdz.hh"
#include "../../src/tydra/layer-to-renderscene.hh"
#include "../../src/tydra/render-data.hh"
#include "../../src/usda-reader.hh"
#include "../../src/usdc-reader.hh"
#include "../../src/crate-reader.hh"
#include "../../src/io-util.hh"
using namespace tinyusdz;
using namespace tinyusdz::tydra;
using namespace tinyusdz::usda;
using namespace tinyusdz::crate;
class MemoryTracker {
public:
void ReportFreed(size_t bytes) {
total_freed_ += bytes;
std::cout << " [Memory] Freed: " << FormatBytes(bytes)
<< " (Total freed: " << FormatBytes(total_freed_) << ")\n";
}
void ReportPeak(size_t bytes) {
std::cout << " [Memory] Peak usage: " << FormatBytes(bytes) << "\n";
}
private:
size_t total_freed_{0};
std::string FormatBytes(size_t bytes) {
const char* units[] = {"B", "KB", "MB", "GB"};
int unit_idx = 0;
double size = static_cast<double>(bytes);
while (size >= 1024.0 && unit_idx < 3) {
size /= 1024.0;
unit_idx++;
}
std::stringstream ss;
ss << std::fixed << std::setprecision(2) << size << " " << units[unit_idx];
return ss.str();
}
};
void PrintRenderSceneStats(const RenderScene& scene) {
std::cout << "\nRenderScene Statistics:\n";
std::cout << " Meshes: " << scene.meshes.size() << "\n";
std::cout << " Materials: " << scene.materials.size() << "\n";
std::cout << " Nodes: " << scene.nodes.size() << "\n";
std::cout << " Textures: " << scene.textures.size() << "\n";
size_t total_vertices = 0;
size_t total_triangles = 0;
for (const auto& mesh : scene.meshes) {
total_vertices += mesh.points.size();
if (mesh.is_triangulated()) {
total_triangles += mesh.triangulatedFaceVertexIndices.size() / 3;
} else {
for (uint32_t count : mesh.usdFaceVertexCounts) {
if (count >= 3) {
total_triangles += count - 2;
}
}
}
}
std::cout << " Total vertices: " << total_vertices << "\n";
std::cout << " Total triangles: " << total_triangles << "\n";
size_t estimated_memory = 0;
for (const auto& mesh : scene.meshes) {
estimated_memory += mesh.estimate_memory_usage();
}
std::cout << " Estimated RenderScene memory: "
<< (estimated_memory / (1024.0 * 1024.0)) << " MB\n";
}
bool LoadLayerDirectly(const std::string& filename, std::unique_ptr<Layer>& layer) {
std::string warn, err;
// Simply use the tinyusdz loader
Layer loaded_layer;
if (!LoadLayerFromFile(filename, &loaded_layer, &warn, &err)) {
std::cerr << "Failed to load file: " << err << std::endl;
return false;
}
layer = std::make_unique<Layer>(std::move(loaded_layer));
return true;
}
void TestNormalConversion(const std::string& filename) {
std::cout << "\n=== Normal Conversion (Stage -> RenderScene) ===\n";
auto start = std::chrono::high_resolution_clock::now();
tinyusdz::Stage stage;
std::string warn, err;
bool ret = tinyusdz::LoadUSDFromFile(filename, &stage, &warn, &err);
if (!ret) {
std::cerr << "Failed to load USD file: " << err << std::endl;
return;
}
auto load_end = std::chrono::high_resolution_clock::now();
RenderScene render_scene;
RenderSceneConverter converter;
RenderSceneConverterEnv env(stage);
converter.ConvertToRenderScene(env, &render_scene);
auto convert_end = std::chrono::high_resolution_clock::now();
auto load_time = std::chrono::duration_cast<std::chrono::milliseconds>(load_end - start);
auto convert_time = std::chrono::duration_cast<std::chrono::milliseconds>(convert_end - load_end);
std::cout << "Load time: " << load_time.count() << " ms\n";
std::cout << "Conversion time: " << convert_time.count() << " ms\n";
std::cout << "Total time: " << (load_time.count() + convert_time.count()) << " ms\n";
PrintRenderSceneStats(render_scene);
}
void TestDirectConversion(const std::string& filename, bool in_place) {
std::cout << "\n=== Direct Conversion (Layer -> RenderScene, "
<< (in_place ? "in-place" : "normal") << ") ===\n";
auto start = std::chrono::high_resolution_clock::now();
std::unique_ptr<Layer> layer;
if (!LoadLayerDirectly(filename, layer)) {
return;
}
auto load_end = std::chrono::high_resolution_clock::now();
RenderScene render_scene;
LayerToRenderSceneConverter converter;
DirectConversionConfig config;
config.triangulate = true;
config.build_vertex_indices = true;
config.enable_inplace_conversion = in_place;
MemoryTracker tracker;
config.progress_callback = [](const std::string& msg) {
std::cout << " [Progress] " << msg << "\n";
};
config.memory_freed_callback = [&tracker](size_t bytes) {
tracker.ReportFreed(bytes);
};
converter.SetConfig(config);
std::string warn, err;
bool ret = false;
if (in_place) {
ret = converter.ConvertLayerInPlace(std::move(layer), &render_scene, &warn, &err);
} else {
ret = converter.ConvertLayer(layer.get(), &render_scene, &warn, &err);
}
auto convert_end = std::chrono::high_resolution_clock::now();
if (!ret) {
std::cerr << "Conversion failed: " << err << std::endl;
return;
}
auto load_time = std::chrono::duration_cast<std::chrono::milliseconds>(load_end - start);
auto convert_time = std::chrono::duration_cast<std::chrono::milliseconds>(convert_end - load_end);
std::cout << "Load time: " << load_time.count() << " ms\n";
std::cout << "Conversion time: " << convert_time.count() << " ms\n";
std::cout << "Total time: " << (load_time.count() + convert_time.count()) << " ms\n";
tracker.ReportPeak(converter.GetPeakMemoryUsage());
PrintRenderSceneStats(render_scene);
}
void TestSinglePrimSpecConversion(const std::string& filename) {
std::cout << "\n=== Single PrimSpec Conversion ===\n";
std::unique_ptr<Layer> layer;
if (!LoadLayerDirectly(filename, layer)) {
return;
}
const auto& primspecs = layer->primspecs();
for (const auto& item : primspecs) {
const std::string& path = item.first;
const PrimSpec& primspec = item.second;
if (primspec.typeName() == "Mesh") {
std::cout << "Converting mesh: " << path << "\n";
RenderMesh mesh;
LayerToRenderSceneConverter converter;
DirectConversionConfig config;
config.triangulate = true;
converter.SetConfig(config);
std::string warn, err;
auto primspec_copy = std::make_unique<PrimSpec>(primspec);
bool ret = converter.ConvertPrimSpecInPlace(std::move(primspec_copy), &mesh, &warn, &err);
if (ret) {
std::cout << " Mesh converted successfully:\n";
std::cout << " Points: " << mesh.points.size() << "\n";
std::cout << " Faces: " << mesh.faceVertexCounts().size() << "\n";
std::cout << " Triangulated: " << (mesh.is_triangulated() ? "yes" : "no") << "\n";
std::cout << " Memory usage: " << (mesh.estimate_memory_usage() / 1024.0) << " KB\n";
} else {
std::cerr << " Conversion failed: " << err << std::endl;
}
break;
}
}
}
int main(int argc, char** argv) {
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " <usd_file> [mode]\n";
std::cout << "Modes:\n";
std::cout << " normal - Traditional Stage->RenderScene conversion\n";
std::cout << " direct - Direct Layer->RenderScene conversion\n";
std::cout << " inplace - In-place Layer->RenderScene conversion\n";
std::cout << " primspec - Single PrimSpec conversion example\n";
std::cout << " all - Run all modes (default)\n";
return 1;
}
std::string filename = argv[1];
std::string mode = (argc > 2) ? argv[2] : "all";
std::cout << "Processing file: " << filename << "\n";
if (mode == "normal" || mode == "all") {
TestNormalConversion(filename);
}
if (mode == "direct" || mode == "all") {
TestDirectConversion(filename, false);
}
if (mode == "inplace" || mode == "all") {
TestDirectConversion(filename, true);
}
if (mode == "primspec" || mode == "all") {
TestSinglePrimSpecConversion(filename);
}
return 0;
}

View File

@@ -3,6 +3,7 @@
#include <algorithm>
#include <unordered_map>
#include <cstring>
#include <vector>
#include "../prim-types.hh"
#include "../usdGeom.hh"
@@ -17,13 +18,16 @@ namespace tydra {
namespace {
#if 0
template<typename T>
void MoveVector(std::vector<T>& src, std::vector<T>& dst) {
dst = std::move(src);
src.clear();
src.shrink_to_fit();
}
#endif
#if 0
template<typename T>
void ExtractAndClearAnimatable(Animatable<T>& src, T* default_val, TypedTimeSamples<T>* ts) {
if (src.has_value() && default_val) {
@@ -37,6 +41,7 @@ void ExtractAndClearAnimatable(Animatable<T>& src, T* default_val, TypedTimeSamp
src.clear_scalar();
src.clear_timesamples();
}
#endif
// TODO: Fix these functions once Property API is clarified
// bool ConvertPrimvarToVertexAttribute(
@@ -112,6 +117,8 @@ bool LayerToRenderSceneConverter::ConvertLayer(
RenderScene* render_scene,
std::string* warn,
std::string* err) {
(void)warn;
if (!layer || !render_scene) {
if (err) {
@@ -182,6 +189,7 @@ bool LayerToRenderSceneConverter::ConvertLayerInPlace(
std::string* warn,
std::string* err) {
(void)warn;
if (!layer || !render_scene) {
if (err) {
*err = "Invalid input: layer or render_scene is null";
@@ -269,6 +277,8 @@ bool LayerToRenderSceneConverter::ConvertPrimSpec(
RenderMesh* render_mesh,
std::string* warn,
std::string* err) {
(void)warn;
if (!prim_spec || !render_mesh) {
if (err) {
@@ -286,6 +296,8 @@ bool LayerToRenderSceneConverter::ConvertPrimSpecInPlace(
std::string* warn,
std::string* err) {
(void)warn;
if (!prim_spec || !render_mesh) {
if (err) {
*err = "Invalid input: prim_spec or render_mesh is null";
@@ -304,6 +316,8 @@ bool LayerToRenderSceneConverter::ConvertGeomMeshPrimSpec(
const PrimSpec* prim_spec,
RenderMesh* render_mesh,
bool free_source) {
(void)free_source;
if (!prim_spec || !render_mesh) {
return false;
@@ -457,6 +471,7 @@ bool LayerToRenderSceneConverter::ConvertMaterialPrimSpec(
RenderMaterial* render_material,
bool free_source) {
(void)free_source;
if (!prim_spec || !render_material) {
return false;
}
@@ -471,6 +486,7 @@ bool LayerToRenderSceneConverter::ConvertXformPrimSpec(
Node* node,
bool free_source) {
(void)free_source;
if (!prim_spec || !node) {
return false;
}
@@ -514,4 +530,4 @@ void LayerToRenderSceneConverter::TrackMemoryUsage(size_t bytes_allocated, size_
}
} // namespace tydra
} // namespace tinyusdz
} // namespace tinyusdz

View File

@@ -126,4 +126,5 @@ inline size_t EstimateMemorySize(const std::vector<uint32_t>& data) {
}
} // namespace tydra
} // namespace tinyusdz
} // namespace tinyusdz