using VTK from within a Docker container on OS X (Intel & ARM)

Hello,

I have a relatively complex use-case that I will try to describe as best as I can. We (my company) uses Docker for our development. We would like to add visualization capabilities to this code using e.g. pyvista, and we would like it to be multiplatform. Our users are data scientists and engineers who may be either on an ARM or an Intel Mac, so we would like to support both architectures. And we’re using Python so of course we’ll need the Python bindings.

I’m attempting to solve this problem by building VTK from source within the image with -DVTK_WRAP_PYTHON=ON. On the host machine (an M1 Mac), I am running XQuartz, and I have set up X redirection between the Docker image and the host so that if I e.g. run xclock I can see the clock on the host. I can also run glxgears and see the gears. The build succeeds and I am able to import vtk and use it without any problems, until I actually try to display something, at which point everything crashes. Here’s an example, using the following pyvista code:

import pyvista as pv
import numpy as np


def get_fresh_plotter():
    plotter = pv.Plotter()
    xyz_arr = np.random.rand(30000).reshape(10000, 3)
    wire_cloud = pv.PolyData(xyz_arr)
    plotter.add_mesh(wire_cloud, opacity=0.5, color=(1.0, 0.5, 0.5))

    xyz_arr = np.random.rand(30000).reshape(10000, 3)
    xyz_arr[:, 0] += 3.0
    wire_cloud = pv.PolyData(xyz_arr)
    plotter.add_mesh(wire_cloud, opacity=0.5, color=(0.5, 0.5, 1.0))

    return plotter

get_fresh_plotter().show(interactive=False, screenshot="pyvista_out_1.jpg")
get_fresh_plotter().show(interactive=True, screenshot="pyvista_out_2.jpg")

And here’s the error that results:

 libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
2022-09-16 19:22:31.396 (   0.185s) [        80D80D30]vtkOpenGLRenderWindow.c:517    ERR| vtkXOpenGLRenderWindow (0xaaaad4f91020): Unable to find a valid OpenGL 3.2 or later implementation. Please update your video card driver to the latest version. If you are using Mesa please make sure you have version 11.2 or later and make sure your driver in Mesa supports OpenGL 3.2 such as llvmpipe or openswr. If you are on windows and using Microsoft remote desktop note that it only supports OpenGL 3.2 with nvidia quadro cards. You can use other remoting software such as nomachine to avoid this issue.
ERROR:root:Unable to find a valid OpenGL 3.2 or later implementation. Please update your video card driver to the latest version. If you are using Mesa please make sure you have version 11.2 or later and make sure your driver in Mesa supports OpenGL 3.2 such as llvmpipe or openswr. If you are on windows and using Microsoft remote desktop note that it only supports OpenGL 3.2 with nvidia quadro cards. You can use other remoting software such as nomachine to avoid this issue.
2022-09-16 19:22:31.398 (   0.187s) [        80D80D30]     vtkOpenGLState.cxx:83    WARN| Error in cache state for GL_BLEND
2022-09-16 19:22:31.399 (   0.188s) [        80D80D30]     vtkOpenGLState.cxx:90    WARN| Error in cache state for GL_DEPTH_TEST
2022-09-16 19:22:31.400 (   0.189s) [        80D80D30]     vtkOpenGLState.cxx:105   WARN| Error in cache state for GL_MULTISAMPLE
2022-09-16 19:22:31.401 (   0.190s) [        80D80D30]     vtkOpenGLState.cxx:113   WARN| Error in cache state for GL_SCISSOR_TEST
2022-09-16 19:22:31.402 (   0.192s) [        80D80D30]     vtkOpenGLState.cxx:144   WARN| Error in cache state for GL_VIEWPORT
2022-09-16 19:22:31.403 (   0.192s) [        80D80D30]     vtkOpenGLState.cxx:152   WARN| Error in cache state for GL_SCISSOR_BOX
2022-09-16 19:22:31.404 (   0.194s) [        80D80D30]     vtkOpenGLState.cxx:173   WARN| Error in cache state for GL_DEPTH_FUNC
2022-09-16 19:22:31.405 (   0.194s) [        80D80D30]     vtkOpenGLState.cxx:180   WARN| Error in cache state for GL_BLEND_SRC_RGB
2022-09-16 19:22:31.409 (   0.198s) [        80D80D30]     vtkOpenGLState.cxx:274   WARN| at stack loc
0xffff72e21314 : ??? [(???) ???:-1]
0xffff72e21c64 : vtksys::SystemInformation::GetProgramStack[abi:cxx11](int, int) [(libvtksys-9.2.so.1) ???:-1]

glxinfo shows the following:

libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
OpenGL vendor string: Apple
OpenGL renderer string: Apple M1 Pro
OpenGL version string: 1.4 (2.1 Metal - 76.3)
OpenGL extensions:

At this point I’m quite lost. Perhaps what I’m trying to do is impossible, or perhaps I’m building VTK with the wrong options, but if anyone has gotten such a case to work or has any suggestions for what I should try, I’d love to hear it. What I’m after ultimately is for our data science users to be able to create interactive visualizations without leaving the Docker container. Thanks in advance for any help.

My understanding is that this is a limitation of XQuartz. So the options would be 1) downgrade to VTK 7 or 8 and use the old VTK OpenGL backend, 2) force software-only rendering in your docker container, or 3) deploy a python environment with a VTK macOS wheel instead of instead of containerized app.

Thanks for the suggestions. I think option 2 probably makes the most sense right now, even if it’s not the most performant. Do you know how to force VTK to render in software?

Actually option 2 might not work. The usual way to force software rendering on Linux is to set environment variables to control the driver:

export __GLX_VENDOR_LIBRARY_NAME=mesa
export LIBGL_ALWAYS_SOFTWARE=1
glxinfo | grep OpenGL

OpenGL vendor string: Mesa/X.org
OpenGL renderer string: llvmpipe (LLVM 12.0.0, 256 bits)
OpenGL core profile version string: 4.5 (Core Profile) Mesa 21.2.6
OpenGL core profile shading language version string: 4.50

But this only works if the X server and X client are both running on Linux. In your situation, the X server is XQuartz and it’s running on the Mac, so you’re stuck with the OpenGL profile that is provided by XQuartz.

This suggests that you need a libGL that does all GL rendering on the client rather than on the server. As far as I understand, this is an option if you build Mesa from source, but you’d have to search around for a good recipe for configuring the build to achieve this.

Yes, it seems that you were right. I played around with this today and I actually did get this to work. I did it by building Mesa from source, and then building VTK against the resulting Mesa libraries. Here’s the configuration I used, in case this is useful to anyone else:

meson                          \
  ../mesa-21.3.1               \
  --buildtype=release          \
  --prefix=/usr/local    \
  -Dvulkan-drivers=            \
  -Ddri-drivers=               \
  -Dgallium-vdpau=disabled     \
  -Dgallium-xvmc=disabled      \
  -Dgallium-omx=disabled       \
  -Dgallium-va=disabled        \
  -Dgallium-xa=disabled        \
  -Dgallium-nine=false         \
  -Dgallium-opencl=disabled    \
  -Dbuild-tests=false          \
  -Degl=disabled               \
  -Dgbm=disabled               \
  -Dglx=gallium-xlib               \
  -Dplatforms=x11                 \
  -Dglvnd=false                \
  -Dosmesa=true                \
  -Dopengl=true                \
  -Dgles1=disabled             \
  -Dgles2=disabled             \
  -Dshared-glapi=enabled       \
  -Dllvm=enabled               \
  -Dshared-llvm=enabled        \
  -Dgallium-drivers=swrast

ninja
ninja install

and then for VTK

cmake  --install-prefix /usr/local -B ./build -S ./ \
    -DVTK_WRAP_PYTHON=ON \
    -DVTK_USE_X=ON \
    -DOPENGL_INCLUDE_DIR=/usr/local/include/GL \
    -DOPEN_gl_LIBRARY=/usr/local/lib/aarch64-linux-gnu/libGL.so \
    -DOPENGL_opengl_LIBRARY=/usr/local/lib/aarch64-linux-gnu/libGL.so

This worked for me on an M1 Mac. I suspect the OpenGL config options for VTK here are superfluous as I would expect CMake to find the libraries automatically but I just haven’t tried it yet and this is just the most recent command in my history that worked. After that you have to setup the X connection between the Docker container and the host, but once I did that I was able to show two cube-shaped point clouds in a window using the pyvista code in the OP.

You could also have been missing the mesa-dri-drivers package (or whatever Debian calls it) in the container.