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;
/**
* 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.
*
* <p>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.</p>
* @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 =
+ "<html><div style='width:400px; font-family: sans-serif;'>" +
+ "<h2>Graphics Benchmark</h2>" +
+ "<p>This will run a series of performance tests.</p>" +
+ "<ul>" +
+ "<li>Each test runs for 30 seconds</li>" +
+ "<li>Press <b>SPACE</b> to skip any test<br>" +
+ "<span style='color: gray;'>(skipping reduces measurement precision)</span></li>" +
+ "<li>A summary will be shown at the end</li>" +
+ "</ul>" +
+ "</div></html>";
+
+ 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() {
viewPanel.addFrameListener(this);
viewPanel.getKeyboardFocusStack().pushFocusOwner(this);
camera = viewPanel.getCamera();
- // Now explicitly start the render thread after all listeners are registered
viewPanel.ensureRenderThreadStarted();
}
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;
}
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() {
@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();
}