Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / tests / benchmarks / declarative / painting / paintbenchmark.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QApplication>
43 #include <QPixmap>
44 #include <QImage>
45 #include <QPainter>
46 #include <QPainterPath>
47 #include <QGLWidget>
48 #include <QTextLayout>
49 #include <QVBoxLayout>
50 #include <QTime>
51 #include <QDebug>
52 #include <QStaticText>
53
54 int iterations = 20;
55 const int count = 600;
56 const int lines = 12;
57 const int spacing = 36;
58 QSizeF size(1000, 800);
59 const qreal lineWidth = 1000;
60 QString strings[lines];
61 QGLWidget *testWidget = 0;
62
63 void paint_QTextLayout(QPainter &p, bool useCache)
64 {
65     static bool first = true;
66     static QTextLayout *textLayout[lines];
67     if (first) {
68         for (int i = 0; i < lines; ++i) {
69             textLayout[i] = new QTextLayout(strings[i]);
70             int leading = p.fontMetrics().leading();
71             qreal height = 0;
72             qreal widthUsed = 0;
73             textLayout[i]->setCacheEnabled(useCache);
74             textLayout[i]->beginLayout();
75             while (1) {
76                 QTextLine line = textLayout[i]->createLine();
77                 if (!line.isValid())
78                         break;
79
80                 line.setLineWidth(lineWidth);
81                 height += leading;
82                 line.setPosition(QPointF(0, height));
83                 height += line.height();
84                 widthUsed = qMax(widthUsed, line.naturalTextWidth());
85             }
86             textLayout[i]->endLayout();
87         }
88         first = false;
89     }
90     for (int i = 0; i < count; ++i) {
91         for (int j = 0; j < lines; ++j) {
92             textLayout[j]->draw(&p, QPoint(0, j*spacing));
93         }
94     }
95 }
96
97 void paint_QTextLayout_noCache(QPainter &p)
98 {
99     paint_QTextLayout(p, false);
100 }
101
102 void paint_QTextLayout_cache(QPainter &p)
103 {
104     paint_QTextLayout(p, true);
105 }
106
107 void paint_QStaticText(QPainter &p, bool useOptimizations)
108 {
109     static QStaticText *staticText[lines];
110     static bool first = true;
111     if (first) {
112         for (int i = 0; i < lines; ++i) {
113             staticText[i] = new QStaticText(strings[i]);
114             if (useOptimizations)
115                 staticText[i]->setPerformanceHint(QStaticText::AggressiveCaching);
116             else
117                 staticText[i]->setPerformanceHint(QStaticText::ModerateCaching);
118         }
119         first = false;
120     }
121     for (int i = 0; i < count; ++i) {
122         for (int j = 0; j < lines; ++j) {
123             p.drawStaticText(QPointF(0, 30 + j*spacing), *staticText[j]);
124         }
125     }
126 }
127
128 void paint_QStaticText_noOptimizations(QPainter &p)
129 {
130     paint_QStaticText(p, false);
131 }
132
133 void paint_QStaticText_optimizations(QPainter &p)
134 {
135     paint_QStaticText(p, true);
136 }
137
138 void paint_QPixmapCachedText(QPainter &p)
139 {
140     static bool first = true;
141     static QPixmap cacheText[lines];
142     if (first) {
143         for (int i = 0; i < lines; ++i) {
144             QRectF trueSize;
145             trueSize = p.boundingRect(QRectF(QPointF(0,0), size), 0, strings[i]);
146             cacheText[i] = QPixmap(trueSize.size().toSize());
147             cacheText[i].fill(Qt::transparent);
148             QPainter paint(&cacheText[i]);
149             paint.setPen(Qt::black);
150             paint.drawText(QRectF(QPointF(0,0), trueSize.size().toSize()), strings[i]);
151         }
152         first = false;
153     }
154     for (int i = 0; i < count; i++) {
155         for (int j = 0; j < lines; ++j) {
156             p.drawPixmap(0,j*spacing,cacheText[j]);
157         }
158     }
159 }
160
161 void paint_RoundedRect(QPainter &p)
162 {
163     static bool first = true;
164     if (first) {
165         if (testWidget) {
166             QGLFormat format = testWidget->format();
167             if (!format.sampleBuffers())
168                 qWarning() << "Cannot paint antialiased rounded rect without sampleBuffers";
169         }
170         first = false;
171     }
172     p.setRenderHint(QPainter::Antialiasing, true);
173     p.setPen(Qt::black);
174     p.setBrush(Qt::red);
175     for (int i = 0; i < count; i++) {
176         for (int j = 0; j < lines; ++j) {
177             QSize size((j+1)*50, spacing-1);
178             p.drawRoundedRect(QRectF(QPointF(0,j*spacing), size), 8, 8);
179         }
180     }
181 }
182
183 void paint_QPixmapCachedRoundedRect(QPainter &p)
184 {
185     static bool first = true;
186     static QPixmap cacheRect;
187     if (first) {
188         const int pw = 0;
189         const int radius = 8;
190         cacheRect = QPixmap(radius*2 + 3 + pw*2, radius*2 + 3 + pw*2);
191         cacheRect.fill(Qt::transparent);
192         QPainter paint(&cacheRect);
193         paint.setRenderHint(QPainter::Antialiasing);
194         paint.setPen(Qt::black);
195         paint.setBrush(Qt::red);
196         if (pw%2)
197             paint.drawRoundedRect(QRectF(qreal(pw)/2+1, qreal(pw)/2+1, cacheRect.width()-(pw+1), cacheRect.height()-(pw+1)), radius, radius);
198         else
199             paint.drawRoundedRect(QRectF(qreal(pw)/2, qreal(pw)/2, cacheRect.width()-pw, cacheRect.height()-pw), radius, radius);
200
201         first = false;
202     }
203     for (int i = 0; i < count; i++) {
204         for (int j = 0; j < lines; ++j) {
205             QSize size((j+1)*50, spacing-1);
206
207             p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, true);
208
209             const int pw = 0;
210
211             int xOffset = (cacheRect.width()-1)/2;
212             int yOffset = (cacheRect.height()-1)/2;
213
214             QMargins margins(xOffset, yOffset, xOffset, yOffset);
215             QTileRules rules(Qt::StretchTile, Qt::StretchTile);
216             //NOTE: even though our item may have qreal-based width and height, qDrawBorderPixmap only supports QRects
217             qDrawBorderPixmap(&p, QRect(-pw/2, j*spacing-pw/2, size.width()+pw, size.height()+pw), margins, cacheRect, cacheRect.rect(), margins, rules);
218         }
219     }
220 }
221
222 void paint_pathCacheRoundedRect(QPainter &p)
223 {
224     static bool first = true;
225     static QPainterPath path[lines];
226     if (first) {
227         for (int j = 0; j < lines; ++j) {
228             path[j].addRoundedRect(QRectF(0,0,(j+1)*50, spacing-1), 8, 8);
229         }
230         first = false;
231     }
232     p.setRenderHint(QPainter::Antialiasing, true);
233     p.setPen(Qt::black);
234     p.setBrush(Qt::red);
235     for (int i = 0; i < count; i++) {
236         for (int j = 0; j < lines; ++j) {
237             p.translate(0,j*spacing);
238             p.drawPath(path[j]);
239             p.translate(0,-j*spacing);
240         }
241     }
242 }
243
244 void paint_QPixmap63x63_opaque(QPainter &p)
245 {
246     static bool first = true;
247     static QPixmap pm;
248     if (first) {
249         pm.load("data/63x63_opaque.png");
250         first = false;
251     }
252     for (int i = 0; i < count; i++) {
253         for (int j = 0; j < lines; ++j) {
254             p.drawPixmap((i%10) * 64,j*spacing, pm);
255         }
256     }
257 }
258
259 void paint_QPixmap64x64_opaque(QPainter &p)
260 {
261     static bool first = true;
262     static QPixmap pm;
263     if (first) {
264         pm.load("data/64x64_opaque.png");
265         first = false;
266     }
267     for (int i = 0; i < count; i++) {
268         for (int j = 0; j < lines; ++j) {
269             p.drawPixmap((i%10) * 64,j*spacing, pm);
270         }
271     }
272 }
273
274 void paint_QPixmap63x63(QPainter &p)
275 {
276     static bool first = true;
277     static QPixmap pm;
278     if (first) {
279         pm.load("data/63x63.png");
280         first = false;
281     }
282     for (int i = 0; i < count; i++) {
283         for (int j = 0; j < lines; ++j) {
284             p.drawPixmap((i%10) * 64,j*spacing, pm);
285         }
286     }
287 }
288
289 void paint_QPixmap64x64(QPainter &p)
290 {
291     static bool first = true;
292     static QPixmap pm;
293     if (first) {
294         pm.load("data/64x64.png");
295         first = false;
296     }
297     for (int i = 0; i < count; i++) {
298         for (int j = 0; j < lines; ++j) {
299             p.drawPixmap((i%10) * 64,j*spacing, pm);
300         }
301     }
302 }
303 typedef void(*PaintFunc)(QPainter &);
304
305 struct {
306     const char *name;
307     PaintFunc func;
308 } funcs[] = {
309     { "QTextLayoutNoCache", &paint_QTextLayout_noCache },
310     { "QTextLayoutWithCache", &paint_QTextLayout_cache },
311     { "QStaticTextNoBackendOptimizations", &paint_QStaticText_noOptimizations },
312     { "QStaticTextWithBackendOptimizations", &paint_QStaticText_optimizations },
313     { "CachedText", &paint_QPixmapCachedText },
314     { "RoundedRect", &paint_RoundedRect },
315     { "CachedRoundedRect", &paint_QPixmapCachedRoundedRect },
316     { "PathCacheRoundedRect", &paint_pathCacheRoundedRect },
317     { "QPixmap63x63_opaque", &paint_QPixmap63x63_opaque },
318     { "QPixmap64x64_opaque", &paint_QPixmap64x64_opaque },
319     { "QPixmap63x63", &paint_QPixmap63x63 },
320     { "QPixmap64x64", &paint_QPixmap64x64 },
321     { 0, 0 }
322 };
323
324 PaintFunc testFunc = 0;
325
326 class MyGLWidget : public QGLWidget
327 {
328 public:
329     MyGLWidget(const QGLFormat &format) : QGLWidget(format), frames(0) {
330         const char chars[] = "abcd efgh ijkl mnop qrst uvwx yz!$. ABCD 1234";
331         int len = strlen(chars);
332         for (int i = 0; i < lines; ++i) {
333             for (int j = 0; j < 60; j++) {
334                 strings[i] += QChar(chars[rand() % len]);
335             }
336         }
337     }
338
339     void paintEvent(QPaintEvent *) {
340         static int last = 0;
341         static bool firstRun = true;
342         if (firstRun) {
343             timer.start();
344             firstRun = false;
345         } else {
346             int elapsed = timer.elapsed();
347             qDebug() << "frame elapsed:" << elapsed - last;
348             last = elapsed;
349         }
350         QPainter p(this);
351         p.fillRect(rect(), Qt::white);
352         p.setPen(Qt::black);
353         QTime drawTimer;
354         drawTimer.start();
355         testFunc(p);
356         qDebug() << "draw time" << drawTimer.elapsed();
357         if (iterations--)
358             update();
359         else
360             qApp->quit();
361     }
362
363     QTime timer;
364     int frames;
365 };
366
367 int main(int argc, char *argv[])
368 {
369     QApplication app(argc, argv);
370
371     bool sampleBuffers = false;
372
373     for (int i = 1; i < argc; ++i) {
374         QString arg = argv[i];
375         if (arg == "-test") {
376             arg = argv[++i];
377             int j = 0;
378             while (funcs[j].name) {
379                 if (arg == funcs[j].name) {
380                     testFunc = funcs[j].func;
381                     qDebug() << "Running test" << arg;
382                     break;
383                 }
384                 ++j;
385             }
386         } else if (arg == "-iterations") {
387             arg = argv[++i];
388             iterations = arg.toInt();
389         } else if (arg == "-sampleBuffers") {
390             sampleBuffers = true;
391         }
392     }
393
394     if (testFunc == 0) {
395         qDebug() << "Usage: textspeed -test <test> [-sampleBuffers] [-iterations n]";
396         qDebug() << "where <test> can be:";
397         int j = 0;
398         while (funcs[j].name) {
399             qDebug() << "  " << funcs[j].name;
400             ++j;
401         }
402         exit(1);
403     }
404
405     QWidget w;
406     QGLFormat format = QGLFormat::defaultFormat();
407     format.setSampleBuffers(sampleBuffers);
408     testWidget = new MyGLWidget(format);
409     testWidget->setAutoFillBackground(false);
410     QVBoxLayout *layout = new QVBoxLayout(&w);
411     w.setLayout(layout);
412     layout->addWidget(testWidget);
413     w.showFullScreen();
414     app.exec();
415
416     return 0;
417 }