QPainter ab Qt 5.6.0 langsam

Alles rund um die Programmierung mit Qt
Antworten
mireiner
Beiträge: 8
Registriert: 20. September 2014 22:03

QPainter ab Qt 5.6.0 langsam

Beitrag von mireiner »

Hallo,

seit Qt 5.6.0 laufen die Grafikanimationen meines Qt Desktop Programms unter Windows 10 64 bit sehr langsam. Das gleiche Programm läuft unter Qt 5.4.2, Qt 5.5.0 und Qt 5.5.1 einwandfrei, unter Qt 5.6.0, Qt 5.6.1 und Qt 5.7.0 jedoch mindestens 100% langsamer. Egal ob der MinGW Compiler in 32bit oder der Microsoft Compiler in 32bit oder 64bit verwendet werden. Als IDE wird Qt Creator benutzt.

Die Grafik Animationen sind der einzige zeitkritische Programmteil. Gut möglich dass das Problem nur dort auffällt, aber an ganz anderer Stelle liegt.

Die Grafik Animation wird über QWidget mit QPainter mit ca. 100 x drawText() und 400 x drawLine() Funktionen realisiert, die über einen PushButton mit gedrückter Maustaste in Bewegung gesetzt und gehalten wird. Beim Pushbutton ist "autorepeat" aktiviert und "autorepeatinterval" = 0. Der gesammte Bildschirm wird also ca. alle 0.1 Sekunden neu gezeichnet.

Ein Verständnisproblem habe ich bei der Grafiktreiber Ansteuerung, da mir nicht klar ist womit mein Programm letztlich ausgeführt wird (ANGLE oder OpenGL?). Kann der Fehler eventuell damit zusammenhängen? Für Qt ist bislang keine Enviroment Variable gestetzt, auch in der Qt Project Datei (*.pro) wurden bei den Tests zwischen den verschiedenen Qt Versionen keine Änderungen vorgenommen (ein OpenGL Eintrag ist dort nicht). Grafikhardware ist eine alte ATI Radeon HD 3600 mit Directx 10.1.

Hat jemand eine Idee, warum das gleiche Programm, ab Qt 5.6.0 plötzlich so langsam läuft?
Volker75
Beiträge: 59
Registriert: 8. April 2009 21:04

Re: QPainter ab Qt 5.6.0 langsam

Beitrag von Volker75 »

hmm... gute Frage.

Also im Changelog von 5.6 steht u.a.:
Raster engine support for rendering internally with 16bits-per-color.

Hat sich da evtl. der Default Wert geändert?

Im Changelog von 5.7 steht u.a.:
Optimized the OpenGL function wrappers for speed and code size.

Evtl. haben sich da Fehler eingeschlichen?

Ich würde das einfach mal als Bugreport mit einem Minimalbeispiel-Code einreichen:
https://bugreports.qt.io/secure/Dashboard.jspa
mireiner
Beiträge: 8
Registriert: 20. September 2014 22:03

Re: QPainter ab Qt 5.6.0 langsam

Beitrag von mireiner »

Hallo Volker,

die Ursache habe ich nach langer Suche jetzt endlich gefunden - es ist womöglich tatsächlich ein Qt Bug, der sich ab Version 5.6.0 eingeschlichen hat.

Wird mehrfach hintereinander QPainter::drawText() mit QPainter::setFont(), d.h. mit wechselnden Fonts aufgerufen, dann bricht die Grafik Performance drastisch ein (wird 9x langsamer!).

Hier einmal ein extrem minimal Beispiel zum selber testen. Falls jemand das Beispiel ausprobiert (Qt 5.5.1 oder ältere Version im Vergleich zu Qt 5.6.0 oder neuere Version), wäre ich für eine Rückmeldung hier um Forum sehr dankbar, weil ich den Code bislang nur auf meinen Computer testen konnte:

Code: Alles auswählen

#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QElapsedTimer>

class Widget : public QWidget
{
public:
	Widget();

protected:
	void timerEvent(QTimerEvent *event);
	void paintEvent(QPaintEvent *);

private:
	QElapsedTimer elapsedTimer;
	int timerId;
	int elapsedTime1, elapsedTime2;
    bool isFinished1, isFinished2, isFinished3;
    int i, x1, x2, y1, y2;
};

Widget::Widget()
{
	setAutoFillBackground(true);
	setPalette(Qt::white);

	timerId = startTimer(1);
	elapsedTimer.start();

    i=0; x1=0; x2=0;
    isFinished1 = isFinished2 = isFinished3 = false;
}

void Widget::timerEvent(QTimerEvent* /* event */)
{
	update();
}

void Widget::paintEvent(QPaintEvent *)
{
	QPainter painter(this);

	if (i > 0 && i < 800)
	{
		y1 = 10;
		painter.setFont(QFont("Arial", 14.0));
		painter.drawText(x1, y1 += 30, "Test 1");
		painter.drawText(x1, y1 += 30, "row 01");
		painter.drawText(x1, y1 += 30, "row 02");
		painter.drawText(x1, y1 += 30, "row 03");
		painter.drawText(x1, y1 += 30, "row 04");
		painter.drawText(x1, y1 += 30, "row 05");
		painter.drawText(x1, y1 += 30, "row 06");
		painter.drawText(x1, y1 += 30, "row 07");
		painter.drawText(x1, y1 += 30, "row 08");
		painter.drawText(x1, y1 += 30, "row 09");
		painter.drawText(x1, y1 += 30, "row 10");
		painter.drawText(x1, y1 += 30, "row 11");
		painter.drawText(x1, y1 += 30, "row 12");
		x1++;
		
		elapsedTime1 = elapsedTimer.elapsed();
	}
	else if (i > 800 && i < 1600)
	{
      // 'With Qt 5.6.0 and later: 'Test2' is about 9 times slower than 'Test1' 
      // (45 seconds on my system)

      // 'With Qt 5.5.1 and earlier versions 'Test2' is same fast as 'Test1' 
      // (5 seconds on my system)

		isFinished1 = true;

		y2 = 300;
		painter.setFont(QFont("Arial", 14));
		painter.drawText(x2, y2 += 30, "Test 2");
		painter.setFont(QFont("Caladea", 14));
		painter.drawText(x2, y2 += 30, "row 01");
		painter.setFont(QFont("Tomaha", 14));
		painter.drawText(x2, y2 += 30, "row 02");
		painter.setFont(QFont("Consolas", 14));
		painter.drawText(x2, y2 += 30, "row 03");
		painter.setFont(QFont("Calibri", 14));
		painter.drawText(x2, y2 += 30, "row 04");
		painter.setFont(QFont("Impact", 14));
		painter.drawText(x2, y2 += 30, "row 05");
		painter.setFont(QFont("Courier New", 14));
		painter.drawText(x2, y2 += 30, "row 06");
		painter.setFont(QFont("Gorgia", 14));
		painter.drawText(x2, y2 += 30, "row 07");
		painter.setFont(QFont("Verdana", 14));
		painter.drawText(x2, y2 += 30, "row 08");
		painter.setFont(QFont("Times New Roman", 14));
		painter.drawText(x2, y2 += 30, "row 09");
		painter.setFont(QFont("Microsoft Sans Serif", 14));
		painter.drawText(x2, y2 += 30, "row 10");
		painter.setFont(QFont("Segoe UI", 14));
		painter.drawText(x2, y2 += 30, "row 11");
		painter.setFont(QFont("Trebuchet MS", 14));
		painter.drawText(x2, y2 += 30, "row 12");
		x2++;

		elapsedTime2 = elapsedTimer.elapsed();
	}
	else if (i > 1600)
	{
		isFinished2 = true;
	}
	i++;
	
	if (isFinished1)
	{
		painter.setFont(QFont("Arial", 12.0, QFont::Bold));
		painter.drawText(QPoint(200, 150), "'Test1' elapsed time in seconds: " + QString::number(elapsedTime1/1000.0));
	}
	if (isFinished2)
	{
        painter.drawText(QPoint(200, 430), "'Test2' elapsed time in seconds: " + QString::number((elapsedTime2-elapsedTime1)/1000.0));
		isFinished3 = true;
	}
	if (isFinished3)
	{
        painter.setFont(QFont("Arial", 11.0));
        painter.drawText(QPoint(200, 620), "On Windows Desktop with Qt 5.4.2, Qt 5.5.0 and Qt 5.5.1 Test1 and Test2 are both equally fast.");
        painter.drawText(QPoint(200, 650), "On Windows Desktop with Qt 5.6.0, Qt 5.6.1 and Qt 5.7.0 Test2 is approx 9 times slower than Test1 !");
        painter.drawText(QPoint(200, 680), "No matter if compiled with MinGW 32 bit or Microsoft Compiler 32 or 64 bit");
        killTimer(timerId);
	}
}

int main(int argc, char *argv[])
{
	QApplication app(argc, argv);
	Widget widget;
	widget.showMaximized();
	return app.exec();
}
Wie im Programm zu sehen handelt es sich dabei um eine schnelle Grafikanimation, d.h. die Schrift bewegt sich über den Bildschirm - so wie es auch im meinem vollständigen Programm der Fall ist. Deshalb ist es möglich, das der Fehler auch im Qt Speichermanagment liegen könnte, weil die Fonts in den Speicher geladen und danach ausgeführt werden.

Danke für den Link zum Qt Bugreport Volker. Den Bug habe ich dort jetzt gemeldet. Nachzulesen unter: https://bugreports.qt.io/browse/QTBUG-54180
Antworten