cmbruns / pyopenvr

Unofficial python bindings for Valve's OpenVR virtual reality SDK

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

On macOS importing openv.init() fails with InterfaceNotFound

tomgoddard opened this issue · comments

I updated from PyOpenVR 1.3.2201 to 1.5.1701 and

openvr.init(openvr.VRApplication_Scene)

fails with

'VRInitError_Init_InterfaceNotFound' (error number 105)

It fails in 1.5.1701 but not in 1.3.2201. In PyOpenVR.init.py version 1.5.1701 has

IVRSystem_Version = 'IVRSystem_020'

while version 1.3.2201 has

IVRSystem_Version = b"IVRSystem_019"

Changing the 1.5.1701 code to use "IVRSystem_019" fixes the problem.

I am running macOS 10.14.6 (Mojave, latest version), and SteamVR beta macosx_default version 1539100633 built Oct 9, 2018 at 08:57. This is the most recent SteamVR runtime and only available SteamVR runtime that works on macOS. I am using a Vive Pro.

While macOS is poorly supported by SteamVR it would be nice if PyOpenVR checked if sys.platform == 'darwin" and used the older compatible IVRSystem_Version. Currently my VR app (ChimeraX) imports openvr and makes this change (setting openvr.IVRSystem_Version = 'IVRSystem_019') if the platform is darwin, so I am able to work around the problem.

I am not sure whether which interface "version" (i.e. IVRSystem_020) is attributed to which OpenVR version is documented anywhere, nor which version is actually the most recent one on every platform. It seems that so far it was safe to assume it was the latest one.

I guess one way to handle it would be adding an optional keyword argument to every OpenVR interface, which would allow specifying the interface version explicitly by the caller and override the default (=latest). But you would still need to figure out the correct version on your own.

IVRSystem_019 started with openvr version 1.012 about 2 years ago, and was updated to IVRSystem_020 at openvr version 1.5.17 this year.

Changing the symbol is a poor approach. Better would be to use a separate version with the actual API version, not just the version symbol.

If we could figure out the correct openvr version for whatever is available on Mac, it might be worth maintaining a branch at that version, then encouraging Mac folks to 'pip install openvr <version>'.

Or is there a way to make pip automatically install different versions depending on OS details?

I was just looking into this version thing again as I thought it might need some substantial work, only to find out that I am not sure I really understand the versioning:

IVRSystem_019 was replaced by IVRSystem_020 in OpenVR SDK 1.15.17 because Valve removed a function

/** Sends a request to the driver for the specified device and returns the response. The maximum response size is 32k,
* but this method can be called with a smaller buffer. If the response exceeds the size of the buffer, it is truncated. 
* The size of the response including its terminating null is returned. */
virtual uint32_t DriverDebugRequest( vr::TrackedDeviceIndex_t unDeviceIndex, const char *pchRequest, VR_OUT_STRING() char *pchResponseBuffer, uint32_t unResponseBufferSize ) = 0;

from IVRSystem interface. There is nothing unexpected about it. But in OpenVR SDK 1.16.10 they introduced two new functions to IVRSystem:

// -------------------------------------
// App container sandbox methods
// -------------------------------------

/** Retrieves a null-terminated, semicolon-delimited list of UTF8 file paths that an application 
* must have read access to when running inside of an app container. Returns the number of bytes
* needed to hold the list. */
virtual uint32_t GetAppContainerFilePaths( VR_OUT_STRING() char *pchBuffer, uint32_t unBufferSize ) = 0;

// -------------------------------------
// System methods
// -------------------------------------

/** Returns the current version of the SteamVR runtime. The returned string will remain valid until VR_Shutdown is called.
*
* NOTE: Is it not appropriate to use this version to test for the presence of any SteamVR feature. Only use this version
* number for logging or showing to a user, and not to try to detect anything at runtime. When appropriate, feature-specific
* presence information is provided by other APIs. */
virtual const char *GetRuntimeVersion() = 0;

And the interface remained the same, i.e. IVRSystem_020. So hypothetically, the app, which was compiled with SDK 1.16.10 and which uses one of those function, will get the IVRSystem_020 on 1.15.17 runtime, but will possibly crash when calling one of the new functions.

This shows two aspects:

  • The interfaces are changing over the versions and they may lose as well as get some new functions, so properly supporting different versions (in general) would require maintaining "the frozen state of the API".
  • If it was not an overlook on Valve's part, the interface designation (i.e. IVRSystem_020) is not a reliable differentiator, because two different interfaces can have the same ID.

Now, when using C++ API, the interfaces are "frozen" by compiling openvr_api.lib, which makes the app use the interfaces defined in the SDK used at the build time. There is no similar mechanism we could use in Python. If you could generate the Python API on the fly from the interface definition (which already happens, but I do no know, how deep it goes), you could simply maintain the interface definitions (e.g. openvr_api.json) with the corresponding API release, and then even let the user generate the Python interface from it depending on his target system.

Updating to the new version would then simply mean just substituting a newer API definition.

Yeah I did not think that pip idea through very well.

One approach that might work would be to use a bootstrapping approach. So "import openvr" would

  • first bind just a few functions; maybe isInterfaceVersionValid and/or getRuntimeVersion
  • use these methods or other techniques to identify the most advanced relevant version
  • then load the rest of the API from one of a library of versioned API files

In my similar pyovr project I save a bunch of different API versions there in the package (but I don't really use them for anything).

Which versions to save?

  • The latest version, of course
  • The previous version. There have been cases where even with Windows and SteamVR, the most mainstream use case, the lastest openvr bindings were briefly ahead of the shipped SteamVR runtime.
  • The very oldest useful version.
  • Particular versions known to be useful, such as whatever the Mac runtime uses.

With openvr 1.9.1601 to get it to work with the old Mac SteamVR (Built Oct 9, 2018 at 08:57, Version 1539100633) requires

    import openvr
    openvr.IVRSystem_Version = "IVRSystem_019"
    openvr.IVRCompositor_Version = "IVRCompositor_022"

replacing the 1.9.1601 values of IVRSystem_021 and IVRCompositor_024.

@tomgoddard I think the most robust solution would be to install an older version of the openvr module on the Mac you want to use with SteamVR. Dynamically adjusting the version is simply too magical.

The last time the OpenVR Mac dylib changed was in release 1.8.19, but those api versions mentioned upthread suggest that the Mac API is/was stuck somewhere from release 1.0.12-1.4.18. So creating a custom pyopenvr release based on, say, openvr 1.4.18 might be helpful for any folks still using Mac.

@tomgoddard Question: Do you still have a working Mac SteamVR setup? I'd like to make a custom release of pyopenvr for Mac users, set at the correct API version(s). Especially since Mac users won't be able to use OpenXR/pyopenxr in the foreseeable future.

@tomgoddard Thanks for the update. I hope you will be available to eventually test whatever Mac-oriented release we create. Yes we include the shared library for Mac. But hard-coding the version numbers for Mac is

  1. Something I believe you inserted into your own pyopenvr source tree, and
  2. Not the best approach, because those version error messages are trying to communcate something important. Better would be to expose the API that is consistent with the actual runtime version.

I can rerun the latest pyopenvr generator against an older version of the OpenVR SDK to create a modern release that supports the exact runtime supported on Mac. I suspect that Valve will never advance the runtime version supported on Mac, so it's not a bad idea to create the best custom Mac-oriented release of pyopenvr we can at this point. It's true every release supports every platform. But different releases of pyopenvr might represent the "best release" for a particular platform.

That's why I'm trying to track down the exact Mac runtime version(s) supported by SteamVR. At first I was thinking of trying to figure out the runtime version by triggering error messages about the versions of more interfaces besides just IVRSystem and IVRCompositor. Then we could deduce the actual runtime version. Sadly, the OpenVR IVRSystem::GetRuntimeVersion() was not implemented until OpenVR 1.6, which I think might be newer than the latest supported Mac runtime.

But first let's try a more direct approach to determining the SteamVR runtime version on Mac.

@JoeLudwig @jeremyselan Question: Could you please tell me the OpenVR runtime version number(s) of the current SteamVR Mac beta releases macos_beta and macos_default ?