cmbruns / pyopenvr

Unofficial python bindings for Valve's OpenVR virtual reality SDK
BSD 3-Clause "New" or "Revised" License
245 stars 39 forks source link

On macOS importing openv.init() fails with InterfaceNotFound #69

Open tomgoddard opened 4 years ago

tomgoddard commented 4 years ago

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.

risa2000 commented 4 years ago

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.

cmbruns commented 4 years ago

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?

risa2000 commented 4 years ago

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:

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.

tomgoddard commented 4 years ago

I agree that just changing the Python IVRSystem_Version pyopenvr variable to 019 instead of 020 on the Mac is not right unless the pyopenvr library is compiled against the OpenVR version 019 headers on Mac. I think that is what should be done since only version 019 of the SteamVR runtime is available on Mac.

In addition I think pyopenvr should continue to work when SteamVR updates from version 020 to version 021 even though pyopenvr was compiled against version 020, if SteamVR is guaranteeing backward compatibility. I think they must be assuring backward compatibility or potentially all VR apps would break when the API version updates.

I don't think it is feasible or desirable to have pip decide which version of pyopenvr to install. Pip would have to figure out what SteamVR runtime is installed which may not be possible without starting SteamVR. In any case this would only make sense if pyopenvr actually provided builds against different SteamVR versions for the same operating system which seems like way too much work unless there is a solid reason for it (like pyopenvr wants to make use of a new SteamVR API, and yet continue to support users with the older SteamVR version).

cmbruns commented 4 years ago

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

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?

tomgoddard commented 4 years ago

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.

cmbruns commented 4 years ago

@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.

cmbruns commented 2 years ago

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.

cmbruns commented 2 years ago

@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 commented 2 years ago

Yes I have an iMac with Radeon Pro 580 graphics which worked fine with a Vive Pro headset last time I tried a few months ago. Why is a special Mac release of pyopenvr needed? I thought you include the shared libraries for Mac, Linux, and Windows, and the way it works now is the Mac version is linked to an old SteamVR for Mac and the PyOpenVR Python code has some special case code to set version numbers for the Mac to older versions. Maybe I misremember this.

At any rate, my iMac is at my office and I don't go their due to covid rules, but I can make a special trip to test. Usually I go in about once per month.

I am interested in pyopenxr for molecular VR visualization but do not expect to have time to work on it in coming months. Almost all my VR effort is on Windows although I have helped some biologists with Mac and Linux -- but that seems a losing battle.

cmbruns commented 2 years ago

@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.

cmbruns commented 2 years ago

@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 ?

tomgoddard commented 2 years ago

I agree that is a good plan. I have not encountered any OpenVR API errors on Mac when using latest pyopenvr, but that is perhaps because my use of the PyOpenVR API has not changed in about 5 years -- I am not using any newer APIs. I am happy to test Mac pyopenvr releases. Thanks!