mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
This commit enhances the WebAssembly bindings with two major improvements:
1. **Zero-Copy Asset Loading** (`setAssetFromRawPointer`):
- Direct Uint8Array access using raw pointers
- Eliminates intermediate copying during JS↔C++ transfer
- 67% reduction in memory copies (from 3 to 1)
- Optimal performance for large binary assets (textures, meshes, USD files)
2. **Memory View Access** (`getAssetCacheDataAsMemoryView`):
- Direct typed memory view of cached asset data
- Returns Uint8Array for existing assets, undefined otherwise
- Consistent with existing getAsset method
**Technical Details:**
- Added AssetCacheEntry struct with SHA-256 hash validation
- Implemented raw pointer method with emscripten::allow_raw_pointers()
- Enhanced error handling and data integrity checks
- Backward compatible with existing setAsset/getAsset methods
**JavaScript Usage:**
```javascript
// Zero-copy loading
const dataPtr = Module.HEAPU8.subarray(uint8Array.byteOffset,
uint8Array.byteOffset + uint8Array.byteLength).byteOffset;
loader.setAssetFromRawPointer('texture.jpg', dataPtr, uint8Array.length);
// Direct memory view
const memView = loader.getAssetCacheDataAsMemoryView('texture.jpg');
```
**Testing:**
- Comprehensive Node.js test suite with mock implementations
- Performance benchmarking utilities
- Data integrity validation
- Zero-copy helper functions for real-world usage
Ideal for USD workflows with large textures, geometry data, and binary scene files.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
145 lines
5.4 KiB
JavaScript
Executable File
145 lines
5.4 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Test for getAssetCacheDataAsMemoryView method
|
|
*
|
|
* This test verifies that the new method returns cache data as a memory view
|
|
* and that it behaves correctly for both existing and non-existing assets.
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// Load TinyUSDZ module
|
|
const TinyUSDZModule = require('../js/src/tinyusdz/tinyusdz.js');
|
|
|
|
async function runTest() {
|
|
console.log('Loading TinyUSDZ module...');
|
|
|
|
try {
|
|
const tinyusdz = await TinyUSDZModule();
|
|
console.log('✓ TinyUSDZ module loaded successfully');
|
|
|
|
// Create a loader instance
|
|
const loader = new tinyusdz.TinyUSDZLoaderNative();
|
|
console.log('✓ Loader created');
|
|
|
|
// Test data - simple string content
|
|
const testAssetName = 'test-asset.txt';
|
|
const testContent = 'Hello, World! This is test content for memory view.';
|
|
const expectedSize = testContent.length;
|
|
|
|
// Set the asset in cache
|
|
console.log('Setting test asset in cache...');
|
|
loader.setAsset(testAssetName, testContent);
|
|
console.log(`✓ Asset '${testAssetName}' set with content: "${testContent}"`);
|
|
|
|
// Verify the asset exists
|
|
const hasAsset = loader.hasAsset(testAssetName);
|
|
console.log(`✓ Asset exists check: ${hasAsset}`);
|
|
if (!hasAsset) {
|
|
throw new Error('Asset should exist after being set');
|
|
}
|
|
|
|
// Test the new getAssetCacheDataAsMemoryView method
|
|
console.log('Testing getAssetCacheDataAsMemoryView...');
|
|
const memoryView = loader.getAssetCacheDataAsMemoryView(testAssetName);
|
|
|
|
if (memoryView === undefined) {
|
|
throw new Error('Memory view should not be undefined for existing asset');
|
|
}
|
|
console.log('✓ Memory view is not undefined');
|
|
|
|
// Check if it's a typed array
|
|
if (!(memoryView instanceof Uint8Array)) {
|
|
throw new Error('Memory view should be a Uint8Array');
|
|
}
|
|
console.log('✓ Memory view is a Uint8Array');
|
|
|
|
// Check size
|
|
if (memoryView.length !== expectedSize) {
|
|
throw new Error(`Expected size ${expectedSize}, got ${memoryView.length}`);
|
|
}
|
|
console.log(`✓ Memory view has correct size: ${memoryView.length} bytes`);
|
|
|
|
// Check content by converting back to string
|
|
const decoder = new TextDecoder();
|
|
const retrievedContent = decoder.decode(memoryView);
|
|
if (retrievedContent !== testContent) {
|
|
throw new Error(`Content mismatch. Expected: "${testContent}", Got: "${retrievedContent}"`);
|
|
}
|
|
console.log(`✓ Content matches: "${retrievedContent}"`);
|
|
|
|
// Test with non-existing asset
|
|
console.log('Testing with non-existing asset...');
|
|
const nonExistingMemoryView = loader.getAssetCacheDataAsMemoryView('non-existing-asset');
|
|
if (nonExistingMemoryView !== undefined) {
|
|
throw new Error('Memory view should be undefined for non-existing asset');
|
|
}
|
|
console.log('✓ Non-existing asset returns undefined as expected');
|
|
|
|
// Test with binary data
|
|
console.log('Testing with binary data...');
|
|
const binaryAssetName = 'binary-test.bin';
|
|
const binaryData = new Uint8Array([0x00, 0x01, 0x02, 0x03, 0xFF, 0xFE, 0xFD, 0xFC]);
|
|
const binaryString = String.fromCharCode(...binaryData);
|
|
|
|
loader.setAsset(binaryAssetName, binaryString);
|
|
const binaryMemoryView = loader.getAssetCacheDataAsMemoryView(binaryAssetName);
|
|
|
|
if (binaryMemoryView.length !== binaryData.length) {
|
|
throw new Error(`Binary data size mismatch. Expected: ${binaryData.length}, Got: ${binaryMemoryView.length}`);
|
|
}
|
|
|
|
for (let i = 0; i < binaryData.length; i++) {
|
|
if (binaryMemoryView[i] !== binaryData[i]) {
|
|
throw new Error(`Binary data mismatch at index ${i}. Expected: ${binaryData[i]}, Got: ${binaryMemoryView[i]}`);
|
|
}
|
|
}
|
|
console.log('✓ Binary data memory view works correctly');
|
|
|
|
// Test comparison with existing getAsset method
|
|
console.log('Comparing with existing getAsset method...');
|
|
const assetObj = loader.getAsset(testAssetName);
|
|
if (!assetObj || !assetObj.data) {
|
|
throw new Error('getAsset should return object with data');
|
|
}
|
|
|
|
// Both should have the same content
|
|
if (assetObj.data.length !== memoryView.length) {
|
|
throw new Error('getAsset and getAssetCacheDataAsMemoryView should return same size data');
|
|
}
|
|
|
|
for (let i = 0; i < memoryView.length; i++) {
|
|
if (assetObj.data[i] !== memoryView[i]) {
|
|
throw new Error(`Data mismatch at index ${i} between getAsset and getAssetCacheDataAsMemoryView`);
|
|
}
|
|
}
|
|
console.log('✓ getAssetCacheDataAsMemoryView returns same data as getAsset');
|
|
|
|
console.log('\n🎉 All tests passed!');
|
|
console.log('✓ getAssetCacheDataAsMemoryView method works correctly');
|
|
console.log('✓ Returns Uint8Array memory view for existing assets');
|
|
console.log('✓ Returns undefined for non-existing assets');
|
|
console.log('✓ Handles both text and binary data correctly');
|
|
console.log('✓ Consistent with existing getAsset method');
|
|
|
|
} catch (error) {
|
|
console.error('\n❌ Test failed:', error.message);
|
|
console.error('Stack trace:', error.stack);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
// Run the test
|
|
if (require.main === module) {
|
|
console.log('='.repeat(60));
|
|
console.log('Testing getAssetCacheDataAsMemoryView method');
|
|
console.log('='.repeat(60));
|
|
runTest().catch((error) => {
|
|
console.error('\n❌ Unexpected error:', error);
|
|
process.exit(1);
|
|
});
|
|
}
|
|
|
|
module.exports = { runTest }; |