Skip to content
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

Crashes when requested OpenGL context cannot be created #2155

Closed
hoechenberger opened this issue Feb 7, 2022 · 21 comments · Fixed by #2250
Closed

Crashes when requested OpenGL context cannot be created #2155

hoechenberger opened this issue Feb 7, 2022 · 21 comments · Fixed by #2250
Labels
bug Uh-oh! Something isn't working as expected.

Comments

@hoechenberger
Copy link

hoechenberger commented Feb 7, 2022

Hello!

On a system with limited OpenGL support (specifically, in an X2go session without OpenGL core and ES3 profiles), PyVista (VTK?) doesn't gracefully handle this lack of advanced technologies and crashes.

To Reproduce

On a Linux system with the following glxinfo |grep OpenGL output:

OpenGL vendor string: Mesa/X.org
OpenGL renderer string: llvmpipe (LLVM 12.0.0, 256 bits)
OpenGL version string: 3.1 Mesa 21.0.3
OpenGL shading language version string: 1.40
OpenGL context flags: (none)
OpenGL extensions:

(core and ES profiles missing), the following code snippets:

from pyvista import GPUInfo
GPUInfo()
from pyvista.utilities import check_depth_peeling
check_depth_peeling()

both result in:

2022-02-07 14:49:00.635 (  15.831s) [        E0112740]vtkXOpenGLRenderWindow.:266    ERR| vtkXOpenGLRenderWindow (0x55935b917270): Could not find a decent config

ERROR:root:Could not find a decent config
2022-02-07 14:49:00.636 (  15.832s) [        E0112740]vtkXOpenGLRenderWindow.:484    ERR| vtkXOpenGLRenderWindow (0x55935b917270): Could not find a decent visual

ERROR:root:Could not find a decent visual
[1]    2925781 abort (core dumped)

According to the docs, depth peeling requires ES3, which isn't supported on this system.

I can reproduce this crash on the VTK level alone:

import vtk
w = vtk.vtkRenderWindow()
w.Render()

Expected behavior would be for things not to crash.


System Information:

# Get system info
import pyvista as pv
print(pv.Report())

Unfortunately, running this code leads to the same crash as reported above.

I'm using pyvista 0.7 with vtk 9.1.0 from conda-forge (their qt build variant; see recipe)

I verified that the installation itself is working in principle by running the above commands via X11 forwarding through SSH (ssh -X), and everything works as expected.

It should also be noted that rather complex 3D visualizations can be produced (tested with MNE-Python's Coregistration UI, which generates an interactive skull surface with numerous overlays) as long as I don't try to enable depth peeling (probably requesting other "advanced" features would produce the same issues; I'm just reporting here what I experienced so far :))

Any advice would be greatly appreciated!

Thanks,
Richard

cc @GuillaumeFavelier @larsoner @agramfort

@hoechenberger hoechenberger added the bug Uh-oh! Something isn't working as expected. label Feb 7, 2022
@github-actions
Copy link
Contributor

github-actions bot commented Feb 7, 2022

Hi and welcome! Thanks for posting your first issue in the PyVista project! Someone from @pyvista/developers will chime in before too long. If your question is support related, we may transfer it to the Discussions.

@banesullivan
Copy link
Member

Can you run the following? Using gpu=False is a safe-mode of sorts

import pyvista as pv
print(pv.Report(gpu=False))

@banesullivan
Copy link
Member

My initial impression with this is that you need the osmesa variant of the VTK build for your system - though this is mostly a drive-by comment without looking too much into this.

We also provide some osmesa wheels here: https://github.com/pyvista/pyvista-wheels/tree/main/osmesa and https://wheels.pyvista.org/osmesa/ for you to try, though they may be missing some of the qt modules

@banesullivan
Copy link
Member

I'd recommend sticking with conda and trying their osmesa variant to see if that solves this initial issue with PyVista

@hoechenberger
Copy link
Author

Hello @banesullivan, thanks for your comments!

Can you run the following? Using gpu=False is a safe-mode of sorts

import pyvista as pv
print(pv.Report(gpu=False))
--------------------------------------------------------------------------------
  Date: Mon Feb 07 18:24:09 2022 CET

                OS : Linux
            CPU(s) : 64
           Machine : x86_64
      Architecture : 64bit
               RAM : 93.0 GiB
       Environment : IPython
       File system : ext4
       GPU Details : None

  Python 3.9.10 | packaged by conda-forge | (main, Feb  1 2022, 21:24:11)
  [GCC 9.4.0]

           pyvista : 0.33.2
               vtk : 9.1.0
             numpy : 1.22.2
           imageio : 2.14.1
           appdirs : 1.4.4
            scooby : 0.5.11
        matplotlib : 3.5.1
         pyvistaqt : 0.7.0
             PyQt5 : 5.12.3
           IPython : 7.31.1
        ipyvtklink : 0.2.2
             scipy : 1.8.0
              tqdm : 4.62.3
--------------------------------------------------------------------------------

I'd recommend sticking with conda and trying their osmesa variant to see if that solves this initial issue with PyVista

Oh, yes, I'd tried that but forgot to mention. With the osmesa build, things don't crash anymore (but the MNE-Python visualizations don't show up – empty render window. Which, I suppose, is a bug in MNE-Python)

My main concern was that I'm getting a segfault if certain OpenGL features are not available. (In my case, lack of ES3)

@banesullivan
Copy link
Member

My main concern was that I'm getting a segfault if certain OpenGL features are not available. (In my case, lack of ES3)

Concerning indeed. The gracefulness of that error handling is up to VTK directly in my opinion... though if someone has a the know-how to write a GL check method in PyVista, I'd support it 100% - its just a tough thing to robustly handle.

With the osmesa build, things don't crash anymore (but the MNE-Python visualizations don't show up – empty render window. Which, I suppose, is a bug in MNE-Python

Hm, I wonder if that's because some qt module is missing in the osmesa conda-forge build variant?

@banesullivan
Copy link
Member

I'm curious. If you spin up a vanilla Python virtual environment and install PyVista and VTK from pip, can you perform plotting in PyVista?

@hoechenberger
Copy link
Author

I'm curious. If you spin up a vanilla Python virtual environment and install PyVista and VTK from pip, can you perform plotting in PyVista?

Do you mean with or without OSMesa?

@GuillaumeFavelier
Copy link
Contributor

though if someone has a the know-how to write a GL check method in PyVista

I did try to import the vtkOpenGLExtensionManager from vtk but all I got was:

Python 3.8.12 (default, Oct 12 2021, 13:49:34) 
[GCC 7.5.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from vtk import vtkOpenGLExtensionManager
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: cannot import name 'vtkOpenGLExtensionManager' from 'vtkmodules.all' (/home/guillaume/source/anaconda3/envs/mne-py38/lib/python3.8/site-packages/vtkmodules/all.py)

on my system:

❯ python -c "import pyvista; print(pyvista.Report())"

--------------------------------------------------------------------------------
  Date: Wed Feb 09 15:46:46 2022 CET

                OS : Linux
            CPU(s) : 4
           Machine : x86_64
      Architecture : 64bit
               RAM : 7.7 GiB
       Environment : Python
       File system : ext4
        GPU Vendor : NVIDIA Corporation
      GPU Renderer : NVIDIA GeForce GTX 960M/PCIe/SSE2
       GPU Version : 4.5.0 NVIDIA 495.46

  Python 3.8.12 (default, Oct 12 2021, 13:49:34)  [GCC 7.5.0]

           pyvista : 0.34.dev0
               vtk : 9.1.0
             numpy : 1.22.0
           imageio : 2.13.5
           appdirs : 1.4.4
            scooby : 0.5.11
        matplotlib : 3.5.1
         pyvistaqt : 0.8.dev0
             PyQt5 : 5.15.6
           IPython : 8.0.1
        ipyvtklink : 0.2.2
             scipy : 1.7.1
              tqdm : 4.46.1
            meshio : 4.4.6
--------------------------------------------------------------------------------

But I tried with @hoechenberger and it's possible to check for a specific extension with PyOpenGL:

from OpenGL.GL import (glGetIntegerv, glGetStringi, GL_NUM_EXTENSIONS,
                       GL_EXTENSIONS)
from OpenGL.GLUT import glutInit, glutCreateWindow

glutInit()
wind = glutCreateWindow("Check OpenGL ES3")

num_extensions = glGetIntegerv(GL_NUM_EXTENSIONS, 0)
extensions = list()
for i in range(num_extensions.value):
    current_ext = glGetStringi(GL_EXTENSIONS, i)
    extensions.append(current_ext.decode("utf-8"))
extensions = [ext for ext in extensions if '_ES3' in ext]  # <--- parse ES3 here
print(extensions)  # return the list of supported OPENGL_ES3 extensions

https://gist.github.com/GuillaumeFavelier/06dcae8677bb66181714d1285fbe8e61

@akaszynski
Copy link
Member

AFAIK vtkOpenGLExtensionManager has been removed; vtkOpenGLExtensionManager.h no longer exists in the repo.

@GuillaumeFavelier
Copy link
Contributor

AFAIK vtkOpenGLExtensionManager has been removed

Thank you for the explanation! But ouch 😅 Do you know any alternative then?

@akaszynski
Copy link
Member

Afraid not, but you might try https://vtk.org/doc/nightly/html/classvtkOpenGLFramebufferObject.html#details.

@GuillaumeFavelier
Copy link
Contributor

GuillaumeFavelier commented Feb 9, 2022

What I found in vtkOpenGLRenderWindow.cxx in the function ReportCapabilities() is strangely similar to the gist 😄

const char* vtkOpenGLRenderWindow::ReportCapabilities()
{
  this->MakeCurrent();

  const char* glVendor = (const char*)glGetString(GL_VENDOR);
  const char* glRenderer = (const char*)glGetString(GL_RENDERER);
  const char* glVersion = (const char*)glGetString(GL_VERSION);

  std::ostringstream strm;
  if (glVendor)
  {
    strm << "OpenGL vendor string:  " << glVendor << endl;
  }
  if (glRenderer)
  {
    strm << "OpenGL renderer string:  " << glRenderer << endl;
  }
  if (glVersion)
  {
    strm << "OpenGL version string:  " << glVersion << endl;
  }

  strm << "OpenGL extensions:  " << endl;
  GLint n, i;
  glGetIntegerv(GL_NUM_EXTENSIONS, &n);
  for (i = 0; i < n; i++)
  {
    const char* ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
    strm << "  " << ext << endl;
  }

  delete[] this->Capabilities;

https://github.com/Kitware/VTK/blob/master/Rendering/OpenGL2/vtkOpenGLRenderWindow.cxx#L261-L293

So I made another gist:

import vtk as _vtk

renderWindow = _vtk.vtkRenderWindow()
renderWindow.SetOffScreenRendering(True)
renderWindow.Render()

extension_name = "_ES3"

if renderWindow.SupportsOpenGL():
    caps = renderWindow.ReportCapabilities()
    caps = caps.split('\n')
else:
    caps = ""

ext_supported = [ext for ext in caps if extension_name in ext]
print(ext_supported)

https://gist.github.com/GuillaumeFavelier/02d7a51ef6aba3cae449bd33777d2c1d

This is what I have on my system:

['  GL_ARB_ES3_compatibility', '  GL_ARB_ES3_1_compatibility', '  GL_ARB_ES3_2_compatibility', '  GL_NV_ES3_1_compatibility']

Feel free to try it @hoechenberger

@hoechenberger
Copy link
Author

hoechenberger commented Feb 10, 2022

@GuillaumeFavelier Unfortunately, this produces the same error as soon as Render is called
(using conda-forge's qt build of VTK (i.e., no OSMesa support)

@larsoner
Copy link
Contributor

This segfault-on-sys-info has been irking me for a while -- I think it's worth digging into a bit. @hoechenberger can you try this gist on the system that fails:

https://gist.github.com/larsoner/05f13182d26b70ceb6c2df739cbb3edd

I adapted it from CreateAWindow and GetDesiredVisualInfo from VTK. On my system I can trigger the "Usable" path by default (because my OpenGL config is good) and the "No display" path by passing an invalid DISPLAY=:99 python vtktest.py, but I can't think of an easy way to make my OpenGL version look insufficient. Hence why I'm hoping you can try @hoechenberger ...

If this works, I think it's worth implementing a cleaner variant as we have seen multiple users in MNE-Python complain about this segfault. It's not perfect, and it's not complete (e.g., doesn't triage based on stereo or stencil etc.), but hopefully some version of it would have caught @hoechenberger's segfault at least. It's not great that any sys_info-type call could segfault, so the fewer of those we can have, the better...

@hoechenberger
Copy link
Author

hoechenberger commented Feb 10, 2022

@larsoner Thanks for looking into this, I can try out your script tomorrow CET and report back

FWIW @GuillaumeFavelier and I had a look at this together again this Paris afternoon, and it appears that it might have something to do with the presence of an interactor (or, rather, the lack thereof). While a MWE with … basically every fancy OpenGL feature disabled still provokes the crash, even a complex scene like MNE's plot_alignment() does render – and it appeared to us that this is related to the fact that it's using pyvistaqt's BackgroundPlotter, which does some interactor magic (???) – I'm no expert on this stuff, maybe @GuillaumeFavelier can correct me if my summary's flawed 😅

@GuillaumeFavelier
Copy link
Contributor

Indeed, as of now, I still have no clue why the MWE with pyvistaqt works when the exact same with pyvista (or even vtk) doesn't.

@hoechenberger
Copy link
Author

hoechenberger commented Feb 16, 2022

@larsoner

This segfault-on-sys-info has been irking me for a while -- I think it's worth digging into a bit. @hoechenberger can you try this gist on the system that fails:

https://gist.github.com/larsoner/05f13182d26b70ceb6c2df739cbb3edd

Actually I get an … interesting error message:

Traceback (most recent call last):
  File "/home/rh265054/eric.py", line 33, in <module>
    glx = CDLL('libGL.so')
  File "/neurospin/meg/mne-python/dev/lib/python3.9/ctypes/__init__.py", line 374, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: libGL.so: cannot open shared object file: No such file or directory
(   3.406s) [main thread     ]             loguru.cpp:485      1| atexit

both when using X2go and when connecting via ssh -X

@larsoner
Copy link
Contributor

Can you try changing it to libGL.so.1 to see if it helps?

@hoechenberger
Copy link
Author

Can you try changing it to libGL.so.1 to see if it helps?

Right, this library does indeed exist! Getting a nice new message now… 😅

Loguru caught a signal: SIGSEGV
Stack trace:
19      0x557124457fb1 python(+0x218fb1) [0x557124457fb1]
18      0x7f951f97a0b3 __libc_start_main + 243
17      0x5571244df9d9 Py_BytesMain + 57
16      0x5571244df88c Py_RunMain + 908
15      0x5571244df1c2 PyRun_SimpleFileExFlags + 434
14      0x55712435567d python(+0x11667d) [0x55712435567d]
13      0x5571244d8524 python(+0x299524) [0x5571244d8524]
12      0x55712449d029 python(+0x25e029) [0x55712449d029]
11      0x55712446af2b PyEval_EvalCode + 27
10      0x55712446af09 PyEval_EvalCodeEx + 57
9       0x55712446aec7 _PyEval_EvalCodeWithName + 71
8       0x55712437fcf0 python(+0x140cf0) [0x55712437fcf0]
7       0x557124430306 _PyEval_EvalFrameDefault + 21222
6       0x5571243b3260 _PyObject_MakeTpCall + 704
5       0x7f951f3b6454 /neurospin/meg/mne-python/dev/lib/python3.9/lib-dynload/_ctypes.cpython-39-x86_64-linux-gnu.so(+0x14454) [0x7f951f3b6454]
4       0x7f951f3b5dc7 /neurospin/meg/mne-python/dev/lib/python3.9/lib-dynload/_ctypes.cpython-39-x86_64-linux-gnu.so(+0x13dc7) [0x7f951f3b5dc7]
3       0x7f951f39bfea /neurospin/meg/mne-python/dev/lib/python3.9/lib-dynload/../../libffi.so.8(+0x5fea) [0x7f951f39bfea]
2       0x7f951f39ca4a /neurospin/meg/mne-python/dev/lib/python3.9/lib-dynload/../../libffi.so.8(+0x6a4a) [0x7f951f39ca4a]
1       0x7f951a746840 XDefaultScreen + 0
0       0x7f951fcbf3c0 /lib/x86_64-linux-gnu/libpthread.so.0(+0x153c0) [0x7f951fcbf3c0]
(   0.934s) [main thread     ]                       :0     FATL| Signal: SIGSEGV
[1]    908656 segmentation fault (core dumped)  python eric.py

@ddrous
Copy link

ddrous commented Jun 11, 2023

I suggest this StackOverflow answer for anyone still facing this issue. It worked like a charm for me: https://stackoverflow.com/a/71421355/8140182

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Uh-oh! Something isn't working as expected.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants