File indexing completed on 2024-04-28 04:21:32

0001 /*
0002  *  SPDX-FileCopyrightText: 2010 Lukáš Tvrdý lukast.dev @gmail.com
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #if defined(_WIN32) || defined(_WIN64)
0008 #include <stdlib.h>
0009 #define srand48 srand
0010 inline double drand48()
0011 {
0012     return double(rand()) / RAND_MAX;
0013 }
0014 #endif
0015 
0016 #include <simpletest.h>
0017 
0018 #include <QImage>
0019 #include <kis_debug.h>
0020 
0021 #include "kis_painter_benchmark.h"
0022 #include "kis_benchmark_values.h"
0023 
0024 #include "kis_paint_device.h"
0025 #include "kis_fixed_paint_device.h"
0026 
0027 #include "kis_selection.h"
0028 #include "kis_pixel_selection.h"
0029 
0030 #include <KoColorSpace.h>
0031 #include <KoColorSpaceRegistry.h>
0032 #include <KoCompositeOpRegistry.h>
0033 #include <KoColor.h>
0034 
0035 #include <kis_image.h>
0036 #include <kis_painter.h>
0037 #include <kis_types.h>
0038 #include "kis_paintop_utils.h"
0039 #include "kis_algebra_2d.h"
0040 #include "kis_paint_device_debug_utils.h"
0041 #include "KisRenderedDab.h"
0042 
0043 
0044 #define SAVE_OUTPUT
0045 
0046 #define CYCLES 20
0047 static const int LINE_COUNT = 100;
0048 static const int LINE_WIDTH = 1;
0049 
0050 void KisPainterBenchmark::initTestCase()
0051 {
0052     m_colorSpace = KoColorSpaceRegistry::instance()->rgb8();    
0053     
0054     m_color = KoColor(m_colorSpace);
0055     m_color.fromQColor(Qt::red);
0056     
0057     
0058     srand48(0);
0059     for (int i = 0; i < LINE_COUNT ;i++){
0060         m_points.append( QPointF(drand48() * TEST_IMAGE_WIDTH, drand48() * TEST_IMAGE_HEIGHT) );
0061         m_points.append( QPointF(drand48() * TEST_IMAGE_WIDTH, drand48() * TEST_IMAGE_HEIGHT) );
0062     }
0063 }
0064 
0065 void KisPainterBenchmark::cleanupTestCase()
0066 {
0067 }
0068 
0069 void KisPainterBenchmark::benchmarkBitBlt()
0070 {
0071     KisPaintDeviceSP src = new KisPaintDevice(m_colorSpace);
0072     KisPaintDeviceSP dst = new KisPaintDevice(m_colorSpace);
0073     src->fill(0,0,TEST_IMAGE_WIDTH, TEST_IMAGE_HEIGHT, m_color.data());
0074     dst->fill(0,0,TEST_IMAGE_WIDTH, TEST_IMAGE_HEIGHT, m_color.data());
0075     
0076     KisPainter gc(dst);
0077     
0078     QPoint pos(0,0);
0079     QRect rc(0,0,TEST_IMAGE_WIDTH, TEST_IMAGE_HEIGHT);
0080     
0081     QBENCHMARK{
0082         for (int i = 0; i < CYCLES ; i++){
0083             gc.bitBlt(pos,src,rc);
0084         }
0085     }
0086 
0087 }
0088 
0089 void KisPainterBenchmark::benchmarkFastBitBlt()
0090 {
0091     KisPaintDeviceSP src = new KisPaintDevice(m_colorSpace);
0092     KisPaintDeviceSP dst = new KisPaintDevice(m_colorSpace);
0093     src->fill(0,0,TEST_IMAGE_WIDTH, TEST_IMAGE_HEIGHT, m_color.data());
0094     dst->fill(0,0,TEST_IMAGE_WIDTH, TEST_IMAGE_HEIGHT, m_color.data());
0095 
0096     KisPainter gc(dst);
0097     gc.setCompositeOpId(COMPOSITE_COPY);
0098 
0099     QPoint pos(0,0);
0100     QRect rc(0,0,TEST_IMAGE_WIDTH, TEST_IMAGE_HEIGHT);
0101 
0102     QBENCHMARK{
0103         for (int i = 0; i < CYCLES ; i++){
0104             gc.bitBlt(pos,src,rc);
0105         }
0106     }
0107 
0108 }
0109 
0110 void KisPainterBenchmark::benchmarkBitBltSelection()
0111 {
0112     KisPaintDeviceSP src = new KisPaintDevice(m_colorSpace);
0113     KisPaintDeviceSP dst = new KisPaintDevice(m_colorSpace);
0114     src->fill(0,0,TEST_IMAGE_WIDTH, TEST_IMAGE_HEIGHT, m_color.data());
0115     dst->fill(0,0,TEST_IMAGE_WIDTH, TEST_IMAGE_HEIGHT, m_color.data());
0116 
0117     KisSelectionSP selection = new KisSelection();
0118     selection->pixelSelection()->select(QRect(0, 0, TEST_IMAGE_WIDTH, TEST_IMAGE_HEIGHT));
0119     selection->updateProjection();
0120 
0121     
0122     KisPainter gc(dst);
0123     gc.setSelection(selection);
0124     
0125     QPoint pos(0,0);
0126     QRect rc(0,0,TEST_IMAGE_WIDTH, TEST_IMAGE_HEIGHT);
0127     
0128     QBENCHMARK{
0129         for (int i = 0; i < CYCLES ; i++){
0130             gc.bitBlt(pos,src,rc);
0131         }
0132     }
0133 
0134     
0135 }
0136 
0137 
0138 void KisPainterBenchmark::benchmarkFixedBitBlt()
0139 {
0140     QImage img(TEST_IMAGE_WIDTH,TEST_IMAGE_HEIGHT,QImage::Format_ARGB32);
0141     img.fill(255);
0142 
0143     KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(m_colorSpace);
0144     fdev->convertFromQImage(img, 0);
0145 
0146     KisPaintDeviceSP dst = new KisPaintDevice(m_colorSpace);
0147     KisPainter gc(dst);
0148     QPoint pos(0, 0);
0149     QRect rc = img.rect();
0150 
0151     QBENCHMARK{
0152         for (int i = 0; i < CYCLES ; i++){
0153             gc.bltFixed(pos,fdev,rc);
0154         }
0155     }
0156 }
0157 
0158 
0159 void KisPainterBenchmark::benchmarkFixedBitBltSelection()
0160 {
0161     QImage img(TEST_IMAGE_WIDTH,TEST_IMAGE_HEIGHT,QImage::Format_ARGB32);
0162     img.fill(128);
0163 
0164     KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(m_colorSpace);
0165     fdev->convertFromQImage(img, 0);
0166 
0167     KisPaintDeviceSP dst = new KisPaintDevice(m_colorSpace);
0168 
0169     KisSelectionSP selection = new KisSelection();
0170     selection->pixelSelection()->select(QRect(0, 0, TEST_IMAGE_WIDTH , TEST_IMAGE_HEIGHT));
0171     selection->updateProjection();
0172 
0173     KisPainter gc(dst);
0174     gc.setSelection(selection);
0175 
0176     QPoint pos(0, 0);
0177     QRect rc = img.rect();
0178 
0179     QBENCHMARK{
0180         for (int i = 0; i < CYCLES ; i++){
0181             gc.bltFixed(pos,fdev,rc);
0182         }
0183     }
0184 
0185 }
0186 
0187 void KisPainterBenchmark::benchmarkDrawThickLine()
0188 {
0189     KisPaintDeviceSP dev = new KisPaintDevice(m_colorSpace);
0190     KoColor color(m_colorSpace);
0191     color.fromQColor(Qt::white);
0192     
0193     dev->clear();
0194     dev->fill(0,0,TEST_IMAGE_WIDTH,TEST_IMAGE_HEIGHT,color.data());
0195     
0196     color.fromQColor(Qt::black);
0197     
0198     KisPainter painter(dev);
0199     painter.setPaintColor(color);
0200     
0201     QBENCHMARK{
0202         for (int i = 0; i < LINE_COUNT; i++){
0203             painter.drawThickLine(m_points[i*2],m_points[i*2+1],LINE_WIDTH,LINE_WIDTH);
0204         }
0205     }
0206 #ifdef SAVE_OUTPUT    
0207     dev->convertToQImage(m_colorSpace->profile()).save("drawThickLine.png");
0208 #endif
0209 }
0210 
0211 
0212 void KisPainterBenchmark::benchmarkDrawQtLine()
0213 {
0214     KisPaintDeviceSP dev = new KisPaintDevice(m_colorSpace);
0215     KoColor color(m_colorSpace);
0216     color.fromQColor(Qt::white);
0217     
0218     dev->clear();
0219     dev->fill(0,0,TEST_IMAGE_WIDTH,TEST_IMAGE_HEIGHT,color.data());
0220     
0221     color.fromQColor(Qt::black);
0222     
0223     KisPainter painter(dev);
0224     painter.setPaintColor(color);
0225     painter.setFillStyle(KisPainter::FillStyleForegroundColor);
0226     
0227     QPen pen;
0228     pen.setWidth(LINE_WIDTH);
0229     pen.setColor(Qt::white);
0230     pen.setCapStyle(Qt::RoundCap);
0231     
0232     QBENCHMARK{
0233         for (int i = 0; i < LINE_COUNT; i++){
0234             QPainterPath path;
0235             path.moveTo(m_points[i*2]);
0236             path.lineTo(m_points[i*2 + 1]);
0237             painter.drawPainterPath(path, pen);
0238         }
0239     }
0240 #ifdef SAVE_OUTPUT        
0241     dev->convertToQImage(m_colorSpace->profile(),0,0,TEST_IMAGE_WIDTH,TEST_IMAGE_HEIGHT).save("drawQtLine.png");
0242 #endif
0243 }
0244 
0245 void KisPainterBenchmark::benchmarkDrawScanLine()
0246 {
0247     KisPaintDeviceSP dev = new KisPaintDevice(m_colorSpace);
0248     KoColor color(m_colorSpace);
0249     color.fromQColor(Qt::white);
0250     
0251     dev->clear();
0252     dev->fill(0,0,TEST_IMAGE_WIDTH,TEST_IMAGE_HEIGHT,color.data());
0253     
0254     color.fromQColor(Qt::black);
0255     
0256     KisPainter painter(dev);
0257     painter.setPaintColor(color);
0258     painter.setFillStyle(KisPainter::FillStyleForegroundColor);
0259     
0260     
0261     QBENCHMARK{
0262         for (int i = 0; i < LINE_COUNT; i++){
0263             painter.drawLine(m_points[i*2],m_points[i*2+1],LINE_WIDTH,true);
0264         }
0265     }
0266 #ifdef SAVE_OUTPUT    
0267     dev->convertToQImage(m_colorSpace->profile(),0,0,TEST_IMAGE_WIDTH,TEST_IMAGE_HEIGHT).save("drawScanLine.png");
0268 #endif
0269 }
0270 
0271 void KisPainterBenchmark::benchmarkBitBlt2()
0272 {
0273     quint8 p = 128;
0274     const KoColorSpace *cs = KoColorSpaceRegistry::instance()->alpha8();
0275 
0276     KisPaintDeviceSP src = new KisPaintDevice(cs);
0277     KisPaintDeviceSP dst = new KisPaintDevice(cs);
0278 
0279     KoColor color(&p, cs);
0280     QRect fillRect(0,0,5000,5000);
0281 
0282     src->fill(fillRect, color);
0283 
0284     QBENCHMARK {
0285         KisPainter gc(dst);
0286         gc.bitBlt(QPoint(), src, fillRect);
0287     }
0288 }
0289 
0290 void KisPainterBenchmark::benchmarkBitBltOldData()
0291 {
0292     quint8 p = 128;
0293     const KoColorSpace *cs = KoColorSpaceRegistry::instance()->alpha8();
0294 
0295     KisPaintDeviceSP src = new KisPaintDevice(cs);
0296     KisPaintDeviceSP dst = new KisPaintDevice(cs);
0297 
0298     KoColor color(&p, cs);
0299     QRect fillRect(0,0,5000,5000);
0300 
0301     src->fill(fillRect, color);
0302 
0303     QBENCHMARK {
0304         KisPainter gc(dst);
0305         gc.bitBltOldData(QPoint(), src, fillRect);
0306     }
0307 }
0308 
0309 
0310 void benchmarkMassiveBltFixedImpl(int numDabs, int size, qreal spacing, int idealNumPatches, Qt::Orientations direction)
0311 {
0312     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
0313     KisPaintDeviceSP dst = new KisPaintDevice(cs);
0314 
0315     QList<QColor> colors;
0316     colors << QColor(255, 0, 0, 200);
0317     colors << QColor(0, 255, 0, 200);
0318     colors << QColor(0, 0, 255, 200);
0319 
0320     QRect devicesRect;
0321     QList<KisRenderedDab> devices;
0322 
0323     const int step = spacing * size;
0324 
0325     for (int i = 0; i < numDabs; i++) {
0326         const QRect rc =
0327             direction == Qt::Horizontal ? QRect(10 + i * step, 0, size, size) :
0328             direction == Qt::Vertical ? QRect(0, 10 + i * step, size, size) :
0329             QRect(10 + i * step, 10 + i * step, size, size);
0330 
0331         KisFixedPaintDeviceSP dev = new KisFixedPaintDevice(cs);
0332         dev->setRect(rc);
0333         dev->initialize();
0334         dev->fill(rc, KoColor(colors[i % 3], cs));
0335         dev->fill(kisGrowRect(rc, -5), KoColor(Qt::white, cs));
0336 
0337         KisRenderedDab dab;
0338         dab.device = dev;
0339         dab.offset = dev->bounds().topLeft();
0340         dab.opacity = 1.0;
0341         dab.flow = 1.0;
0342 
0343         devices << dab;
0344         devicesRect |= rc;
0345     }
0346 
0347     const QRect fullRect = kisGrowRect(devicesRect, 10);
0348 
0349     {
0350         KisPainter painter(dst);
0351         painter.bltFixed(fullRect, devices);
0352         painter.end();
0353         //QVERIFY(TestUtil::checkQImage(dst->convertToQImage(0, fullRect),
0354         //                              "kispainter_test",
0355         //                              "massive_bitblt_benchmark",
0356         //                              "initial"));
0357         dst->clear();
0358     }
0359 
0360 
0361     QVector<QRect> dabRects;
0362     Q_FOREACH (const KisRenderedDab &dab, devices) {
0363         dabRects.append(dab.realBounds());
0364     }
0365 
0366     QElapsedTimer t;
0367 
0368     qint64 massiveTime = 0;
0369     int massiveTries = 0;
0370     int numRects = 0;
0371     int avgPatchSize = 0;
0372 
0373     for (int i = 0; i < 50 || massiveTime > 5000000; i++) {
0374         QVector<QRect> rects = KisPaintOpUtils::splitDabsIntoRects(dabRects, idealNumPatches, size, spacing);
0375         numRects = rects.size();
0376 
0377         // HACK: please calculate real *average*!
0378         avgPatchSize = KisAlgebra2D::maxDimension(rects.first());
0379 
0380         t.start();
0381 
0382         KisPainter painter(dst);
0383         Q_FOREACH (const QRect &rc, rects) {
0384             painter.bltFixed(rc, devices);
0385         }
0386         painter.end();
0387 
0388         massiveTime += t.nsecsElapsed() / 1000;
0389         massiveTries++;
0390         dst->clear();
0391     }
0392 
0393     qint64 linearTime = 0;
0394     int linearTries = 0;
0395 
0396     for (int i = 0; i < 50 || linearTime > 5000000; i++) {
0397         t.start();
0398 
0399         KisPainter painter(dst);
0400         Q_FOREACH (const KisRenderedDab &dab, devices) {
0401             painter.setOpacity(255 * dab.opacity);
0402             painter.setFlow(255 * dab.flow);
0403             painter.bltFixed(dab.offset, dab.device, dab.device->bounds());
0404         }
0405         painter.end();
0406 
0407         linearTime += t.nsecsElapsed() / 1000;
0408         linearTries++;
0409         dst->clear();
0410     }
0411 
0412     const qreal avgMassive = qreal(massiveTime) / massiveTries;
0413     const qreal avgLinear = qreal(linearTime) / linearTries;
0414 
0415     const QString directionMark =
0416         direction == Qt::Horizontal ? "H" :
0417         direction == Qt::Vertical ? "V" : "D";
0418 
0419     qDebug()
0420             << "D:" << size
0421             << "S:" << spacing
0422             << "N:" << numDabs
0423             << "P (px):" << avgPatchSize
0424             << "R:" << numRects
0425             << "Dir:" << directionMark
0426             << "\t"
0427             << qPrintable(QString("Massive (usec): %1").arg(QString::number(avgMassive, 'f', 2), 8))
0428             << "\t"
0429             << qPrintable(QString("Linear (usec): %1").arg(QString::number(avgLinear, 'f', 2), 8))
0430             << (avgMassive < avgLinear ? "*" : " ")
0431             << qPrintable(QString("%1")
0432                    .arg(QString::number((avgMassive - avgLinear) / avgLinear * 100.0, 'f', 2), 8))
0433             << qRound(size + size * spacing * (numDabs - 1));
0434 }
0435 
0436 
0437 void KisPainterBenchmark::benchmarkMassiveBltFixed()
0438 {
0439     const qreal sp = 0.14;
0440     const int idealThreadCount = 8;
0441 
0442     for (int d = 50; d < 301; d += 50) {
0443         for (int n = 1; n < 150; n = qCeil(n * 1.5)) {
0444             benchmarkMassiveBltFixedImpl(n, d, sp, idealThreadCount, Qt::Horizontal);
0445             benchmarkMassiveBltFixedImpl(n, d, sp, idealThreadCount, Qt::Vertical);
0446             benchmarkMassiveBltFixedImpl(n, d, sp, idealThreadCount, Qt::Vertical | Qt::Horizontal);
0447         }
0448     }
0449 }
0450 
0451 
0452 
0453 SIMPLE_TEST_MAIN(KisPainterBenchmark)