Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 36 additions & 11 deletions jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglCanvas.java
Original file line number Diff line number Diff line change
Expand Up @@ -340,16 +340,14 @@ public void removeNotify() {
hasNativePeer.set(false);
reinitcontext.set(true);

while (reinitcontext.get()) {
while (reinitcontext.get() && parallel.get()) {
try {
lock.wait();
} catch (InterruptedException ex) {
super.removeNotify();
return;
}
}

reinitcontext.set(false);
}

// GL context is dead at this point
Expand Down Expand Up @@ -411,6 +409,13 @@ public Graphics getGraphics() {
/** Notify if there is a change in canvas dimensions. */
private final AtomicBoolean needResize = new AtomicBoolean(false);

/**
* Flag indicating whether a custom thread is used to separate GL rendering
* from the EDT; its value is false if the main thread is used via the
* {@code SwingUtilities.invokeLater() } function.
*/
private final AtomicBoolean parallel = new AtomicBoolean(false);

/**
* Flag that uses the context to check if it is initialized or not, this prevents
* it from being initialized multiple times and potentially breaking the JVM.
Expand Down Expand Up @@ -513,6 +518,7 @@ public boolean checkVisibilityState() {
* Here the entire GL context is rendered and initialized.
*/
@Override
@SuppressWarnings("deprecation")
public void run() {
if (listener == null) {
throw new IllegalStateException(
Expand All @@ -525,8 +531,8 @@ public void run() {
while (true) {
if (needResize.getAndSet(false)) {
settings.setResolution(framebufferWidth, framebufferHeight);
listener.reshape(framebufferWidth, framebufferHeight, framebufferWidth, framebufferHeight);
listener.reshape(framebufferWidth, framebufferHeight);
listener.reshape(framebufferWidth, framebufferHeight, framebufferWidth, framebufferHeight);
Comment on lines 533 to 535

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This removes the call to SystemListener.reshape(int, int). That overload is deprecated but explicitly "kept only for backward compatibility", and LwjglWindow.updateSizes() still invokes both overloads. After this change an AWT-canvas app whose SystemListener/Application overrides only the 2-arg method silently stops receiving resize notifications when the canvas is resized, while the same app on the Display path still gets them. This is also outside the scope of the main-thread fix. Keep both calls unless the removal is deliberate and documented:

Suggested change
settings.setResolution(framebufferWidth, framebufferHeight);
listener.reshape(framebufferWidth, framebufferHeight, framebufferWidth, framebufferHeight);
settings.setResolution(framebufferWidth, framebufferHeight);
listener.reshape(framebufferWidth, framebufferHeight, framebufferWidth, framebufferHeight);
listener.reshape(framebufferWidth, framebufferHeight);

@JNightRider JNightRider Sep 19, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I started working on this PR, the new reshape() method called the old method (causing a duplicate call) but it seems this has been removed (in this PR #2881).

Was there really any difference between having the new method call the old one and making the call explicitly whenever necessary?

working on the changes

}

synchronized (lock) {
Expand Down Expand Up @@ -588,9 +594,6 @@ public void run() {
} finally {
canvas.unlock();
}

// Sync the display on some systems.
Toolkit.getDefaultToolkit().sync();
}
} catch (Throwable ex) {
listener.handleError("Error while swapping buffers", ex);
Expand All @@ -607,6 +610,17 @@ public void run() {
if (needClose.get()) {
break;
}

if (! parallel.get()) {
// Sync the display on some systems.
Toolkit.getDefaultToolkit().sync();
break;
}
Comment thread
JNightRider marked this conversation as resolved.
}

if (!parallel.get() && !needClose.get()) {
SwingUtilities.invokeLater(() -> run());
return;
}

deinitInThread();
Expand Down Expand Up @@ -669,6 +683,12 @@ public void create(boolean waitFor) {
if (this.contextFlag.get()) {
return;
}
/*
* Note that JME does not run on a thread parallel to the AWT EDT;
* this applies only to macOS.
*/
this.parallel.set(Platform.get() != Platform.MACOSX);

// create context
super.create(waitFor);
this.contextFlag.set(true);
Expand Down Expand Up @@ -720,8 +740,8 @@ protected void createContext(AppSettings settings) {

RENDER_CONFIGS.computeIfAbsent(settings.getRenderer(), (t) -> {
return (data) -> {
data.majorVersion = 2;
data.minorVersion = 0;
data.majorVersion = 3;
data.minorVersion = 2;
Comment on lines +743 to +744

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fallback renderer configuration changed from GL 2.0 to GL 3.2 here. It is unrelated to the main-thread fix (it only triggers for renderer strings missing from RENDER_CONFIGS) and it changes which context is requested on every platform. Bundling it makes the diff harder to reason about and to bisect; please split it into its own PR or state why the canvas path needs 3.2 as the fallback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though it is a minor change that doesn't actually affect anything (since the minimum supported version is already set to that value) should I create a separate PR for it?

};
}).accept(glData);

Expand Down Expand Up @@ -759,9 +779,14 @@ protected void createContext(AppSettings settings) {
glData.forwardCompatible = false;

allowSwapBuffers = settings.isSwapBuffers();

canvas.createContext();
canvas.makeCurrent();

try {
canvas.lock();
canvas.makeCurrent();
} finally {
canvas.unlock();
}

SwingUtilities.invokeLater(() -> {
canvas.validate();
Expand Down