Skip to content

Commit ffa66ad

Browse files
authored
Replace desktop backend with SDL3 GL and ANGLE-GLES (#2585)
* Fix issues in GLES backends * rewrite lwjgl3 backend to use SDL * remove debug libraries * support msaa framebuffer extension in gles * use auxiliary framebuffer for srgb conversion * deprecate old opengl versions * update deps * use lib catalog for angle native * fix * remove debug override * update libs * add task to run tests in proton * increase memory * Implement GPU timer query support across multiple platforms and handle unsupported cases * Revert "Implement GPU timer query support across multiple platforms and handle unsupported cases" This reverts commit 36dbf9f. * add packed float toggler to getBestColorTargetFormat and disallow packed floats in env backer * fix wayland selection * Reapply "Implement GPU timer query support across multiple platforms and handle unsupported cases" This reverts commit feaf8ea. * Revert "Reapply "Implement GPU timer query support across multiple platforms and handle unsupported cases"" This reverts commit 4bf14ab. * fix gpu timer support * fixes * use Blit.j3md for gamma correction * Revert "fixes" This reverts commit 79734e7. * Reapply "fixes" This reverts commit f0a76dc740a9cd370cf76891d5edc8f8f2e103b6. * add explicit GLSL310 support for Blit material * force GL 3.2 in screenshot tests * add renderer selector to settings dialog * catch swapwindow failures * reset hint on renderer change, fix sRGB for non angle renderer * set __GL_THREADED_OPTIMIZATIONS=0 on start to workaround known nvidia bug that causes lwjgl apps to break * bypass aux framebuffer if native gl * use isGraphicsDebug * use 24 bit buffer in Xvfb * Fix examples launcher and disable AWT dialogs in macos * use angle in tests with vulkan software rendering * make all extensions optional * update libs * fix angle version * Revert "make all extensions optional" This reverts commit 748e584. * Reapply "make all extensions optional" This reverts commit 275cfd4. * Revert "use angle in tests with vulkan software rendering" This reverts commit a288755. * fallback to aux framebuffer if srgb framebuffer is not available * revert change to Xvfb color depth * Revert "Reapply "make all extensions optional"" This reverts commit 8285cf7. * restore main framebuffer override when it changes inside the app update loop * revert unrelated changes to tests
1 parent b50082c commit ffa66ad

60 files changed

Lines changed: 2998 additions & 6142 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,4 @@ javadoc_deploy.pub
4545
!.vscode/settings.json
4646
!.vscode/JME_style.xml
4747
!.vscode/extensions.json
48-
joysticks-*.txt
48+
joysticks-*.txt

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
"editor.formatOnPaste": false,
66
"editor.formatOnType": false,
77
"editor.formatOnSave": false,
8-
"java.jdt.ls.vmargs": "-Xms512M -Xmx2G -XX:+UseG1GC -XX:+UseStringDeduplication -XX:AdaptiveSizePolicyWeight=90"
8+
"java.jdt.ls.vmargs": "-Xms512M -Xmx4G -XX:+UseG1GC -XX:+UseStringDeduplication -XX:AdaptiveSizePolicyWeight=90"
99
}

gradle/libs.versions.toml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
checkstyle = "13.3.0"
66
jacoco = "0.8.12"
77
lwjgl3 = "3.4.1"
8+
angle = "2026-05-09"
9+
saferalloc = "0.0.8"
810
nifty = "1.4.3"
911
spotbugs = "4.9.8"
1012

@@ -35,9 +37,10 @@ lwjgl3-glfw = { module = "org.lwjgl:lwjgl-glfw", version.ref = "lwjgl3"
3537
lwjgl3-jawt = { module = "org.lwjgl:lwjgl-jawt", version.ref = "lwjgl3" }
3638
lwjgl3-jemalloc = { module = "org.lwjgl:lwjgl-jemalloc", version.ref = "lwjgl3" }
3739
lwjgl3-openal = { module = "org.lwjgl:lwjgl-openal", version.ref = "lwjgl3" }
38-
lwjgl3-opencl = { module = "org.lwjgl:lwjgl-opencl", version.ref = "lwjgl3" }
3940
lwjgl3-opengl = { module = "org.lwjgl:lwjgl-opengl", version.ref = "lwjgl3" }
4041
lwjgl3-sdl = { module = "org.lwjgl:lwjgl-sdl", version.ref = "lwjgl3" }
42+
lwjgl3-opengles = { module = "org.lwjgl:lwjgl-opengles", version.ref = "lwjgl3" }
43+
lwjgl3-egl = { module = "org.lwjgl:lwjgl-egl", version.ref = "lwjgl3" }
4144

4245
mokito-core = "org.mockito:mockito-core:5.23.0"
4346
mokito-junit-jupiter = "org.mockito:mockito-junit-jupiter:5.23.0"
@@ -52,8 +55,18 @@ vecmath = "javax.vecmath:vecmath:1.5.2"
5255

5356
stb-image = "org.ngengine:stb-image:2.30.4"
5457
imagewebp = "org.ngengine:image-webp-decoder:1.3.0"
58+
angle = { module = "org.ngengine:angle-natives", version.ref = "angle" }
59+
saferalloc = { module = "org.ngengine:saferalloc", version.ref = "saferalloc" }
60+
saferalloc-natives-linux-x8664 = { module = "org.ngengine:saferalloc-natives-linux-x86_64", version.ref = "saferalloc" }
61+
saferalloc-natives-linux-aarch64 = { module = "org.ngengine:saferalloc-natives-linux-aarch64", version.ref = "saferalloc" }
62+
saferalloc-natives-windows-x8664 = { module = "org.ngengine:saferalloc-natives-windows-x86_64", version.ref = "saferalloc" }
63+
saferalloc-natives-windows-aarch64 = { module = "org.ngengine:saferalloc-natives-windows-aarch64", version.ref = "saferalloc" }
64+
saferalloc-natives-macos-x8664 = { module = "org.ngengine:saferalloc-natives-macos-x86_64", version.ref = "saferalloc" }
65+
saferalloc-natives-macos-aarch64 = { module = "org.ngengine:saferalloc-natives-macos-aarch64", version.ref = "saferalloc" }
66+
saferalloc-natives-android = { module = "org.ngengine:saferalloc-natives-android", version.ref = "saferalloc" }
5567

5668
[bundles]
69+
saferalloc = ["saferalloc", "saferalloc-natives-linux-x8664", "saferalloc-natives-linux-aarch64", "saferalloc-natives-windows-x8664", "saferalloc-natives-windows-aarch64", "saferalloc-natives-macos-x8664", "saferalloc-natives-macos-aarch64", "saferalloc-natives-android"]
5770

5871
[plugins]
5972
jacoco = { id = "jacoco", version.ref = "jacoco" }

jme3-android/src/main/java/com/jme3/renderer/android/AndroidGL.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ public class AndroidGL implements GL, GL2, GLES_30, GLExt, GLFbo {
5151
public void resetStats() {
5252
}
5353

54+
@Override
55+
public boolean supportsGpuTimerQuery() {
56+
return false;
57+
}
58+
5459
private static int getLimitBytes(ByteBuffer buffer) {
5560
checkLimit(buffer);
5661
return buffer.limit();
@@ -100,6 +105,9 @@ public void glAttachShader(int program, int shader) {
100105

101106
@Override
102107
public void glBeginQuery(int target, int query) {
108+
if (target == GL.GL_TIME_ELAPSED) {
109+
throw new UnsupportedOperationException("64-bit GPU timer queries are not exposed by the Android GLES bindings");
110+
}
103111
GLES30.glBeginQuery(target, query);
104112
}
105113

@@ -287,6 +295,9 @@ public void glEnableVertexAttribArray(int index) {
287295

288296
@Override
289297
public void glEndQuery(int target) {
298+
if (target == GL.GL_TIME_ELAPSED) {
299+
throw new UnsupportedOperationException("64-bit GPU timer queries are not exposed by the Android GLES bindings");
300+
}
290301
GLES30.glEndQuery(target);
291302
}
292303

@@ -348,16 +359,13 @@ public String glGetProgramInfoLog(int program, int maxLength) {
348359

349360
@Override
350361
public long glGetQueryObjectui64(int query, int pname) {
351-
IntBuffer buff = IntBuffer.allocate(1);
352-
//FIXME This is wrong IMO should be glGetQueryObjectui64v with a LongBuffer but it seems the API doesn't provide it.
353-
GLES30.glGetQueryObjectuiv(query, pname, buff);
354-
return buff.get(0);
362+
throw new UnsupportedOperationException("64-bit query results are not exposed by the Android GLES bindings");
355363
}
356364

357365
@Override
358366
public int glGetQueryObjectiv(int query, int pname) {
359-
IntBuffer buff = IntBuffer.allocate(1);
360-
GLES30.glGetQueryiv(query, pname, buff);
367+
IntBuffer buff = (IntBuffer)tmpBuff.clear();
368+
GLES30.glGetQueryObjectuiv(query, pname, buff);
361369
return buff.get(0);
362370
}
363371

@@ -786,4 +794,9 @@ public void glGenVertexArrays(IntBuffer arrays) {
786794

787795
}
788796

797+
@Override
798+
public String glGetString(int name, int index) {
799+
return GLES30.glGetStringi(name, index);
800+
}
801+
789802
}

jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -669,21 +669,37 @@ private boolean renderFrameWithBlitSrgbConversion() {
669669
return false;
670670
}
671671

672+
FrameBuffer previousMainFramebuffer = renderer.getCurrentFrameBuffer();
673+
if (previousMainFramebuffer != null) {
674+
return false;
675+
}
676+
672677
rebuildLinearFrameBufferIfNeeded();
673678
if (linearFrameBuffer == null || !ensureBlitResources()) {
674679
return false;
675680
}
676681

682+
FrameBuffer restoreMainFramebuffer = previousMainFramebuffer;
683+
677684
renderer.setMainFrameBufferOverride(linearFrameBuffer);
678685
try {
679686
listener.update();
687+
FrameBuffer currentMainFramebuffer = renderer.getCurrentFrameBuffer();
688+
if (currentMainFramebuffer != linearFrameBuffer) {
689+
restoreMainFramebuffer = currentMainFramebuffer;
690+
}
680691
} finally {
681-
renderer.setMainFrameBufferOverride(null);
692+
renderer.setMainFrameBufferOverride(restoreMainFramebuffer);
682693
}
683694

684-
renderer.setFrameBuffer(null);
685-
blitGeometry.updateGeometricState();
686-
application.getRenderManager().renderGeometry(blitGeometry);
695+
renderer.setMainFrameBufferOverride(null);
696+
try {
697+
renderer.setFrameBuffer(null);
698+
blitGeometry.updateGeometricState();
699+
application.getRenderManager().renderGeometry(blitGeometry);
700+
} finally {
701+
renderer.setMainFrameBufferOverride(restoreMainFramebuffer);
702+
}
687703
return true;
688704
}
689705

jme3-awt-dialogs/src/main/java/com/jme3/awt/AWTSettingsDialog.java

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ public interface SelectionListener {
129129
private JComboBox<String> colorDepthCombo = null;
130130
private JComboBox<String> displayFreqCombo = null;
131131
private JComboBox<String> antialiasCombo = null;
132+
private JComboBox<String> rendererCombo = null;
132133
private JLabel icon = null;
133134
private int selection = 0;
134135
private SelectionListener selectionListener = null;
@@ -463,6 +464,8 @@ public void keyPressed(KeyEvent e) {
463464
displayFreqCombo.addKeyListener(aListener);
464465
antialiasCombo = new JComboBox<>();
465466
antialiasCombo.addKeyListener(aListener);
467+
rendererCombo = setUpRendererChooser();
468+
rendererCombo.addKeyListener(aListener);
466469
fullscreenBox = new JCheckBox(resourceBundle.getString("checkbox.fullscreen"));
467470
fullscreenBox.setSelected(source.isFullscreen());
468471
fullscreenBox.addActionListener(new ActionListener() {
@@ -549,6 +552,20 @@ public void actionPerformed(ActionEvent e) {
549552
gbc.anchor = GridBagConstraints.WEST;
550553
mainPanel.add(antialiasCombo, gbc);
551554

555+
gbc = new GridBagConstraints();
556+
gbc.insets = new Insets(4, 4, 4, 4);
557+
gbc.gridx = 0;
558+
gbc.gridy = 4;
559+
gbc.anchor = GridBagConstraints.EAST;
560+
gbc.weightx = 0.5;
561+
mainPanel.add(new JLabel(resourceBundle.getString("label.renderer")), gbc);
562+
gbc = new GridBagConstraints();
563+
gbc.gridx = 1;
564+
gbc.gridy = 4;
565+
gbc.gridwidth = 3;
566+
gbc.anchor = GridBagConstraints.WEST;
567+
mainPanel.add(rendererCombo, gbc);
568+
552569
// Set the button action listeners. Cancel disposes without saving, OK
553570
// saves.
554571
ok.addActionListener(new ActionListener() {
@@ -583,14 +600,14 @@ public void actionPerformed(ActionEvent e) {
583600
gbc = new GridBagConstraints();
584601
gbc.gridx = 0;
585602
gbc.gridwidth = 2;
586-
gbc.gridy = 4;
603+
gbc.gridy = 5;
587604
gbc.anchor = GridBagConstraints.EAST;
588605
mainPanel.add(ok, gbc);
589606
gbc = new GridBagConstraints();
590607
gbc.insets = new Insets(4, 16, 4, 4);
591608
gbc.gridx = 2;
592609
gbc.gridwidth = 2;
593-
gbc.gridy = 4;
610+
gbc.gridy = 5;
594611
gbc.anchor = GridBagConstraints.WEST;
595612
mainPanel.add(cancel, gbc);
596613

@@ -662,6 +679,7 @@ private boolean verifyAndSaveCurrentSelection() {
662679
boolean fullscreen = fullscreenBox.isSelected();
663680
boolean vsync = vsyncBox.isSelected();
664681
boolean gamma = gammaBox.isSelected();
682+
String renderer = (String) rendererCombo.getSelectedItem();
665683

666684
String[] parts = display.split(" x ");
667685
int width = Integer.parseInt(parts[0]);
@@ -721,7 +739,7 @@ private boolean verifyAndSaveCurrentSelection() {
721739
source.setFullscreen(fullscreen);
722740
source.setVSync(vsync);
723741
source.setGammaCorrection(gamma);
724-
// source.setRenderer(renderer);
742+
source.setRenderer(renderer);
725743
source.setSamples(multisample);
726744

727745
String appTitle = source.getTitle();
@@ -762,6 +780,30 @@ public void actionPerformed(ActionEvent e) {
762780
return resolutionBox;
763781
}
764782

783+
private JComboBox<String> setUpRendererChooser() {
784+
JComboBox<String> rendererBox = new JComboBox<>();
785+
Set<String> renderers = new LinkedHashSet<>(Arrays.asList(
786+
AppSettings.ANGLE_GLES3,
787+
AppSettings.LWJGL_OPENGL32,
788+
AppSettings.LWJGL_OPENGL33,
789+
AppSettings.LWJGL_OPENGL40,
790+
AppSettings.LWJGL_OPENGL41,
791+
AppSettings.LWJGL_OPENGL42,
792+
AppSettings.LWJGL_OPENGL43,
793+
AppSettings.LWJGL_OPENGL44,
794+
AppSettings.LWJGL_OPENGL45
795+
));
796+
String currentRenderer = source.getRenderer();
797+
if (currentRenderer != null) {
798+
renderers.add(currentRenderer);
799+
}
800+
for (String renderer : renderers) {
801+
rendererBox.addItem(renderer);
802+
}
803+
rendererBox.setSelectedItem(currentRenderer);
804+
return rendererBox;
805+
}
806+
765807
/**
766808
* <code>updateDisplayChoices</code> updates the available color depth and
767809
* display frequency options to match the currently selected resolution.

jme3-awt-dialogs/src/main/java/com/jme3/system/JmeDialogsFactoryImpl.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,26 @@
3232

3333
package com.jme3.system;
3434

35+
import java.util.logging.Logger;
36+
3537
import com.jme3.awt.AWTErrorDialog;
3638
import com.jme3.awt.AWTSettingsDialog;
3739

3840
public class JmeDialogsFactoryImpl implements JmeDialogsFactory {
39-
41+
private final static Logger logger = Logger.getLogger(JmeDialogsFactoryImpl.class.getName());
4042
public boolean showSettingsDialog(AppSettings settings, boolean loadFromRegistry){
43+
if(JmeSystem.getPlatform()==Platform.MacOSX64||JmeSystem.getPlatform()==Platform.MacOSX_ARM64){
44+
logger.warning("AWT settings dialog skipped in MacOS");
45+
return true;
46+
}
4147
return AWTSettingsDialog.showDialog(settings,loadFromRegistry);
4248
}
4349

4450
public void showErrorDialog(String message){
51+
if(JmeSystem.getPlatform()==Platform.MacOSX64||JmeSystem.getPlatform()==Platform.MacOSX_ARM64){
52+
logger.warning("AWT error dialog skipped in MacOS");
53+
return;
54+
}
4555
AWTErrorDialog.showDialog(message);
4656
}
4757

jme3-core/src/main/java/com/jme3/app/DetailedProfiler.java

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
package com.jme3.app;
3333

3434
import com.jme3.profile.*;
35+
import com.jme3.renderer.Caps;
3536
import com.jme3.renderer.Renderer;
3637
import com.jme3.renderer.ViewPort;
3738
import com.jme3.renderer.queue.RenderQueue;
@@ -86,14 +87,16 @@ public void appStep(AppStep step) {
8687
frameTime.setNewFrameValueCpu(System.nanoTime());
8788

8889
frameEnded = false;
89-
for (StatLine statLine : data.values()) {
90-
for (Iterator<Integer> i = statLine.taskIds.iterator(); i.hasNext(); ) {
91-
int id = i.next();
92-
if (renderer.isTaskResultAvailable(id)) {
93-
long val = renderer.getProfilingTime(id);
94-
statLine.setValueGpu(val);
95-
i.remove();
96-
idsPool.push(id);
90+
if (renderer != null) {
91+
for (StatLine statLine : data.values()) {
92+
for (Iterator<Integer> i = statLine.taskIds.iterator(); i.hasNext(); ) {
93+
int id = i.next();
94+
if (renderer.isTaskResultAvailable(id)) {
95+
long val = renderer.getProfilingTime(id);
96+
statLine.setValueGpu(val);
97+
i.remove();
98+
idsPool.push(id);
99+
}
97100
}
98101
}
99102
}
@@ -222,8 +225,8 @@ private void addStep(String path, long value) {
222225
int id = getUnusedTaskId();
223226
line.taskIds.add(id);
224227
renderer.startProfiling(id);
228+
ongoingGpuProfiling = true;
225229
}
226-
ongoingGpuProfiling = true;
227230
prevPath = path;
228231

229232
}
@@ -239,8 +242,13 @@ private String getPath(String step, String... subPath) {
239242
}
240243

241244
public void setRenderer(Renderer renderer) {
242-
this.renderer = renderer;
243-
poolTaskIds(renderer);
245+
idsPool.clear();
246+
if (renderer != null && renderer.getCaps().contains(Caps.GpuTimerQuery)) {
247+
this.renderer = renderer;
248+
poolTaskIds(renderer);
249+
} else {
250+
this.renderer = null;
251+
}
244252
}
245253

246254
private void poolTaskIds(Renderer renderer) {

jme3-core/src/main/java/com/jme3/renderer/Caps.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,12 @@ public enum Caps {
467467
* GPU support for binary shaders.
468468
*/
469469
BinaryShader,
470+
471+
/**
472+
* Supports GPU timer queries with full 64-bit elapsed-time results.
473+
*/
474+
GpuTimerQuery,
475+
470476
/**
471477
* Supporting working with UniformBufferObject.
472478
*/

jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,16 @@ public void glCompressedTexSubImage2D(int target, int level, int xoffset, int yo
890890
*/
891891
public String glGetProgramInfoLog(int program, int maxSize);
892892

893+
/**
894+
* Returns whether this GL binding can execute elapsed-time timer queries
895+
* and read their full 64-bit results.
896+
*
897+
* @return true if full GPU timer query support is exposed by the binding
898+
*/
899+
public default boolean supportsGpuTimerQuery() {
900+
return true;
901+
}
902+
893903
/**
894904
* Unsigned version.
895905
*

0 commit comments

Comments
 (0)