MacOS support overhaul, Apple M1 and breaking changes

What if you run it with this environment variable:

AWT_FORCE_HEADFUL=true ./gradlew clean run

can you run ps aux and see if windowserver is running?

Try disabling headless mode by adding:

static {
	System.setProperty("java.awt.headless", "false");
}

It is already disabled.

1 Like

The application hangs with no output.

I suspect our best course is to rewrite the test chooser and the settings dialog so that they don’t use AWT/Swing.

3 Likes

I see. Anyway, dear @sgold thank you so much for putting in your time and trying the test. It is so much appreciated :heart: :slightly_smiling_face:

4 Likes

I’ve had a busy fortnight, porting my libraries and JME apps to run on the Mac Mini while publishing 2 Minie feature releases plus JME v3.5.1.

I’ve got native physics working for macOS-on-ARM.
I’ve had no success combining LWJGL v3 with Swing/AWT on macOS.
I’ve had some success using the -XstartOnFirstThread JVM argument (on macOS only) and setting application.setShowSettings(false).

I’ve stumbled on a few issues that seem worth noting:

I still think our way forward with macOS is to rewrite the current test chooser and settings dialog so that they don’t use AWT/Swing. I hope to begin work soon on these projects.

Sadly, I haven’t got a good answer for JME apps that rely on AWT/Swing.

2 Likes

For clarity, are you referring only to transitioning between AWT/Swing and another windowing system, (A la the TestChooser) or do you also mean embedding an LWJGL Display in an AWT Canvas?

1 Like

I’ve only tried transitioning, not embedding. Is there a jme3-examples app that does embedding?

This feature does not currently work with LWJGL 3. There is the issue and one PR about it. I have briefly looked using GitHub - LWJGLX/lwjgl3-awt: AWT support for LWJGL3. But it requires some time and skill to implement.

2 Likes

I’m checking back in on this issue. I’m on a mac M1 arm. I don’t need AWT or swing, but I do need to be able to run GLFW off the main thread for my own application’s test framework. I just tried pulling master, updating the build to use jme3-lwjgl3 and running a simple blue cube hello world, which works on main, but not off with glfw_async. Below is my sample code, runOnMain() works, runOffMain() just hangs with no error. This is with openjdk 11.

package jme3test.animation;
 
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.system.AppSettings;
import org.lwjgl.system.Configuration;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class Main2 extends SimpleApplication {

    static Executor executor= Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws InterruptedException {
      // runOnMain();
        runOffMain();
    }

    public static void runOnMain() {
        Main2 app = new Main2();
        AppSettings settings = new AppSettings(true);
        settings.setTitle("My Awesome Game");
        app.setSettings(settings);
        app.setShowSettings(false);
        app.start();
    }

    public static void runOffMain() throws InterruptedException {
        Main2 app = new Main2();
        Configuration.GLFW_CHECK_THREAD0.set(false);
        Configuration.GLFW_LIBRARY_NAME.set("glfw_async");//"libglfw_async.dylib"
        AppSettings settings = new AppSettings(true);
        settings.setTitle("My Awesome Game");
        app.setSettings(settings);
        app.setShowSettings(false);
        executor.execute(()->app.start());
        Thread.sleep(1000000);
    }

    @Override
    public void start() {
        try {
            super.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void simpleInitApp() {
 
        Box b = new Box(1, 1, 1);
        Geometry geom = new Geometry("Box", b);
 
        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom.setMaterial(mat);
 
        rootNode.attachChild(geom);
 
    }
 
    @Override
    public void simpleUpdate(float tpf) {
        //TODO: add update code
    }
 
}```
1 Like

Turns out that issue was also related to mixing AWT with LWJGL. I was using AWT’s GraphicsEnvironment to enumerate the available display modes. Does LWJGL provide equivalent functionality?

Edit: It looks like I should be using glfwGetVideoModes.

Do lwjgl3 demos (available on LWJGL GitHub repo) run fine with glfw_async?

1 Like

Ok, I’ve not played around with lwjgl3’s build before, the demo’s do not work out of the box. They throw

Failed to locate library: liblwjgl.dylib

But if you modify line 140 of the pom.xml at lwjgl3-demos/pom.xml at main Ā· LWJGL/lwjgl3-demos Ā· GitHub to read:

<platform>macos-arm64</platform>

They then throw…

GLFW may only be used on the main thread and that thread must be the first thread in the process. Please run the JVM with -XstartOnFirstThread. This check may be disabled with Configuration.GLFW_CHECK_THREAD0.

But if you then add

Configuration.GLFW_LIBRARY_NAME.set("glfw_async");

to the static main method of org.lwjgl.demo.intro.Intro2 you get a dialog with a triangle. So with some caveats, they seem to work.

I just modified GeometryShaderTest’s static main method to:

    static Executor executor= Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws InterruptedException {
        Configuration.GLFW_LIBRARY_NAME.set("glfw_async");
        executor.execute(()->{
            new GeometryShaderTest().run();
        });
        Thread.sleep(10000);
    }

And it does run correctly off the main thread.

2 Likes

So I believe I’ve found the problem. My earlier example works if you turn off inputs.

        Main2 app = new Main2();
        Configuration.GLFW_CHECK_THREAD0.set(false);
        Configuration.GLFW_LIBRARY_NAME.set("glfw_async");//"libglfw_async.dylib"
        AppSettings settings = new AppSettings(true);
        settings.setTitle("My Awesome Game");
        settings.setUseInput(false);
        app.setSettings(settings);
        app.setShowSettings(false);

        executor.execute(()->app.start());
        Thread.sleep(1000000);
    }

With inputs on, when you get to the native method org.lwjgl.glfw.GLFW.glfwSetInputMode() it fails without a stack trace.

3 Likes

I opened an issue on LWJGL… glfw_async native method crashes when GLFW.glfwSetInputMode() is invoked Ā· Issue #754 Ā· LWJGL/lwjgl3 Ā· GitHub no motion so far.

2 Likes

I’m investigating glfw_async again. I have more practical experience with it—in the LbjExamples project, where it works great—but that’s not JMonkeyEngine.

  1. The intermittent and confusing headless exceptions I saw before were probably caused by a Gradle daemon with its DISPLAY environment variable unset. When running apps via the Gradle daemon, the daemon’s environment is used, which may differ from the shell’s environment—especially if a user has multiple logins to the host. One workaround is to bypass Gradle and execute the app (or its start script) directly, from the command line. But I find that awkward. My preferred workaround is to execute gradlew with the ā€œā€“no-daemonā€ option, which creates a temporary daemon with a copy of the shell’s environment.

  2. The -XstartOnFirstThread option (which default GLFW requires on macOS) is not required with glfw_async, or even a good idea.

When I try using ā€œglfw_asyncā€ with JMonkeyEngine 3.5.2, my apps hang somewhere between invoking run() in LwjglWindow.create() and invoking simpleInitApp(). Investigation continues …

EDIT: The hang occurs in glfwInit(). I’ll try initializing GLFW sooner in case that helps.

EDIT2: Near as I can determine, set("glfw_async") should be invoked from main() and as early as possible! Invoking a mostly harmless utility method prior to set() is causing glfwInit() to hang. Commenting out the utility method eliminated the hang. If this holds up, PR 1779 won’t be useful.

8 Likes

I made some progress with ā€œglfw_asyncā€ and JME 3.5.2 on macOS, but now I’ve got an issue where some apps terminate cleanly, while others terminate with exit value 133 and a ā€œjava quit unexpectedly.ā€ system dialog.

It’s not clear what distinguishes the one group of apps from the other. It doesn’t seem to matter whether the apps are terminated using the Esc key (LegacyApplication.stop(false)) or the red button in the window decorations. I plan to gradually delete features from an ā€œexit value 133ā€ app until it stops misbehaving. Hopefully that will provide a clue as to the cause.

EDIT: It’s bizarre. The failing apps all set the background color of the default viewport. If I comment out the calls to viewPort.setBackgroundColor(), they no longer fail! I’m stumped and unsure how to proceed.

6 Likes