pyvista: Crashes when requested OpenGL context cannot be created

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

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 3
  • Comments: 21 (14 by maintainers)

Most upvoted comments

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

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

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

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