Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#4130 closed enhancement (fixed)

Enable offscreen rendering on macOS

Reported by: Tom Goddard Owned by: Tom Goddard
Priority: moderate Milestone:
Component: Graphics Version:
Keywords: Cc:
Blocked By: Blocking:
Notify when closed: Platform: all
Project: ChimeraX

Description

Provide OSMesa in macOS ChimeraX builds for offscreen rendering with Python scripts.

Currently we provide the OSMesa (Offscreen Mesa) library in the Linux ChimeraX builds to allow rendering images without a window or on a headless machine without a windowing system. We compile mesa and llvm which is used by the gallium osmesa implementation I think because OSMesa is not available already compiled.

On macOS the only compiled OSMesa I could find online comes with XQuartz 2.7.11, this is the latest XQuartz from 2016. I tried that osmesa in ChimeraX and it could only provide OpenGL 2.1 and only compatibility contexts, so it is not usable since ChimeraX needs 3.3 and a core context.

I tried compiling mesa, the same version we use on Linux, version 19.0.8 from June 2019 and it failed on a missing system header declaration of timespec_get, supposedly a problem caused by using C99 instead of C11 std.

I then tried the current mesa version 20.3.2. This version uses a different build system called meson. That worked but gave the same error, but was easy to fix with a build option.

cd /mesa/src/dir
mkdir build
meson build/ -Dc_std=c11 -Dosmesa=gallium
ninja -C build/
sudo ninja -C build/ install

The resulting libOSMesa.8.dylib rendered molecule images in ChimeraX. That required editing PyOpenGL

OpenGL/platform/ctypesloader.py

to recognized the Darwin platform and hardcoding the path in loadLibrary()

elif sys.platform == 'darwin' and name == 'OSMesa':

return dllType('/usr/local/lib/libOSMesa.8.dylib', mode)

I used llvm from homebrew to compile (brew install llvm), which is here /usr/local/opt/llvm/bin/llvm-config.

The compiled libOSMesa.8.dylib unfortunately depends on other non-system libraries

otool -L /usr/local/lib/libOSMesa.8.dylib
/usr/local/lib/libOSMesa.8.dylib:

/usr/local/lib/libOSMesa.8.dylib (compatibility version 8.0.0, current version 8.0.0)
/usr/local/lib/libglapi.0.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/local/opt/llvm/lib/libLLVM-C.dylib (compatibility version 1.0.0, current version 11.0.0)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.100.1)
/usr/local/opt/zstd/lib/libzstd.1.dylib (compatibility version 1.0.0, current version 1.4.5)
/usr/local/opt/llvm/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1.0.0)

I believe on Linux our compiled version was statically linked to llvm and has no non-system dependencies like zstd here. Probably need some more build options to achieve that. The libglapi.0.dylib dependency was built by meson. Would prefer that is also statically linked. The mesa 19.0.8 build using configure / make lists the needed options I think (--disable-llvm-shared-libraries, --disable-shared-glapi)

Change History (5)

comment:1 by Tom Goddard, 5 years ago

Using the newer libOSMesa on macOS gave the following non-fatal OpenGL error using chimerax --offscreen and saving an image:

Mesa: User error: GL_INVALID_ENUM in glGetString(GL_EXTENSIONS)

The glGetString() call allows that argument in a compatibility profile but not in a core profile. PyOpenGL is using for our core profile. Could easily be patched using glGetStringi(GL_EXTENSIONS,i) which is the correct core profile call -- we use this in our graphics/opengl.py code. Or could probably ignore it since it is looking for OpenGL extensions and ChimeraX I think does not need any extensions.

comment:2 by Tom Goddard, 5 years ago

Why support offscreen on macOS? I don't think this will be used much, I think it is rarely used on linux which is the most likely operating system for server applications using ChimeraX. But I am trying to make ChimeraX work as a Python module instead of an application and it is useful to be able to test that including image saving on macOS. The libOSMesa is currently in the app lib directory which is not good for ChimeraX module use. So I'd like to move it to a Python osmesa module that PyOpenGL can be configured to use. Can develop this on Linux if macOS is too difficult for getting libOSMesa working.

The envisioned osmesa Python module might be something nice to put on PyPi so others can use PyOpenGL with offscreen rendering. Could even provide a Windows libOSMesa so PyPi builds could support Linux, Mac and Windows.

comment:3 by Tom Goddard, 5 years ago

Was able to build libOSMesa.dylib with static llvm linking using mesa 20.3.2 on macOS 10.15.7 and the following commands

$ meson build/ -Dc_std=c11 -Dosmesa=gallium -Dshared-glapi=false -Dshared-llvm=false -Dzstd=false -Dglx=disabled -Dgallium-drivers="swrast" -Ddri-drivers= -Dplatforms= >& meson.out
$ ninja -C build/ >& ninja.out
$ sudo ninja -C build/ install

This allows chimerax --offscreen to save images.

Version 0, edited 5 years ago by Tom Goddard (next)

comment:4 by Tom Goddard, 5 years ago

Resolution: fixed
Status: assignedclosed

Made new prereqs/osmesa that can install libOSmesa for Mac or Linux. Not including it in Mac distribution since the library is 9 Mbytes and will be used by almost no one. But using "make app-install" in prereqs/osmesa will install it for development work on macOS.

I switched Linux build to also use this osmesa Python module instead of putting libOSMesa in the application lib directory.

For PyOpenGL to find libOSMesa I patched it to look at environment variable OSMESA_LIB_PATH which is set by chimerax/graphics/opengl.py when setting up offscreen rendering.

comment:5 by Tom Goddard, 5 years ago

Here are notes about my attempt to use libOSMesa from XQuartz 2.7.11:

I tried offscreen rendering on macOS 10.15 using /opt/X11/lib/libOSMesa.dylib provided by XQuartz 2.7.11 (2016, most recent). First I needed to edit PyOpenGL to find the library

ChimeraX.app/Contents/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/OpenGL/platform/ctypesloader.py

in routine loadLibrary() add

elif sys.platform == 'darwin':

filename = '/opt/X11/lib/libOSMesa.dylib'
return dllType(filename, mode)

Running ChimeraX with --offscreen then gives message "OSMesa needs to be configured with --enable-gallium-osmesa for OpenGL Core Context support.". This error message really just means OSMesa could not provide the requested context. Changing the requested attributes in graphics/opengl.py OffScreenRenderingContext.init() to not request version 3.3 and not request core profile as follows

attribs = [

osmesa.OSMESA_FORMAT, osmesa.OSMESA_RGBA,
osmesa.OSMESA_DEPTH_BITS, 32,
# osmesa.OSMESA_STENCIL_BITS, 8,

# osmesa.OSMESA_PROFILE, osmesa.OSMESA_CORE_PROFILE,
# osmesa.OSMESA_PROFILE,
# osmesa.OSMESA_CONTEXT_MAJOR_VERSION, 3,
# osmesa.OSMESA_CONTEXT_MINOR_VERSION, 3,

0 # must end with zero

]

it gets a context but it is version OpenGL 2.1 and ChimeraX needs 3.3. Asking for major version 3 returns None for he contet. Asking for core context with no version also returns None.

So it appears the XQuartz 2.7.11 version of libOSMesa.dylib can only provide legacy contexts and only version 2.1.

Note: See TracTickets for help on using tickets.