From: Svjatoslav Agejenko Date: Sun, 15 Mar 2026 17:04:32 +0000 (+0200) Subject: fix(demos): explicitly start render thread and fix benchmark timing X-Git-Url: http://www2.svjatoslav.eu/gitweb/?a=commitdiff_plain;h=311d29fe2b11a044002e0ab1bbc3ac65aba72035;p=sixth-3d-demos.git fix(demos): explicitly start render thread and fix benchmark timing - Add ensureRenderThreadStarted() call to all demo constructors - Reorder GraphicsBenchmark initialization (registerTests before initializeWindow) - Defer test transitions to beginning of next frame to avoid threading issues - Add pendingTestTransition flag for safe test state changes --- diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/GraphDemo.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/GraphDemo.java index ae7ff23..5aa5e3f 100755 --- a/src/main/java/eu/svjatoslav/sixth/e3d/examples/GraphDemo.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/examples/GraphDemo.java @@ -197,6 +197,9 @@ public class GraphDemo { addWobblySurface(geometryCollection, -200); setCameraLocation(viewFrame); + + // Ensure the render thread is started + viewFrame.getViewPanel().ensureRenderThreadStarted(); } /** diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/OctreeDemo.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/OctreeDemo.java index 23a5282..6b3accc 100755 --- a/src/main/java/eu/svjatoslav/sixth/e3d/examples/OctreeDemo.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/examples/OctreeDemo.java @@ -161,6 +161,9 @@ public class OctreeDemo extends WorldNavigationUserInputTracker { viewPanel.getKeyboardFocusStack().pushFocusOwner(this); viewPanel.repaintDuringNextViewUpdate(); + + // Ensure the render thread is started + viewPanel.ensureRenderThreadStarted(); } /** diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/RainingNumbersDemo.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/RainingNumbersDemo.java index 7f97540..b3c9d3c 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/examples/RainingNumbersDemo.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/examples/RainingNumbersDemo.java @@ -94,5 +94,8 @@ public class RainingNumbersDemo implements FrameListener { } viewFrame.getViewPanel().addFrameListener(this); + + // Ensure the render thread is started + viewFrame.getViewPanel().ensureRenderThreadStarted(); } } diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/RandomPolygonsDemo.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/RandomPolygonsDemo.java index 8754044..30c4ef9 100755 --- a/src/main/java/eu/svjatoslav/sixth/e3d/examples/RandomPolygonsDemo.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/examples/RandomPolygonsDemo.java @@ -96,5 +96,8 @@ public class RandomPolygonsDemo { for (int i = 0; i < POLYGON_COUNT; i++) addRandomPolygon(shapeCollection); + // Ensure the render thread is started + viewFrame.getViewPanel().ensureRenderThreadStarted(); + } } diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/ShadedShapesDemo.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/ShadedShapesDemo.java index c0cbd50..7d0b27d 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/examples/ShadedShapesDemo.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/examples/ShadedShapesDemo.java @@ -103,6 +103,9 @@ public class ShadedShapesDemo { viewPanel.addFrameListener(animator); viewPanel.repaintDuringNextViewUpdate(); + + // Ensure the render thread is started + viewPanel.ensureRenderThreadStarted(); } /** diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/TextEditorDemo.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/TextEditorDemo.java index ec5c6b6..c9292a5 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/examples/TextEditorDemo.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/examples/TextEditorDemo.java @@ -44,6 +44,9 @@ public class TextEditorDemo { addGrid(shapeCollection); addTextEditors(viewPanel, shapeCollection); + + // Ensure the render thread is started + viewFrame.getViewPanel().ensureRenderThreadStarted(); } /** diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/TextEditorDemo2.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/TextEditorDemo2.java index 887fb30..936aed6 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/examples/TextEditorDemo2.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/examples/TextEditorDemo2.java @@ -66,6 +66,9 @@ public class TextEditorDemo2 { addGrid(shapeCollection); addCity(viewPanel, shapeCollection); + + // Ensure the render thread is started + viewFrame.getViewPanel().ensureRenderThreadStarted(); } /** diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/benchmark/GraphicsBenchmark.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/benchmark/GraphicsBenchmark.java index dc93a19..1f93318 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/examples/benchmark/GraphicsBenchmark.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/examples/benchmark/GraphicsBenchmark.java @@ -59,6 +59,7 @@ public class GraphicsBenchmark implements FrameListener, KeyboardInputHandler { private BenchmarkTest currentTest; private boolean testFinished = false; private boolean benchmarkFinished = false; + private boolean pendingTestTransition = false; private final List results = new ArrayList<>(); private final List tests = new ArrayList<>(); @@ -70,13 +71,12 @@ public class GraphicsBenchmark implements FrameListener, KeyboardInputHandler { new GraphicsBenchmark(); } - /** +/** * Constructs and runs the graphics benchmark. */ public GraphicsBenchmark() { - initializeWindow(); - registerTests(); - startNextTest(); + registerTests(); // populate tests FIRST, before render thread starts + initializeWindow(); // now onFrame can safely access the tests list } private void initializeWindow() { @@ -87,6 +87,8 @@ public class GraphicsBenchmark implements FrameListener, KeyboardInputHandler { viewPanel.addFrameListener(this); viewPanel.getKeyboardFocusStack().pushFocusOwner(this); camera = viewPanel.getCamera(); + // Now explicitly start the render thread after all listeners are registered + viewPanel.ensureRenderThreadStarted(); } private void registerTests() { @@ -122,7 +124,14 @@ public class GraphicsBenchmark implements FrameListener, KeyboardInputHandler { double durationSeconds = elapsed / 1000.0; results.add(new TestResult(currentTest.getName(), frameCount, durationSeconds)); - currentTest.teardown(shapes); + // Defer test transition to safe point (beginning of next frame) + pendingTestTransition = true; + } + + private void performTestTransition() { + if (currentTest != null) { + currentTest.teardown(shapes); + } startNextTest(); } @@ -169,12 +178,23 @@ public class GraphicsBenchmark implements FrameListener, KeyboardInputHandler { @Override public boolean onFrame(ViewPanel viewPanel, int millisecondsSinceLastFrame) { + // Perform deferred test transition at safe point (before render cycle starts) + if (pendingTestTransition) { + pendingTestTransition = false; + performTestTransition(); + } + + // Deferred first-test start: runs on the render thread, before renderFrame() + if (currentTest == null && !benchmarkFinished && results.isEmpty()) { + startNextTest(); + } + if (benchmarkFinished) { return false; } if (currentTest == null) { - return true; + return false; } orbitAngle += ORBIT_SPEED * millisecondsSinceLastFrame; diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/galaxy_demo/PointCloudDemo.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/galaxy_demo/PointCloudDemo.java index bc9f227..02d3c3e 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/examples/galaxy_demo/PointCloudDemo.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/examples/galaxy_demo/PointCloudDemo.java @@ -33,5 +33,8 @@ public class PointCloudDemo { // add galaxy geometryCollection.addShape(new Galaxy(500, 3, 10000, transform)); + // Ensure the render thread is started + viewFrame.getViewPanel().ensureRenderThreadStarted(); + } } diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Main.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Main.java index 86ac7f1..fd8398b 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Main.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Main.java @@ -87,6 +87,9 @@ public class Main extends WorldNavigationUserInputTracker { // Done! World is built. So ensure screen is updated too. viewPanel.repaintDuringNextViewUpdate(); + + // Ensure the render thread is started + viewPanel.ensureRenderThreadStarted(); } /**