File indexing completed on 2024-05-12 16:01:31
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_fps_decoration.h" 0008 0009 #include <QApplication> 0010 #include <QPainter> 0011 #include "kis_canvas2.h" 0012 #include "kis_coordinates_converter.h" 0013 #include "opengl/kis_opengl_canvas_debugger.h" 0014 #include <KisStrokeSpeedMonitor.h> 0015 #include <QGraphicsScene> 0016 #include <QGraphicsPixmapItem> 0017 #include <QGraphicsDropShadowEffect> 0018 0019 const QString KisFpsDecoration::idTag = "fps_decoration"; 0020 0021 KisFpsDecoration::KisFpsDecoration(QPointer<KisView> view) 0022 : KisCanvasDecoration(idTag, view) 0023 , m_font(QApplication::font()) 0024 , m_pixmap(1, 1) // need non-zero pixmap for initial setup 0025 { 0026 setVisible(true); 0027 0028 m_shadow = new QGraphicsDropShadowEffect(this); 0029 m_shadow->setBlurRadius(0.5); 0030 m_shadow->setOffset(0); 0031 m_shadow->setColor(QColor(0x30, 0x30, 0x30)); 0032 0033 m_scene = new QGraphicsScene(this); 0034 m_pixmapItem = m_scene->addPixmap(m_pixmap); 0035 m_pixmapItem->setGraphicsEffect(m_shadow); 0036 } 0037 0038 KisFpsDecoration::~KisFpsDecoration() 0039 { 0040 } 0041 0042 void KisFpsDecoration::drawDecoration(QPainter& gc, const QRectF& /*updateRect*/, const KisCoordinatesConverter */*converter*/, KisCanvas2* /*canvas*/) 0043 { 0044 // we always paint into a pixmap instead of directly into gc, as the latter 0045 // approach is known to cause garbled graphics on macOS, Windows, and even 0046 // sometimes Linux. 0047 0048 const QString text = getText(); 0049 0050 // note that USUALLY the pixmap will have the right size. in very rare cases 0051 // (e.g. on the very first call) the computed bounding rect will not be right 0052 // and the pixmap will need a resize. it is faster to NOT usually calculate 0053 // the necessary bounds with an extra call like QFontMetrics::boundingRect() 0054 // here, as USUALLY the pixmap will be right and thus an extra call would be 0055 // unnecessary overhead. 0056 0057 QSize size; 0058 0059 if (!draw(text, size)) { 0060 // the pixmap is too small, we need to make it larger. make it 10% wider 0061 // than the measured width to avoid resizing again as soon as the text 0062 // gets a bit wider due to different content. 0063 0064 m_pixmap = QPixmap(size.width() * 1.1f, size.height()); 0065 0066 KIS_ASSERT(draw(text, size)); 0067 } 0068 0069 QRectF r = m_pixmap.rect(); 0070 r |= m_shadow->boundingRectFor(r); 0071 0072 m_pixmapItem->setPixmap(m_pixmap); 0073 m_scene->render(&gc, r.translated(20, 20), r); 0074 } 0075 0076 bool KisFpsDecoration::draw(const QString &text, QSize &outSize) 0077 { 0078 m_pixmap.fill(Qt::transparent); 0079 0080 const int flags = Qt::AlignLeft | Qt::AlignTop | Qt::TextDontClip; 0081 QRect bounds; 0082 0083 QPainter painter(&m_pixmap); 0084 painter.setFont(m_font); 0085 0086 painter.setPen(QPen(QColor(0xF0, 0xF0, 0xF0))); 0087 painter.drawText(m_pixmap.rect().translated(1, 1), flags, text, &bounds); 0088 0089 outSize = bounds.size() + QSize(1, 1); 0090 0091 if (m_pixmap.width() < outSize.width() || m_pixmap.height() != outSize.height()) { 0092 return false; // pixmap is too small and needs a resize. rarely happens. 0093 } 0094 0095 return true; 0096 } 0097 0098 QString KisFpsDecoration::getText() const 0099 { 0100 QStringList lines; 0101 0102 if (KisOpenglCanvasDebugger::instance()->showFpsOnCanvas()) { 0103 const qreal value = KisOpenglCanvasDebugger::instance()->accumulatedFps(); 0104 lines << QString("Canvas FPS: %1").arg(QString::number(value, 'f', 1)); 0105 } 0106 0107 KisStrokeSpeedMonitor *monitor = KisStrokeSpeedMonitor::instance(); 0108 0109 if (monitor->haveStrokeSpeedMeasurement()) { 0110 lines << QString("Last cursor/brush speed (px/ms): %1/%2%3") 0111 .arg(monitor->lastCursorSpeed(), 0, 'f', 1) 0112 .arg(monitor->lastRenderingSpeed(), 0, 'f', 1) 0113 .arg(monitor->lastStrokeSaturated() ? " (!)" : ""); 0114 lines << QString("Last brush framerate: %1 fps") 0115 .arg(monitor->lastFps(), 0, 'f', 1); 0116 0117 lines << QString("Average cursor/brush speed (px/ms): %1/%2") 0118 .arg(monitor->avgCursorSpeed(), 0, 'f', 1) 0119 .arg(monitor->avgRenderingSpeed(), 0, 'f', 1); 0120 lines << QString("Average brush framerate: %1 fps") 0121 .arg(monitor->avgFps(), 0, 'f', 1); 0122 } 0123 0124 return lines.join('\n'); 0125 }