diff options
Diffstat (limited to 'tests/benchmarks/gui')
15 files changed, 1390 insertions, 5 deletions
diff --git a/tests/benchmarks/gui/graphicsview/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp b/tests/benchmarks/gui/graphicsview/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp index faacec4..01285d1 100644 --- a/tests/benchmarks/gui/graphicsview/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp +++ b/tests/benchmarks/gui/graphicsview/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the documentation of the Qt Toolkit. +** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage diff --git a/tests/benchmarks/gui/painting/painting.pro b/tests/benchmarks/gui/painting/painting.pro index 878567d..76c26c1 100644 --- a/tests/benchmarks/gui/painting/painting.pro +++ b/tests/benchmarks/gui/painting/painting.pro @@ -2,4 +2,6 @@ TEMPLATE = subdirs SUBDIRS = \ qpainter \ qregion \ - qtransform + qtransform \ + qtracebench \ + qtbench diff --git a/tests/benchmarks/gui/painting/qpainter/tst_qpainter.cpp b/tests/benchmarks/gui/painting/qpainter/tst_qpainter.cpp index 39b2244..d570bb3 100644 --- a/tests/benchmarks/gui/painting/qpainter/tst_qpainter.cpp +++ b/tests/benchmarks/gui/painting/qpainter/tst_qpainter.cpp @@ -1395,7 +1395,7 @@ void tst_QPainter::drawTransformedImageRoundedRect() } } -//code from QmlGraphicsRectangle for drawing rounded rects +//code from QDeclarativeRectangle for drawing rounded rects void tst_QPainter::drawBorderPixmapRoundedRect() { //setup image @@ -1446,7 +1446,7 @@ void tst_QPainter::drawScaledBorderPixmapRoundedRect_data() // QTest::newRow(QString(QLatin1String("scale=%1; imagetype=ARGB8565_Pre")).arg(i).toLatin1()) << i << (int)QImage::Format_ARGB8565_Premultiplied; } -//code from QmlGraphicsRectangle for drawing rounded rects +//code from QDeclarativeRectangle for drawing rounded rects void tst_QPainter::drawScaledBorderPixmapRoundedRect() { QFETCH(float, scale); @@ -1502,7 +1502,7 @@ void tst_QPainter::drawTransformedBorderPixmapRoundedRect_data() } -//code from QmlGraphicsRectangle for drawing rounded rects +//code from QDeclarativeRectangle for drawing rounded rects void tst_QPainter::drawTransformedBorderPixmapRoundedRect() { QFETCH(QTransform, transform); diff --git a/tests/benchmarks/gui/painting/qtbench/benchmarktests.h b/tests/benchmarks/gui/painting/qtbench/benchmarktests.h new file mode 100644 index 0000000..362d121 --- /dev/null +++ b/tests/benchmarks/gui/painting/qtbench/benchmarktests.h @@ -0,0 +1,841 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BENCHMARKTESTS_H +#define BENCHMARKTESTS_H + +#include <QApplication> +#include <QTextDocument> +#include <QDesktopWidget> +#include <QTextLayout> +#include <QFontMetrics> +#include <QDebug> + +#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) +# include <QStaticText> +#endif + +class Benchmark +{ +public: + virtual ~Benchmark() {} + + Benchmark(const QSize &size) + : m_size(size) + { + for (int i=0; i<16; ++i) { + m_colors[i] = QColor::fromRgbF((rand() % 4) / 3.0, + (rand() % 4) / 3.0, + (rand() % 4) / 3.0, + 1); + } + } + + virtual void draw(QPainter *p, const QRect &rect, int iteration) = 0; + virtual QString name() const = 0; + + inline const QSize &size() const + { + return m_size; + } + virtual void begin(QPainter *, int iterations = 1) { Q_UNUSED(iterations); } + virtual void end(QPainter *) { } + + inline const QColor &randomColor(int i) { return m_colors[i % 16]; } + +protected: + QColor m_colors[16]; + QSize m_size; +}; + +class PaintingRectAdjuster +{ +public: + PaintingRectAdjuster() + : m_benchmark(0), + m_bounds(), + m_screen_filled(false) + { + } + + const QRect &newPaintingRect() { + m_rect.translate(m_rect.width(), 0); + + if (m_rect.right() > m_bounds.width()) { + m_rect.moveLeft(m_bounds.left()); + m_rect.translate(0,m_rect.height()); + if (m_rect.bottom() > m_bounds.height()) { + m_screen_filled = true; + m_rect.moveTo(m_bounds.topLeft()); + } + } + return m_rect; + } + + inline bool isScreenFilled() const + { return m_screen_filled; } + + void reset(const QRect &bounds) + { + m_bounds = bounds; + m_rect.moveTo(m_bounds.topLeft()); + m_rect = QRect(m_bounds.topLeft(),m_benchmark->size()); + m_rect.translate(-m_rect.width(),0); + m_screen_filled = false; + } + + inline void setNewBenchmark( Benchmark *benchmark ) + { + m_benchmark = benchmark; + } + +protected: + Benchmark *m_benchmark; + QRect m_rect; + QRect m_bounds; + bool m_screen_filled; +}; + +class FillRectBenchmark : public Benchmark +{ +public: + FillRectBenchmark(int size) + : Benchmark(QSize(size, size)) + { + } + + virtual void draw(QPainter *p, const QRect &rect, int iterationCount) { + p->fillRect(rect, randomColor(iterationCount)); + } + + virtual QString name() const { + return QString::fromLatin1("fillRect(%1)").arg(m_size.width()); + } +}; + +class ImageFillRectBenchmark : public Benchmark +{ +public: + ImageFillRectBenchmark(int size) + : Benchmark(QSize(size, size)) + { + int s = rand() % 24 + 8; + m_content = QImage(s, s, QImage::Format_ARGB32_Premultiplied); + QPainter p(&m_content); + p.fillRect(0, 0, s, s, Qt::white); + p.fillRect(s/2, 0, s/2, s/2, Qt::gray); + p.fillRect(0, s/2, s/2, s/2, Qt::gray); + p.end(); + + m_brush = QBrush(m_content); + } + + virtual void draw(QPainter *p, const QRect &rect, int) { + p->fillRect(rect, m_brush); + } + + virtual QString name() const { + return QString::fromLatin1("fillRect with image(%1)").arg(m_size.width()); + } + +private: + QImage m_content; + QBrush m_brush; +}; + + +class DrawRectBenchmark : public Benchmark +{ +public: + DrawRectBenchmark(int size) + : Benchmark(QSize(size, size)) + { + } + + virtual void begin(QPainter *p, int) { + p->setPen(Qt::NoPen); + p->setBrush(randomColor(m_size.width())); + } + + + virtual void draw(QPainter *p, const QRect &rect, int) { + p->drawRect(rect); + } + + virtual QString name() const { + return QString::fromLatin1("drawRect(%1)").arg(m_size.width()); + } +}; + + +class DrawRectWithBrushChangeBenchmark : public Benchmark +{ +public: + DrawRectWithBrushChangeBenchmark(int size) + : Benchmark(QSize(size, size)) + { + } + + virtual void begin(QPainter *p, int) { + p->setPen(Qt::NoPen); + } + + + virtual void draw(QPainter *p, const QRect &rect, int i) { + p->setBrush(randomColor(i)); + p->drawRect(rect); + } + + virtual QString name() const { + return QString::fromLatin1("drawRect with brushchange(%1)").arg(m_size.width()); + } +}; + +class RoundRectBenchmark : public Benchmark +{ +public: + RoundRectBenchmark(int size) + : Benchmark(QSize(size, size)) + { + m_roundness = size / 4.; + } + + virtual void begin(QPainter *p, int) { + p->setPen(Qt::NoPen); + p->setBrush(Qt::red); + } + + virtual void draw(QPainter *p, const QRect &rect, int) { + p->drawRoundedRect(rect, m_roundness, m_roundness); + } + + virtual QString name() const { + return QString::fromLatin1("drawRoundedRect(%1)").arg(m_size.width()); + } + + qreal m_roundness; +}; + + +class ArcsBenchmark : public Benchmark +{ +public: + enum Type { + Stroked = 0x0001, + Filled = 0x0002, + + ArcShape = 0x0010, + ChordShape = 0x0020, + PieShape = 0x0040, + CircleShape = 0x0080, + Shapes = 0x00f0 + + }; + + ArcsBenchmark(int size, uint type) + : Benchmark(QSize(size, size)), + m_type(type) + { + } + + virtual void begin(QPainter *p, int) { + if (m_type & Stroked) + p->setPen(Qt::black); + else + p->setPen(Qt::NoPen); + + if (m_type & Filled) + p->setBrush(Qt::red); + else + p->setBrush(Qt::NoBrush); + } + + virtual void draw(QPainter *p, const QRect &rect, int) { + switch (m_type & Shapes) { + case ArcShape: + p->drawArc(rect, 45*16, 120*16); + break; + case ChordShape: + p->drawChord(rect, 45*16, 120*16); + break; + case PieShape: + p->drawPie(rect, 45*16, 120*16); + break; + case CircleShape: + p->drawEllipse(rect); + break; + } + } + + virtual QString name() const { + QString fillStroke; + + if ((m_type & (Stroked|Filled)) == (Stroked|Filled)) { + fillStroke = QLatin1String("Fill & Outline"); + } else if (m_type & Stroked) { + fillStroke = QLatin1String("Outline"); + } else if (m_type & Filled) { + fillStroke = QLatin1String("Fill"); + } + + QString shape; + if (m_type & PieShape) shape = QLatin1String("drawPie"); + else if (m_type & ChordShape) shape = QLatin1String("drawChord"); + else if (m_type & ArcShape) shape = QLatin1String("drawArc"); + else if (m_type & CircleShape) shape = QLatin1String("drawEllipse"); + + return QString::fromLatin1("%1(%2) %3").arg(shape).arg(m_size.width()).arg(fillStroke); + } + + uint m_type; +}; + + +class DrawScaledImage : public Benchmark +{ +public: + DrawScaledImage(const QImage &image, qreal scale, bool asPixmap) + : Benchmark(QSize(image.width(), image.height())), + m_image(image), + m_type(m_as_pixmap ? "Pixmap" : "Image"), + m_scale(scale), + m_as_pixmap(asPixmap) + { + m_pixmap = QPixmap::fromImage(m_image); + } + DrawScaledImage(const QString& type, const QPixmap &pixmap, qreal scale) + : Benchmark(QSize(pixmap.width(), pixmap.height())), + m_type(type), + m_scale(scale), + m_as_pixmap(true), + m_pixmap(pixmap) + { + } + + virtual void begin(QPainter *p, int) { + p->scale(m_scale, m_scale); + } + + virtual void draw(QPainter *p, const QRect &rect, int) { + if (m_as_pixmap) + p->drawPixmap(rect.topLeft(), m_pixmap); + else + p->drawImage(rect.topLeft(), m_image); + } + + virtual QString name() const { + return QString::fromLatin1("draw%4(%1) at scale=%2, depth=%3") + .arg(m_size.width()) + .arg(m_scale) + .arg(m_as_pixmap ? m_pixmap.depth() : m_image.depth()) + .arg(m_type); + } + +private: + QImage m_image; + QString m_type; + qreal m_scale; + bool m_as_pixmap; + QPixmap m_pixmap; +}; + +class DrawTransformedImage : public Benchmark +{ +public: + DrawTransformedImage(const QImage &image, bool asPixmap) + : Benchmark(QSize(image.width(), image.height())), + m_image(image), + m_type(m_as_pixmap ? "Pixmap" : "Image"), + m_as_pixmap(asPixmap) + { + m_pixmap = QPixmap::fromImage(m_image); + } + DrawTransformedImage(const QString& type, const QPixmap &pixmap) + : Benchmark(QSize(pixmap.width(), pixmap.height())), + m_type(type), + m_as_pixmap(true), + m_pixmap(pixmap) + { + } + + virtual void draw(QPainter *p, const QRect &rect, int) { + QTransform oldTransform = p->transform(); + p->translate(0.5 * rect.width() + rect.left(), 0.5 * rect.height() + rect.top()); + p->shear(0.25, 0.0); + p->rotate(5.0); + if (m_as_pixmap) + p->drawPixmap(-0.5 * rect.width(), -0.5 * rect.height(), m_pixmap); + else + p->drawImage(-0.5 * rect.width(), -0.5 * rect.height(), m_image); + p->setTransform(oldTransform); + } + + virtual QString name() const { + return QString::fromLatin1("draw%3(%1) w/transform, depth=%2") + .arg(m_size.width()) + .arg(m_as_pixmap ? m_pixmap.depth() : m_image.depth()) + .arg(m_type); + } + +private: + QImage m_image; + QString m_type; + bool m_as_pixmap; + QPixmap m_pixmap; +}; + + +class DrawImage : public Benchmark +{ +public: + DrawImage(const QImage &image, bool asPixmap) + : Benchmark(QSize(image.width(), image.height())), + m_image(image), + m_type(m_as_pixmap ? "Pixmap" : "Image"), + m_as_pixmap(asPixmap) + { + m_pixmap = QPixmap::fromImage(image); + } + DrawImage(const QString& type, const QPixmap &pixmap) + : Benchmark(QSize(pixmap.width(), pixmap.height())), + m_type(type), + m_as_pixmap(true), + m_pixmap(pixmap) + { + } + + virtual void draw(QPainter *p, const QRect &rect, int) { + if (m_as_pixmap) + p->drawPixmap(rect.topLeft(), m_pixmap); + else + p->drawImage(rect.topLeft(), m_image); + } + + virtual QString name() const { + return QString::fromLatin1("draw%2(%1), depth=%3") + .arg(m_size.width()) + .arg(m_type) + .arg(m_as_pixmap ? m_pixmap.depth() : m_image.depth()); + } + +private: + QImage m_image; + QString m_type; + bool m_as_pixmap; + QPixmap m_pixmap; +}; + + +class DrawText : public Benchmark +{ +public: + enum Mode { + PainterMode, + PainterQPointMode, + LayoutMode, + DocumentMode, + PixmapMode + +#if QT_VERSION >= 0x040700 + , StaticTextMode, + StaticTextWithMaximumSizeMode, + StaticTextBackendOptimizations +#endif + }; + + DrawText(const QString &text, Mode mode) + : Benchmark(QSize()), m_mode(mode), m_text(text), m_document(text), m_layout(text) + { + } + + virtual void begin(QPainter *p, int iterations) { +#if QT_VERSION >= 0x040700 + m_staticTexts.clear(); + m_currentStaticText = 0; +#else + Q_UNUSED(iterations); +#endif + m_pixmaps.clear(); + m_currentPixmap = 0; + QRect m_bounds = QRect(0,0,p->device()->width(), p->device()->height()); + switch (m_mode) { + case PainterMode: + m_size = (p->boundingRect(m_bounds, 0, m_text)).size(); +// m_rect = m_rect.translated(-m_rect.topLeft()); + break; + case DocumentMode: + m_size = QSize(m_document.size().toSize()); + break; + case PixmapMode: + for (int i=0; i<4; ++i) { + m_size = (p->boundingRect(m_bounds, 0, m_text)).size(); + QPixmap pixmap = QPixmap(m_size); + pixmap.fill(Qt::transparent); + { + QPainter p(&pixmap); + p.drawText(pixmap.rect(), m_text); + } + m_pixmaps.append(pixmap); + } + break; + + case LayoutMode: { + QRect r = p->boundingRect(m_bounds, 0, m_text); + QStringList lines = m_text.split('\n'); + int height = 0; + int leading = p->fontMetrics().leading(); + m_layout.beginLayout(); + for (int i=0; i<lines.size(); ++i) { + QTextLine textLine = m_layout.createLine(); + if (textLine.isValid()) { + textLine.setLineWidth(r.width()); + textLine.setPosition(QPointF(0, height)); + height += leading + textLine.height(); + } + } + m_layout.endLayout(); + m_layout.setCacheEnabled(true); + m_size = m_layout.boundingRect().toRect().size(); + break; } + +#if QT_VERSION >= 0x040700 + case StaticTextWithMaximumSizeMode: { + QStaticText staticText; + m_size = (p->boundingRect(m_bounds, 0, m_text)).size(); + staticText.setMaximumSize(m_size + QSize(10, 10)); + staticText.setText(m_text); + staticText.prepare(p->transform(), p->font()); + m_staticTexts.append(staticText); + break; + } + case StaticTextBackendOptimizations: { + m_size = (p->boundingRect(m_bounds, 0, m_text)).size(); + for (int i=0; i<iterations; ++i) { + QStaticText staticText; + staticText.setPerformanceHint(QStaticText::AggressiveCaching); + staticText.setMaximumSize(m_size + QSize(10, 10)); + staticText.setText(m_text); + staticText.prepare(p->transform(), p->font()); + m_staticTexts.append(staticText); + } + + break; + } + case StaticTextMode: { + QStaticText staticText; + staticText.setText(m_text); + staticText.prepare(p->transform(), p->font()); + m_staticTexts.append(staticText); + + QFontMetrics fm(p->font()); + m_size = QSize(fm.width(m_text, m_text.length()), fm.height()); + + break; + } +#endif + + case PainterQPointMode: { + QFontMetrics fm(p->font()); + m_size = QSize(fm.width(m_text, m_text.length()), fm.height()); + break; + } + + } + } + + virtual void draw(QPainter *p, const QRect &rect, int) + { + switch (m_mode) { + case PainterMode: + p->drawText(rect, 0, m_text); + break; + case PainterQPointMode: + p->drawText(rect.topLeft(), m_text); + break; + case PixmapMode: + p->drawPixmap(rect.topLeft(), m_pixmaps.at(m_currentPixmap)); + m_currentPixmap = (m_currentPixmap + 1) % m_pixmaps.size(); + break; + case DocumentMode: + p->translate(rect.topLeft()); + m_document.drawContents(p); + p->translate(-rect.topLeft()); + break; + case LayoutMode: + m_layout.draw(p, rect.topLeft()); + break; + +#if QT_VERSION >= 0x040700 + case StaticTextWithMaximumSizeMode: + case StaticTextMode: + p->drawStaticText(rect.topLeft(), m_staticTexts.at(0)); + break; + case StaticTextBackendOptimizations: + p->drawStaticText(rect.topLeft(), m_staticTexts.at(m_currentStaticText)); + m_currentStaticText = (m_currentStaticText + 1) % m_staticTexts.size(); + break; +#endif + } + } + + virtual QString name() const { + int letters = m_text.length(); + int lines = m_text.count('\n'); + if (lines == 0) + lines = 1; + QString type; + switch (m_mode) { + case PainterMode: type = "drawText(rect)"; break; + case PainterQPointMode: type = "drawText(point)"; break; + case LayoutMode: type = "layout.draw()"; break; + case DocumentMode: type = "doc.drawContents()"; break; + case PixmapMode: type = "pixmap cached text"; break; + +#if QT_VERSION >= 0x040700 + case StaticTextMode: type = "drawStaticText()"; break; + case StaticTextWithMaximumSizeMode: type = "drawStaticText() w/ maxsize"; break; + case StaticTextBackendOptimizations: type = "drawStaticText() w/ backend optimizations"; break; +#endif + } + + return QString::fromLatin1("%3, len=%1, lines=%2") + .arg(letters) + .arg(lines) + .arg(type); + } + +private: + Mode m_mode; + QString m_text; + QTextDocument m_document; + QTextLayout m_layout; + + QList<QPixmap> m_pixmaps; + int m_currentPixmap; + +#if QT_VERSION >= 0x040700 + int m_currentStaticText; + QList<QStaticText> m_staticTexts; +#endif +}; + + + + +class ClippedDrawRectBenchmark : public Benchmark +{ +public: + enum ClipType { + RectClip, + TwoRectRegionClip, + EllipseRegionClip, + TwoRectPathClip, + EllipsePathClip, + AAEllipsePathClip, + EllipseRegionThenRectClip, + EllipsePathThenRectClip + }; + + ClippedDrawRectBenchmark(int size, ClipType type) + : Benchmark(QSize(size, size)), m_type(type) + { + } + + virtual void begin(QPainter *p, int) { + QRect m_bounds = QRect(0,0,p->device()->width(), p->device()->height()); + p->setPen(Qt::NoPen); + p->setBrush(Qt::red); + + switch (m_type) { + case RectClip: + p->setClipRect(m_bounds.adjusted(1, 1, -1, -1)); + break; + case TwoRectRegionClip: + p->setClipRegion(QRegion(m_bounds.adjusted(0, 0, -1, -1)) + | QRegion(m_bounds.adjusted(1, 1, 0, 0))); + break; + case EllipseRegionClip: + p->setClipRegion(QRegion(m_bounds, QRegion::Ellipse)); + break; + case TwoRectPathClip: + { + QPainterPath path; + path.addRect(m_bounds.adjusted(0, 0, -1, -1)); + path.addRect(m_bounds.adjusted(1, 1, 0, 0)); + path.setFillRule(Qt::WindingFill); + p->setClipPath(path); + } + break; + case EllipsePathClip: + { + QPainterPath path; + path.addEllipse(m_bounds); + p->setClipPath(path); + } + break; + case AAEllipsePathClip: + { + QPainterPath path; + path.addEllipse(m_bounds); + p->setRenderHint(QPainter::Antialiasing); + p->setClipPath(path); + p->setRenderHint(QPainter::Antialiasing, false); + } + break; + case EllipseRegionThenRectClip: + p->setClipRegion(QRegion(m_bounds, QRegion::Ellipse)); + p->setClipRegion(QRegion(m_bounds.width() / 4, + m_bounds.height() / 4, + m_bounds.width() / 2, + m_bounds.height() / 2), Qt::IntersectClip); + break; + case EllipsePathThenRectClip: + { + QPainterPath path; + path.addEllipse(m_bounds); + p->setClipPath(path); + p->setClipRegion(QRegion(m_bounds.width() / 4, + m_bounds.height() / 4, + m_bounds.width() / 2, + m_bounds.height() / 2), Qt::IntersectClip); + } + break; + } + } + + virtual void draw(QPainter *p, const QRect &rect, int) { + p->drawRect(rect); + } + + virtual QString name() const { + QString namedType; + switch (m_type) { + case RectClip: + namedType = "rect"; + break; + case TwoRectRegionClip: + namedType = "two-rect-region"; + break; + case EllipseRegionClip: + namedType = "ellipse-region"; + break; + case TwoRectPathClip: + namedType = "two-rect-path"; + break; + case EllipsePathClip: + namedType = "ellipse-path"; + break; + case AAEllipsePathClip: + namedType = "aa-ellipse-path"; + break; + case EllipseRegionThenRectClip: + namedType = "ellipseregion&rect"; + break; + case EllipsePathThenRectClip: + namedType = "ellipsepath&rect"; + break; + } + return QString::fromLatin1("%1-clipped-drawRect(%2)").arg(namedType).arg(m_size.width()); + } + + ClipType m_type; +}; + +class LinesBenchmark : public Benchmark +{ +public: + enum LineType { + Horizontal_Integer, + Diagonal_Integer, + Vertical_Integer, + Horizontal_Float, + Diagonal_Float, + Vertical_Float + }; + + LinesBenchmark(int length, LineType type) + : Benchmark(QSize(qAbs(length), qAbs(length))), + m_type(type), + m_length(length) + { + + } + + virtual void draw(QPainter *p, const QRect &rect, int) { + switch (m_type) { + case Horizontal_Integer: + p->drawLine(QLine(rect.x(), rect.y(), rect.x() + m_length, rect.y())); + break; + case Diagonal_Integer: + p->drawLine(QLine(rect.x(), rect.y(), rect.x() + m_length, rect.y() + m_length)); + break; + case Vertical_Integer: + p->drawLine(QLine(rect.x() + 4, rect.y(), rect.x() + 4, rect.y() + m_length)); + break; + case Horizontal_Float: + p->drawLine(QLineF(rect.x(), rect.y(), rect.x() + m_length, rect.y())); + break; + case Diagonal_Float: + p->drawLine(QLineF(rect.x(), rect.y(), rect.x() + m_length, rect.y() + m_length)); + break; + case Vertical_Float: + p->drawLine(QLineF(rect.x() + 4, rect.y(), rect.x() + 4, rect.y() + m_length)); + break; + } + } + + virtual QString name() const { + const char *names[] = { + "Hor_I", + "Diag_I", + "Ver_I", + "Hor_F", + "Diag_F", + "Ver_F" + }; + return QString::fromLatin1("drawLine(size=%1,type=%2)").arg(m_length).arg(names[m_type]); + } + + LineType m_type; + int m_length; +}; + +#endif // BENCHMARKTESTS_H diff --git a/tests/benchmarks/gui/painting/qtbench/qtbench.pro b/tests/benchmarks/gui/painting/qtbench/qtbench.pro new file mode 100644 index 0000000..91f416d --- /dev/null +++ b/tests/benchmarks/gui/painting/qtbench/qtbench.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_qtbench + +SOURCES += tst_qtbench.cpp + diff --git a/tests/benchmarks/gui/painting/qtbench/tst_qtbench.cpp b/tests/benchmarks/gui/painting/qtbench/tst_qtbench.cpp new file mode 100644 index 0000000..8eef472 --- /dev/null +++ b/tests/benchmarks/gui/painting/qtbench/tst_qtbench.cpp @@ -0,0 +1,254 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> + +#include <QtGui> + +#include "benchmarktests.h" + +//TESTED_FILES= + +class BenchWidget : public QWidget +{ +public: + BenchWidget(Benchmark *benchmark); + + void paintEvent(QPaintEvent *event); + + bool done() const { return m_done; } + qreal result() const { return m_result; } + +public: + QTime timer; + + Benchmark *m_benchmark; + + bool m_done; + qreal m_result; + + uint m_total; + uint m_iteration; + + QVector<uint> iterationTimes; +}; + +void BenchWidget::paintEvent(QPaintEvent *) +{ + if (m_done) + return; + + QPainter p(this); + + m_benchmark->begin(&p, 100); + + PaintingRectAdjuster adjuster; + adjuster.setNewBenchmark(m_benchmark); + adjuster.reset(rect()); + + for (int i = 0; i < 100; ++i) + m_benchmark->draw(&p, adjuster.newPaintingRect(), i); + + m_benchmark->end(&p); + + ++m_iteration; + + uint currentElapsed = timer.isNull() ? 0 : timer.elapsed(); + timer.restart(); + + m_total += currentElapsed; + + // warm up for at most 5 iterations or half a second + if (m_iteration >= 5 || m_total >= 500) { + iterationTimes << currentElapsed; + + if (iterationTimes.size() >= 5) { + qreal mean = 0; + qreal stddev = 0; + uint min = INT_MAX; + + for (int i = 0; i < iterationTimes.size(); ++i) { + mean += iterationTimes.at(i); + min = qMin(min, iterationTimes.at(i)); + } + + mean /= qreal(iterationTimes.size()); + + for (int i = 0; i < iterationTimes.size(); ++i) { + qreal delta = iterationTimes.at(i) - mean; + stddev += delta * delta; + } + + stddev = qSqrt(stddev / iterationTimes.size()); + + stddev = 100 * stddev / mean; + // do 50 iterations, break earlier if we spend more than 5 seconds or have a low std deviation after 2 seconds + if (iterationTimes.size() >= 50 || m_total >= 5000 || (m_total >= 2000 && stddev < 4)) { + m_result = min; + m_done = true; + return; + } + } + } +} + +BenchWidget::BenchWidget(Benchmark *benchmark) + : m_benchmark(benchmark) + , m_done(false) + , m_result(0) + , m_total(0) + , m_iteration(0) +{ + setWindowTitle(benchmark->name()); + resize(640, 480); +} + +class tst_QtBench : public QObject +{ + Q_OBJECT + +private slots: + void qtBench(); + void qtBench_data(); +}; + +QString makeString(int length) +{ + const char chars[] = "abcd efgh ijkl mnop qrst uvwx yz!$. ABCD 1234"; + int len = strlen(chars); + + QString ret; + for (int j = 0; j < length; j++) { + ret += QChar(chars[(j * 97) % len]); + } + + return ret; +} + +void tst_QtBench::qtBench_data() +{ + QTest::addColumn<void *>("benchmark"); + + QString shortString = makeString(5); + QString middleString = makeString(50); + QString longString = makeString(35) + "\n" + + makeString(45) + "\n" + + makeString(75); + QString superLongString = "Lorem ipsum dolor sit am\n" + "et, consectetur adipisci\n" + "ng elit. Integer mi leo,\n" + "interdum ut congue at, p\n" + "ulvinar et tellus. Quisq\n" + "ue pretium eleifend laci\n" + "nia. Ut semper gravida l\n" + "ectus in commodo. Vestib\n" + "ulum pharetra arcu in en\n" + "im ultrices hendrerit. P\n" + "ellentesque habitant mor\n" + "bi tristique senectus et\n" + "netus et malesuada fames\n" + "ac turpis egestas. Ut er\n" + "os sem, feugiat in eleme\n" + "ntum in, porta sit amet \n" + "neque. Fusce mi tellus, \n" + "congue non dapibus eget,\n" + "pharetra quis quam. Duis\n" + "dui massa, pulvinar ac s\n" + "odales pharetra, dictum \n" + "in enim. Phasellus a nis\n" + "i erat, sed pellentesque\n" + "mi. Curabitur sed."; + + QList<Benchmark *> benchmarks; + benchmarks << (new DrawText(shortString, DrawText::PainterMode)); + benchmarks << (new DrawText(middleString, DrawText::PainterMode)); + benchmarks << (new DrawText(longString, DrawText::PainterMode)); + benchmarks << (new DrawText(superLongString, DrawText::PainterMode)); + + benchmarks << (new DrawText(shortString, DrawText::PainterQPointMode)); + benchmarks << (new DrawText(middleString, DrawText::PainterQPointMode)); + benchmarks << (new DrawText(longString, DrawText::PainterQPointMode)); + benchmarks << (new DrawText(superLongString, DrawText::PainterQPointMode)); + + benchmarks << (new DrawText(shortString, DrawText::PixmapMode)); + benchmarks << (new DrawText(middleString, DrawText::PixmapMode)); + benchmarks << (new DrawText(longString, DrawText::PixmapMode)); + benchmarks << (new DrawText(superLongString, DrawText::PixmapMode)); + +#if QT_VERSION >= 0x040700 + benchmarks << (new DrawText(shortString, DrawText::StaticTextMode)); + benchmarks << (new DrawText(middleString, DrawText::StaticTextMode)); + benchmarks << (new DrawText(longString, DrawText::StaticTextMode)); + benchmarks << (new DrawText(superLongString, DrawText::StaticTextMode)); + + benchmarks << (new DrawText(shortString, DrawText::StaticTextWithMaximumSizeMode)); + benchmarks << (new DrawText(middleString, DrawText::StaticTextWithMaximumSizeMode)); + benchmarks << (new DrawText(longString, DrawText::StaticTextWithMaximumSizeMode)); + benchmarks << (new DrawText(superLongString, DrawText::StaticTextWithMaximumSizeMode)); + + benchmarks << (new DrawText(shortString, DrawText::StaticTextBackendOptimizations)); + benchmarks << (new DrawText(middleString, DrawText::StaticTextBackendOptimizations)); + benchmarks << (new DrawText(longString, DrawText::StaticTextBackendOptimizations)); + benchmarks << (new DrawText(superLongString, DrawText::StaticTextBackendOptimizations)); +#endif + + foreach (Benchmark *benchmark, benchmarks) + QTest::newRow(qPrintable(benchmark->name())) << reinterpret_cast<void *>(benchmark); +} + +void tst_QtBench::qtBench() +{ + QFETCH(void *, benchmark); + + BenchWidget widget(reinterpret_cast<Benchmark *>(benchmark)); + widget.show(); + QTest::qWaitForWindowShown(&widget); + + while (!widget.done()) { + widget.update(); + QApplication::processEvents(); + } + + QTest::setBenchmarkResult(widget.result(), QTest::WalltimeMilliseconds); +} + +QTEST_MAIN(tst_QtBench) +#include "tst_qtbench.moc" diff --git a/tests/benchmarks/gui/painting/qtracebench/qtracebench.pro b/tests/benchmarks/gui/painting/qtracebench/qtracebench.pro new file mode 100644 index 0000000..56ec8bb --- /dev/null +++ b/tests/benchmarks/gui/painting/qtracebench/qtracebench.pro @@ -0,0 +1,10 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_qtracebench + +INCLUDEPATH += . $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src + +RESOURCES += qtracebench.qrc + +SOURCES += tst_qtracebench.cpp + diff --git a/tests/benchmarks/gui/painting/qtracebench/qtracebench.qrc b/tests/benchmarks/gui/painting/qtracebench/qtracebench.qrc new file mode 100644 index 0000000..5569550 --- /dev/null +++ b/tests/benchmarks/gui/painting/qtracebench/qtracebench.qrc @@ -0,0 +1,10 @@ +<RCC> + <qresource> + <file>traces/basicdrawing.trace</file> + <file>traces/webkit.trace</file> + <file>traces/textedit.trace</file> + <file>traces/creator.trace</file> + <file>traces/qmlphoneconcept.trace</file> + <file>traces/qmlsamegame.trace</file> + </qresource> +</RCC> diff --git a/tests/benchmarks/gui/painting/qtracebench/traces/basicdrawing.trace b/tests/benchmarks/gui/painting/qtracebench/traces/basicdrawing.trace Binary files differnew file mode 100644 index 0000000..0241d08 --- /dev/null +++ b/tests/benchmarks/gui/painting/qtracebench/traces/basicdrawing.trace diff --git a/tests/benchmarks/gui/painting/qtracebench/traces/creator.trace b/tests/benchmarks/gui/painting/qtracebench/traces/creator.trace Binary files differnew file mode 100644 index 0000000..55ee9e1 --- /dev/null +++ b/tests/benchmarks/gui/painting/qtracebench/traces/creator.trace diff --git a/tests/benchmarks/gui/painting/qtracebench/traces/qmlphoneconcept.trace b/tests/benchmarks/gui/painting/qtracebench/traces/qmlphoneconcept.trace Binary files differnew file mode 100644 index 0000000..835ebfa --- /dev/null +++ b/tests/benchmarks/gui/painting/qtracebench/traces/qmlphoneconcept.trace diff --git a/tests/benchmarks/gui/painting/qtracebench/traces/qmlsamegame.trace b/tests/benchmarks/gui/painting/qtracebench/traces/qmlsamegame.trace Binary files differnew file mode 100644 index 0000000..1d76195 --- /dev/null +++ b/tests/benchmarks/gui/painting/qtracebench/traces/qmlsamegame.trace diff --git a/tests/benchmarks/gui/painting/qtracebench/traces/textedit.trace b/tests/benchmarks/gui/painting/qtracebench/traces/textedit.trace Binary files differnew file mode 100644 index 0000000..998716d --- /dev/null +++ b/tests/benchmarks/gui/painting/qtracebench/traces/textedit.trace diff --git a/tests/benchmarks/gui/painting/qtracebench/traces/webkit.trace b/tests/benchmarks/gui/painting/qtracebench/traces/webkit.trace Binary files differnew file mode 100644 index 0000000..43e752d --- /dev/null +++ b/tests/benchmarks/gui/painting/qtracebench/traces/webkit.trace diff --git a/tests/benchmarks/gui/painting/qtracebench/tst_qtracebench.cpp b/tests/benchmarks/gui/painting/qtracebench/tst_qtracebench.cpp new file mode 100644 index 0000000..ff2633d --- /dev/null +++ b/tests/benchmarks/gui/painting/qtracebench/tst_qtracebench.cpp @@ -0,0 +1,262 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> + +#include <QtGui> + +#include <private/qpaintengineex_p.h> +#include <private/qpaintbuffer_p.h> + +//TESTED_FILES= + +class ReplayWidget : public QWidget +{ + Q_OBJECT +public: + ReplayWidget(const QString &filename); + + void paintEvent(QPaintEvent *event); + void resizeEvent(QResizeEvent *event); + + bool done() const { return m_done; } + qreal result() const { return m_result; } + +public slots: + void updateRect(); + +public: + QList<QRegion> updates; + QPaintBuffer buffer; + + int currentFrame; + int currentIteration; + QTime timer; + + QList<uint> visibleUpdates; + QList<uint> iterationTimes; + QString filename; + + bool m_done; + qreal m_result; + + uint m_total; +}; + +void ReplayWidget::updateRect() +{ + if (!visibleUpdates.isEmpty()) + update(updates.at(visibleUpdates.at(currentFrame))); +} + +void ReplayWidget::paintEvent(QPaintEvent *) +{ + if (m_done) + return; + + QPainter p(this); + + // if partial updates don't work + // p.setClipRegion(frames.at(currentFrame).updateRegion); + + buffer.draw(&p, visibleUpdates.at(currentFrame)); + + ++currentFrame; + if (currentFrame >= visibleUpdates.size()) { + currentFrame = 0; + ++currentIteration; + + uint currentElapsed = timer.isNull() ? 0 : timer.elapsed(); + timer.restart(); + + m_total += currentElapsed; + + // warm up for at most 5 iterations or half a second + if (currentIteration >= 5 || m_total >= 500) { + iterationTimes << currentElapsed; + + if (iterationTimes.size() >= 5) { + qreal mean = 0; + qreal stddev = 0; + uint min = INT_MAX; + + for (int i = 0; i < iterationTimes.size(); ++i) { + mean += iterationTimes.at(i); + min = qMin(min, iterationTimes.at(i)); + } + + mean /= qreal(iterationTimes.size()); + + for (int i = 0; i < iterationTimes.size(); ++i) { + qreal delta = iterationTimes.at(i) - mean; + stddev += delta * delta; + } + + stddev = qSqrt(stddev / iterationTimes.size()); + + qSort(iterationTimes.begin(), iterationTimes.end()); + uint median = iterationTimes.at(iterationTimes.size() / 2); + + stddev = 100 * stddev / mean; + // do 100 iterations, break earlier if we spend more than 5 seconds or have a low std deviation after 2 seconds + if (iterationTimes.size() >= 100 || m_total >= 5000 || (m_total >= 2000 && stddev < 4)) { + printf("%s, iterations: %d, frames: %d, min(ms): %d, median(ms): %d, stddev: %f %%, max(fps): %f\n", qPrintable(filename), + iterationTimes.size(), visibleUpdates.size(), min, median, stddev, 1000. * visibleUpdates.size() / min); + m_result = min; + m_done = true; + return; + } + } + } + } +} + +void ReplayWidget::resizeEvent(QResizeEvent *event) +{ + visibleUpdates.clear(); + + QRect bounds = rect(); + for (int i = 0; i < updates.size(); ++i) { + if (updates.at(i).intersects(bounds)) + visibleUpdates << i; + } + + if (visibleUpdates.size() != updates.size()) + printf("Warning: skipped %d frames due to limited resolution\n", updates.size() - visibleUpdates.size()); + +} + +ReplayWidget::ReplayWidget(const QString &filename_) + : currentFrame(0) + , currentIteration(0) + , filename(filename_) + , m_done(false) + , m_result(0) + , m_total(0) +{ + setWindowTitle(filename); + QFile file(filename); + + if (!file.open(QIODevice::ReadOnly)) { + printf("Failed to load input file '%s'\n", qPrintable(filename_)); + return; + } + + QDataStream in(&file); + + char *data; + uint size; + in.readBytes(data, size); + bool isTraceFile = size >= 7 && qstrncmp(data, "qttrace", 7) == 0; + uint version = 0; + if (size == 9 && qstrncmp(data, "qttraceV2", 9) == 0) { + in.setFloatingPointPrecision(QDataStream::SinglePrecision); + in >> version; + } + + delete [] data; + if (!isTraceFile) { + printf("File '%s' is not a trace file\n", qPrintable(filename_)); + return; + } + + in >> buffer >> updates; + + resize(buffer.boundingRect().size().toSize()); + + setAutoFillBackground(false); + setAttribute(Qt::WA_NoSystemBackground); +} + + +class tst_QTraceBench : public QObject +{ + Q_OBJECT + +private slots: + void trace(); + void trace_data(); +}; + +static const QLatin1String prefix(":/traces/"); + +void tst_QTraceBench::trace_data() +{ + QTest::addColumn<QString>("filename"); + + QTest::newRow("basicdrawing") << (prefix + "basicdrawing.trace"); + QTest::newRow("webkit") << (prefix + "webkit.trace"); + QTest::newRow("creator") << (prefix + "creator.trace"); + QTest::newRow("textedit") << (prefix + "textedit.trace"); + QTest::newRow("qmlphoneconcept") << (prefix + "qmlphoneconcept.trace"); + QTest::newRow("qmlsamegame") << (prefix + "qmlsamegame.trace"); +} + +void tst_QTraceBench::trace() +{ + QFETCH(QString, filename); + + QFile file(filename); + if (!file.exists()) { + qWarning() << "Missing file" << filename; + return; + } + + ReplayWidget widget(filename); + + if (widget.updates.isEmpty()) { + qWarning() << "No trace updates" << filename; + return; + } + + widget.show(); + QTest::qWaitForWindowShown(&widget); + + while (!widget.done()) { + widget.updateRect(); + QApplication::processEvents(); + } + + QTest::setBenchmarkResult(widget.result(), QTest::WalltimeMilliseconds); +} + +QTEST_MAIN(tst_QTraceBench) +#include "tst_qtracebench.moc" |