Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / kwin / effects / showfps.cpp
blobdb73faf373f9e7e35ad7a2d57fbe17c14e2896f7
1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
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.
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.
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 *********************************************************************/
21 #include "showfps.h"
23 #include <kwinconfig.h>
25 #include <kconfiggroup.h>
26 #include <kglobal.h>
27 #include <ksharedconfig.h>
29 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
30 #include <GL/gl.h>
31 #endif
32 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
33 #include <X11/Xlib.h>
34 #include <X11/extensions/Xrender.h>
35 #endif
37 #include <math.h>
38 #include <QPainter>
40 namespace KWin
43 KWIN_EFFECT( showfps, ShowFpsEffect )
45 const int FPS_WIDTH = 10;
46 const int MAX_TIME = 100;
48 ShowFpsEffect::ShowFpsEffect()
49 : paints_pos( 0 )
50 , frames_pos( 0 )
51 , fpsText(0)
53 for( int i = 0;
54 i < NUM_PAINTS;
55 ++i )
57 paints[ i ] = 0;
58 paint_size[ i ] = 0;
60 for( int i = 0;
61 i < MAX_FPS;
62 ++i )
63 frames[ i ] = 0;
64 KConfigGroup config( KGlobal::config(), "EffectShowFps" );
65 alpha = config.readEntry( "Alpha", 0.5 );
66 x = config.readEntry( "X", -10000 );
67 y = config.readEntry( "Y", 0 );
68 if( x == -10000 ) // there's no -0 :(
69 x = displayWidth() - 2*NUM_PAINTS - FPS_WIDTH;
70 else if ( x < 0 )
71 x = displayWidth() - 2*NUM_PAINTS - FPS_WIDTH - x;
72 if( y == -10000 )
73 y = displayHeight() - MAX_TIME;
74 else if ( y < 0 )
75 y = displayHeight() - MAX_TIME - y;
76 fps_rect = QRect( x, y, FPS_WIDTH + 2*NUM_PAINTS, MAX_TIME );
78 config = effects->effectConfig("ShowFps");
79 int textPosition = config.readEntry("TextPosition", int(INSIDE_GRAPH));
80 textFont = config.readEntry("TextFont", QFont());
81 textColor = config.readEntry("TextColor", QColor());
82 double textAlpha = config.readEntry("TextAlpha", 1.0);
84 if(!textColor.isValid())
85 textColor = QPalette().color(QPalette::Active, QPalette::WindowText);
86 textColor.setAlphaF(textAlpha);
88 switch(textPosition)
90 case TOP_LEFT:
91 fpsTextRect = QRect(0, 0, 100, 100);
92 textAlign = Qt::AlignTop|Qt::AlignLeft;
93 break;
94 case TOP_RIGHT:
95 fpsTextRect = QRect(displayWidth()-100, 0, 100, 100);
96 textAlign = Qt::AlignTop|Qt::AlignRight;
97 break;
98 case BOTTOM_LEFT:
99 fpsTextRect = QRect(0, displayHeight()-100, 100, 100);
100 textAlign = Qt::AlignBottom|Qt::AlignLeft;
101 break;
102 case BOTTOM_RIGHT:
103 fpsTextRect = QRect(displayWidth()-100, displayHeight()-100, 100, 100);
104 textAlign = Qt::AlignBottom|Qt::AlignRight;
105 break;
106 case NOWHERE:
107 fpsTextRect = QRect();
108 break;
109 case INSIDE_GRAPH:
110 default:
111 fpsTextRect = QRect(x, y, FPS_WIDTH + NUM_PAINTS, MAX_TIME);
112 textAlign = Qt::AlignTop|Qt::AlignRight;
113 break;
117 void ShowFpsEffect::prePaintScreen( ScreenPrePaintData& data, int time )
119 if( time == 0 ) {
120 // TODO optimized away
122 t.start();
123 frames[ frames_pos ] = t.minute() * 60000 + t.second() * 1000 + t.msec();
124 if( ++frames_pos == MAX_FPS )
125 frames_pos = 0;
126 effects->prePaintScreen( data, time );
127 data.paint += fps_rect;
129 paint_size[ paints_pos ] = 0;
132 void ShowFpsEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
134 effects->paintWindow( w, mask, region, data );
136 // Take intersection of region and actual window's rect, minus the fps area
137 // (since we keep repainting it) and count the pixels.
138 QRegion r2 = region & QRect( w->x(), w->y(), w->width(), w->height() );
139 r2 -= fps_rect;
140 int winsize = 0;
141 foreach( const QRect& r, r2.rects())
142 winsize += r.width() * r.height();
143 paint_size[ paints_pos ] += winsize;
146 void ShowFpsEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
148 effects->paintScreen( mask, region, data );
149 int fps = 0;
150 for( int i = 0;
151 i < MAX_FPS;
152 ++i )
153 if( abs( t.minute() * 60000 + t.second() * 1000 + t.msec() - frames[ i ] ) < 1000 )
154 ++fps; // count all frames in the last second
155 if( fps > MAX_TIME )
156 fps = MAX_TIME; // keep it the same height
157 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
158 if( effects->compositingType() == OpenGLCompositing)
160 paintGL( fps );
161 glFinish(); // make sure all rendering is done
163 #endif
164 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
165 if( effects->compositingType() == XRenderCompositing)
167 paintXrender( fps );
168 XSync( display(), False ); // make sure all rendering is done
170 #endif
173 void ShowFpsEffect::paintGL( int fps )
175 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
176 int x = this->x;
177 int y = this->y;
178 glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT );
179 glEnable( GL_BLEND );
180 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
181 // TODO painting first the background white and then the contents
182 // means that the contents also blend with the background, I guess
183 glColor4f( 1, 1, 1, alpha ); // white
184 glBegin( GL_QUADS );
185 glVertex2i( x, y );
186 glVertex2i( x + 2*NUM_PAINTS + FPS_WIDTH, y );
187 glVertex2i( x + 2*NUM_PAINTS + FPS_WIDTH, y + MAX_TIME );
188 glVertex2i( x, y + MAX_TIME );
189 glEnd();
190 y += MAX_TIME; // paint up from the bottom
191 glBegin( GL_QUADS );
192 glColor4f( 0, 0, 1, alpha ); // blue
193 glVertex2i( x, y );
194 glVertex2i( x + FPS_WIDTH, y );
195 glVertex2i( x + FPS_WIDTH, y - fps );
196 glVertex2i( x, y - fps );
197 glEnd();
200 glColor4f( 0, 0, 0, alpha ); // black
201 glBegin( GL_LINES );
202 for( int i = 10;
203 i < MAX_TIME;
204 i += 10 )
206 glVertex2i( x, y - i );
207 glVertex2i( x + FPS_WIDTH, y - i );
209 glEnd();
210 x += FPS_WIDTH;
212 // Paint FPS graph
213 paintFPSGraph( x, y );
214 x += NUM_PAINTS;
216 // Paint amount of rendered pixels graph
217 paintDrawSizeGraph( x, y );
219 // Paint FPS numerical value
220 paintFPSText(fps);
222 // Paint paint sizes
223 glPopAttrib();
224 #endif
228 Differences between OpenGL and XRender:
229 - differently specified rectangles (X: width/height, O: x2,y2)
230 - XRender uses pre-multiplied alpha
232 void ShowFpsEffect::paintXrender( int fps )
234 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
235 Pixmap pixmap = XCreatePixmap( display(), rootWindow(), FPS_WIDTH, MAX_TIME, 32 );
236 XRenderPictFormat* format = XRenderFindStandardFormat( display(), PictStandardARGB32 );
237 Picture p = XRenderCreatePicture( display(), pixmap, format, 0, NULL );
238 XFreePixmap( display(), pixmap );
239 XRenderColor col;
240 col.alpha = int( alpha * 0xffff );
241 col.red = int( alpha * 0xffff ); // white
242 col.green = int( alpha * 0xffff );
243 col.blue= int( alpha * 0xffff );
244 XRenderFillRectangle( display(), PictOpSrc, p, &col, 0, 0, FPS_WIDTH, MAX_TIME );
245 col.red = 0; // blue
246 col.green = 0;
247 col.blue = int( alpha * 0xffff );
248 XRenderFillRectangle( display(), PictOpSrc, p, &col, 0, MAX_TIME - fps, FPS_WIDTH, fps );
249 col.red = 0; // black
250 col.green = 0;
251 col.blue = 0;
252 for( int i = 10;
253 i < MAX_TIME;
254 i += 10 )
256 XRenderFillRectangle( display(), PictOpSrc, p, &col, 0, MAX_TIME - i, FPS_WIDTH, 1 );
258 XRenderComposite( display(), alpha != 1.0 ? PictOpOver : PictOpSrc, p, None,
259 effects->xrenderBufferPicture(), 0, 0, 0, 0, x, y, FPS_WIDTH, MAX_TIME );
260 XRenderFreePicture( display(), p );
262 // Paint FPS graph
263 paintFPSGraph( x + FPS_WIDTH, y );
265 // Paint amount of rendered pixels graph
266 paintDrawSizeGraph( x + FPS_WIDTH + MAX_TIME, y );
268 #endif
271 void ShowFpsEffect::paintFPSGraph(int x, int y)
273 // Paint FPS graph
274 QList<int> lines;
275 lines << 10 << 20 << 50;
276 QList<int> values;
277 for( int i = 0;
278 i < NUM_PAINTS;
279 ++i )
281 values.append( paints[ ( i + paints_pos ) % NUM_PAINTS ] );
283 paintGraph( x, y, values, lines, true );
286 void ShowFpsEffect::paintDrawSizeGraph(int x, int y)
288 int max_drawsize = 0;
289 for( int i = 0; i < NUM_PAINTS; i++)
290 max_drawsize = qMax(max_drawsize, paint_size[ i ] );
292 // Log of min/max values shown on graph
293 const float max_pixels_log = 7.2f;
294 const float min_pixels_log = 2.0f;
295 const int minh = 5; // Minimum height of the bar when value > 0
297 float drawscale = (MAX_TIME - minh) / (max_pixels_log - min_pixels_log);
298 QList<int> drawlines;
300 for( int logh = (int)min_pixels_log; logh <= max_pixels_log; logh++ )
301 drawlines.append( (int)(( logh - min_pixels_log ) * drawscale ) + minh );
303 QList<int> drawvalues;
304 for( int i = 0;
305 i < NUM_PAINTS;
306 ++i )
308 int value = paint_size[ ( i + paints_pos ) % NUM_PAINTS ];
309 int h = 0;
310 if( value > 0)
312 h = (int)(( log10( (double)value ) - min_pixels_log ) * drawscale );
313 h = qMin( qMax( 0, h ) + minh, MAX_TIME );
315 drawvalues.append( h );
317 paintGraph( x, y, drawvalues, drawlines, false );
320 void ShowFpsEffect::paintGraph( int x, int y, QList<int> values, QList<int> lines, bool colorize)
322 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
323 if( effects->compositingType() == OpenGLCompositing)
325 glColor4f( 0, 0, 0, alpha ); // black
326 glBegin( GL_LINES );
327 // First draw the lines
328 foreach( int h, lines)
330 glVertex2i( x, y - h );
331 glVertex2i( x + values.count(), y - h );
333 // Then the graph values
334 glColor4f( 0.5, 0.5, 0.5, alpha );
335 for( int i = 0; i < values.count(); i++ )
337 int value = values[ i ];
338 if( colorize )
340 if( value <= 10 )
341 glColor4f( 0, 1, 0, alpha ); // green
342 else if( value <= 20 )
343 glColor4f( 1, 1, 0, alpha ); // yellow
344 else if( value <= 50 )
345 glColor4f( 1, 0, 0, alpha ); // red
346 else
347 glColor4f( 0, 0, 0, alpha ); // black
349 glVertex2i( x + values.count() - i, y );
350 glVertex2i( x + values.count() - i, y - value );
352 glEnd();
354 #endif
355 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
356 if( effects->compositingType() == XRenderCompositing)
358 Pixmap pixmap = XCreatePixmap( display(), rootWindow(), values.count(), MAX_TIME, 32 );
359 XRenderPictFormat* format = XRenderFindStandardFormat( display(), PictStandardARGB32 );
360 Picture p = XRenderCreatePicture( display(), pixmap, format, 0, NULL );
361 XFreePixmap( display(), pixmap );
362 XRenderColor col;
363 col.alpha = int( alpha * 0xffff );
365 // Draw background
366 col.red = col.green = col.blue = int( alpha * 0xffff ); // white
367 XRenderFillRectangle( display(), PictOpSrc, p, &col, 0, 0, values.count(), MAX_TIME );
369 // Then the values
370 col.red = col.green = col.blue = int( alpha * 0x8000 ); // grey
371 for( int i = 0; i < values.count(); i++ )
373 int value = values[ i ];
374 if( colorize )
376 if( value <= 10 )
377 { // green
378 col.red = 0;
379 col.green = int( alpha * 0xffff );
380 col.blue = 0;
382 else if( value <= 20 )
383 { // yellow
384 col.red = int( alpha * 0xffff );
385 col.green = int( alpha * 0xffff );
386 col.blue = 0;
388 else if( value <= 50 )
389 { // red
390 col.red = int( alpha * 0xffff );
391 col.green = 0;
392 col.blue = 0;
394 else
395 { // black
396 col.red = 0;
397 col.green = 0;
398 col.blue = 0;
401 XRenderFillRectangle( display(), PictOpSrc, p, &col,
402 values.count() - i, MAX_TIME - value, 1, value );
405 // Then the lines
406 col.red = col.green = col.blue = 0; // black
407 foreach( int h, lines)
408 XRenderFillRectangle( display(), PictOpSrc, p, &col, 0, MAX_TIME - h, values.count(), 1 );
410 // Finally render the pixmap onto screen
411 XRenderComposite( display(), alpha != 1.0 ? PictOpOver : PictOpSrc, p, None,
412 effects->xrenderBufferPicture(), 0, 0, 0, 0, x, y, values.count(), MAX_TIME );
413 XRenderFreePicture( display(), p );
415 #endif
418 void ShowFpsEffect::postPaintScreen()
420 effects->postPaintScreen();
421 paints[ paints_pos ] = t.elapsed();
422 if( ++paints_pos == NUM_PAINTS )
423 paints_pos = 0;
424 effects->addRepaint( fps_rect );
427 void ShowFpsEffect::paintFPSText(int fps)
429 if( !fpsTextRect.isValid())
430 return;
431 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
432 QImage im(100, 100, QImage::Format_ARGB32);
433 im.fill(Qt::transparent);
434 QPainter painter(&im);
435 painter.setFont(textFont);
436 painter.setPen(textColor);
437 painter.drawText(QRect(0, 0, 100, 100), textAlign, QString::number(fps));
438 if(fpsText)
439 delete fpsText;
440 fpsText = new GLTexture(im);
441 fpsText->bind();
442 fpsText->render(QRegion(fpsTextRect), fpsTextRect);
443 fpsText->unbind();
444 effects->addRepaint(fpsTextRect);
445 #endif
448 } // namespace