Performance-Messung des Frame-Zeichnens

Hallo,

ich möchte wie der Titel schon sagt messen welche Zeit zwischen dem Auftrag zum Zeichenen einer Komponente oder ähnlichem und dem tatsächlichem Erscheinen auf dem Bildschirm vergeht:

Ich speichere die Zeit, gebe dann den Zeichenauftrag (z.B. drawLine()) und rufe dann repaint() auf. Diese Methode heißt benchmarkGraphics(). Am Ende der repaint()-Methode meines Frames wird dann erneut die Zeit geholt und die Differenz berechnet. Soweit funktioniert das auch ganz gut. Weil ich aber einen möglichst genauen Mittelwert für die Zeit haben will, soll das ganze nicht einmal, sondern zum Beispiel 10000mal durchgeführt werden. Der erste Versuch mit den oben beschriebenen Code-Block in eine Schleife zu setzen, funktioniert logischerweise nicht, da dann ja der Thread, der den Frame neu zeichnen soll, bis zum Ende der Schleife blockiert ist. Der Frame bleibt also leer und wird erst am Ende gezeichnet. Dann habe ich versucht, das Problem mit einem rekursiven Methodenaufruf zu lösen: Am Ende der paint()-Methode des Frames wird benchmarkGraphics erneut aufgerufenbis eine bestimmte Anzahl Durchläufe vorbei ist. Dies erzielt und allerdings das gleiche Ergebnis und ergibt außerdem noch eine StackOverFlowException.

Hat irgendjemand eine Idee, wie ich das Problem relativ einfach lösen kann.

Vielen Dank schon mal

jojo

Vorneweg: Das könnte schwierig werden.

Es ist nicht klar, wo du die Zeit misst. Der Beschreibung nach könnte es auch

long before = System.nanoTime();
for (int i=0; i<1000; i++) component.repaint();
long after = System.nanoTime();

sein, aber das würde natürlich keinen Sinn machen: repaint() sagt nur: „Zeiche bei Gelegenheit mal neu“, aber das eigentliche Zeichnen ist entkoppelt davon. Außerdem werden mehrere schnell hintereinaderfolgende Aufrufe von ‚repaint()‘ zusammengefasst, so dass z.B. bei 100 Aufrufen von ‚repaint()‘ nur 10 mal wirklich neu gezeichnet wird.

Das einzig potentiell sinnvolle könnte sowas sein wie

@Override
protected void paintComponent(Graphics g)
{
    long before = System.nanoTime();
    super.paintComponent(g);
    long after = System.nanoTime();
    ...
}

in der „obersten“ Klasse der Zeichenhierarchie. (Wenn man das in einem JFrame machen wollte, müßte man das in paint() reinbasteln, aber … in einem JFrame wird eigentlich nichts gezeichnet, was messbar viel Zeit erfordern würde. Deswegen würde man diese Zeitmessung wohl in einer von JPanel abgeleiteten Klasse einfügen, das die einzige JComponent ist, die in der ContentPane eines Frames liegt, und die ALLE Components enthält, die irgendwelche eigenen painting-Operationen (wie etwa g.drawLine(…)) durchführen).

Um das ganze dann für mehrere Durchläufe zu testen, könnte man ganz pragmatisch sowas machen wie

class BenchmarkingPanel extends JPanel
{
    private long sumNS = 0; 
    private int inverval = 10000;
    private int frameCounter = 0;

    @Override
    protected void paintComponent(Graphics g)
    {
        long before = System.nanoTime();
        super.paintComponent(g);
        Toolkit.getDefaultToolkit().sync(); // Siehe "Erklärung" unten im Text
        long after = System.nanoTime();

        sumNS += (after-before);
        frameCounter++;
        if (frameCounter == interval)
        {
            double avgMS = sumNS / interval / 1e6;
            System.out.println("Average ms: "+avgMS);
            sumNS = 0;
            frameCounter = 0;
        }

    }
}

Und dann dafür sorgen, dass 10000 mal neu gezeichnet wird (wie auch immer man das macht, weil bei 10000 repaint()-Aufrufen ja vielleicht nur 10mal oder 100mal neu gezeichnet wird ;))

Zu dem
Toolkit.getDefaultToolkit().sync();
Ich habe es noch nie benutzt, und wohl auch nie gebraucht, und bin nicht ganz sicher, was es macht, aber glaube, dass man es hier zumindest der Vollständigkeit halber einfügen sollte :wink: Das auch zu der allgemeinen Aussage: Das könnte schwierig werden. Java/Swing abstrahiert schon sehr stark vom eigentlichen Zeichensystem. Das ist gut so, weil nur damit so herrlich einfache, praktische Klassen wie Graphics2D möglich sind, und nur so Plattformunabhängigkeit erreicht werden kann. Aber es hat auch zur Folge, dass die Frage, wann wie viele Pixel in den Grafikkartenspeicher geschrieben werden, schwierig zu beantworten sein kann.

Je nachdem, was das eigentliche Ziel ist, könnte ein Profilerlauf vielleicht sinnvoll sein. Oder sich mal mit Dingen wie „active Rendering“ befassen, weil man damit vielleicht, stark vereinfacht gesagt, mehr Kontrolle darüber hat, WANN genau WAS „zum Bildschirm geschickt“ wird.

vom ‚Erscheinen auf dem Bildschirm‘ sind strenggenommen auch die paint-Ausführungen unabhängig,
wobei Swing wohl eher nicht in Verdacht hoher FPS steht, seltenes painten kommt sicherlich ‚zeitnah‘ am Monitor an,

wenn es nur um die paint-Aufrufe geht, könnte man auf auf einem BufferedImage üben,
besser zu messen, keine Problem wie repaint() ohne paint,
aber ich weiß gerade nicht ob sich das in der Performance vom richtigen paint unterscheidet,
könnte schneller oder auch langsamer sein durch die Umstände, Pixel in einem BufferedImage ablegen,
oder schlicht (nahezu) gleich, ich weiß es eben nicht :wink:

wenn man nur vergleichen will ‚was geht schneller, erst 1000 Kreise malen, dann noch 5 Rechtecke, oder …‘
dann mögen die absoluten Zahlen auch egal sein,
nur der Vergleich zwischen Variante A und B, Unterschied in %, wichtig

Ich hatte es so probiert:

...
public void paint(Graphics g){
super.paint(g);
timer.stop();
}
public void benchmarkGraphics(){
timer.start();
getGraphics.drawLine(...);
repaint();
}

@Marco13 : ich werde deinen Vorschlag mal probieren, sage dann Bescheid ob es funktioniert.

@SlaterB : Wenn ich dich richtig verstanden habe, meinst du, dass es einfache wäre, die Zeit zu messen um in ein BufferedImage zu zeichnen als auf den Bildschirm?

[QUOTE=SlaterB]vom ‚Erscheinen auf dem Bildschirm‘ sind strenggenommen auch die paint-Ausführungen unabhängig,
[/quote]

Meiner unfundiert-spekulativen Interpretation nach soll das Toolkit#sync ja genau diese „Unabhängigkeit“ aufheben, aber… es ist schwierig.

[QUOTE=SlaterB;28922]
wenn es nur um die paint-Aufrufe geht, könnte man auf auf einem BufferedImage üben,

nur der Vergleich zwischen Variante A und B, Unterschied in %, wichtig[/QUOTE]

Das mit dem BufferedImage hatte ich auch kurz in Betracht gezogen, aber es könnte aus 2 Gründen ungünstig sein:

  1. Die Daten in das BufferedImage zu legen könnte (!) u.U. was GANZ anderes sein, als sie „in den Bildschirmspeicher“ zu legen. Schon die verschiedenen Types, TYPE_INT_ARGB, TYPE_3BYTE_RGB, … machen da einen gewaltigen Unterschied, und indirekt damit verbunden ist auch …:
  2. Man weiß nicht, was ‚Graphics‘ ist. Selbst wenn es nur um prozentuale Unterschiede geht. Es ist nicht sichergestellt, dass das die Implementierung von ‚Graphics‘, die man in der paintComponent übergeben bekommt, sich gleich oder auch nur ähnlich verhält, wie das ‚Graphics‘, das man sich von einem BufferedImage abholen kann. Für das, das auf den Bildschirm zeichnet, hatte ich da mal im Sun-OpenJDK-Quellcode gewühlt: Da werden für die unterschiedlichen „Dinge“, die gezeichnet werden, unterschiedliche sogenannte „Pipes“ verwendet, und das Graphics selbst ist aus unterschiedlichen Pipes zusammengebaut (ganz grob sowas wie „TextPipe“, „ImagePipe“, „ShapePipe“, ggf. auch DA schon mit unterschiedlichen Implemementierungen, je nachdem, ob z.B. Antialiasing eingeschaltet ist oder nicht…). Es könnte also theoretisch (!) sein, dass das Bildschrim-Graphics eine „ShapePipe“ hat, die für das Zeichnen eines Kreises 1ms und für das Zeichnen eines Rechtecks 5ms braucht, während es beim Image-Graphics umgekehrt ist. (Natürlich nur grob gesagt, zur Verdeutlichung…)

(Disclaimer: Bei all dem ist viel Spekulation im Spiel - man braucht sich ja zum Glück meistens keine Gedanken darüber zu machen, und wenn ich durch das, was ich bisher so im (teilweise nativen) OpenJDK-Code gesehen habe, etwas gelernt habe, dann dass ich froh bin, mir darüber meistens keine Gedanken machen zu müssen :wink: )

[QUOTE=Marco13]Meiner unfundiert-spekulativen Interpretation nach soll das Toolkit#sync ja genau diese „Unabhängigkeit“ aufheben, aber… es ist schwierig.
[/quote]
ah, dafür das sync(), diese Erklärung hast du davor glaube ich vergessen :wink: trotz manchem Text,
steht aber auch mehr oder weniger in der API

Das mit dem BufferedImage hatte ich auch kurz in Betracht gezogen, aber es könnte aus 2 Gründen ungünstig sein:

sag ich doch, ungewisse Alternative,
mit Erklärung natürlich besser

[QUOTE=jojo;28931]

@SlaterB : Wenn ich dich richtig verstanden habe, meinst du, dass es einfache wäre, die Zeit zu messen um in ein BufferedImage zu zeichnen als auf den Bildschirm?[/QUOTE]

so isses,
also das ist was ich sage, muss nicht unbedingt so sein (einfacher)

Ich habe jetzt mal die Lösung von Marco ausprobiert: Es sieht meiner Meinung ganz gut aus, gibt allerdings zwei Probleme/Fragen:

  1. Wie Marco schon angemerkt hat, soll die paintComponent()-Methode genau 10000-mal aufgerufen werden. Wenn ich in einer Schleife 10000 mal repaint() aufrufe, wird sie maximal 5000mal aufgerufen).
  2. Die Anzeige im Panel flackert stark. Woran liegt das?

Hier mal der Code:


import java.awt.Graphics;
import java.awt.Toolkit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 *
 * @author Jojo
 */
public class BenchmarkPanel extends JPanel{
    long[]dauer=new long[10000];
    public BenchmarkPanel(){
        super();
        setSize(1000,1000);
    }
    @Override
    protected void paintComponent(Graphics g)
    {
        
        long before = System.nanoTime();
        super.paintComponent(g);
        Toolkit.getDefaultToolkit().sync(); // Siehe "Erklärung" unten im Text
        long after = System.nanoTime();
        System.out.println(after-before);
        
 
    }
    public static void main(String[]args){
        JFrame jf=new JFrame();
        jf.setSize(1000,1000);
        jf.setVisible(true);
        BenchmarkPanel bp=new BenchmarkPanel();
        jf.add(bp);
        for(int a=0;a<10000;a++){
            bp.getGraphics().drawLine(100,100,700,900);
            bp.repaint();
            jf.repaint();
        }
        System.exit(0);
    }
}```
Ich weiß ist kein besonders schöner Code, ich habe ihn aber auch nur mal schnell zum Testen geschrieben. Wenn es funktioniert verbesser ich den noch.;)

wiederhole so lange bis frameCounter bei 10.000 steht?

Flackern bei Swing ist ein Grundthema, zu dem man manches findet, vielleicht reicht schon

was setzt du denn als Zeichnung ein, welche Komponenten, welchen Code (edit: inzwischen mit dabei)

edit:
getGraphics() geht natürlich überhaupt nicht, wunderte mich schon am Anfang bei der Reihenfolge
“Ich speichere die Zeit, gebe dann den Zeichenauftrag (z.B. drawLine()) und rufe dann repaint() auf.”
aber das hatte sich ja zwischenzeitlich eh gewandelt,

erstmal muss sauberes Zeichnen gelernt sein, nur in überschriebener paintComponent(), nie getGraphics()

In dem Code zwischendrin hattest du “getGraphics” drin, aber ich nehme an/hoffe, das ist jetzt raus.

Ansonsten, das Flackern… schwer zu sagen… wenn auf einem LCD-Bildschirm mit 60Hz in einer Sekunde >60mal gezeichnet werden soll, kommt zwangsläufig irgendwas nicht-sinnvolles raus. Man könnte jetzt nochmal auf Active Rendering verweisen (alles, was mit http://docs.oracle.com/javase/6/docs/api/java/awt/image/BufferStrategy.html zu tun hat, habe aber selbst noch nicht wirklich damit gearbeitet), und schon fast “Hardwarenahe” Dinge wie VSync, was man ggf. irgendwo in der Systemsteuerung/Grafiktreibereinstellungen einschalten kann. Man könnte auch erwähnen, dass es bei dieser Art der Messung eigentlich nicht notwendig ist, “möglichst schnell hintereinander” zu zeichnen - auch wenn z.B. 10000 mal jede Sekunde neu gezeichnet wird, sollten theoretisch (!) die gleichen Ergebnisse rauskommen, wie wenn man die 10000 paint-Durchläufe in 5 Sekunden runterrattert.

Insgesamt klingt das aber alles etwas schwammig-diffus - WAS ist denn das eigentliche Ziel?

jetzt verstehe ich gar nichts mehr…
habe das mit dem Zeichnen so geändert wie Slater meinte,oder:

    protected void paintComponent(Graphics g)
    {
        
        long before = System.nanoTime();
        g.drawLine(100,100,700,900);
        super.paintComponent(g);
        Toolkit.getDefaultToolkit().sync(); // Siehe "Erklärung" unten im Text
        long after = System.nanoTime();
        System.out.println(after-before);
        
 
    }
    public static void main(String[]args){
        JFrame jf=new JFrame();
        jf.setSize(1000,1000);
        jf.setVisible(true);
        BenchmarkPanel bp=new BenchmarkPanel();
        jf.add(bp);
        for(int a=0;a<10000;a++){
            bp.repaint();
        }
        
    }```
jetzt erscheint allerdings gar nichts mehr im frame/panel

Das mit dem Flackern ist jetzt erst mal nebensächlich.

 @Marc o: Das eigentliche Ziel: Ich schreibe einen Benchmark für Java in verschiedenen Teilgebieten (u.a. IO,... und eben zeichnen). Später kommt der selbe Benchmark in C# und dann wird verglichen...

es gibt so viele Tutorials, auch hier im Wiki zum Forum
http://wiki.byte-welt.net/wiki/Malen_in_AWT_und_Swing
(Swing etwas weiter unten)

wozu ohne Tutorial, ohne Anleitung, ohne Beispiele überhaupt in Swing malen?
der super-Aufruf löscht alles, malt mit Hintergrundfarbe, eigene Befehle müssen natürlich dahinter stehen…, nicht davor…


für Stress-häufiges Malen, für Flackern evtl. auf den super-Aufruf verzichten,
das dürfte bei dir das Flackern komplett vermeiden, allerdings bei Bewegung schwierig, vorheriges zu löschen…

oje, auf so wackligen Stand,
allein in Java kann man je nach Optimierung (wie super-Aufruf weglassen) weit unterschiedliche Ergebnisse erhalten, was mag das aussagen

Dummer Fehler.:wut:

Stand gerade irgendwie total auf dem Schlauch.
Jetzt funktionierts auch wieder.

Allerdings bleibt immer noch das Problem, dass trotz 10000 Aufrufen der repaint()-Methode nur ca. 50 mal paintComponent() aufgerufen wird. Gibts dafür irgendeine Lösung? (Außer öfter aufrufem;)

mache eine gewisse Pause zwischen den Aufrufen, Thread.sleep()
oder richte dich wie gesagt nach dem Counter, sofern du einen hast, ich sehe gerade keinen

solange wiederholen bis 10.000, oder den nächsten Aufruf generell erst wenn counter von paintComponent um 1 erhöht wurde

Ja, den Code hatte ich bei meiner letzten Antwort auch noch nicht gesehen. Habe jetzt auch mal was gebastelt, zum Testen, und aus Neugier, aber das ist ziemlich fragwürdig, deswegen im Spoiler:

HÖCHST fragwürdiger ‚‚Benchmark‘‘
[spoiler]

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.Toolkit;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

class BenchmarkPanel extends JPanel
{
    private long sumNS = 0;
    private int interval = 100;
    private int frameCounter = 0;

    BenchmarkPanel(JComponent benchmarkedComponent)
    {
        super(new GridLayout(1, 1));
        add(benchmarkedComponent);
    }

    @Override
    public void paint(Graphics g)
    {
        long before = System.nanoTime();
        super.paint(g);
        Toolkit.getDefaultToolkit().sync();
        long after = System.nanoTime();

        sumNS += (after - before);
        frameCounter++;
        if (frameCounter == interval)
        {
            double avgMS = sumNS / interval / 1e6;
            System.out.println("Average ms: " + avgMS);
            sumNS = 0;
            frameCounter = 0;
        }
        else if (frameCounter % 10 == 0)
        {
            System.out.println("Repainted "+frameCounter+" times");
        }
        
        // Trigger a repaint when painting is finished.
        // Usually, this should NOT be done!!!
        // But this is a benchmark.
        repaint();

    }
}

class TestedPanel extends JPanel
{
    @Override
    protected void paintComponent(Graphics gr)
    {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D) gr;

        int stepSize = 5;
        boolean antiAlias = false;
        //antiAlias = true;
        if (antiAlias)
        {
            stepSize = 50;
            g.setRenderingHint(
                RenderingHints.KEY_ANTIALIASING, 
                RenderingHints.VALUE_ANTIALIAS_ON);
        }
        
        int w = getWidth();
        int h = getHeight();
        g.setColor(Color.RED);
        for (int x = 0; x < 1000; x += stepSize)
        {
            for (int y = 0; y < 1000; y += stepSize)
            {
                g.drawLine(x, y, w - x, h - y);
            }
        }
    }
}

public class BenchmarkPanelTest
{
    public static void main(String[] args)
    {

        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame f=new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        final TestedPanel testedPanel = new TestedPanel();
        final BenchmarkPanel benchmarkPanel = 
            new BenchmarkPanel(testedPanel);
        f.getContentPane().add(benchmarkPanel);
        
        f.setSize(1000,1000);
        f.setVisible(true);
    }
}

[/spoiler]

Die Art und Weise, wie dort das „repaint-Problem“ gelöst ist, sollte NICHT auf andere Anwendungen übertragen werden, und ist NUR für den Benchmark so gemacht (er schickt ihn quasi in eine „Endlosschleife“, wo er theoretisch „so oft wie möglich“ neu zeichnet).

Die Ergebnisse scheinen im ersten Moment einigermaßen konsistent, aber wenn man mal
//antiAlias = true;
EINkommentiert, sieht man, dass da irgendwas nicht stimmen kann: Er braucht für das Neuzeichnen offensichtlich VIEL länger, als die gemessene Zeit.

Ich glaube, dass ein derartiger Benchmark kaum sinnvoll sein kann. Insbesondere, wenn dort die Zeit gemessen werden soll, die benötigt wird, um EINE Linie zu zeichnen :wink: Aber auch wenn man (wie bei meinem Code durch Erweiterung der TestedPanel-Klasse leicht möglich) mehrere unterschiedliche Dinge zeichnet (Bilder, Shapes…).

Man könnte/sollte wirklich nochmal probieren, ob man mit Active Rendering + BufferStrategy da was sinnvolleres hinkriegt, aber… im Moment erscheint mir das Ziel etwas seltsam: Als allgemeiner Vergleich der Geschwidigkeit von C# und Java kann das nicht herhalten. Als Vergleich der reinen Zeichengeschwindigkeit ist das auch nicht unbedingt sinnvoll. Bei Java kann man z.B. explizit ein/ausschalten, ob für das Zeichnen OpenGL, DirectX oder irgendwas anderes verwendet werden soll, und diese Fragen, zusammen mit vielen anderen Fragen (allen voran der, WAS denn überhaupt gezeichnet wird) hätte vermutlich mehr Einfluß auf das „Ergebnis“, als die Wahl der Sprache an sich.

Das hat zwar den Vorteil, dass man durch geeignete Wahl der Parameter das Benchmarkergebnis erreichen kann, das man haben will (bei dem also die Lieblingssprache besser abschneidet), aber die Aussagekraft wäre eben nichts, was genau darüber hinausgeht.

Es ist ja allgemein bekannt: Es gibt die Wahrheit - und es gibt Benchmarks :wink:

Moin,

[ot] Imho ist FCAT von Nvidia das derzeit einzige System das halbwegs realistische Werte messen kann. Dabei werden die einzelnen Frames farblich markiert und von einem zweiten Rechner per DVI-Capture analysiert. Leider ist die dazu notwendige Hartware nicht günstig, so das man als Hobbybastler auf Schätzeisen wie System.nanoTime(); (oder dem GL Timer Query) angewiesen bleibt. Aber damit kann man eben immer nur die vorderen Teile der Pipline abschätzen. [/ot]

Viele Grüße
Fancy

Das mit den genau 10000 Aufrufen funktioniert jetzt, indem ich mit Thread.sleep zwischen den Aufrufen Zeit lasse.

Also wie lange ein Frame fürs Zeichnen benötigt, kann man afaik nur auf eine Art genau berechnen:


import javax.swing.JFrame;
import javax.swing.JPanel;

public class FPS_Counter extends JPanel {
	private static final long serialVersionUID = 1L;

	private long frame, time;
	private double fps, frameTime;

	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		long t = System.nanoTime();
		long delta = t - time;
		frame++;
		if (delta >= 250000000) {
			fps = frame * 1000000000.0 / delta;
			frameTime = 1000000.0 / fps;
			time = t;
			frame = 0;
		}
		// paintstuff goes here
		String ff = String.format("@%1.3ffps", fps);
		String ft = String.format("frameTime: %1.3fus", frameTime);
		g.drawString(ff, 0, 20);
		g.drawString(ft, 0, 40);
	}

	public static void main(String[] args) {
		final JFrame f = new JFrame();
		f.add(new FPS_Counter());
		Thread anim = new Thread() {
			@Override
			public void run() {
				while(true) {
					f.repaint();
				}
			}
		};
		Toolkit.getDefaultToolkit().sync(); // siehe Anmerkung
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.pack();
		f.setVisible(true);
		anim.start();
	}
}```Bei dem Programm kann man deutlich erkennen, dass für jedes "repaint()" definitiv ein "paintComponent()"-Aufruf stattfindet, sonst wäre die Framerate niemals höher als jene vom Monitor (Wert "frame" würde nicht so oft inkrementiert werden). Um die Genauigkeit des FPS_Counters zu testen, könnt ihr ja mal die Werte von z.B. Fraps zusätzlich in dem Fenster anzeigen lassen.

Anmerkung: Sync ist, wie Marco13 schon vermutete die vertikale Synchronisierung des Monitors mit dem Framebuffer der Grafikkarte und hat mit Java relativ wenig zu tun, sondern eigentlich nur mt dem Treiber der Grafikkarte. Es sorgt dafür, dass nur programmtechnisch fertig gerenderte Frames im Framebuffer (so ne Art Ringspeicher) an den Monitor weitergegeben werden. Bei FPS, die über der Bildwiderholrate des Screens liegen zeichnet das Programm fröhlich Frame nach Frame in den BackBuffer, bis "der Monitor" (eigentlich der Chip auf der GK, der die Signale erzeugt) den FrontBuffer wieder freigibt. Sind die FPS unterhalb dieser Widerholrate, wird solange der FrontBuffer erneut an den Monitor geschickt, bis der BackBuffer komplett gezeichnet wurde. Ohne diese Synchronisation würde man teilweise vertikale "Bruchkanten" (im 3D-Bereich sogar sog. Artefakte) im Bild erkennen, je nachdem, wie dynamisch die Bewegung gerade ist.

Edit: :o Hab' auf die schnelle vergessen, dem Panel 'ne grösse zu verpassen... einfach bissl grösser ziehen, bis man was sieht.

Zu euren Bedenken bezüglich des Sinnes eines solchen Tests: Ich mache das ganze nicht nur für mich, sondern als Thema einer Seminararbeit/Facharbeit. Der Lehrer der das später korrigiert ist eigentlich sowieso Physiklehrer und hat von Informatik daher nur eingeschränkt Ahnung. Folglich ist es nicht unbedint notwendig 1000% korrekte Ergebnisse zu erzielen. Wichtiger ist das überhaupt ein Ergebnis herauskommt, das auf den ersten Blick professionell aussieht. :wink:
Dafür reicht das was ich dank eurer Hilfe jetzt habe vollkommen aus.

Vielen Dank für die Hilfe

jojo

EDIT: Wenn hier noch relativ einfache Lösungen auftauchen, die ein besseres Ergebnis liefern, werde ich sie mir natürlich trotzdem anschauen.

[QUOTE=Spacerat]Bei dem Programm kann man deutlich erkennen, dass für jedes “repaint()” definitiv ein “paintComponent()”-Aufruf stattfindet, sonst wäre die Framerate niemals höher als jene vom Monitor (Wert “frame” würde nicht so oft inkrementiert werden). Um die Genauigkeit des FPS_Counters zu testen, könnt ihr ja mal die Werte von z.B. Fraps zusätzlich in dem Fenster anzeigen lassen.
[/QUOTE]
‘definitiv’ ist ja eine definitive Aussage,
bei mir sieht es so aus:

FPS unter 3000, das Delta steht für 0.25 sec, darin im Schnitt um die 700 Frames,
ich lasse die while Schleife bis 40x Delta-Erreichen, 40x Aktualisieren laufen,

macht in 10 sec ca. 27.000 paints,
und wie oft lief die Schleife dabei? über 10 Mio. Mal…

nur weil Java viele paints schafft, heißt das nicht dass nicht noch viel mehr repaints

[QUOTE=SlaterB]nur weil Java viele paints schafft, heißt das nicht dass nicht noch viel mehr repaints[/QUOTE]Okay, daran hatte ich noch gar nicht gedacht und die Berechnung mal eben im Thread ausgeführt. Und tatsächlich… “repaint()” wird noch viel viel öfters ausgeführt. Aber wieso? Wär’s nicht sinnvoller, wenn “repaint()” dort 'ne Weile blockt?