-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add initial implementation of usdSemantics
#3103
Conversation
Filed as internal issue #USD-9719 |
/AzurePipelines run |
Azure Pipelines successfully started running 1 pipeline(s). |
/AzurePipelines run |
Azure Pipelines successfully started running 1 pipeline(s). |
/AzurePipelines run |
Azure Pipelines successfully started running 1 pipeline(s). |
/AzurePipelines run |
Azure Pipelines successfully started running 1 pipeline(s). |
02d4fcd
to
89624aa
Compare
/AzurePipelines run |
Azure Pipelines successfully started running 1 pipeline(s). |
/AzurePipelines run |
Azure Pipelines successfully started running 1 pipeline(s). |
/AzurePipelines run |
Azure Pipelines successfully started running 1 pipeline(s). |
pxr/usd/usdSemantics/labelsQuery.h
Outdated
/// Compute the union of values for `semantics:labels:<taxonomy>` in the | ||
/// specified interval. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this and other methods that return an array of labels, please specify whether there is a stable ordering of the returned values, or client must expect them to be disordered.
For this method specifically, it WBN to just reinforce the convention that "Direct" means this prim's contributions only.
pxr/usd/usdSemantics/labelsQuery.cpp
Outdated
|
||
bool | ||
UsdSemanticsLabelsQuery::_PopulateLabels(const UsdPrim& prim) { | ||
TF_DEV_AXIOM(!prim.IsPseudoRoot()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TF_VERIFY is preferred to TF_DEV_AXIOM
pxr/usd/usdSemantics/labelsQuery.cpp
Outdated
UsdSemanticsLabelsQuery::_PopulateLabels(const UsdPrim& prim) { | ||
TF_DEV_AXIOM(!prim.IsPseudoRoot()); | ||
UsdSemanticsLabelsAPI schema(prim, _taxonomy); | ||
if (!schema.GetPrim().HasAPI<decltype(schema)>(schema.GetName())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Constructing a schema object is not trivial in cost; can we do this check first, using the given prim
, UsdSemanticsLabelsAPI
, and _taxonomy
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should be doing this check at all-- we should just be validating the schema.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The HasAPI check is a faster check, though, and given that we expect, in many scenes, to have few if any applications of the schema, it may be worth doing the fast check up front?
pxr/usd/usdSemantics/labelsQuery.h
Outdated
/// The query caches certain reads and computations and should be discarded | ||
/// when the state of the stage changes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Helpful to mention that it is safe to use in a multi-threaded context... not all caches in Usd schemas are currently, regrettably.
pxr/usd/usdSemantics/schema.usda
Outdated
|
||
class "SemanticsLabelsAPI" ( | ||
inherits = </APISchemaBase> | ||
doc = """Applied set of labels for a prim for a taxonomy specified by the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given implied meanings of "set", can we be specific on what we mean, here? Is it an ordered list of labels, or is authored order insignificant?
/AzurePipelines run |
Azure Pipelines successfully started running 1 pipeline(s). |
/AzurePipelines run |
Azure Pipelines successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comments contained herein came from our internal code review.
return {std::cbegin(labelsAtTime), std::cend(labelsAtTime)}; | ||
} | ||
if constexpr (std::is_same_v<TimeType, GfInterval>) { | ||
TF_DEV_AXIOM(!queryTime.IsEmpty()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe this could use TF_VERIFY? Unless checking this condition is expensive enough to have a real impact on performance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. Shouldn't be performance critical.
VtTokenArray labelsAtTime; | ||
if (!labelsAttr.Get(&labelsAtTime, timeInInterval)) { | ||
TF_RUNTIME_ERROR("Failed to read value at %s", | ||
UsdDescribe(labelsAttr).c_str()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious when we would hit the two conditions here that cause runtime errors to be emitted. Are those really runtime conditions that make that happen?
(Sorry to be so focused on error policy here, rather than what I'm supposed to be weighing in on!!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for doing so, @nvmkuruc , as I was just about to. RUNTIME_ERRORs should be reserved for system-level errors. Here and elsewhere, if we really expected there should have been something authored but there wasn't, it would be more of a TF_WARN, I think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@matthewcpp The following layer can trigger that runtime error
def "test" (apiSchemas = ["SemanticsLabelsAPI:test"])
{
int[] semantics:labels:test.timeSamples = {100: [1]}
}
with the following code.
from pxr import Usd, UsdSemantics
s = Usd.Stage.Open('sl.usda')
query = UsdSemantics.LabelsQuery('test', 100)
print(query.ComputeUniqueDirectLabels(s.GetPrimAtPath('/test')))
@spiffmon I'm happy to use whatever diagnostic makes the most sense, but it did seem like an error to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, so that's "bad scene description", similar to having something like
over "mySphere"
{
string radius = "five"
}
which is not considered a runtime error. In Presto (and future USD) it would be a validation error, but at scene-interrogation-time, I think we are silent about it, actually.
// cache. Attempting to collapse this expression using |= or the | ||
// STL may result in some population being skipped and incorrect | ||
// results. | ||
if (_PopulateLabels(stage->GetPrimAtPath(path))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could do this population in parallel?
return {}; | ||
} | ||
|
||
std::shared_lock lock{_cachedLabelsMutex}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious why we need to lock here; I assume the locking is only to protect against simultaneous writes (or reads while writing is happening). But at this point, we know the cache has already been populated, so presumably it is safe to allow multiple readers to proceed in parallel?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If another thread is querying the cache, a rehash could be triggered, invalidating the iterator.
return {}; | ||
} | ||
VtTokenArray result{std::cbegin(it->second), std::cend(it->second)}; | ||
std::sort(result.begin(), result.end()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we sort as part of population?
Ah, I guess we can't because we use sets so that we can combine inherited results. It seems like it would be nice to frontload the sorting, somehow, but there are tradeoffs to consider, and we'd want to actually measure performance to understand the impact, most likely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's possible it would be more efficient to use std::merge
on sorted token arrays. But perhaps we could address later?
|
||
_UnorderedTokenSet uniqueElements; | ||
{ | ||
std::shared_lock lock{_cachedLabelsMutex}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I'm not yet understanding why we need to lock once population is complete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the previous note about the iterator lifetime.
Description of Change(s)
Implementation of https://github.com/PixarAnimationStudios/OpenUSD-proposals/tree/main/proposals/semantic_schema which adds a
SemanticsLabelsAPI
schema for labeling prims with tokens.Note that the implementation diverges slightly with the proposal with the taxonomy being after
labels
instead of before in the property name. (ie.semantics:labels:<taxonomy>
instead ofsemantics:<taxonomy>:labels
).In addition to the schema, a utility
UsdSemanticsLabelsQuery
provides a reference for how ancestor labeling is expected to work and inherit.Fixes Issue(s)