File indexing completed on 2025-02-16 04:05:07
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)