From: Svjatoslav Agejenko Date: Sun, 15 Mar 2026 22:51:56 +0000 (+0200) Subject: feat(benchmark): show results in dialog with copy-to-clipboard X-Git-Url: http://www2.svjatoslav.eu/gitweb/?a=commitdiff_plain;h=af1e163ef49747d441678673c0d3ab9f2aab720e;p=sixth-3d-demos.git feat(benchmark): show results in dialog with copy-to-clipboard - Add intro dialog with instructions before benchmark starts - Display results in scrollable dialog instead of console - Add Copy to Clipboard button for easy sharing - Show system info and FPS results in formatted text --- 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 96a50dc..1f9728a 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 @@ -13,7 +13,9 @@ import eu.svjatoslav.sixth.e3d.gui.ViewPanel; import eu.svjatoslav.sixth.e3d.gui.humaninput.KeyboardInputHandler; import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection; -import javax.swing.SwingUtilities; +import javax.swing.*; +import java.awt.*; +import java.awt.datatransfer.StringSelection; import java.awt.event.KeyEvent; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -22,8 +24,8 @@ import java.util.List; /** * Automated graphics benchmark that tests the engine's rendering performance. - * Runs multiple tests sequentially, each for a fixed duration, and outputs - * reproducible benchmark results to standard output. + * Runs multiple tests sequentially, each for a fixed duration, and displays + * results in a dialog with copy-to-clipboard functionality. * *

The benchmark creates a 16x16x16 grid of cubes (4096 total) with the camera * following a deterministic orbital path. Each test runs for 30 seconds by default.

@@ -68,15 +70,43 @@ public class GraphicsBenchmark implements FrameListener, KeyboardInputHandler { * @param args command line arguments (ignored) */ public static void main(String[] args) { - new GraphicsBenchmark(); + SwingUtilities.invokeLater(() -> { + if (showIntroDialog()) { + new GraphicsBenchmark(); + } + }); } -/** + private static boolean showIntroDialog() { + String message = + "
" + + "

Graphics Benchmark

" + + "

This will run a series of performance tests.

" + + "" + + "
"; + + int choice = JOptionPane.showConfirmDialog( + null, + message, + "Graphics Benchmark", + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.INFORMATION_MESSAGE + ); + + return choice == JOptionPane.OK_OPTION; + } + + /** * Constructs and runs the graphics benchmark. */ public GraphicsBenchmark() { - registerTests(); // populate tests FIRST, before render thread starts - initializeWindow(); // now onFrame can safely access the tests list + registerTests(); + initializeWindow(); } private void initializeWindow() { @@ -87,7 +117,6 @@ 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(); } @@ -124,7 +153,6 @@ public class GraphicsBenchmark implements FrameListener, KeyboardInputHandler { double durationSeconds = elapsed / 1000.0; results.add(new TestResult(currentTest.getName(), frameCount, durationSeconds)); - // Defer test transition to safe point (beginning of next frame) pendingTestTransition = true; } @@ -146,39 +174,89 @@ public class GraphicsBenchmark implements FrameListener, KeyboardInputHandler { viewPanel.removeFrameListener(this); viewPanel.stop(); viewFrame.dispose(); - printResults(); + + showResultsDialog(); } - private void printResults() { + private String formatResults() { + StringBuilder sb = new StringBuilder(); String separator = "================================================================================"; String thinSeparator = "--------------------------------------------------------------------------------"; Runtime runtime = Runtime.getRuntime(); - System.out.println(separator); - System.out.println(" GRAPHICS BENCHMARK RESULTS"); - System.out.println(separator); - System.out.println("Date: " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); - System.out.println("Resolution: " + WINDOW_WIDTH + "x" + WINDOW_HEIGHT); - System.out.println("Cubes: " + (GRID_SIZE * GRID_SIZE * GRID_SIZE) + " (" + GRID_SIZE + "x" + GRID_SIZE + "x" + GRID_SIZE + " grid)"); - System.out.println("Duration: " + (TEST_DURATION_MS / 1000) + " seconds per test"); - System.out.println(); - System.out.println(thinSeparator); - System.out.println("SYSTEM INFORMATION"); - System.out.println(thinSeparator); - System.out.println("CPU Name: " + getCpuName()); - System.out.println("Arch: " + System.getProperty("os.arch")); - System.out.println("Cores: " + runtime.availableProcessors()); - System.out.println(); - System.out.println(thinSeparator); - System.out.printf("%-28s %s%n", "Test", "Avg FPS"); - System.out.println(thinSeparator); + sb.append(separator).append("\n"); + sb.append(" GRAPHICS BENCHMARK RESULTS\n"); + sb.append(separator).append("\n"); + sb.append("Date: ").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("\n"); + sb.append("Resolution: ").append(WINDOW_WIDTH).append("x").append(WINDOW_HEIGHT).append("\n"); + sb.append("Cubes: ").append(GRID_SIZE * GRID_SIZE * GRID_SIZE) + .append(" (").append(GRID_SIZE).append("x").append(GRID_SIZE).append("x").append(GRID_SIZE).append(" grid)\n"); + sb.append("Duration: ").append(TEST_DURATION_MS / 1000).append(" seconds per test\n"); + sb.append("\n"); + sb.append(thinSeparator).append("\n"); + sb.append("SYSTEM INFORMATION\n"); + sb.append(thinSeparator).append("\n"); + sb.append("CPU Name: ").append(getCpuName()).append("\n"); + sb.append("Arch: ").append(System.getProperty("os.arch")).append("\n"); + sb.append("Cores: ").append(runtime.availableProcessors()).append("\n"); + sb.append("\n"); + sb.append(thinSeparator).append("\n"); + sb.append(String.format("%-28s %s%n", "Test", "Avg FPS")); + sb.append(thinSeparator).append("\n"); for (TestResult result : results) { - System.out.printf("%-28s %.2f%n", result.testName, result.averageFps); + sb.append(String.format("%-28s %.2f%n", result.testName, result.averageFps)); } - System.out.println(separator); + sb.append(separator).append("\n"); + + return sb.toString(); + } + + private void showResultsDialog() { + String resultsText = formatResults(); + + JTextArea textArea = new JTextArea(resultsText); + textArea.setEditable(false); + textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 13)); + textArea.setCaretPosition(0); + + JScrollPane scrollPane = new JScrollPane(textArea); + scrollPane.setPreferredSize(new Dimension(600, 400)); + + JButton copyButton = new JButton("Copy to Clipboard"); + JButton closeButton = new JButton("Close"); + + copyButton.addActionListener(e -> { + StringSelection selection = new StringSelection(resultsText); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null); + copyButton.setText("Copied!"); + copyButton.setEnabled(false); + }); + + closeButton.addActionListener(e -> { + Window window = SwingUtilities.getWindowAncestor(closeButton); + if (window != null) { + window.dispose(); + } + }); + + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + buttonPanel.add(copyButton); + buttonPanel.add(closeButton); + + JPanel panel = new JPanel(new BorderLayout(0, 10)); + panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + panel.add(scrollPane, BorderLayout.CENTER); + panel.add(buttonPanel, BorderLayout.SOUTH); + + JOptionPane.showMessageDialog( + null, + panel, + "Benchmark Results", + JOptionPane.PLAIN_MESSAGE + ); } private String getCpuName() { @@ -199,13 +277,11 @@ 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(); }