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
refactor ResourceManager render assets #935
refactor ResourceManager render assets #935
Conversation
@@ -180,31 +188,85 @@ bool ResourceManager::loadStage( | |||
((_physicsManager != nullptr) && | |||
(_physicsManager->getInitializationAttributes()->getSimulator().compare( | |||
"none") != 0)); | |||
const Magnum::ResourceKey& renderLightSetup(stageAttributes->getLightSetup()); | |||
const std::string renderLightSetupKey(stageAttributes->getLightSetup()); |
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.
std::map<std::string, AssetInfo> assetInfoMap = | ||
createStageAssetInfosFromAttributes(stageAttributes, buildCollisionMesh, | ||
loadSemanticMesh); | ||
|
||
// set equal to current Simulator::activeSemanticSceneID_ value |
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.
This is not new code. I've simply moved this semantic loading code to happen earlier in this function. I did this because I need to know if a render asset instance is going to be used for RGBD/Semantic/both at the time of creation. I want to know as early as possible whether we're going to be in "single scene graph" vs "dual scene graph" mode.
src/esp/assets/ResourceManager.cpp
Outdated
RenderAssetInstanceCreation creation{ | ||
.filepath = semanticStageFilename, | ||
.scale = Cr::Containers::NullOpt, | ||
.isStatic = |
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.
isStatic roughly corresponds to the previous logic for computeSemanticAABBs.
Broke the JS bindings... |
} else if (info.type == AssetType::FRL_PTEX_MESH) { | ||
meshSuccess = loadPTexMeshData(info, parent, drawables); | ||
} else if (info.type == AssetType::SUNCG_SCENE) { | ||
if (info.type == AssetType::SUNCG_SCENE) { |
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.
SunCG scenes are not render assets.
// Right now, we only allow for an asset to be loaded with one | ||
// configuration, since generated mesh data may be invalid for a new | ||
// configuration | ||
LOG(ERROR) |
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.
This logic was moved from loadGeneralMeshData
to here.
pTexMeshData->uploadBuffersToGPU(false); | ||
|
||
for (int jSubmesh = 0; jSubmesh < pTexMeshData->getSize(); ++jSubmesh) { | ||
scene::SceneNode& node = instanceRoot->createChild(); |
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.
This is one of the few behavior changes in the PR. For the instance mesh, instead of adding all these mesh child sceneNodes directly to the parent sceneNode, I first create an instanceRoot
sceneNode. I want every render asset instance to have a single root sceneNode. This is needed for render replay.
I acknowledge there's probably a slight perf cost. Long-term, our new Vulkan batched renderer probably won't use a SceneNode hierarchy, so this shouldn't matter.
scene::SceneNode* instanceRoot = &parent->createChild(); | ||
|
||
for (uint32_t iMesh = start; iMesh <= end; ++iMesh) { | ||
scene::SceneNode& node = instanceRoot->createChild(); |
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.
return false; | ||
DrawableGroup* drawables) { | ||
ASSERT(!creation.scale); // PTex doesn't support scale | ||
ASSERT(creation.lightSetupKey == |
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.
Explicit asserts to show what a render asset type supports.
} // forceReload | ||
// TODO: cache visual nodes added by this process | ||
std::vector<scene::SceneNode*> visNodeCache; | ||
if (creation.scale) { |
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.
Currently, instances for objects use scale and instances for stages do not.
@@ -1833,7 +1899,15 @@ bool ResourceManager::loadSUNCGHouseFile(const AssetInfo& houseInfo, | |||
nodeIds.push_back(id); | |||
objectNode.setId(nodeIndex); | |||
if (info.type == AssetType::SUNCG_OBJECT) { | |||
loadGeneralMeshData(info, &objectNode, drawables); | |||
CHECK(loadRenderAsset(info)); |
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.
This codepath is untested so who knows if it actually works. https://cvmlp.slack.com/archives/G0131KVLBLL/p1604940887000900
* @param parent The @ref scene::SceneNode to which the mesh will be added | ||
* as a child. | ||
* as a child. See also creation->isRGBD and creation->isSemantic. nullptr if |
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.
There's an important subtlety here: currently, the way the user chooses RGBD vs Semantic is by passing the appropriate parent and drawables (from either the RGBD or Semantic scene graph). But I'm also requiring the user to specify isRGBD and isSemantic in the creation struct (so that I can record the choice in the replay data).
Eventually, we could refactor this interface so that the user just specifies the creation struct, and then we choose the correct parent and drawables on the backend.
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.
Overall looks fine to me. Minor comment that we are using the renderAsset loading pipeline for importing collision proxy assets also. Technically these are render-ready and could be instanced, so I don't think the re-naming is a problem. Just wanted to point this out.
namespace assets { | ||
|
||
// parameters to control how a render asset instance is created | ||
struct RenderAssetInstanceCreation { |
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 clarify that this is an info struct?
struct RenderAssetInstanceCreation { | |
struct RenderAssetInstanceCreationInfo { |
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.
Do we want to rename the file to match the struct?
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.
@mosra : Can you take another round of review? Thanks!
namespace { | ||
bool isRenderAssetGeneral(AssetType type) { | ||
return type == AssetType::MP3D_MESH || type == AssetType::UNKNOWN || | ||
type == AssetType::SUNCG_OBJECT; |
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.
Shall we remove the last one? We should not touch it, or have any "new" code that relatives to it.
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 chatted with Kathryn Duvall from FB legal and she says this will be fine. What I'm trying to do here is not break the SUNCG loading codepath, with the big caveat that we can't test this loading path on SUNCG data or otherwise use SUNCG data. We should consider support for SUNCG data to be deprecated. I will add a runtime warning about this codepath being deprecated.
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.
Awesome! Thanks for following up on this!
struct RenderAssetInstanceCreation { | ||
std::string filepath; // see also AssetInfo::filepath | ||
Corrade::Containers::Optional<Magnum::Vector3> scale; | ||
bool isStatic = |
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.
can we use the Flags instead of a couple of booleans? It is more efficient.
Here is a good example:
habitat-sim/src/esp/gfx/RenderCamera.h
Line 22 in fe9f78b
enum class Flag : unsigned int { |
meshSuccess = loadRenderAssetIMesh(info); | ||
} else if (isRenderAssetGeneral(info.type)) { | ||
meshSuccess = loadRenderAssetGeneral(info); | ||
} else { |
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.
CORRADE_INTERNAL_ASSERT_UNREACHABLE() ??
https://doc.magnum.graphics/corrade/Assert_8h.html
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.
Yes, compared to what's there now, CORRADE_INTERNAL_ASSERT_UNREACHABLE()
will give the compiler a correct hint, allowing for better optimizations even in release builds.
src/esp/assets/ResourceManager.cpp
Outdated
DrawableGroup* drawables, | ||
std::vector<scene::SceneNode*>* visNodeCache) { | ||
// assert that asset is already loaded | ||
CHECK(resourceDict_.count(creation.filepath)); |
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.
Do we have anything equivalent to the CHECK or more powerful in Corrade? @mosra
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.
How is a CHECK different from an ASSERT? I'd just use CORRADE_ASSERT here.
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.
CHECK simply outputs Warning while ASSERT interrupts system running, I believe.
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.
Oh. But the comment says assert
and I feel like it should be an assert :)
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 believe CHECK
will also abort if the condition is not met. Similar to CORRADE_ASSERT.
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.
OK. I checked the google docs. Yes, you guys are right. I was wrong.
// CHECK dies with a fatal error if condition is not true.
src/esp/assets/ResourceManager.cpp
Outdated
const auto& info = loadedAssetData.assetInfo; | ||
scene::SceneNode* newNode = nullptr; | ||
if (info.type == AssetType::FRL_PTEX_MESH) { | ||
ASSERT( |
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.
Suggest using CORRADE_ASSERT which is much more powerful and informative.
https://doc.magnum.graphics/corrade/Assert_8h.html
Good example is here:
https://github.com/facebookresearch/habitat-sim/blob/master/src/esp/assets/PTexMeshData.cpp
Search: CORRADE_ASSERT.
return false; | ||
} | ||
} else { | ||
if (resourceDict_[filename].assetInfo != info) { |
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 cases that just output warning, but the system will not be interrupted, do you have similar stuffs in Magnum? @mosra
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.
Mn::Warning{} << bla
:) Behaviorally same as Error{}
but can be redirected / muted independently of it.
src/esp/assets/ResourceManager.cpp
Outdated
} | ||
// create render asset instance if requested | ||
if (parent) { | ||
ASSERT(creation); |
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.
CORRADE_ASSERT(...)
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 feel a bit like being thrown in a cold water here -- I'm not fully aware of the progress / design / ideas around replay, so I can't really do a thorough review without first accompanying myself with everything related to this work (which I'm not sure I have capacity for, right now).
So all I can offer is random hints and suggestions re Magnum usage :) Hope that's fine.
Oh, and in addition to the comments below basically everything @bigbike says.
src/esp/assets/ResourceManager.cpp
Outdated
.isStatic = true, | ||
.isRGBD = true, | ||
.isSemantic = !isSeparateSemanticScene, | ||
.lightSetupKey = renderLightSetupKey}; |
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.
Apologies if I'm not up-to-date on C++ standard requirements in Habitat, but designated initializers are standard only since C++20 or require a particular GNU extension, which may hurt portability (especially if we'd want to reconsider Windows support again). I'd personally stay with standard C++ with no compiler-specific extensions.
Same in other places (I spotted one or two more occurence at least).
meshSuccess = loadRenderAssetIMesh(info); | ||
} else if (isRenderAssetGeneral(info.type)) { | ||
meshSuccess = loadRenderAssetGeneral(info); | ||
} else { |
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.
Yes, compared to what's there now, CORRADE_INTERNAL_ASSERT_UNREACHABLE()
will give the compiler a correct hint, allowing for better optimizations even in release builds.
src/esp/assets/ResourceManager.cpp
Outdated
ASSERT(false); // createRenderAssetInstance doesn't yet support the | ||
// requested asset type | ||
newNode = nullptr; |
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.
CORRADE_INTERNAL_ASSERT_UNREACHABLE()
here again, and because it marks the code as unreachable, the newNode = nullptr
isn't needed to suppress "potentially uninitialized variable" warnings.
return false; | ||
} | ||
} else { | ||
if (resourceDict_[filename].assetInfo != info) { |
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.
Mn::Warning{} << bla
:) Behaviorally same as Error{}
but can be redirected / muted independently of it.
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.
One minor question (feel free to ignore) otherwise LGTM.
namespace assets { | ||
|
||
// parameters to control how a render asset instance is created | ||
struct RenderAssetInstanceCreation { |
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.
Do we want to rename the file to match the struct?
0041bbf
to
69eebef
Compare
Pull from master to fix pre-commit |
c059881
to
efcc55c
Compare
RenderAssetInstanceCreationInfo( | ||
const std::string& _filepath, | ||
const Corrade::Containers::Optional<Magnum::Vector3>& _scale, | ||
bool isStatic, |
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.
Because you have defined Flags, these 3 booleans can be replaced by a single argument Flags flags
, aren't they? And it will be less error-prone.
That is the purpose to have the Flags introduced.
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.
LGTM
Motivation and Context
This PR is (mostly) a no-op refactor of ResourceManager (no behavior change). The motivation is to unblock the upcoming render replay feature.
I introduce the terms "render asset" and "render asset instance". A render asset is basically a mesh. A render asset can be of type InstanceMesh ("IMesh"), PTex, Primitive, or General (see
isRenderAssetGeneral
).A somewhat unrelated change is mixed in here: I'm converting some usage of ResourceKey (a hash) to std::string so that I can better serialize the key.
This is (mostly) a no-op refactor that conceptually replaces
loadPTexMeshData / loadInstanceMeshData / loadGeneralMeshData
withloadRenderAssetPTex,createRenderAssetInstancePTex / loadRenderAssetIMesh,createRenderAssetInstanceIMesh / loadRenderAssetGeneral,createRenderAssetInstanceGeneralPrimitive
.Some things you can do with render assets and instances:
loadRenderAsset
).createRenderAssetInstance
).More details about render assets:
Some goals/benefits of this refactor:
Some possible future use cases this unlocks (these are side benefits; the main motivation for this PR is unblocking render replay):
How Has This Been Tested
Loading stages with render assets of type PTex, InstanceMesh, and General (GLB), in the viewer
Adding physics objects in the viewer
Testing semantic rendering using a modified semantic_id_tutorial.py
I ran SimTest, which tests adding a primitive
Types of changes
Checklist