Replace "Show FPS" effect with a QML version
This removes a bunch of custom rendering, replacing it with a simple QML file that makes use of KQuickCharts for chart rendering. Functionally, it should be mostly the same except that I removed all configuration options as I don't see why we have those.master
parent
fa5be54a6d
commit
5aa7a48f93
@ -1,38 +1,20 @@
|
||||
#######################################
|
||||
# Effect
|
||||
# SPDX-FileCopyrightText: 2022 Arjen Hiemstra <ahiemstra@heimr.nl>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
set(showfps_SOURCES
|
||||
main.cpp
|
||||
showfps.cpp
|
||||
)
|
||||
|
||||
kconfig_add_kcfg_files(showfps_SOURCES
|
||||
showfpsconfig.kcfgc
|
||||
showfpseffect.cpp
|
||||
)
|
||||
|
||||
kwin4_add_effect_module(kwin4_effect_showfps ${showfps_SOURCES})
|
||||
|
||||
target_link_libraries(kwin4_effect_showfps PRIVATE
|
||||
kwineffects
|
||||
kwinglutils
|
||||
|
||||
KF5::ConfigGui
|
||||
KF5::I18n
|
||||
)
|
||||
|
||||
#######################################
|
||||
# Config
|
||||
if (KWIN_BUILD_KCMS)
|
||||
set(kwin_showfps_config_SRCS showfps_config.cpp)
|
||||
ki18n_wrap_ui(kwin_showfps_config_SRCS showfps_config.ui)
|
||||
kconfig_add_kcfg_files(kwin_showfps_config_SRCS showfpsconfig.kcfgc)
|
||||
|
||||
kwin_add_effect_config(kwin_showfps_config ${kwin_showfps_config_SRCS})
|
||||
|
||||
target_link_libraries(kwin_showfps_config
|
||||
KF5::ConfigWidgets
|
||||
KF5::CoreAddons
|
||||
KF5::I18n
|
||||
Qt::DBus
|
||||
KWinEffectsInterface
|
||||
Qt::Quick
|
||||
)
|
||||
endif()
|
||||
|
||||
install(DIRECTORY qml DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/showfps)
|
||||
|
@ -0,0 +1,195 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2022 Arjen Hiemstra <ahiemstra@heimr.nl>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import org.kde.kirigami 2.18 as Kirigami
|
||||
import org.kde.quickcharts 1.0 as Charts
|
||||
import org.kde.quickcharts.controls 1.0 as ChartControls
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
required property QtObject effect
|
||||
|
||||
readonly property color gridColor: Qt.rgba(Kirigami.Theme.backgroundColor.r,
|
||||
Kirigami.Theme.backgroundColor.g,
|
||||
Kirigami.Theme.backgroundColor.b,
|
||||
0.25)
|
||||
|
||||
color: Qt.rgba(1.0, 1.0, 1.0, 0.5)
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Charts.BarChart {
|
||||
id: fpsChart
|
||||
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit
|
||||
Layout.fillHeight: true
|
||||
|
||||
yRange.minimum: root.effect.maximumFps + 10
|
||||
yRange.increment: 10
|
||||
|
||||
valueSources: Charts.SingleValueSource { value: root.effect.fps }
|
||||
|
||||
colorSource: Charts.SingleValueSource { value: Kirigami.Theme.highlightColor }
|
||||
|
||||
Charts.GridLines {
|
||||
anchors.fill: parent
|
||||
z: -1
|
||||
|
||||
chart: fpsChart
|
||||
|
||||
direction: Charts.GridLines.Vertical;
|
||||
|
||||
major.visible: false
|
||||
|
||||
minor.frequency: 10
|
||||
minor.lineWidth: 1
|
||||
minor.color: root.gridColor
|
||||
}
|
||||
}
|
||||
|
||||
Charts.BarChart {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
yRange.minimum: 100
|
||||
yRange.increment: 10
|
||||
|
||||
xRange.from: 0
|
||||
xRange.to: 50
|
||||
xRange.automatic: false
|
||||
|
||||
indexingMode: Charts.Chart.IndexSourceValues
|
||||
|
||||
valueSources: Charts.HistoryProxySource {
|
||||
source: Charts.SingleValueSource {
|
||||
value: root.effect.paintDuration
|
||||
}
|
||||
maximumHistory: 100
|
||||
fillMode: Charts.HistoryProxySource.FillFromStart
|
||||
}
|
||||
|
||||
colorSource: Charts.HistoryProxySource {
|
||||
source: Charts.SingleValueSource {
|
||||
value: root.effect.paintColor
|
||||
}
|
||||
maximumHistory: 100
|
||||
fillMode: Charts.HistoryProxySource.FillFromStart
|
||||
}
|
||||
|
||||
Charts.GridLines {
|
||||
anchors.fill: parent
|
||||
z: -1
|
||||
|
||||
chart: parent
|
||||
|
||||
direction: Charts.GridLines.Vertical;
|
||||
|
||||
major.visible: false
|
||||
|
||||
minor.frequency: 10
|
||||
minor.lineWidth: 1
|
||||
minor.color: root.gridColor
|
||||
}
|
||||
|
||||
Label {
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: i18nc("@label", "Paint Duration")
|
||||
font: Kirigami.Theme.smallFont
|
||||
}
|
||||
}
|
||||
|
||||
Charts.BarChart {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
yRange.minimum: Qt.application.screens[0].width * Qt.application.screens[0].height
|
||||
yRange.increment: 500000
|
||||
|
||||
xRange.from: 0
|
||||
xRange.to: 50
|
||||
xRange.automatic: false
|
||||
|
||||
indexingMode: Charts.Chart.IndexSourceValues
|
||||
|
||||
valueSources: Charts.HistoryProxySource {
|
||||
source: Charts.SingleValueSource {
|
||||
value: root.effect.paintAmount
|
||||
}
|
||||
maximumHistory: 100
|
||||
fillMode: Charts.HistoryProxySource.FillFromStart
|
||||
}
|
||||
|
||||
colorSource: Charts.HistoryProxySource {
|
||||
source: Charts.SingleValueSource {
|
||||
value: root.effect.paintColor
|
||||
}
|
||||
maximumHistory: 100
|
||||
fillMode: Charts.HistoryProxySource.FillFromStart
|
||||
}
|
||||
|
||||
Charts.GridLines {
|
||||
anchors.fill: parent
|
||||
z: -1
|
||||
|
||||
chart: parent
|
||||
|
||||
direction: Charts.GridLines.Vertical;
|
||||
|
||||
major.visible: false
|
||||
|
||||
minor.frequency: 100000
|
||||
minor.lineWidth: 1
|
||||
minor.color: root.gridColor
|
||||
}
|
||||
|
||||
Label {
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: i18nc("@label", "Paint Amount")
|
||||
font: Kirigami.Theme.smallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
ChartControls.LegendDelegate {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: 0
|
||||
|
||||
name: i18nc("@label", "Current FPS")
|
||||
value: root.effect.fps
|
||||
color: Kirigami.Theme.highlightColor
|
||||
}
|
||||
|
||||
ChartControls.LegendDelegate {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: 0
|
||||
|
||||
name: i18nc("@label", "Maximum FPS")
|
||||
value: root.effect.maximumFps
|
||||
color: Kirigami.Theme.neutralTextColor
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: i18nc("@label", "This effect is not a benchmark")
|
||||
}
|
||||
}
|
||||
}
|
@ -1,447 +0,0 @@
|
||||
/*
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "showfps.h"
|
||||
|
||||
// KConfigSkeleton
|
||||
#include "showfpsconfig.h"
|
||||
|
||||
#include <kwinconfig.h>
|
||||
|
||||
#include <kwinglutils.h>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPalette>
|
||||
#include <QVector2D>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
const int FPS_WIDTH = 10;
|
||||
const int MAX_TIME = 100;
|
||||
|
||||
ShowFpsEffect::ShowFpsEffect()
|
||||
: paints_pos(0)
|
||||
, frames_pos(0)
|
||||
, m_noBenchmark(effects->effectFrame(EffectFrameUnstyled, false))
|
||||
{
|
||||
initConfig<ShowFpsConfig>();
|
||||
for (int i = 0; i < NUM_PAINTS; i++) {
|
||||
paints[i] = 0;
|
||||
paint_size[i] = 0;
|
||||
}
|
||||
for (int i = 0; i < MAX_FPS; i++) {
|
||||
frames[i] = 0;
|
||||
}
|
||||
if (m_showNoBenchmark) {
|
||||
m_noBenchmark->setAlignment(Qt::AlignTop | Qt::AlignRight);
|
||||
m_noBenchmark->setText(i18n("This effect is not a benchmark"));
|
||||
}
|
||||
reconfigure(ReconfigureAll);
|
||||
}
|
||||
|
||||
ShowFpsEffect::~ShowFpsEffect() = default;
|
||||
|
||||
void ShowFpsEffect::reconfigure(ReconfigureFlags)
|
||||
{
|
||||
ShowFpsConfig::self()->read();
|
||||
alpha = ShowFpsConfig::alpha();
|
||||
x = ShowFpsConfig::x();
|
||||
y = ShowFpsConfig::y();
|
||||
m_showNoBenchmark = ShowFpsConfig::showNoBenchmark();
|
||||
m_showGraph = ShowFpsConfig::showGraph();
|
||||
m_colorizeText = ShowFpsConfig::colorizeText();
|
||||
const QSize screenSize = effects->virtualScreenSize();
|
||||
if (x == -10000) { // there's no -0 :(
|
||||
x = screenSize.width() - 2 * NUM_PAINTS - FPS_WIDTH;
|
||||
} else if (x < 0) {
|
||||
x = screenSize.width() - 2 * NUM_PAINTS - FPS_WIDTH - x;
|
||||
}
|
||||
if (y == -10000) {
|
||||
y = screenSize.height() - MAX_TIME;
|
||||
} else if (y < 0) {
|
||||
y = screenSize.height() - MAX_TIME - y;
|
||||
}
|
||||
fps_rect = QRect(x, y, FPS_WIDTH + 2 * NUM_PAINTS, MAX_TIME);
|
||||
m_noBenchmark->setPosition(fps_rect.bottomRight() + QPoint(-6, 6));
|
||||
|
||||
int textPosition = ShowFpsConfig::textPosition();
|
||||
textFont = ShowFpsConfig::textFont();
|
||||
textColor = ShowFpsConfig::textColor();
|
||||
double textAlpha = ShowFpsConfig::textAlpha();
|
||||
|
||||
if (!textColor.isValid()) {
|
||||
textColor = QPalette().color(QPalette::Active, QPalette::WindowText);
|
||||
}
|
||||
textColor.setAlphaF(textAlpha);
|
||||
|
||||
switch (textPosition) {
|
||||
case TOP_LEFT:
|
||||
fpsTextRect = QRect(0, 0, 100, 100);
|
||||
textAlign = Qt::AlignTop | Qt::AlignLeft;
|
||||
break;
|
||||
case TOP_RIGHT:
|
||||
fpsTextRect = QRect(screenSize.width() - 100, 0, 100, 100);
|
||||
textAlign = Qt::AlignTop | Qt::AlignRight;
|
||||
break;
|
||||
case BOTTOM_LEFT:
|
||||
fpsTextRect = QRect(0, screenSize.height() - 100, 100, 100);
|
||||
textAlign = Qt::AlignBottom | Qt::AlignLeft;
|
||||
break;
|
||||
case BOTTOM_RIGHT:
|
||||
fpsTextRect = QRect(screenSize.width() - 100, screenSize.height() - 100, 100, 100);
|
||||
textAlign = Qt::AlignBottom | Qt::AlignRight;
|
||||
break;
|
||||
case NOWHERE:
|
||||
fpsTextRect = QRect();
|
||||
break;
|
||||
case INSIDE_GRAPH:
|
||||
default:
|
||||
fpsTextRect = QRect(x, y, FPS_WIDTH + NUM_PAINTS, MAX_TIME);
|
||||
textAlign = Qt::AlignTop | Qt::AlignRight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ShowFpsEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime)
|
||||
{
|
||||
frames[frames_pos] = QDateTime::currentMSecsSinceEpoch();
|
||||
if (++frames_pos == MAX_FPS) {
|
||||
frames_pos = 0;
|
||||
}
|
||||
effects->prePaintScreen(data, presentTime);
|
||||
data.paint += fps_rect;
|
||||
|
||||
paint_size[paints_pos] = 0;
|
||||
t.restart();
|
||||
|
||||
// detect highest monitor refresh rate
|
||||
int num_screens = effects->screens().size();
|
||||
detectedMaxFps = 0;
|
||||
for (int i = 0; i < num_screens; ++i) {
|
||||
detectedMaxFps = std::max(effects->screens().at(i)->refreshRate(), detectedMaxFps);
|
||||
}
|
||||
detectedMaxFps /= 1000; // convert mHz to Hz (see kwineffects.h: EffectScreen)
|
||||
}
|
||||
|
||||
void ShowFpsEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data)
|
||||
{
|
||||
effects->paintWindow(w, mask, region, data);
|
||||
|
||||
// Take intersection of region and actual window's rect, minus the fps area
|
||||
// (since we keep repainting it) and count the pixels.
|
||||
QRegion r2 = region & QRect(w->x(), w->y(), w->width(), w->height());
|
||||
r2 -= fps_rect;
|
||||
int winsize = 0;
|
||||
for (const QRect &r : r2) {
|
||||
winsize += r.width() * r.height();
|
||||
}
|
||||
paint_size[paints_pos] += winsize;
|
||||
}
|
||||
|
||||
void ShowFpsEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data)
|
||||
{
|
||||
effects->paintScreen(mask, region, data);
|
||||
int lastFrame = frames_pos - 1;
|
||||
if (lastFrame < 0) {
|
||||
lastFrame = MAX_FPS - 1;
|
||||
}
|
||||
const qint64 lastTimestamp = frames[lastFrame];
|
||||
int fps = 0;
|
||||
for (int i = 0; i < MAX_FPS; i++) {
|
||||
if (abs(lastTimestamp - frames[i]) < 1000) {
|
||||
++fps; // count all frames in the last second
|
||||
}
|
||||
}
|
||||
if (effects->isOpenGLCompositing()) {
|
||||
paintGL(fps, data.projectionMatrix());
|
||||
glFinish(); // make sure all rendering is done
|
||||
} else if (effects->compositingType() == QPainterCompositing) {
|
||||
paintQPainter(fps);
|
||||
}
|
||||
if (m_showNoBenchmark) {
|
||||
m_noBenchmark->render(infiniteRegion(), 1.0, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
void ShowFpsEffect::paintGL(int fps, const QMatrix4x4 &projectionMatrix)
|
||||
{
|
||||
int x = this->x;
|
||||
int y = this->y;
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
// TODO painting first the background white and then the contents
|
||||
// means that the contents also blend with the background, I guess
|
||||
ShaderBinder binder(ShaderTrait::UniformColor);
|
||||
binder.shader()->setUniform(GLShader::ModelViewProjectionMatrix, projectionMatrix);
|
||||
if (m_showGraph) {
|
||||
GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
|
||||
vbo->reset();
|
||||
QColor color(255, 255, 255);
|
||||
color.setAlphaF(alpha);
|
||||
vbo->setColor(color);
|
||||
QVector<float> verts;
|
||||
verts.reserve(12);
|
||||
verts << x + 2 * NUM_PAINTS + FPS_WIDTH << y;
|
||||
verts << x << y;
|
||||
verts << x << y + MAX_TIME;
|
||||
verts << x << y + MAX_TIME;
|
||||
verts << x + 2 * NUM_PAINTS + FPS_WIDTH << y + MAX_TIME;
|
||||
verts << x + 2 * NUM_PAINTS + FPS_WIDTH << y;
|
||||
vbo->setData(6, 2, verts.constData(), nullptr);
|
||||
vbo->render(GL_TRIANGLES);
|
||||
y += MAX_TIME; // paint up from the bottom
|
||||
color.setRed(0);
|
||||
color.setGreen(0);
|
||||
vbo->setColor(color);
|
||||
verts.clear();
|
||||
verts << x + FPS_WIDTH << y - fps;
|
||||
verts << x << y - fps;
|
||||
verts << x << y;
|
||||
verts << x << y;
|
||||
verts << x + FPS_WIDTH << y;
|
||||
verts << x + FPS_WIDTH << y - fps;
|
||||
vbo->setData(6, 2, verts.constData(), nullptr);
|
||||
vbo->render(GL_TRIANGLES);
|
||||
|
||||
color.setBlue(0);
|
||||
vbo->setColor(color);
|
||||
QVector<float> vertices;
|
||||
for (int i = 10; i < MAX_TIME; i += 10) {
|
||||
vertices << x << y - i;
|
||||
vertices << x + FPS_WIDTH << y - i;
|
||||
}
|
||||
vbo->setData(vertices.size() / 2, 2, vertices.constData(), nullptr);
|
||||
vbo->render(GL_LINES);
|
||||
x += FPS_WIDTH;
|
||||
|
||||
// Paint FPS graph
|
||||
paintFPSGraph(x, y);
|
||||
x += NUM_PAINTS;
|
||||
|
||||
// Paint amount of rendered pixels graph
|
||||
paintDrawSizeGraph(x, y);
|
||||
}
|
||||
|
||||
// Paint FPS numerical value
|
||||
if (fpsTextRect.isValid()) {
|
||||
fpsText.reset(new GLTexture(fpsTextImage(fps)));
|
||||
fpsText->bind();
|
||||
ShaderBinder binder(ShaderTrait::MapTexture);
|
||||
QMatrix4x4 mvp = projectionMatrix;
|
||||
mvp.translate(fpsTextRect.x(), fpsTextRect.y());
|
||||
binder.shader()->setUniform(GLShader::ModelViewProjectionMatrix, mvp);
|
||||
fpsText->render(fpsTextRect);
|
||||
fpsText->unbind();
|
||||
effects->addRepaint(fpsTextRect);
|
||||
}
|
||||
|
||||
// Paint paint sizes
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
void ShowFpsEffect::paintQPainter(int fps)
|
||||
{
|
||||
QPainter *painter = effects->scenePainter();
|
||||
painter->save();
|
||||
|
||||
if (m_showGraph) {
|
||||
QColor color(255, 255, 255);
|
||||
color.setAlphaF(alpha);
|
||||
|
||||
painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
painter->fillRect(x, y, 2 * NUM_PAINTS + FPS_WIDTH, MAX_TIME, color);
|
||||
color.setRed(0);
|
||||
color.setGreen(0);
|
||||
painter->fillRect(x, y + MAX_TIME - fps, FPS_WIDTH, fps, color);
|
||||
|
||||
color.setBlue(0);
|
||||
for (int i = 10; i < MAX_TIME; i += 10) {
|
||||
painter->setPen(color);
|
||||
painter->drawLine(x, y + MAX_TIME - i, x + FPS_WIDTH, y + MAX_TIME - i);
|
||||
}
|
||||
|
||||
// Paint FPS graph
|
||||
paintFPSGraph(x + FPS_WIDTH, y + MAX_TIME - 1);
|
||||
|
||||
// Paint amount of rendered pixels graph
|
||||
paintDrawSizeGraph(x + FPS_WIDTH + NUM_PAINTS, y + MAX_TIME - 1);
|
||||
}
|
||||
|
||||
// Paint FPS numerical value
|
||||
painter->setPen(Qt::black);
|
||||
painter->drawText(fpsTextRect, textAlign, QString::number(fps));
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void ShowFpsEffect::paintFPSGraph(int x, int y)
|
||||
{
|
||||
// Paint FPS graph
|
||||
QList<int> lines;
|
||||
lines << 10 << 20 << 50;
|
||||
QList<int> values;
|
||||
for (int i = 0;
|
||||
i < NUM_PAINTS;
|
||||
++i) {
|
||||
values.append(paints[(i + paints_pos) % NUM_PAINTS]);
|
||||
}
|
||||
paintGraph(x, y, values, lines, true);
|
||||
}
|
||||
|
||||
void ShowFpsEffect::paintDrawSizeGraph(int x, int y)
|
||||
{
|
||||
int max_drawsize = 0;
|
||||
for (int i = 0; i < NUM_PAINTS; i++) {
|
||||
max_drawsize = qMax(max_drawsize, paint_size[i]);
|
||||
}
|
||||
|
||||
// Log of min/max values shown on graph
|
||||
const float max_pixels_log = 7.2f;
|
||||
const float min_pixels_log = 2.0f;
|
||||
const int minh = 5; // Minimum height of the bar when value > 0
|
||||
|
||||
float drawscale = (MAX_TIME - minh) / (max_pixels_log - min_pixels_log);
|
||||
QList<int> drawlines;
|
||||
|
||||
for (int logh = (int)min_pixels_log; logh <= max_pixels_log; logh++) {
|
||||
drawlines.append((int)((logh - min_pixels_log) * drawscale) + minh);
|
||||
}
|
||||
|
||||
QList<int> drawvalues;
|
||||
for (int i = 0;
|
||||
i < NUM_PAINTS;
|
||||
++i) {
|
||||
int value = paint_size[(i + paints_pos) % NUM_PAINTS];
|
||||
int h = 0;
|
||||
if (value > 0) {
|
||||
h = (int)((log10((double)value) - min_pixels_log) * drawscale);
|
||||
h = qMin(qMax(0, h) + minh, MAX_TIME);
|
||||
}
|
||||
drawvalues.append(h);
|
||||
}
|
||||
paintGraph(x, y, drawvalues, drawlines, false);
|
||||
}
|
||||
|
||||
void ShowFpsEffect::paintGraph(int x, int y, QList<int> values, QList<int> lines, bool colorize)
|
||||
{
|
||||
if (effects->isOpenGLCompositing()) {
|
||||
QColor color(0, 0, 0);
|
||||
color.setAlphaF(alpha);
|
||||
GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
|
||||
vbo->reset();
|
||||
vbo->setColor(color);
|
||||
QVector<float> verts;
|
||||
// First draw the lines
|
||||
for (int h : qAsConst(lines)) {
|
||||
verts << x << y - h;
|
||||
verts << x + values.count() << y - h;
|
||||
}
|
||||
vbo->setData(verts.size() / 2, 2, verts.constData(), nullptr);
|
||||
vbo->render(GL_LINES);
|
||||
// Then the graph values
|
||||
int lastValue = 0;
|
||||
verts.clear();
|
||||
for (int i = 0; i < values.count(); i++) {
|
||||
int value = values[i];
|
||||
if (colorize && value != lastValue) {
|
||||
if (!verts.isEmpty()) {
|
||||
vbo->setData(verts.size() / 2, 2, verts.constData(), nullptr);
|
||||
vbo->render(GL_LINES);
|
||||
}
|
||||
verts.clear();
|
||||
if (value <= 10) {
|
||||
color = QColor(0, 255, 0);
|
||||
} else if (value <= 20) {
|
||||
color = QColor(255, 255, 0);
|
||||
} else if (value <= 50) {
|
||||
color = QColor(255, 0, 0);
|
||||
} else {
|
||||
color = QColor(0, 0, 0);
|
||||
}
|
||||
vbo->setColor(color);
|
||||
}
|
||||
verts << x + values.count() - i << y;
|
||||
verts << x + values.count() - i << y - value;
|
||||
lastValue = value;
|
||||
}
|
||||
if (!verts.isEmpty()) {
|
||||
vbo->setData(verts.size() / 2, 2, verts.constData(), nullptr);
|
||||
vbo->render(GL_LINES);
|
||||
}
|
||||
} else if (effects->compositingType() == QPainterCompositing) {
|
||||
QPainter *painter = effects->scenePainter();
|
||||
painter->setPen(Qt::black);
|
||||
// First draw the lines
|
||||
for (int h : qAsConst(lines)) {
|
||||
painter->drawLine(x, y - h, x + values.count(), y - h);
|
||||
}
|
||||
QColor color(0, 0, 0);
|
||||
color.setAlphaF(alpha);
|
||||
for (int i = 0; i < values.count(); i++) {
|
||||
int value = values[i];
|
||||
if (colorize) {
|
||||
if (value <= 10) {
|
||||
color = QColor(0, 255, 0);
|
||||
} else if (value <= 20) {
|
||||
color = QColor(255, 255, 0);
|
||||
} else if (value <= 50) {
|
||||
color = QColor(255, 0, 0);
|
||||
} else {
|
||||
color = QColor(0, 0, 0);
|
||||
}
|
||||
}
|
||||
painter->setPen(color);
|
||||
painter->drawLine(x + values.count() - i, y, x + values.count() - i, y - value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShowFpsEffect::postPaintScreen()
|
||||
{
|
||||
effects->postPaintScreen();
|
||||
paints[paints_pos] = t.elapsed();
|
||||
if (++paints_pos == NUM_PAINTS) {
|
||||
paints_pos = 0;
|
||||
}
|
||||
effects->addRepaint(fps_rect);
|
||||
}
|
||||
|
||||
QImage ShowFpsEffect::fpsTextImage(int fps)
|
||||
{
|
||||
QImage im(100, 100, QImage::Format_ARGB32);
|
||||
im.fill(Qt::transparent);
|
||||
QPainter painter(&im);
|
||||
painter.setFont(textFont);
|
||||
QColor col = textColor;
|
||||
if (detectedMaxFps > 0) {
|
||||
fps = std::min(fps, detectedMaxFps);
|
||||
}
|
||||
if (m_colorizeText) {
|
||||
if (fps >= detectedMaxFps * 0.75) {
|
||||
col = QColor(0, 255, 0); // green
|
||||
} else if (fps >= detectedMaxFps * 0.5) {
|
||||
col = QColor(255, 255, 0); // yellow
|
||||
} else if (fps >= detectedMaxFps * 0.25) {
|
||||
col = QColor(255, 0, 0); // red
|
||||
} else {
|
||||
col = QColor(0, 0, 0); // black
|
||||
}
|
||||
}
|
||||
painter.setPen(col);
|
||||
painter.drawText(QRect(0, 0, 100, 100), textAlign, QString::number(fps));
|
||||
painter.end();
|
||||
return im;
|
||||
}
|
||||
|
||||
} // namespace
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KWIN_SHOWFPS_H
|
||||
#define KWIN_SHOWFPS_H
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QFont>
|
||||
|
||||
#include <kwineffects.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
class GLTexture;
|
||||
|
||||
class ShowFpsEffect
|
||||
: public Effect
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(qreal alpha READ configuredAlpha)
|
||||
Q_PROPERTY(int x READ configuredX)
|
||||
Q_PROPERTY(int y READ configuredY)
|
||||
Q_PROPERTY(QRect fpsTextRect READ configuredFpsTextRect)
|
||||
Q_PROPERTY(int textAlign READ configuredTextAlign)
|
||||
Q_PROPERTY(QFont textFont READ configuredTextFont)
|
||||
Q_PROPERTY(QColor textColor READ configuredTextColor)
|
||||
Q_PROPERTY(bool showGraph READ configuredShowGraph)
|
||||
Q_PROPERTY(bool showNoBenchmark READ configuredShowNoBenchmark)
|
||||
Q_PROPERTY(bool colorizeText READ configuredColorizeText)
|
||||
public:
|
||||
ShowFpsEffect();
|
||||
~ShowFpsEffect() override;
|
||||
|
||||
void reconfigure(ReconfigureFlags) override;
|
||||
void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override;
|
||||
void paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data) override;
|
||||
void paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override;
|
||||
void postPaintScreen() override;
|
||||
enum {
|
||||
INSIDE_GRAPH,
|
||||
NOWHERE,
|
||||
TOP_LEFT,
|
||||
TOP_RIGHT,
|
||||
BOTTOM_LEFT,
|
||||
BOTTOM_RIGHT,
|
||||
}; // fps text position
|
||||
|
||||
// for properties
|
||||
qreal configuredAlpha() const
|
||||
{
|
||||
return alpha;
|
||||
}
|
||||
int configuredX() const
|
||||
{
|
||||
return x;
|
||||
}
|
||||
int configuredY() const
|
||||
{
|
||||
return y;
|
||||
}
|
||||
QRect configuredFpsTextRect() const
|
||||
{
|
||||
return fpsTextRect;
|
||||
}
|
||||
int configuredTextAlign() const
|
||||
{
|
||||
return textAlign;
|
||||
}
|
||||
QFont configuredTextFont() const
|
||||
{
|
||||
return textFont;
|
||||
}
|
||||
QColor configuredTextColor() const
|
||||
{
|
||||
return textColor;
|
||||
}
|
||||
bool configuredShowGraph() const
|
||||
{
|
||||
return m_showGraph;
|
||||
}
|
||||
bool configuredShowNoBenchmark() const
|
||||
{
|
||||
return m_showNoBenchmark;
|
||||
}
|
||||
bool configuredColorizeText() const
|
||||
{
|
||||
return m_colorizeText;
|
||||
}
|
||||
|
||||
private:
|
||||
void paintGL(int fps, const QMatrix4x4 &projectionMatrix);
|
||||
void paintQPainter(int fps);
|
||||
void paintFPSGraph(int x, int y);
|
||||
void paintDrawSizeGraph(int x, int y);
|
||||
void paintGraph(int x, int y, QList<int> values, QList<int> lines, bool colorize);
|
||||
QImage fpsTextImage(int fps);
|
||||
QElapsedTimer t;
|
||||
enum {
|
||||
NUM_PAINTS = 100,
|
||||
}; // remember time needed to paint this many paints
|
||||
int paints[NUM_PAINTS]; // time needed to paint
|
||||
int paint_size[NUM_PAINTS]; // number of pixels painted
|
||||
int paints_pos; // position in the queue
|
||||
enum {
|
||||
MAX_FPS = 200,
|
||||
};
|
||||
qint64 frames[MAX_FPS]; // the time when the frame was done
|
||||
int frames_pos; // position in the queue
|
||||
double alpha;
|
||||
bool m_showNoBenchmark;
|
||||
bool m_showGraph;
|
||||
bool m_colorizeText;
|
||||
int detectedMaxFps;
|
||||
int x;
|
||||
int y;
|
||||
QRect fps_rect;
|
||||
std::unique_ptr<GLTexture> fpsText;
|
||||
int textPosition;
|
||||
QFont textFont;
|
||||
QColor textColor;
|
||||
QRect fpsTextRect;
|
||||
int textAlign;
|
||||
std::unique_ptr<EffectFrame> m_noBenchmark;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
@ -1,37 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
|
||||
<kcfgfile arg="true"/>
|
||||
<group name="Effect-showfps">
|
||||
<entry name="TextPosition" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="TextFont" type="Font"/>
|
||||
<entry name="TextColor" type="Color">
|
||||
<default>invalid</default>
|
||||
</entry>
|
||||
<entry name="TextAlpha" type="Double">
|
||||
<default>1.0</default>
|
||||
</entry>
|
||||
<entry name="Alpha" type="Double">
|
||||
<default>0.5</default>
|
||||
</entry>
|
||||
<entry name="X" type="Int">
|
||||
<default>-10000</default>
|
||||
</entry>
|
||||
<entry name="Y" type="Int">
|
||||
<default>0</default>
|
||||
</entry>
|
||||
<entry name="ShowGraph" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="ShowNoBenchmark" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="ColorizeText" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
SPDX-FileCopyrightText: 2007 Rivo Laks <rivolaks@hot.ee>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "showfps_config.h"
|
||||
|
||||
#include <config-kwin.h>
|
||||
|
||||
// KConfigSkeleton
|
||||
#include "showfpsconfig.h"
|
||||
#include <kwineffects_interface.h>
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <KPluginFactory>
|
||||
|
||||
K_PLUGIN_CLASS(KWin::ShowFpsEffectConfig)
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
ShowFpsEffectConfig::ShowFpsEffectConfig(QWidget *parent, const QVariantList &args)
|
||||
: KCModule(parent, args)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
ShowFpsConfig::instance(KWIN_CONFIG);
|
||||
addConfig(ShowFpsConfig::self(), this);
|
||||
}
|
||||
|
||||
void ShowFpsEffectConfig::save()
|
||||
{
|
||||
KCModule::save();
|
||||
OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"),
|
||||
QStringLiteral("/Effects"),
|
||||
QDBusConnection::sessionBus());
|
||||
interface.reconfigureEffect(QStringLiteral("showfps"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#include "showfps_config.moc"
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
SPDX-FileCopyrightText: 2007 Rivo Laks <rivolaks@hot.ee>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KWIN_SHOWFPS_CONFIG_H
|
||||
#define KWIN_SHOWFPS_CONFIG_H
|
||||
|
||||
#include <kcmodule.h>
|
||||
|
||||
#include "ui_showfps_config.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class ShowFpsEffectConfig : public KCModule
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ShowFpsEffectConfig(QWidget *parent = nullptr, const QVariantList &args = QVariantList());
|
||||
|
||||
public Q_SLOTS:
|
||||
void save() override;
|
||||
|
||||
private:
|
||||
Ui::ShowFpsEffectConfigForm m_ui;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
@ -1,230 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>KWin::ShowFpsEffectConfigForm</class>
|
||||
<widget class="QWidget" name="KWin::ShowFpsEffectConfigForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>356</width>
|
||||
<height>250</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Text</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Text position:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>kcfg_TextPosition</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="kcfg_TextPosition">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Inside Graph</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Nowhere</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Top Left</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Top Right</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Bottom Left</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Bottom Right</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Text font:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="KFontRequester" name="kcfg_TextFont">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Text color:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>kcfg_TextColor</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="KColorButton" name="kcfg_TextColor">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Text alpha:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>kcfg_TextAlpha</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="kcfg_TextAlpha">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Show graph:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>kcfg_ShowGraph</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="kcfg_ShowGraph">
|
||||
<property name="text">
|
||||
<string>Show on active screen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Show Message:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>kcfg_ShowNoBenchmark</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="kcfg_ShowNoBenchmark">
|
||||
<property name="text">
|
||||
<string>Show "not a benchmark" message</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Colorize Text:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>kcfg_ColorizeText</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QCheckBox" name="kcfg_ColorizeText">
|
||||
<property name="text">
|
||||
<string>Color text by value (green > yellow > red)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KColorButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>kcolorbutton.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>KFontRequester</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>kfontrequester.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -1,5 +0,0 @@
|
||||
File=showfps.kcfg
|
||||
ClassName=ShowFpsConfig
|
||||
NameSpace=KWin
|
||||
Singleton=true
|
||||
Mutators=true
|
@ -0,0 +1,126 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
SPDX-FileCopyrightText: 2022 Arjen Hiemstra <ahiemstra@heimr.nl>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "showfpseffect.h"
|
||||
|
||||
#include <QQmlContext>
|
||||
#include <QWindow>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
ShowFpsEffect::ShowFpsEffect()
|
||||
{
|
||||
}
|
||||
|
||||
ShowFpsEffect::~ShowFpsEffect() = default;
|
||||
|
||||
int ShowFpsEffect::fps() const
|
||||
{
|
||||
return m_fps;
|
||||
}
|
||||
|
||||
int ShowFpsEffect::maximumFps() const
|
||||
{
|
||||
return m_maximumFps;
|
||||
}
|
||||
|
||||
int ShowFpsEffect::paintDuration() const
|
||||
{
|
||||
return m_paintDuration;
|
||||
}
|
||||
|
||||
int ShowFpsEffect::paintAmount() const
|
||||
{
|
||||
return m_paintAmount;
|
||||
}
|
||||
|
||||
QColor ShowFpsEffect::paintColor() const
|
||||
{
|
||||
auto normalizedDuration = std::min(1.0, m_paintDuration / 100.0);
|
||||
return QColor::fromHsvF(0.3 - (0.3 * normalizedDuration), 1.0, 1.0);
|
||||
}
|
||||
|
||||
void ShowFpsEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime)
|
||||
{
|
||||
effects->prePaintScreen(data, presentTime);
|
||||
|
||||
m_newFps += 1;
|
||||
|
||||
m_paintDurationTimer.restart();
|
||||
m_paintAmount = 0;
|
||||
|
||||
// detect highest monitor refresh rate
|
||||
int maximumFps = 0;
|
||||
const auto screens = effects->screens();
|
||||
for (auto screen : screens) {
|
||||
maximumFps = std::max(screen->refreshRate(), maximumFps);
|
||||
}
|
||||
maximumFps /= 1000; // Convert from mHz to Hz.
|
||||
|
||||
if (maximumFps != m_maximumFps) {
|
||||
m_maximumFps = maximumFps;
|
||||
Q_EMIT maximumFpsChanged();
|
||||
}
|
||||
|
||||
if (!m_scene) {
|
||||
m_window = std::make_unique<QWindow>();
|
||||
m_window->create();
|
||||
m_scene = std::make_unique<OffscreenQuickScene>(nullptr, m_window.get());
|
||||
const auto url = QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/effects/showfps/qml/main.qml")));
|
||||
m_scene->setSource(url, {{QStringLiteral("effect"), QVariant::fromValue(this)}});
|
||||
}
|
||||
|
||||
const auto rect = effects->renderTargetRect();
|
||||
m_scene->setGeometry(QRect(rect.x() + rect.width() - 300, 0, 300, 150));
|
||||
}
|
||||
|
||||
void ShowFpsEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data)
|
||||
{
|
||||
effects->paintScreen(mask, region, data);
|
||||
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
if ((now - m_lastFpsTime) >= std::chrono::milliseconds(1000)) {
|
||||
m_fps = m_newFps;
|
||||
m_newFps = 0;
|
||||
m_lastFpsTime = now;
|
||||
Q_EMIT fpsChanged();
|
||||
}
|
||||
|
||||
effects->renderOffscreenQuickView(m_scene.get());
|
||||
}
|
||||
|
||||
void ShowFpsEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data)
|
||||
{
|
||||
effects->paintWindow(w, mask, region, data);
|
||||
|
||||
// Take intersection of region and actual window's rect, minus the fps area
|
||||
// (since we keep repainting it) and count the pixels.
|
||||
QRegion repaintRegion = region & w->frameGeometry().toRect();
|
||||
repaintRegion -= m_scene->geometry();
|
||||
for (const QRect &rect : repaintRegion) {
|
||||
m_paintAmount += rect.width() * rect.height();
|
||||
}
|
||||
}
|
||||
|
||||
void ShowFpsEffect::postPaintScreen()
|
||||
{
|
||||
effects->postPaintScreen();
|
||||
|
||||
m_paintDuration = m_paintDurationTimer.elapsed();
|
||||
Q_EMIT paintChanged();
|
||||
|
||||
effects->addRepaint(m_scene->geometry());
|
||||
}
|
||||
|
||||
bool ShowFpsEffect::supported()
|
||||
{
|
||||
return effects->isOpenGLCompositing();
|
||||
}
|
||||
|
||||
} // namespace KWin
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
SPDX-FileCopyrightText: 2022 Arjen Hiemstra <ahiemstra@heimr.nl>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <kwineffects.h>
|
||||
#include <kwinoffscreenquickview.h>
|
||||
|
||||
#include <QElapsedTimer>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class ShowFpsEffect : public Effect
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int fps READ fps NOTIFY fpsChanged)
|
||||
Q_PROPERTY(int maximumFps READ maximumFps NOTIFY maximumFpsChanged)
|
||||
Q_PROPERTY(int paintDuration READ paintDuration NOTIFY paintChanged)
|
||||
Q_PROPERTY(int paintAmount READ paintAmount NOTIFY paintChanged)
|
||||
Q_PROPERTY(QColor paintColor READ paintColor NOTIFY paintChanged)
|
||||
|
||||
public:
|
||||
ShowFpsEffect();
|
||||
~ShowFpsEffect() override;
|
||||
|
||||
int fps() const;
|
||||
int maximumFps() const;
|
||||
int paintDuration() const;
|
||||
int paintAmount() const;
|
||||
QColor paintColor() const;
|
||||
|
||||
void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override;
|
||||
void paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data) override;
|
||||
void paintWindow(KWin::EffectWindow *w, int mask, QRegion region, KWin::WindowPaintData &data) override;
|
||||
void postPaintScreen() override;
|
||||
|
||||
static bool supported();
|
||||
|
||||
Q_SIGNALS:
|
||||
void fpsChanged();
|
||||
void maximumFpsChanged();
|
||||
void paintChanged();
|
||||
|
||||
private:
|
||||
std::unique_ptr<QWindow> m_window;
|
||||
std::unique_ptr<OffscreenQuickScene> m_scene;
|
||||
|
||||
int m_maximumFps = 0;
|
||||
|
||||
int m_fps = 0;
|
||||
int m_newFps = 0;
|
||||
std::chrono::steady_clock::time_point m_lastFpsTime;
|
||||
|
||||
int m_paintDuration = 0;
|
||||
int m_paintAmount = 0;
|
||||
QElapsedTimer m_paintDurationTimer;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
Loading…
Reference in New Issue