Repository navigation
fix: pcp, value clip and usda writer correctness - #139
Merged
Merged
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Clip reads eagerly load all clips, and internal unresolved-target diagnostics can identify the wrong layer.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Corrects composition, value-clip resolution, and USDA serialization behavior to match C++ OpenUSD.
Changes:
- Fixes index caching, payload-offset matching, and unresolved-target diagnostics.
- Interpolates values across clip activations.
- Preserves reference
customDataduring USDA serialization.
| File | Description |
|---|---|
crates/openusd/tests/stage.rs |
Updates clip interpolation expectations. |
crates/openusd/src/usda/writer.rs |
Serializes reference custom data. |
crates/openusd/src/usd/stage.rs |
Adds cache and payload regression tests. |
crates/openusd/src/pcp/prim_indexer.rs |
Reports unresolved arc targets. |
crates/openusd/src/pcp/prim_index.rs |
Tests missing target diagnostics. |
crates/openusd/src/pcp/index_cache.rs |
Skips empty paths and tests clip switching. |
crates/openusd/src/pcp/compose_site.rs |
Normalizes identity payload offsets. |
crates/openusd/src/pcp/clip.rs |
Interpolates across clip activation boundaries. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This was referenced Oct 4, 2026
Bracket clip values from samples in the active window, consulting the next activation only when it supplies an interpolation bound. Honor manifest blocks while gathering those samples. Unused, distant, and manifest-blocked clips remain unopened, so a malformed asset outside the query's dependencies cannot fail the read. Use the target stack's root layer for unresolved reference and payload diagnostics, including sub-root targets. Internal arcs on a stage with a session layer now identify the root layer in their errors. Define payload equality in sdf so an omitted layer offset compares equal to an explicit identity offset. Direct comparisons and list-op deletion and deduplication share this behavior, with no normalization in pcp. Add regression coverage for lazy clip reads, manifest-blocked malformed clips, session-layer diagnostics, and payload equality and list ops. Validation: cargo test --workspace --all-targets --all-features; cargo clippy --workspace --all-targets --all-features -- -D warnings; cargo fmt --all -- --check --files-with-diff.
sdf::Payload::layer_offset is a plain LayerOffset, as on Reference and C++ SdfPayload, so an omitted offset and an explicit identity offset compare equal without a hand-written PartialEq. The reference/payload arc computes its target stack's root layer once and names it in every target diagnostic, including arc cycles and prohibited relocation sources, which named the stack's strongest layer (the session layer for the root stack). Clip resolution shares one active-clip lookup and one contributes check, and reads plain sample times when bracketing an activation. The usda writer emits sublayer, reference, and payload metadata through one helper.
Report an unresolved reference or payload target from a task that only the top-level build runs, after every other task, as C++ EvalUnresolvedPrimPathError does. A nested build defers its variants, so a reference composed inside another reference's target whose prim a variant supplies was reported as unresolved. The check reads each node's path at introduction, which now skips variant selections the way C++ _GetPathAtIntroDepth does. An index at a variant selection path starts from its own site without ancestral opinions, as in C++ Pcp_BuildPrimIndex.
Owner
|
Thanks! and welcome back! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Hi man, now that I'm using this more across multiple projects I'm upstreaming some of the fixes I've been carrying locally. This one is just correctness fixes, and I'll have a few more PRs with some features later.
Six correctness fixes, one per commit, so any of them can be cherry-picked on its own (6 builds on 5). Each was checked against C++ OpenUSD 25.05.01 (Python bindings and
usdcat), and each commit's test fails onmainand passes with the fix.1.
fix(pcp): keep empty path out of index cacheQuerying an attribute on the pseudo-root caches a prim index for the empty path, and muting a sublayer afterwards panics in
index_store.rs.ensure_indexnow skips the empty path. In C++, a stage with a sublayer, thenGetPseudoRoot().GetAttribute("x").Get(), then mute, unmute, mute raises no error. Test:mute_after_pseudo_root_attribute_queryinusd/stage.rs.2.
fix(pcp): interpolate across clip activationsBetween two active clips the value comes only from the clip active at the query time, so clips
0:1 / 20:3and0:5 / 20:7withactive = [(0, 0), (10, 1)]give 1.5 at stage time 5.value_in_setnow brackets the query with the clip set's stage sample times, reads each bracketing value from the clip active at that time and interpolates between them. Across atimesjump discontinuity it does not interpolate, and the earlier clip time holds up to the jump, as C++ does. In C++ the fixture above gives (0, 1.0), (5, 3.5), (9, 5.5), (10, 6.0), (15, 6.5), (20, 7.0), the values the new testclip_switch_interpolates_activation_samplesinpcp/index_cache.rsexpects, andclip_multiholds -15 just before its jump at 16 (C++ adds a sample at 15.999999995559108).This commit also updates
clip_interpolate_missing_boundary_is_a_sample, which expected 0.0 at 9.999 where C++ gives 49.994998931884766 (and 50 at 10). That test still assertstime_sample_times == [0, 10, 20]while C++ reports[0, 20], which this PR leaves as it is.3.
fix(usda): write customData on referencesThe usda writer drops
customDataon references.write_referencenow writes it when present and leaves out an identity layer offset, as C++ does:SdfLayer::ExportToStringwrites@./b.usda@ ( customData = { string note = "identity" } ), and C++ reads the Rust output back with the same values. Test:reference_custom_data_roundtripparses C++'s own output, round-trips it and checks that nooffset = 0is written.4.
fix(pcp): match identity payload offsetsdelete payload = @content.usda@</Box> (offset = 0; scale = 1)does not remove a weakerprepend payload = @content.usda@</Box>, becauseSome(LayerOffset::default())is compared as different fromNone.compose_sitenow normalises an identity offset toNonebefore list-op matching. In C++,Sdf.Payload("./p.usda") == Sdf.Payload("./p.usda", layerOffset=Sdf.LayerOffset(0, 1))isTrue, andusdcat --flattenof the same fixture gives an empty/Root. Test:identity_payload_offset_matches_omittedinusd/stage.rs.5.
fix(pcp): report missing reference targetsA reference or payload whose target prim does not exist in an external layer composes silently, with no composition error, both for
@a.usda@</Nope>and for a layer with no default prim.prim_indexernow reports empty external targets for references and payloads, and checks sub-root targets after all composition tasks finish so a target whose specs arrive through a later arc is not reported. In C++,UsdStage::GetCompositionErrors()reportsUnresolved reference prim path @a.usda@</Nope>. Test:absent_external_targets_report_reference_and_payload_errorsinpcp/prim_index.rs.6.
fix(pcp): report missing same-layer targetsInternal references and payloads such as
</Nope>are not reported either. Root targets are now reported like external ones, and sub-root targets use the end-of-composition check from commit 5. C++ reports a missing same-layer target at the root, below a prim and for payloads, and does not report it when a variant supplies the target. Test:absent_internal_targets_report_reference_and_payload_errorsis built from that C++ fixture and expectsRootMissing,SubMissingandPayloadMissingto be reported andSubPresentandFromVariantRefnot to be.PS: you can cherry pick each of them if you want separate from each other...