dockerjavafxdriver

Running JavaFX app inside Docker container: failed to load driver: iris


I am struggling with making an old JavaFX (+ JFoenix) school project work inside a Docker container. I made a multi-project Gradle build config (commons, server and client) that runs well with Java 21 directly on my computer (Manjaro 6.6.32 64-bits / Wayland / Intel Core 11th Gen i3-1115G4 x4), but not with the following Dockerfile for the client app :

FROM gradle:8-jdk21-alpine AS builder
WORKDIR /home/gradle
COPY --chown=gradle:gradle . .
RUN gradle build

FROM eclipse-temurin:21-jre-alpine
WORKDIR /usr/app
COPY --from=builder /home/gradle/client/build/distributions/client.tar .
RUN tar -xf client.tar
ENTRYPOINT ["./client/bin/client"]

With the command docker build -t jfxclient . && docker run --rm -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix:ro jfxclient.

I have already solved some issues by adding the following line in the last stage :

RUN apk add --no-cache libx11 libxxf86vm mesa-gl mesa-dri-gallium

And running sudo xhost +local:docker before to start the container.

Now, I am facing the following error at startup, and I have not been able to solve it:

MESA: error: Failed to query drm device.
glx: failed to create dri3 screen
failed to load driver: iris
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x0000000000003fe6, pid=7, tid=34
#
# JRE version: OpenJDK Runtime Environment Temurin-21.0.3+9 (21.0.3+9) (build 21.0.3+9-LTS)
# Java VM: OpenJDK 64-Bit Server VM Temurin-21.0.3+9 (21.0.3+9-LTS, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, linux-amd64)
# Problematic frame:
# C  [libprism_es2.so+0x8a1a]  Java_com_sun_prism_es2_X11GLFactory_nInitialize+0x1fa
#
# Core dump will be written. Default location: Core dumps may be processed with "/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h" (or dumping to /usr/app/core.7)
#
# An error report file with more information is saved as:
# /usr/app/hs_err_pid7.log
#
# If you would like to submit a bug report, please visit:
#   https://github.com/adoptium/adoptium-support/issues
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Aborted (core dumped)

Changing the entrypoint to ENTRYPOINT ["/bin/sh"], I obtained the file /usr/app/hs_err_pid7.log, but it is pretty long, 1181 lines. Here are what I consider to be the most interesting parts:

Stack: [0x00007fad00684000,0x00007fad00784a90],  sp=0x00007fad00783600,  free space=1021k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [libprism_es2.so+0x8a1a]  Java_com_sun_prism_es2_X11GLFactory_nInitialize+0x1fa
j  com.sun.prism.es2.X11GLFactory.nInitialize([I)J+0 javafx.graphics@21.0.3
j  com.sun.prism.es2.X11GLFactory.initialize(Ljava/lang/Class;Lcom/sun/prism/es2/GLPixelFormat$Attributes;)Z+73 javafx.graphics@21.0.3
j  com.sun.prism.es2.ES2Pipeline.<clinit>()V+52 javafx.graphics@21.0.3
v  ~StubRoutines::call_stub 0x00007fad53a64cc6
V  [libjvm.so+0x912765]  JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, JavaThread*)+0x2e5
V  [libjvm.so+0x8ea08d]  InstanceKlass::call_class_initializer(JavaThread*)+0x2ed
V  [libjvm.so+0x8eb173]  InstanceKlass::initialize_impl(JavaThread*)+0x6f3
V  [libjvm.so+0x9f105d]  find_class_from_class_loader(JNIEnv_*, Symbol*, unsigned char, Handle, Handle, unsigned char, JavaThread*)+0x7d
V  [libjvm.so+0x9f9d40]  JVM_FindClassFromCaller+0x110
C  [libjava.so+0xe4d7]  Java_java_lang_Class_forName0+0xd7
j  java.lang.Class.forName0(Ljava/lang/String;ZLjava/lang/ClassLoader;Ljava/lang/Class;)Ljava/lang/Class;+0 java.base@21.0.3
j  java.lang.Class.forName(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;+19 java.base@21.0.3
j  java.lang.Class.forName(Ljava/lang/String;)Ljava/lang/Class;+6 java.base@21.0.3
j  com.sun.prism.GraphicsPipeline.createPipeline()Lcom/sun/prism/GraphicsPipeline;+183 javafx.graphics@21.0.3
j  com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init()V+0 javafx.graphics@21.0.3
j  com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run()V+1 javafx.graphics@21.0.3
j  java.lang.Thread.runWith(Ljava/lang/Object;Ljava/lang/Runnable;)V+5 java.base@21.0.3
j  java.lang.Thread.run()V+19 java.base@21.0.3
v  ~StubRoutines::call_stub 0x00007fad53a64cc6
V  [libjvm.so+0x912765]  JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, JavaThread*)+0x2e5
V  [libjvm.so+0x9140ab]  JavaCalls::call_virtual(JavaValue*, Handle, Klass*, Symbol*, Symbol*, JavaThread*)+0x1cb
V  [libjvm.so+0x9ee64a]  thread_entry(JavaThread*, JavaThread*)+0x8a
V  [libjvm.so+0x928ccf]  JavaThread::thread_main_inner() [clone .part.0]+0xaf
V  [libjvm.so+0xf82c98]  Thread::call_run()+0xa8
V  [libjvm.so+0xd0b23a]  thread_native_entry(Thread*)+0x12a
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  com.sun.prism.es2.X11GLFactory.nInitialize([I)J+0 javafx.graphics@21.0.3
j  com.sun.prism.es2.X11GLFactory.initialize(Ljava/lang/Class;Lcom/sun/prism/es2/GLPixelFormat$Attributes;)Z+73 javafx.graphics@21.0.3
j  com.sun.prism.es2.ES2Pipeline.<clinit>()V+52 javafx.graphics@21.0.3
v  ~StubRoutines::call_stub 0x00007fad53a64cc6
j  java.lang.Class.forName0(Ljava/lang/String;ZLjava/lang/ClassLoader;Ljava/lang/Class;)Ljava/lang/Class;+0 java.base@21.0.3
j  java.lang.Class.forName(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;+19 java.base@21.0.3
j  java.lang.Class.forName(Ljava/lang/String;)Ljava/lang/Class;+6 java.base@21.0.3
j  com.sun.prism.GraphicsPipeline.createPipeline()Lcom/sun/prism/GraphicsPipeline;+183 javafx.graphics@21.0.3
j  com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init()V+0 javafx.graphics@21.0.3
j  com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run()V+1 javafx.graphics@21.0.3
j  java.lang.Thread.runWith(Ljava/lang/Object;Ljava/lang/Runnable;)V+5 java.base@21.0.3
j  java.lang.Thread.run()V+19 java.base@21.0.3
v  ~StubRoutines::call_stub 0x00007fad53a64cc6
Internal exceptions (7 events):
Event: 0.098 Thread 0x00007fad616eb890 Implicit null exception at 0x00007fad540049e3 to 0x00007fad54004b40
Event: 0.100 Thread 0x00007fad616eb890 Exception <a 'java/lang/NoSuchMethodError'{0x000000008f2e7dc8}: 'void java.lang.invoke.DirectMethodHandle$Holder.invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object)'> (0x000000008f2e7dc8) 
thrown [src/hotspot/share/interpreter/linkResolver.cpp, line 772]
[...]
VM Arguments:
jvm_args: --module-path=/usr/app/client/lib/client.jar:/usr/app/client/lib/commun.jar:/usr/app/client/lib/jfoenix-9.0.10.jar:/usr/app/client/lib/javafx-fxml-21.0.3-linux.jar:/usr/app/client/lib/javafx-controls-21.0.3-linux.jar:/usr/app/client/lib/javafx-graphics-21.0.3-linux.jar:/usr/app/client/lib/javafx-base-21.0.3-linux.jar -Djdk.module.main=application.client 
java_command: application.client/application.client.Main
java_class_path (initial): \"\"
Launcher Type: SUN_STANDARD
Logging:
Log output configuration:
 #0: stdout all=warning uptime,level,tags foldmultilines=false
 #1: stderr all=off uptime,level,tags foldmultilines=false

Environment Variables:
JAVA_HOME=/opt/java/openjdk
PATH=/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LD_LIBRARY_PATH=/opt/java/openjdk/lib/server:/opt/java/openjdk/lib:/opt/java/openjdk/../lib
DISPLAY=:0
LANG=en_US.UTF-8
LC_ALL=en_US.UTF-8
TERM=xterm

I have installed mesa-demos package and been successful to run glxgears inside the container. It still prints the following message though:

MESA: error: Failed to query drm device.
glx: failed to create dri3 screen
failed to load driver: iris

Here is some info provided by glxinfo:

name of display: :0
MESA: error: Failed to query drm device.
glx: failed to create dri3 screen
failed to load driver: iris
display: :0  screen: 0
direct rendering: Yes
server glx vendor string: SGI
server glx version string: 1.4

OpenGL vendor string: Mesa
OpenGL renderer string: llvmpipe (LLVM 17.0.5, 256 bits)
OpenGL core profile version string: 4.5 (Core Profile) Mesa 23.3.6
OpenGL core profile shading language version string: 4.50

eglinfo has more info:

GBM platform:
eglinfo: eglInitialize failed

Wayland platform:
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
eglinfo: eglInitialize failed

X11 platform:
MESA: error: Failed to query drm device.
libEGL warning: egl: failed to create dri2 screen
MESA: error: ZINK: vkCreateInstance failed (VK_ERROR_INCOMPATIBLE_DRIVER)
libEGL warning: egl: failed to create dri2 screen
EGL API version: 1.5
EGL vendor string: Mesa Project
EGL version string: 1.5
EGL client APIs: OpenGL OpenGL_ES 
EGL driver name: swrast

I have tried many suggestions found on SO or elsewhere, but none did work so far.

I am now completely lost here. Any help would be greatly appreciated!


Solution

  • I resumed it just today and I got it.

    From within the container with entrypoint /bin/sh, I modified the client/bin/client shell script to add the -Dprism.order=sw -Dprism.verbose=true options in DEFAULT_JVM_OPTS="", as recommended by user jewelsea. (Actually, I could have just executed export JAVA_OPTS="-Dprism.order=sw" before running the script to achieve the same result, so that's what I have done after.)

    The first line when running the script changed from Prism pipeline init order: es2 sw to [...]: sw.

    A new error log told me about ld-linux-x86-64.so.2: No such file or directory and java.lang.UnsatisfiedLinkError: no glassgtk3 in java.library.path. I have also installed libc6-compat to fix it.

    Then, finally, the app launched successfully. So far so good! Thanks to @jewelsea for the tip to finish this.

    Final Dockerfile, run command and Docker Compose

    FROM gradle:8-jdk21-alpine AS builder
    WORKDIR /home/gradle
    COPY --chown=gradle:gradle . .
    RUN gradle build
    
    FROM eclipse-temurin:21-jre-alpine AS client
    WORKDIR /usr/app
    RUN apk upgrade --no-cache && apk add --no-cache gtk+3.0 libc6-compat libcanberra-gtk3
    # no more mesa packages required with sw, but I added libcanberra to fix a warning
    COPY --from=builder /home/gradle/client/build/distributions/client.tar .
    RUN tar -xf client.tar
    ENV JAVA_OPTS="-Dprism.order=sw"
    ENTRYPOINT ["./client/bin/client"]
    
    sudo xhost +local:docker
    # Reverse command: sudo xhost -local:docker
    docker build -t client . && docker run -it --rm -e DISPLAY=$DISPLAY -e NO_AT_BRIDGE=1 -v /tmp/.X11-unix:/tmp/.X11-unix:ro --net=host --name client client
    # $DISPLAY contains `:0`
    
    services:
      client:
        build:
          target: client
        environment:
          DISPLAY: $DISPLAY
          NO_AT_BRIDGE: 1  # to ignore some warnings raised by GTK
        network_mode: host
        ports: []
        volumes:
          - /tmp/.X11-unix:/tmp/.X11-unix:ro
    

    Other clues I found while doing research, but that did not fixed anything or not even tried: