Usd APISchemaAdapter not loading

   1624   13   3
User Avatar
Member
7 posts
Joined: Nov. 2019
Offline
Hey everyone!

I've built a SceneIndexPlugin for USD with an APISchemaAdapter. The plugin works correct for native USD 23.11. However, when loading the plugin for Houdini (tested with H20 NC using Houdini GL and Karma), it's not recognizing the APISchemaAdapter. My sceneIndex is loaded, and I've confirmed that the adapter is registered to the adapter registry. It's just that the adapter never gets invoked. Is this behavior expected? Or is there anything I can do to get around it?

I'm on macOS 14.1.1.

All the best,
Viktor
User Avatar
Staff
453 posts
Joined: June 2020
Offline
Hi Viktor,

I was hoping you could elaborate a little bit on what you're trying to achieve. I'm a bit confused when I read about both a SceneIndex and an APISchemaAdaptor and wondering if/how you're combining these or if they're quite separate.

Do you get any useful messages with TF_DEBUG="PLUG*"set when you launch Houdini?

Also, just to check, does it work for you with native USD 23.08? That's the version we're using in H20.0

Thanks!
User Avatar
Member
7 posts
Joined: Nov. 2019
Offline
Hey Rob! Thanks for your reply. I'll try to elaborate, however I'm not sure I fully understand how all this works myself

What I'm trying to achieve is a render-time deformer for Hydra 2.0, and I'd love to see if I could get it working inside of Houdini as well. I've used this [github.com] example quite a lot to set it up.

The APISchemaAdapter will create some data sources for my custom API schema prim before my SceneIndex is invoked. That allows my SceneIndex to distinguish between prims that has my API schema applied, and those that don't. It also allow me to use my custom UsdProperties inside of Hydra. The SceneIndex makes use of an HdSchema and HdSchema::GetFromParent() [github.com], which expects a certain token to exist in the data source in order to work. Hence, I need the APISchemaAdapter to set those prior to my SceneIndex being invoked.

From what I gather, an APISchemaAdapter registers to the UsdImagingAdapterRegistry, which the StageSceneIndex use. During the StageSceneIndex::GetPrim() [github.com] function call, the StageSceneIndex calls GetImagingSubprimData() [github.com] on all the registered adapters, which is where the adapters can initialize what data should be available in the Hydra scene.

Yes, running with TF_DEBUG="PLUG_*" show me that the plugin is loaded. I've ran it with TF_DEBUG="USDIMAGING_PLUGINS" as well, which when I run for native USD, I see:

Plugin discovered 'myAPIAdapter'
Loaded plugin 'myAPISchema' > 'myAPIAdapter'

but when run in Houdini, I only see the 'plugin discovered', but not 'Loaded plugin'. I'm not sure what that means.

I checked that my adapter was registered as well, by doing:
for (auto i: UsdImagingAdapterRegistry::GetInstance().GetAPISchemaAdapterKeys()) {
        std::cout<<i<<std::endl;
}
And it seems to be. Yet the data sources are not being applied as I'd expect.

Good idea to test for 23.08, I'll do that and get back to you

Thank you!
User Avatar
Member
7 posts
Joined: Nov. 2019
Offline
Just confirmed it works with native USD 23.08
User Avatar
Staff
453 posts
Joined: June 2020
Offline
Thanks Viktor, that's a great explanation and much better grounds me in what you're trying to do.

A few thoughts:

First, Houdini 20.0 isn't particularly Hydra2 ready. You *can* run it with USDIMAGINGGL_ENGINE_ENABLE_SCENE_INDEX=1, but you'll run into no shortage of "huh, why isn't _____ working?" issues. Sometimes forcing the renderer to restart (from the drop-down menu in the viewport) helps move things forward a bit.

With that environment variable set, I *was* able to get a custom UsdImagingAPISchemaAdapterregistered and instantiated (if I forced the renderer to restart - it didn't seem to get instantiated on the first run), targeting HoudiniCameraPlateAPI.

You mentioned you've been testing in vanilla USD usdview. Have you also tried in the usdviewshipped with Houdini?

When you're building the plugin(s), are you using the USD headers & libraries shipped with Houdini?

Is the custom Scene Index running as-expected (other than the fact that it can't find the data your adapter is meant to be inserting)?

Does the Scene Index "chain"/"tree" look like what you'd expect? You might be able to run this from the constructor of your Scene Index, after the inputSceneIndexhas been chained up (by calling the base constructor):
void dumpSceneIndexTree(HdSceneIndexBaseRefPtr sceneIndex,
int depth = 0)
{
std::cout << std::string(depth*2, ' ')
<< sceneIndex->GetDisplayName()
<< std::endl;
auto filteringIndex =
TfDynamic_cast<HdFilteringSceneIndexBaseRefPtr>(sceneIndex);
if (filteringIndex)
for (auto &&inputIndex : filteringIndex->GetInputScenes())
dumpSceneIndexTree(inputIndex, depth+1);
}

A few things to investigate ... let me know how it goes, and I'll see what I can do to help further based on your feedback.
User Avatar
Member
7 posts
Joined: Nov. 2019
Offline
Thank you so much for your answer!

I see, this could very well be one of those issues then, hehe! In my case, it unfortunately didn't help to restart the render. I checked for other APISchemaAdapters as well, but none seems to instantiate for me. However, there seems to be nothing wrong with the regular prim adapters though, such as UsdImagingCameraAdapter, which seems to load perfectly fine.

I did try with the usdview from Houdini, but I keep getting some errors which I believe are related to Metal:
ERROR: Usdview encountered an error while updating selection.
Error in 'pxrInternal_v0_23__pxrReserved__::PlugRegistry::GetPluginForType' at line 181 in file /Users/prisms/builder-new/WeeklyDevToolsHEAD/dev_tools/src/usd/usd-23.08/USD-py3.10/pxr/base/plug/registry.cpp : 'Unknown base type'
Error in '*pxrInternal_v0_23__pxrReserved__::_MakeNewPlatformDefaultHgi' at line 95 in file /Users/prisms/builder-new/WeeklyDevToolsHEAD/dev_tools/src/usd/usd-23.08/USD-py3.10/pxr/imaging/hgi/hgi.cpp : '[PluginLoad] PlugPlugin could not be loaded for TfType 'TfType::_Unknown'
'
Error in 'pxrInternal_v0_23__pxrReserved__::PlugRegistry::GetPluginForType' at line 181 in file /Users/prisms/builder-new/WeeklyDevToolsHEAD/dev_tools/src/usd/usd-23.08/USD-py3.10/pxr/base/plug/registry.cpp : 'Unknown base type'
Error in '*pxrInternal_v0_23__pxrReserved__::_MakeNewPlatformDefaultHgi' at line 95 in file /Users/prisms/builder-new/WeeklyDevToolsHEAD/dev_tools/src/usd/usd-23.08/USD-py3.10/pxr/imaging/hgi/hgi.cpp : '[PluginLoad] PlugPlugin could not be loaded for TfType 'TfType::_Unknown'
'
Traceback (most recent call last):
File "/Applications/Houdini/Houdini20.0.506/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pxr/Usdviewq/stageView.py", line 1621, in paintGL
renderer = self._getRenderer()
File "/Applications/Houdini/Houdini20.0.506/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pxr/Usdviewq/stageView.py", line 943, in _getRenderer
self._renderer = UsdImagingGL.Engine()
pxr.Tf.ErrorException:
Error in 'pxrInternal_v0_23__pxrReserved__::PlugRegistry::GetPluginForType' at line 181 in file /Users/prisms/builder-new/WeeklyDevToolsHEAD/dev_tools/src/usd/usd-23.08/USD-py3.10/pxr/base/plug/registry.cpp : 'Unknown base type'
Error in '*pxrInternal_v0_23__pxrReserved__::_MakeNewPlatformDefaultHgi' at line 95 in file /Users/prisms/builder-new/WeeklyDevToolsHEAD/dev_tools/src/usd/usd-23.08/USD-py3.10/pxr/imaging/hgi/hgi.cpp : '[PluginLoad] PlugPlugin could not be loaded for TfType 'TfType::_Unknown'
'
and it renders black, so I unfortunately can't seem to test with it atm. Worth noting that this happens with or without my plugin loaded, and with the --noplugins flag and also --renderer "Metal". Since I'm not getting these errors in Houdini, I figured it's unrelated, but I'm just guessing at this point. I was going to report as bug but haven't gotten to it just yet

Yes, I'm building against the Houdini libraries & headers for the Houdini plugin, not for the vanilla plugin though.

I believe the scene index works as expected, logging from the _primsAdded() and GetPrim() functions prints correctly. Running that function you sent results in:
HdMergingSceneIndex
HdNoticeBatchingSceneIndex
HdLegacyPrimSceneIndex
which is the same as I'm getting when running it in the vanilla usdview, so I believe it's correct, however I'm not entirely sure here.

I will look around a bit more to see if I can narrow down the problem, but this might very well be related to Hydra2.0 being very fresh, and me being a bit too eager to play around with it! I'll see if I can get my hands on a linux machine as well, perhaps that would help.

One thing I did notice though, was that my Houdini/toolkit install is missing the adapterManager [github.com] header. Reinstalled and still missing. Not sure if that affects anything since the other prim adapters still load, and you managed to get it working, but it could perhaps explain if the StageSceneIndex wouldn't find my adapter?

Again, thank you so much for your time
Viktor
User Avatar
Staff
453 posts
Joined: June 2020
Offline
Hmm ... okay, let's take a step back and double-check a few things in Houdini. Apologies if you've already looked at all these.

First, let's be sure that the Hydra2 env var is set. In the Python shell:
hou.getenv("USDIMAGINGGL_ENGINE_ENABLE_SCENE_INDEX")

If this doesn't return "1"we're off to a bad start. In the shell it should also be pretty obvious with a warning about overriding the default value.
##########################################################################################
# USDIMAGINGGL_ENGINE_ENABLE_SCENE_INDEX is overridden to 'true'. Default is 'false'. #
##########################################################################################

Next let's make sure the API is properly registered and assigned to some prims. In the Python shell:
from pxr import Usd

stage = # <- FILL THIS IN
api_name = # <- FILL THIS IN

api_type = Usd.SchemaRegistry.GetAPITypeFromSchemaTypeName(api_name)
predicates = Usd.PrimIsDefined or Usd.PrimIsAbstract
prims = [prim for prim in stage.Traverse(predicates) if prim.HasAPI(api_type)]
for prim in prims:
print(prim.GetPath(), prim.GetTypeName())

Then let's also double-check on the C++ side that the API adapter is registered. In the Scene Index constructor (or anywhere where you can trigger execution at a predictable time):

auto &reg = UsdImagingAdapterRegistry::GetInstance();
for (auto &&key : reg.GetAPISchemaAdapterKeys())
std::cout << key.GetString() << std::endl;

If everything still looks good and it's still not working ... if you're willing to share the code, I'm happy to try building & testing on my machine.

my Houdini/toolkit install is missing the adapterManager header

That should be fine. As best I can tell, that's not a public header. You shouldn't see it in a vanilla USD installation either (outside of the builddirectory). For example:

$ find _usd23.08/ -name "adapterManager.h"
_usd23.08/build/USD/include/pxr/usdImaging/usdImaging/adapterManager.h

$ find _usd23.08/ -name "adapterRegistry.h"
_usd23.08/build/USD/include/pxr/usdImaging/usdImaging/adapterRegistry.h
_usd23.08/include/pxr/usdImaging/usdImaging/adapterRegistry.h
User Avatar
Member
7 posts
Joined: Nov. 2019
Offline
Hey! Sorry for the late reply!

Ah you're right, the header's missing in the vanilla install as well!

I'm running Houdini with the USDIMAGINGGL_ENGINE_ENABLE_SCENE_INDEX env var, and I've tried with these as well:
export HD_ENABLE_SCENE_INDEX_EMULATION=true;
export USDIMAGING_ENABLE_PLUGINS=true;

I've confirmed the schema and the adapter are registered in Houdini.

I went back a bit to what you said about checking the input scene index chain and realized I wasn't seeing the stage scene index there, so tried this in order to look for it explicitly:

static UsdImagingStageSceneIndexRefPtr
FindUsdImagingSceneIndex(const std::vector<HdSceneIndexBaseRefPtr>& inputScenes, int depth=0)
{
    TfRefPtr<UsdImagingStageSceneIndex> retVal;

    for (size_t i = 0; i < inputScenes.size(); i++) {
        HdSceneIndexBaseRefPtr const &sceneIdx = inputScenes[i];
        if (UsdImagingStageSceneIndexRefPtr const imagingSI = TfDynamic_cast<UsdImagingStageSceneIndexRefPtr>(sceneIdx)) {
            std::cout << std::string(depth*2, ' ') << imagingSI->GetDisplayName() << std::endl;

            retVal = imagingSI;
            break;
        }
        if (HdFilteringSceneIndexBaseRefPtr const filteringSi = TfDynamic_cast<HdFilteringSceneIndexBaseRefPtr>(sceneIdx)) {
            std::cout << std::string(depth*2, ' ') << filteringSi->GetDisplayName() << std::endl;

            retVal = FindUsdImagingSceneIndex(filteringSi->GetInputScenes(), depth+1);
            if (retVal) {
                break;
            }
        }
    }
    return retVal;
}

When running this in vanilla usdview I get:

SEARCHING FOR SCENE INDEX....
HdNoticeBatchingSceneIndex
HdsiLegacyDisplayStyleOverrideSceneIndex
UsdImagingRenderSettingsFlatteningSceneIndex
UsdImagingSelectionSceneIndex
UsdImagingNiPrototypePropagatingSceneIndex
UsdImagingPiPrototypePropagatingSceneIndex
UsdImagingExtentResolvingSceneIndex
UsdImagingRootOverridesSceneIndex
HdsiPrimTypePruningSceneIndex
HdsiPrimTypePruningSceneIndex
UsdImagingStageSceneIndex
FOUND SCENE INDEX: UsdImagingStageSceneIndex
Whereas in Houdini, no stage scene index is found. Notice the two inputs to my scene index: HdNoticebatchingSceneIndex and HdsiLegacyDisplayStyleOverrideSceneIndex, in Houdini, it only prints the former.

I then went ahead and tried:

HdSceneIndexNameRegistry& reg = HdSceneIndexNameRegistry::GetInstance();
for(auto i: reg.GetRegisteredNames()) {
    std::cout<<"SCENE INDEX NAME REG: " << i<<std::endl;
}

Which in vanilla usdview prints
SCENE INDEX NAME REG: delegate adapter: / @ UsdImagingGLEngine_HdStormRendererPlugin_0x2804be6b0
and Houdini:
SCENE INDEX NAME REG: delegate adapter: / @ 0x2def08c00
SCENE INDEX NAME REG: delegate adapter: / @ 0x2ddd96a00

This confuses me a bit. Does it mean there's no registered stage scene index, or that they just don't have names? Why are there two?

I'm happy to share the code if you'd like to take a look! I haven't tested building for other platforms yet though, so you'll need to make sure the Houdini paths are correct in the cmake files. I made a stripped branch without my deformer just to minimize it a bit for testing. I also include a testenv/hairProc.usda file that has the schema applied and all the properties to test with. I should also mention that I am not a very seasoned programmer, and the repository is a bit messy. I hope that's not a problem
Repository [github.com]

Thanks again!
User Avatar
Staff
453 posts
Joined: June 2020
Offline
Hi Viktor, I'm off for the holidays, but I'll happily look at the code when I'm back. Thanks for the link.
User Avatar
Staff
453 posts
Joined: June 2020
Offline
Happy New Year!

I've been re-reading this thread trying to remember where exactly we left things. I was able to build your code (with some very very small modifications and a custom build script), and get things loading in Houdini 20.

I added debug output in the constructors of the API Adapter and SI Plugin, as well as hacked a Scene Index tree dump into GetPrimwhere the entire hierarchy should be in-place.

void __dumpSceneIndexTree(HdSceneIndexBaseConstRefPtr sceneIndex, int depth = 0)
{
std::cout << std::string(depth*2, ' ') << sceneIndex->GetDisplayName() << std::endl;
if (auto filteringIndex = TfDynamic_cast<HdFilteringSceneIndexBaseConstRefPtr>(sceneIndex))
for (auto &&inputIndex : filteringIndex->GetInputScenes())
dumpSceneIndexTree(inputIndex, depth + 1);
}

HdSceneIndexPrim HairProcHairProceduralSceneIndex::GetPrim(const SdfPath& primPath) const {
static bool __init = false;
if (!__init) { __dumpSceneIndexTree(TfCreateRefPtr(this)); __init = true; }
...

With all that done, and using USDIMAGINGGL_ENGINE_ENABLE_SCENE_INDEX=1, when I switch to Solaris, I get:
HairProcHairProceduralSceneIndex CTOR
HairProcHairProceduralSceneIndex
HdMergingSceneIndex
HdNoticeBatchingSceneIndex
HdLegacyPrimSceneIndex
UsdImagingDrawModeSceneIndex
HdFlatteningSceneIndex
UsdImagingRenderSettingsFlatteningSceneIndex
UsdImagingSelectionSceneIndex
UsdImagingNiPrototypePropagatingSceneIndex
UsdImagingPiPrototypePropagatingSceneIndex
UsdImagingStageSceneIndex

This is good because it demonstrates your custom Scene Index is running, and we have the UsdImagingStageSceneIndexshowing up.

Switching to Karma, I get:
HairProcHairProceduralSceneIndex CTOR

Sublayering in a test USD file:
#usda 1.0
(
framesPerSecond = 24
metersPerUnit = 1
timeCodesPerSecond = 24
)

def Sphere "sphere1" (
apiSchemas = ["HairProceduralAPI"]
)
{
float3[] extent = [(-1, -1, -1), (1, 1, 1)]
double radius = 1.0
}

I don't get any new output.

Then choosing "Restart Render" in the viewport, I get:
HairProcHairProceduralSceneIndex CTOR
HairProcHairProceduralAPIAdapter CTOR
GetImagingSubprimData called on /sphere1
GetImagingSubprimData called on /sphere1
GetImagingSubprimData called on /sphere1
GetImagingSubprimData called on /sphere1

Which shows the API Adapter constructed and working.

So the good news is that it can work. The bad news is I don't yet know why for you it doesn't work. But maybe you can follow what I did step-by-step and, if it suddenly works for you, identify the difference between this and your previous test/setup.
Edited by robp_sidefx - Jan. 2, 2024 07:43:24
User Avatar
Member
7 posts
Joined: Nov. 2019
Offline
Happy new year Rob!

Thank you again for looking in to this.

That is promising that it works for you! I recreated the steps you mentioned and unfortunately it still doesn't work on my side. I am still only seeing the one branch of the scene index tree from the HdMergingSceneIndex:
HairProcHairProceduralSceneIndex
  HdMergingSceneIndex
    HdNoticeBatchingSceneIndex
      HdLegacyPrimSceneIndex

and not the UsdImagingDrawModeSceneIndex ... chain.

Only the scene index prints from constructor also.

I tested targeting the x86_64 Houdini version as well and running through Rosetta, but got the same result.

Would you know if there'd be any reason to not have the stage scene index in the Mac version of karma? Or if using Apprentice would somehow be the reason for this?
User Avatar
Staff
453 posts
Joined: June 2020
Offline
This is very strange indeed. To double-double-check something mentioned earlier, what does hou.getenv("USDIMAGINGGL_ENGINE_ENABLE_SCENE_INDEX")return?

Looking through the earlier replies, I notice you mention setting some of those env vars to true. What if you set it to 1?
User Avatar
Member
7 posts
Joined: Nov. 2019
Offline
Hey Rob!

Changing to 1 instead of 'true' on the environment variable did the trick Now the StageSceneIndex is Loaded and everything works! Very nice! Thank you so much! I was sure the scene index was enabled since I was always getting the

##########################################################################################
#  USDIMAGINGGL_ENGINE_ENABLE_SCENE_INDEX is overridden to 'true'.  Default is 'false'.  #
##########################################################################################

print in my terminal. But I guess there's more checks going on behind the scenes that I was not considering.

I feel a bit silly wasting your time on such a simple thing, hehe! I suppose using 1 instead of 'true' is generally better, will for sure be doing that from now on!

Again, thank you for your help and your patience, It's been very informative and greatly appreciated!

All the best,
Viktor
User Avatar
Staff
453 posts
Joined: June 2020
Offline
AbsolutViktor
I guess there's more checks going on behind the scenes that I was not considering.

It's actually something specific on the SideFX side where we're not using Pixar's TfGetEnvSettingmechanism, and thus aren't as robust to handling various input. I've made a note to improve this.
  • Quick Links