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
Arjen Hiemstra 2 years ago committed by Vlad Zahorodnii
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)

@ -4,13 +4,14 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "showfps.h"
#include "showfpseffect.h"
namespace KWin
{
KWIN_EFFECT_FACTORY(ShowFpsEffect,
"metadata.json.stripped")
KWIN_EFFECT_FACTORY_SUPPORTED(ShowFpsEffect,
"metadata.json.stripped",
return ShowFpsEffect::supported();)
} // namespace KWin

@ -72,6 +72,5 @@
"Name[x-test]": "xxShow FPSxx",
"Name[zh_CN]": "显示每秒帧数",
"Name[zh_TW]": "顯示 FPS"
},
"X-KDE-ConfigModule": "kwin_showfps_config"
}
}

@ -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 &region, 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 &region, 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 &region, 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 &region, 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…
Cancel
Save