~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kwin/effects/showfps/showfps.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/********************************************************************
 
2
 KWin - the KDE window manager
 
3
 This file is part of the KDE project.
 
4
 
 
5
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
 
6
 
 
7
This program is free software; you can redistribute it and/or modify
 
8
it under the terms of the GNU General Public License as published by
 
9
the Free Software Foundation; either version 2 of the License, or
 
10
(at your option) any later version.
 
11
 
 
12
This program is distributed in the hope that it will be useful,
 
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
GNU General Public License for more details.
 
16
 
 
17
You should have received a copy of the GNU General Public License
 
18
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
*********************************************************************/
 
20
 
 
21
#include "showfps.h"
 
22
 
 
23
#include <kwinconfig.h>
 
24
 
 
25
#include <kconfiggroup.h>
 
26
#include <kglobal.h>
 
27
#include <ksharedconfig.h>
 
28
 
 
29
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
 
30
#include <kwinglutils.h>
 
31
#endif
 
32
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
 
33
#include <X11/Xlib.h>
 
34
#include <X11/extensions/Xrender.h>
 
35
#endif
 
36
 
 
37
#include <kwinxrenderutils.h>
 
38
 
 
39
#include <math.h>
 
40
#include <QPainter>
 
41
#include <QVector2D>
 
42
 
 
43
namespace KWin
 
44
{
 
45
 
 
46
KWIN_EFFECT(showfps, ShowFpsEffect)
 
47
 
 
48
const int FPS_WIDTH = 10;
 
49
const int MAX_TIME = 100;
 
50
 
 
51
ShowFpsEffect::ShowFpsEffect()
 
52
    : paints_pos(0)
 
53
    , frames_pos(0)
 
54
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
 
55
    , fpsText(0)
 
56
#endif
 
57
{
 
58
    for (int i = 0;
 
59
            i < NUM_PAINTS;
 
60
            ++i) {
 
61
        paints[ i ] = 0;
 
62
        paint_size[ i ] = 0;
 
63
    }
 
64
    for (int i = 0;
 
65
            i < MAX_FPS;
 
66
            ++i)
 
67
        frames[ i ] = 0;
 
68
    reconfigure(ReconfigureAll);
 
69
}
 
70
 
 
71
void ShowFpsEffect::reconfigure(ReconfigureFlags)
 
72
{
 
73
    KConfigGroup config(KGlobal::config(), "EffectShowFps");
 
74
    alpha = config.readEntry("Alpha", 0.5);
 
75
    x = config.readEntry("X", -10000);
 
76
    y = config.readEntry("Y", 0);
 
77
    if (x == -10000)   // there's no -0 :(
 
78
        x = displayWidth() - 2 * NUM_PAINTS - FPS_WIDTH;
 
79
    else if (x < 0)
 
80
        x = displayWidth() - 2 * NUM_PAINTS - FPS_WIDTH - x;
 
81
    if (y == -10000)
 
82
        y = displayHeight() - MAX_TIME;
 
83
    else if (y < 0)
 
84
        y = displayHeight() - MAX_TIME - y;
 
85
    fps_rect = QRect(x, y, FPS_WIDTH + 2 * NUM_PAINTS, MAX_TIME);
 
86
 
 
87
    config = effects->effectConfig("ShowFps");
 
88
    int textPosition = config.readEntry("TextPosition", int(INSIDE_GRAPH));
 
89
    textFont = config.readEntry("TextFont", QFont());
 
90
    textColor = config.readEntry("TextColor", QColor());
 
91
    double textAlpha = config.readEntry("TextAlpha", 1.0);
 
92
 
 
93
    if (!textColor.isValid())
 
94
        textColor = QPalette().color(QPalette::Active, QPalette::WindowText);
 
95
    textColor.setAlphaF(textAlpha);
 
96
 
 
97
    switch(textPosition) {
 
98
    case TOP_LEFT:
 
99
        fpsTextRect = QRect(0, 0, 100, 100);
 
100
        textAlign = Qt::AlignTop | Qt::AlignLeft;
 
101
        break;
 
102
    case TOP_RIGHT:
 
103
        fpsTextRect = QRect(displayWidth() - 100, 0, 100, 100);
 
104
        textAlign = Qt::AlignTop | Qt::AlignRight;
 
105
        break;
 
106
    case BOTTOM_LEFT:
 
107
        fpsTextRect = QRect(0, displayHeight() - 100, 100, 100);
 
108
        textAlign = Qt::AlignBottom | Qt::AlignLeft;
 
109
        break;
 
110
    case BOTTOM_RIGHT:
 
111
        fpsTextRect = QRect(displayWidth() - 100, displayHeight() - 100, 100, 100);
 
112
        textAlign = Qt::AlignBottom | Qt::AlignRight;
 
113
        break;
 
114
    case NOWHERE:
 
115
        fpsTextRect = QRect();
 
116
        break;
 
117
    case INSIDE_GRAPH:
 
118
    default:
 
119
        fpsTextRect = QRect(x, y, FPS_WIDTH + NUM_PAINTS, MAX_TIME);
 
120
        textAlign = Qt::AlignTop | Qt::AlignRight;
 
121
        break;
 
122
    }
 
123
}
 
124
 
 
125
void ShowFpsEffect::prePaintScreen(ScreenPrePaintData& data, int time)
 
126
{
 
127
    if (time == 0) {
 
128
        // TODO optimized away
 
129
    }
 
130
    t.start();
 
131
    frames[ frames_pos ] = t.minute() * 60000 + t.second() * 1000 + t.msec();
 
132
    if (++frames_pos == MAX_FPS)
 
133
        frames_pos = 0;
 
134
    effects->prePaintScreen(data, time);
 
135
    data.paint += fps_rect;
 
136
 
 
137
    paint_size[ paints_pos ] = 0;
 
138
}
 
139
 
 
140
void ShowFpsEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data)
 
141
{
 
142
    effects->paintWindow(w, mask, region, data);
 
143
 
 
144
    // Take intersection of region and actual window's rect, minus the fps area
 
145
    //  (since we keep repainting it) and count the pixels.
 
146
    QRegion r2 = region & QRect(w->x(), w->y(), w->width(), w->height());
 
147
    r2 -= fps_rect;
 
148
    int winsize = 0;
 
149
    foreach (const QRect & r, r2.rects())
 
150
    winsize += r.width() * r.height();
 
151
    paint_size[ paints_pos ] += winsize;
 
152
}
 
153
 
 
154
void ShowFpsEffect::paintScreen(int mask, QRegion region, ScreenPaintData& data)
 
155
{
 
156
    effects->paintScreen(mask, region, data);
 
157
    int fps = 0;
 
158
    for (int i = 0;
 
159
            i < MAX_FPS;
 
160
            ++i)
 
161
        if (abs(t.minute() * 60000 + t.second() * 1000 + t.msec() - frames[ i ]) < 1000)
 
162
            ++fps; // count all frames in the last second
 
163
    if (fps > MAX_TIME)
 
164
        fps = MAX_TIME; // keep it the same height
 
165
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
 
166
    if (effects->compositingType() == OpenGLCompositing) {
 
167
        paintGL(fps);
 
168
        glFinish(); // make sure all rendering is done
 
169
    }
 
170
#endif
 
171
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
 
172
    if (effects->compositingType() == XRenderCompositing) {
 
173
        paintXrender(fps);
 
174
        XSync(display(), False);   // make sure all rendering is done
 
175
    }
 
176
#endif
 
177
}
 
178
 
 
179
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
 
180
void ShowFpsEffect::paintGL(int fps)
 
181
{
 
182
    int x = this->x;
 
183
    int y = this->y;
 
184
#ifndef KWIN_HAVE_OPENGLES
 
185
    glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT);
 
186
#endif
 
187
    glEnable(GL_BLEND);
 
188
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
189
    // TODO painting first the background white and then the contents
 
190
    // means that the contents also blend with the background, I guess
 
191
    if (ShaderManager::instance()->isValid()) {
 
192
        ShaderManager::instance()->pushShader(ShaderManager::ColorShader);
 
193
    }
 
194
    GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
 
195
    vbo->reset();
 
196
    QColor color(255, 255, 255);
 
197
    color.setAlphaF(alpha);
 
198
    vbo->setColor(color);
 
199
    QVector<float> verts;
 
200
    verts.reserve(12);
 
201
    verts << x + 2 * NUM_PAINTS + FPS_WIDTH << y;
 
202
    verts << x << y;
 
203
    verts << x << y + MAX_TIME;
 
204
    verts << x << y + MAX_TIME;
 
205
    verts << x + 2 * NUM_PAINTS + FPS_WIDTH << y + MAX_TIME;
 
206
    verts << x + 2 * NUM_PAINTS + FPS_WIDTH << y;
 
207
    vbo->setData(6, 2, verts.constData(), NULL);
 
208
    vbo->render(GL_TRIANGLES);
 
209
    y += MAX_TIME; // paint up from the bottom
 
210
    color.setRed(0);
 
211
    color.setGreen(0);
 
212
    vbo->setColor(color);
 
213
    verts.clear();
 
214
    verts << x + FPS_WIDTH << y - fps;
 
215
    verts << x << y - fps;
 
216
    verts << x << y;
 
217
    verts << x << y;
 
218
    verts << x + FPS_WIDTH << y;
 
219
    verts << x + FPS_WIDTH << y - fps;
 
220
    vbo->setData(6, 2, verts.constData(), NULL);
 
221
    vbo->render(GL_TRIANGLES);
 
222
 
 
223
 
 
224
    color.setBlue(0);
 
225
    vbo->setColor(color);
 
226
    QVector<float> vertices;
 
227
    for (int i = 10;
 
228
            i < MAX_TIME;
 
229
            i += 10) {
 
230
        vertices << x << y - i;
 
231
        vertices << x + FPS_WIDTH << y - i;
 
232
    }
 
233
    vbo->setData(vertices.size() / 2, 2, vertices.constData(), NULL);
 
234
    vbo->render(GL_LINES);
 
235
    x += FPS_WIDTH;
 
236
 
 
237
    // Paint FPS graph
 
238
    paintFPSGraph(x, y);
 
239
    x += NUM_PAINTS;
 
240
 
 
241
    // Paint amount of rendered pixels graph
 
242
    paintDrawSizeGraph(x, y);
 
243
    if (ShaderManager::instance()->isValid()) {
 
244
        ShaderManager::instance()->popShader();
 
245
    }
 
246
 
 
247
    // Paint FPS numerical value
 
248
    paintFPSText(fps);
 
249
 
 
250
    // Paint paint sizes
 
251
    glDisable(GL_BLEND);
 
252
#ifndef KWIN_HAVE_OPENGLES
 
253
    glPopAttrib();
 
254
#endif
 
255
}
 
256
#endif
 
257
 
 
258
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
 
259
/*
 
260
 Differences between OpenGL and XRender:
 
261
 - differently specified rectangles (X: width/height, O: x2,y2)
 
262
 - XRender uses pre-multiplied alpha
 
263
*/
 
264
void ShowFpsEffect::paintXrender(int fps)
 
265
{
 
266
    Pixmap pixmap = XCreatePixmap(display(), rootWindow(), FPS_WIDTH, MAX_TIME, 32);
 
267
    XRenderPicture p(pixmap, 32);
 
268
    XFreePixmap(display(), pixmap);
 
269
    XRenderColor col;
 
270
    col.alpha = int(alpha * 0xffff);
 
271
    col.red = int(alpha * 0xffff);   // white
 
272
    col.green = int(alpha * 0xffff);
 
273
    col.blue = int(alpha * 0xffff);
 
274
    XRenderFillRectangle(display(), PictOpSrc, p, &col, 0, 0, FPS_WIDTH, MAX_TIME);
 
275
    col.red = 0; // blue
 
276
    col.green = 0;
 
277
    col.blue = int(alpha * 0xffff);
 
278
    XRenderFillRectangle(display(), PictOpSrc, p, &col, 0, MAX_TIME - fps, FPS_WIDTH, fps);
 
279
    col.red = 0; // black
 
280
    col.green = 0;
 
281
    col.blue = 0;
 
282
    for (int i = 10;
 
283
            i < MAX_TIME;
 
284
            i += 10) {
 
285
        XRenderFillRectangle(display(), PictOpSrc, p, &col, 0, MAX_TIME - i, FPS_WIDTH, 1);
 
286
    }
 
287
    XRenderComposite(display(), alpha != 1.0 ? PictOpOver : PictOpSrc, p, None,
 
288
                     effects->xrenderBufferPicture(), 0, 0, 0, 0, x, y, FPS_WIDTH, MAX_TIME);
 
289
 
 
290
    // Paint FPS graph
 
291
    paintFPSGraph(x + FPS_WIDTH, y);
 
292
 
 
293
    // Paint amount of rendered pixels graph
 
294
    paintDrawSizeGraph(x + FPS_WIDTH + MAX_TIME, y);
 
295
}
 
296
#endif
 
297
 
 
298
void ShowFpsEffect::paintFPSGraph(int x, int y)
 
299
{
 
300
    // Paint FPS graph
 
301
    QList<int> lines;
 
302
    lines << 10 << 20 << 50;
 
303
    QList<int> values;
 
304
    for (int i = 0;
 
305
            i < NUM_PAINTS;
 
306
            ++i) {
 
307
        values.append(paints[(i + paints_pos) % NUM_PAINTS ]);
 
308
    }
 
309
    paintGraph(x, y, values, lines, true);
 
310
}
 
311
 
 
312
void ShowFpsEffect::paintDrawSizeGraph(int x, int y)
 
313
{
 
314
    int max_drawsize = 0;
 
315
    for (int i = 0; i < NUM_PAINTS; i++)
 
316
        max_drawsize = qMax(max_drawsize, paint_size[ i ]);
 
317
 
 
318
    // Log of min/max values shown on graph
 
319
    const float max_pixels_log = 7.2f;
 
320
    const float min_pixels_log = 2.0f;
 
321
    const int minh = 5;  // Minimum height of the bar when  value > 0
 
322
 
 
323
    float drawscale = (MAX_TIME - minh) / (max_pixels_log - min_pixels_log);
 
324
    QList<int> drawlines;
 
325
 
 
326
    for (int logh = (int)min_pixels_log; logh <= max_pixels_log; logh++)
 
327
        drawlines.append((int)((logh - min_pixels_log) * drawscale) + minh);
 
328
 
 
329
    QList<int> drawvalues;
 
330
    for (int i = 0;
 
331
            i < NUM_PAINTS;
 
332
            ++i) {
 
333
        int value = paint_size[(i + paints_pos) % NUM_PAINTS ];
 
334
        int h = 0;
 
335
        if (value > 0) {
 
336
            h = (int)((log10((double)value) - min_pixels_log) * drawscale);
 
337
            h = qMin(qMax(0, h) + minh, MAX_TIME);
 
338
        }
 
339
        drawvalues.append(h);
 
340
    }
 
341
    paintGraph(x, y, drawvalues, drawlines, false);
 
342
}
 
343
 
 
344
void ShowFpsEffect::paintGraph(int x, int y, QList<int> values, QList<int> lines, bool colorize)
 
345
{
 
346
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
 
347
    if (effects->compositingType() == OpenGLCompositing) {
 
348
        QColor color(0, 0, 0);
 
349
        color.setAlphaF(alpha);
 
350
        GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer();
 
351
        vbo->reset();
 
352
        vbo->setColor(color);
 
353
        QVector<float> verts;
 
354
        // First draw the lines
 
355
        foreach (int h, lines) {
 
356
            verts << x << y - h;
 
357
            verts << x + values.count() << y - h;
 
358
        }
 
359
        vbo->setData(verts.size() / 2, 2, verts.constData(), NULL);
 
360
        vbo->render(GL_LINES);
 
361
        // Then the graph values
 
362
        int lastValue = 0;
 
363
        verts.clear();
 
364
        for (int i = 0; i < values.count(); i++) {
 
365
            int value = values[ i ];
 
366
            if (colorize && value != lastValue) {
 
367
                if (!verts.isEmpty()) {
 
368
                    vbo->setData(verts.size() / 2, 2, verts.constData(), NULL);
 
369
                    vbo->render(GL_LINES);
 
370
                }
 
371
                verts.clear();
 
372
                if (value <= 10) {
 
373
                    color = QColor(0, 255, 0);
 
374
                } else if (value <= 20) {
 
375
                    color = QColor(255, 255, 0);
 
376
                } else if (value <= 50) {
 
377
                    color = QColor(255, 0, 0);
 
378
                } else {
 
379
                    color = QColor(0, 0, 0);
 
380
                }
 
381
                vbo->setColor(color);
 
382
            }
 
383
            verts << x + values.count() - i << y;
 
384
            verts << x + values.count() - i << y - value;
 
385
            lastValue = value;
 
386
        }
 
387
        if (!verts.isEmpty()) {
 
388
            vbo->setData(verts.size() / 2, 2, verts.constData(), NULL);
 
389
            vbo->render(GL_LINES);
 
390
        }
 
391
    }
 
392
#endif
 
393
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
 
394
    if (effects->compositingType() == XRenderCompositing) {
 
395
        Pixmap pixmap = XCreatePixmap(display(), rootWindow(), values.count(), MAX_TIME, 32);
 
396
        XRenderPicture p(pixmap, 32);
 
397
        XFreePixmap(display(), pixmap);
 
398
        XRenderColor col;
 
399
        col.alpha = int(alpha * 0xffff);
 
400
 
 
401
        // Draw background
 
402
        col.red = col.green = col.blue = int(alpha * 0xffff);   // white
 
403
        XRenderFillRectangle(display(), PictOpSrc, p, &col, 0, 0, values.count(), MAX_TIME);
 
404
 
 
405
        // Then the values
 
406
        col.red = col.green = col.blue = int(alpha * 0x8000);    // grey
 
407
        for (int i = 0; i < values.count(); i++) {
 
408
            int value = values[ i ];
 
409
            if (colorize) {
 
410
                if (value <= 10) {
 
411
                    // green
 
412
                    col.red = 0;
 
413
                    col.green = int(alpha * 0xffff);
 
414
                    col.blue = 0;
 
415
                } else if (value <= 20) {
 
416
                    // yellow
 
417
                    col.red = int(alpha * 0xffff);
 
418
                    col.green = int(alpha * 0xffff);
 
419
                    col.blue = 0;
 
420
                } else if (value <= 50) {
 
421
                    // red
 
422
                    col.red = int(alpha * 0xffff);
 
423
                    col.green = 0;
 
424
                    col.blue = 0;
 
425
                } else {
 
426
                    // black
 
427
                    col.red = 0;
 
428
                    col.green = 0;
 
429
                    col.blue = 0;
 
430
                }
 
431
            }
 
432
            XRenderFillRectangle(display(), PictOpSrc, p, &col,
 
433
                                 values.count() - i, MAX_TIME - value, 1, value);
 
434
        }
 
435
 
 
436
        // Then the lines
 
437
        col.red = col.green = col.blue = 0;  // black
 
438
        foreach (int h, lines)
 
439
        XRenderFillRectangle(display(), PictOpSrc, p, &col, 0, MAX_TIME - h, values.count(), 1);
 
440
 
 
441
        // Finally render the pixmap onto screen
 
442
        XRenderComposite(display(), alpha != 1.0 ? PictOpOver : PictOpSrc, p, None,
 
443
                         effects->xrenderBufferPicture(), 0, 0, 0, 0, x, y, values.count(), MAX_TIME);
 
444
    }
 
445
#endif
 
446
}
 
447
 
 
448
void ShowFpsEffect::postPaintScreen()
 
449
{
 
450
    effects->postPaintScreen();
 
451
    paints[ paints_pos ] = t.elapsed();
 
452
    if (++paints_pos == NUM_PAINTS)
 
453
        paints_pos = 0;
 
454
    effects->addRepaint(fps_rect);
 
455
}
 
456
 
 
457
void ShowFpsEffect::paintFPSText(int fps)
 
458
{
 
459
    if (!fpsTextRect.isValid())
 
460
        return;
 
461
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
 
462
    QImage im(100, 100, QImage::Format_ARGB32);
 
463
    im.fill(0);
 
464
    QPainter painter(&im);
 
465
    painter.setFont(textFont);
 
466
    painter.setPen(textColor);
 
467
    painter.drawText(QRect(0, 0, 100, 100), textAlign, QString::number(fps));
 
468
    delete fpsText;
 
469
    fpsText = new GLTexture(im);
 
470
    fpsText->bind();
 
471
    if (ShaderManager::instance()->isValid()) {
 
472
        GLShader *shader = ShaderManager::instance()->pushShader(ShaderManager::SimpleShader);
 
473
        shader->setUniform("offset", QVector2D(0, 0));
 
474
    }
 
475
    fpsText->render(QRegion(fpsTextRect), fpsTextRect);
 
476
    if (ShaderManager::instance()->isValid()) {
 
477
        ShaderManager::instance()->popShader();
 
478
    }
 
479
    fpsText->unbind();
 
480
    effects->addRepaint(fpsTextRect);
 
481
#endif
 
482
}
 
483
 
 
484
} // namespace