mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-04 16:25:27 +08:00
qt 6.5.1 original
This commit is contained in:
15
tests/benchmarks/gui/painting/qtbench/CMakeLists.txt
Normal file
15
tests/benchmarks/gui/painting/qtbench/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qtbench Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qtbench
|
||||
SOURCES
|
||||
tst_qtbench.cpp
|
||||
LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::Test
|
||||
Qt::Widgets
|
||||
)
|
794
tests/benchmarks/gui/painting/qtbench/benchmarktests.h
Normal file
794
tests/benchmarks/gui/painting/qtbench/benchmarktests.h
Normal file
@ -0,0 +1,794 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef BENCHMARKTESTS_H
|
||||
#define BENCHMARKTESTS_H
|
||||
|
||||
#include <QApplication>
|
||||
#include <QTextDocument>
|
||||
#include <QTextLayout>
|
||||
#include <QFontMetrics>
|
||||
#include <QDebug>
|
||||
#include <QStaticText>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QRandomGenerator>
|
||||
|
||||
class Benchmark
|
||||
{
|
||||
public:
|
||||
virtual ~Benchmark() {}
|
||||
|
||||
Benchmark(const QSize &size)
|
||||
: m_size(size)
|
||||
{
|
||||
for (int i=0; i<16; ++i) {
|
||||
m_colors[i] = QColor::fromRgbF((QRandomGenerator::global()->bounded(4)) / 3.0,
|
||||
(QRandomGenerator::global()->bounded(4)) / 3.0,
|
||||
(QRandomGenerator::global()->bounded(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))
|
||||
{
|
||||
}
|
||||
|
||||
void draw(QPainter *p, const QRect &rect, int iterationCount) override
|
||||
{
|
||||
p->fillRect(rect, randomColor(iterationCount));
|
||||
}
|
||||
|
||||
QString name() const override
|
||||
{
|
||||
return QString::fromLatin1("fillRect(%1)").arg(m_size.width());
|
||||
}
|
||||
};
|
||||
|
||||
class ImageFillRectBenchmark : public Benchmark
|
||||
{
|
||||
public:
|
||||
ImageFillRectBenchmark(int size)
|
||||
: Benchmark(QSize(size, size))
|
||||
{
|
||||
int s = QRandomGenerator::global()->bounded(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);
|
||||
}
|
||||
|
||||
void draw(QPainter *p, const QRect &rect, int) override { p->fillRect(rect, m_brush); }
|
||||
|
||||
QString name() const override
|
||||
{
|
||||
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))
|
||||
{
|
||||
}
|
||||
|
||||
void begin(QPainter *p, int) override
|
||||
{
|
||||
p->setPen(Qt::NoPen);
|
||||
p->setBrush(randomColor(m_size.width()));
|
||||
}
|
||||
|
||||
void draw(QPainter *p, const QRect &rect, int) override { p->drawRect(rect); }
|
||||
|
||||
QString name() const override
|
||||
{
|
||||
return QString::fromLatin1("drawRect(%1)").arg(m_size.width());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class DrawRectWithBrushChangeBenchmark : public Benchmark
|
||||
{
|
||||
public:
|
||||
DrawRectWithBrushChangeBenchmark(int size)
|
||||
: Benchmark(QSize(size, size))
|
||||
{
|
||||
}
|
||||
|
||||
void begin(QPainter *p, int) override { p->setPen(Qt::NoPen); }
|
||||
|
||||
void draw(QPainter *p, const QRect &rect, int i) override
|
||||
{
|
||||
p->setBrush(randomColor(i));
|
||||
p->drawRect(rect);
|
||||
}
|
||||
|
||||
QString name() const override
|
||||
{
|
||||
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.;
|
||||
}
|
||||
|
||||
void begin(QPainter *p, int) override
|
||||
{
|
||||
p->setPen(Qt::NoPen);
|
||||
p->setBrush(Qt::red);
|
||||
}
|
||||
|
||||
void draw(QPainter *p, const QRect &rect, int) override
|
||||
{
|
||||
p->drawRoundedRect(rect, m_roundness, m_roundness);
|
||||
}
|
||||
|
||||
QString name() const override
|
||||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
void begin(QPainter *p, int) override
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void draw(QPainter *p, const QRect &rect, int) override
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
QString name() const override
|
||||
{
|
||||
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(asPixmap ? "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)
|
||||
{
|
||||
}
|
||||
|
||||
void begin(QPainter *p, int) override { p->scale(m_scale, m_scale); }
|
||||
|
||||
void draw(QPainter *p, const QRect &rect, int) override
|
||||
{
|
||||
if (m_as_pixmap)
|
||||
p->drawPixmap(rect.topLeft(), m_pixmap);
|
||||
else
|
||||
p->drawImage(rect.topLeft(), m_image);
|
||||
}
|
||||
|
||||
QString name() const override
|
||||
{
|
||||
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(asPixmap ? "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)
|
||||
{
|
||||
}
|
||||
|
||||
void draw(QPainter *p, const QRect &rect, int) override
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
QString name() const override
|
||||
{
|
||||
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(asPixmap ? "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)
|
||||
{
|
||||
}
|
||||
|
||||
void draw(QPainter *p, const QRect &rect, int) override
|
||||
{
|
||||
if (m_as_pixmap)
|
||||
p->drawPixmap(rect.topLeft(), m_pixmap);
|
||||
else
|
||||
p->drawImage(rect.topLeft(), m_image);
|
||||
}
|
||||
|
||||
QString name() const override
|
||||
{
|
||||
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,
|
||||
StaticTextMode,
|
||||
StaticTextWithMaximumSizeMode,
|
||||
StaticTextBackendOptimizations
|
||||
};
|
||||
|
||||
DrawText(const QString &text, Mode mode)
|
||||
: Benchmark(QSize()), m_mode(mode), m_text(text), m_document(text), m_layout(text)
|
||||
{
|
||||
}
|
||||
|
||||
void begin(QPainter *p, int iterations) override
|
||||
{
|
||||
m_staticTexts.clear();
|
||||
m_currentStaticText = 0;
|
||||
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; }
|
||||
|
||||
case StaticTextWithMaximumSizeMode: {
|
||||
QStaticText staticText;
|
||||
m_size = (p->boundingRect(m_bounds, 0, m_text)).size();
|
||||
staticText.setTextWidth(m_size.width() + 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.setTextWidth(m_size.width() + 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.horizontalAdvance(m_text, m_text.size()), fm.height());
|
||||
|
||||
break;
|
||||
}
|
||||
case PainterQPointMode: {
|
||||
QFontMetrics fm(p->font());
|
||||
m_size = QSize(fm.horizontalAdvance(m_text, m_text.size()), fm.height());
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void draw(QPainter *p, const QRect &rect, int) override
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
QString name() const override
|
||||
{
|
||||
int letters = m_text.size();
|
||||
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;
|
||||
case StaticTextMode: type = "drawStaticText()"; break;
|
||||
case StaticTextWithMaximumSizeMode: type = "drawStaticText() w/ maxsize"; break;
|
||||
case StaticTextBackendOptimizations: type = "drawStaticText() w/ backend optimizations"; break;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
int m_currentStaticText;
|
||||
QList<QStaticText> m_staticTexts;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
void begin(QPainter *p, int) override
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void draw(QPainter *p, const QRect &rect, int) override { p->drawRect(rect); }
|
||||
|
||||
QString name() const override
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void draw(QPainter *p, const QRect &rect, int) override
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
QString name() const override
|
||||
{
|
||||
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
|
214
tests/benchmarks/gui/painting/qtbench/tst_qtbench.cpp
Normal file
214
tests/benchmarks/gui/painting/qtbench/tst_qtbench.cpp
Normal file
@ -0,0 +1,214 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <qtest.h>
|
||||
|
||||
#include <QtCore/qmath.h>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
#include "benchmarktests.h"
|
||||
|
||||
class BenchWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
BenchWidget(Benchmark *benchmark);
|
||||
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
bool done() const { return m_done; }
|
||||
qreal result() const { return m_result; }
|
||||
|
||||
public:
|
||||
QElapsedTimer timer;
|
||||
|
||||
Benchmark *m_benchmark;
|
||||
|
||||
bool m_done;
|
||||
qreal m_result;
|
||||
|
||||
uint m_total;
|
||||
uint m_iteration;
|
||||
|
||||
QList<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.isValid() ? timer.elapsed() : 0;
|
||||
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";
|
||||
const int len = int(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));
|
||||
|
||||
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));
|
||||
|
||||
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();
|
||||
QVERIFY(QTest::qWaitForWindowExposed(&widget));
|
||||
|
||||
while (!widget.done()) {
|
||||
widget.update();
|
||||
QApplication::processEvents();
|
||||
}
|
||||
|
||||
QTest::setBenchmarkResult(widget.result(), QTest::WalltimeMilliseconds);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QtBench)
|
||||
#include "tst_qtbench.moc"
|
Reference in New Issue
Block a user