Hello Guest

[SOLVED] JVM macOS issue

  • 3 Replies
  • 8486 Views
[SOLVED] JVM macOS issue
« on: March 03, 2020, 15:33:53 »
So I'm trying to develop a LWJGL application in Scala and build it with sbt. The challenge I'm facing is that my skeleton project seems to work on Linux, but not on macOS (crashes with a JVM fatal error).

The only difference between the Linux and macOS version is the reference to the native libraries (of lwjgl) in the build.sbt file. On both macOS and Linux I'm running openjdk 13 (on Mac already tried running it on 11 and 8 without success).

It seems to be crashing on "glfwCreateWindow", but I don't know why.

My question is: How do I properly debug this issue? Is it a problem in my code, JLWGL or the JVM?

For reference here is some of the out- and input.

The JVM fatal error
Code: [Select]
[info] Hello LWJGL 3.2.3 build 13!
[info] #
[info] # A fatal error has been detected by the Java Runtime Environment:
[info] #
[info] #  SIGSEGV (0xb) at pc=0x00007fff2caab4a0, pid=11896, tid=775
[info] #
[info] # JRE version: OpenJDK Runtime Environment (13.0.2+8) (build 13.0.2+8)
[info] # Java VM: OpenJDK 64-Bit Server VM (13.0.2+8, mixed mode, sharing, tiered, compressed oops, g1 gc, bsd-amd64)
[info] # Problematic frame:
[info] # C  [HIToolbox+0x274a0]  THIThemeTextInfoFinder::GetOptions() const+0x8
[info] #
[info] # No core dump will be written. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
[info] #
[info] # An error report file with more information is saved as:
[info] # /<path to my project>/hs_err_pid11896.log
[info] #
[info] # If you would like to submit a bug report, please visit:
[info] #   http://bugreport.java.com/bugreport/crash.jsp


My build.sbt
Code: [Select]
ThisBuild / scalaVersion := "2.13.1"
ThisBuild / version      := "0.0.1"
fork := true
 lazy val testlwjgl = (project in file("."))
  .settings(
    name := "TestLWJGL",
    libraryDependencies ++= {
      val version = "3.2.3"
      val os = "macos" // TODO: Change to "windows", "linux" or "macos" if necessary

      Seq(
        "lwjgl",
        "lwjgl-glfw",
        "lwjgl-opengl"
        // TODO: Add more modules here
      ).flatMap {
        module => {
          Seq(
            "org.lwjgl" % module % version,
            "org.lwjgl" % module % version classifier s"natives-$os"
          )
        }
      }
    }
  )

My source code (scala file)

Code: [Select]
package mypackagename

import org.lwjgl._
import org.lwjgl.glfw._
import org.lwjgl.opengl._
import org.lwjgl.system._
import java.nio._
import org.lwjgl.glfw.Callbacks._
import org.lwjgl.glfw.GLFW._
import org.lwjgl.opengl.GL11._
import org.lwjgl.system.MemoryStack._
import org.lwjgl.system.MemoryUtil._


object HelloWorld {
  def main(args: Array[String]): Unit = {
    new HelloWorld().run()
  }
}

class HelloWorld { // The window handle
  private var window = 0L

  def run(): Unit = {
    System.out.println("Hello LWJGL " + Version.getVersion + "!")
    init()
    loop()
    // Free the window callbacks and destroy the window
    glfwFreeCallbacks(window)
    glfwDestroyWindow(window)
    // Terminate GLFW and free the error callback
    glfwTerminate
    glfwSetErrorCallback(null).free
  }

  private def init(): Unit = { // Setup an error callback. The default implementation
    // will print the error message in System.err.
    GLFWErrorCallback.createPrint(System.err).set
    // Initialize GLFW. Most GLFW functions will not work before doing this.
    if (!glfwInit) throw new IllegalStateException("Unable to initialize GLFW")
    // Configure GLFW
    glfwDefaultWindowHints // optional, the current window hints are already the default

    glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE) // the window will stay hidden after creation

    glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE) // the window will be resizable

    // Create the window
    window = glfwCreateWindow(300, 300, "Hello World!", NULL, NULL)
    if (window == NULL) throw new RuntimeException("Failed to create the GLFW window")
    // Setup a key callback. It will be called every time a key is pressed, repeated or released.

    glfwSetKeyCallback(window, (window: Long, key: Int, scancode: Int, action: Int, mods: Int) => {
      if ((key == GLFW_KEY_ESCAPE) && (action == GLFW_RELEASE)) {
        glfwSetWindowShouldClose(window, true)
      }
    })
    // Get the thread stack and push a new frame
    try {
      val stack = stackPush
      try {
        val pWidth = stack.mallocInt(1) // int*
        val pHeight = stack.mallocInt(1)
        // Get the window size passed to glfwCreateWindow
        glfwGetWindowSize(window, pWidth, pHeight)
        // Get the resolution of the primary monitor
        val vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor)
        // Center the window
        glfwSetWindowPos(window, (vidmode.width - pWidth.get(0)) / 2, (vidmode.height - pHeight.get(0)) / 2)
      } finally if (stack != null) stack.close()
    } // the stack frame is popped automatically

    // Make the OpenGL context current
    glfwMakeContextCurrent(window)
    // Enable v-sync
    glfwSwapInterval(1)
    // Make the window visible
    glfwShowWindow(window)
  }

  private def loop(): Unit = { // This line is critical for LWJGL's interoperation with GLFW's
    // OpenGL context, or any context that is managed externally.
    // LWJGL detects the context that is current in the current thread,
    // creates the GLCapabilities instance and makes the OpenGL
    // bindings available for use.
    GL.createCapabilities
    // Set the clear color
    glClearColor(1.0f, 0.0f, 0.0f, 0.0f)
    // Run the rendering loop until the user has attempted to close
    // the window or has pressed the ESCAPE key.
    while ( {
      !glfwWindowShouldClose(window)
    }) {
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) // clear the framebuffer

      glfwSwapBuffers(window) // swap the color buffers

      // Poll for window events. The key callback above will only be
      // invoked during this call.
      glfwPollEvents
    }
  }
}

Ps: I'm still working on optimizing for Scala properly, but want to fix this issue first.
« Last Edit: March 04, 2020, 06:15:58 by Arend-Jan »

Re: [BUG] JVM macOS issue
« Reply #1 on: March 04, 2020, 06:15:39 »
So I solved the issue. The problem was that it wasn't started on the main thread, so i added -XstartOnFirstThread to my javaOptions.

Solution: change the build.sbt file to
Code: [Select]
ThisBuild / scalaVersion := "2.13.1"
ThisBuild / version      := "0.0.1"
javaOptions in run := Seq("-XstartOnFirstThread")
fork := true
 lazy val testlwjgl = (project in file("."))
  .settings(
    name := "TestLWJGL",
    libraryDependencies ++= {
      val version = "3.2.3"
      val os = "macos" // TODO: Change to "windows", "linux" or "macos" if necessary

      Seq(
        "lwjgl",
        "lwjgl-glfw",
        "lwjgl-opengl"
        // TODO: Add more modules here
      ).flatMap {
        module => {
          Seq(
            "org.lwjgl" % module % version,
            "org.lwjgl" % module % version classifier s"natives-$os"
          )
        }
      }
    }
  )

In version 3.2.0 there was a clear error messages which I could debug.
Quote
[error] Caused by: java.lang.IllegalStateException: GLFW windows may only be created on the main thread and that thread must be the first thread in the process. Please run the JVM with -XstartOnFirstThread. For offscreen rendering, make sure another window toolkit (e.g. A
WT or JavaFX) is initialized before GLFW.
.
It would be great if we could have that back  ;D

*

Offline spasi

  • *****
  • 2261
    • WebHotelier
Re: [SOLVED] JVM macOS issue
« Reply #2 on: March 04, 2020, 10:44:28 »
The main thread check is still there in 3.2.3. How do you launch the application?

*

Offline spasi

  • *****
  • 2261
    • WebHotelier
Re: [SOLVED] JVM macOS issue
« Reply #3 on: March 04, 2020, 19:11:56 »
Reproduced and responded here: https://github.com/LWJGL/lwjgl3/issues/538