add more spacing
[personal-kdebase.git] / workspace / kwin / effects / showfps.cpp
blobba8194ff57e60a0274a1d5aa4b42e4389a3ed648
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 <kwinxrenderutils.h>
39 #include <math.h>
40 #include <QPainter>
42 namespace KWin
45 KWIN_EFFECT( showfps, ShowFpsEffect )
47 const int FPS_WIDTH = 10;
48 const int MAX_TIME = 100;
50 ShowFpsEffect::ShowFpsEffect()
51 : paints_pos( 0 )
52 , frames_pos( 0 )
53 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
54 , fpsText(0)
55 #endif
57 for( int i = 0;
58 i < NUM_PAINTS;
59 ++i )
61 paints[ i ] = 0;
62 paint_size[ i ] = 0;
64 for( int i = 0;
65 i < MAX_FPS;
66 ++i )
67 frames[ i ] = 0;
68 reconfigure( ReconfigureAll );
71 void ShowFpsEffect::reconfigure( ReconfigureFlags )
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 );
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);
93 if(!textColor.isValid())
94 textColor = QPalette().color(QPalette::Active, QPalette::WindowText);
95 textColor.setAlphaF(textAlpha);
97 switch(textPosition)
99 case TOP_LEFT:
100 fpsTextRect = QRect(0, 0, 100, 100);
101 textAlign = Qt::AlignTop|Qt::AlignLeft;
102 break;
103 case TOP_RIGHT:
104 fpsTextRect = QRect(displayWidth()-100, 0, 100, 100);
105 textAlign = Qt::AlignTop|Qt::AlignRight;
106 break;
107 case BOTTOM_LEFT:
108 fpsTextRect = QRect(0, displayHeight()-100, 100, 100);
109 textAlign = Qt::AlignBottom|Qt::AlignLeft;
110 break;
111 case BOTTOM_RIGHT:
112 fpsTextRect = QRect(displayWidth()-100, displayHeight()-100, 100, 100);
113 textAlign = Qt::AlignBottom|Qt::AlignRight;
114 break;
115 case NOWHERE:
116 fpsTextRect = QRect();
117 break;
118 case INSIDE_GRAPH:
119 default:
120 fpsTextRect = QRect(x, y, FPS_WIDTH + NUM_PAINTS, MAX_TIME);
121 textAlign = Qt::AlignTop|Qt::AlignRight;
122 break;
126 void ShowFpsEffect::prePaintScreen( ScreenPrePaintData& data, int time )
128 if( time == 0 ) {
129 // TODO optimized away
131 t.start();
132 frames[ frames_pos ] = t.minute() * 60000 + t.second() * 1000 + t.msec();
133 if( ++frames_pos == MAX_FPS )
134 frames_pos = 0;
135 effects->prePaintScreen( data, time );
136 data.paint += fps_rect;
138 paint_size[ paints_pos ] = 0;
141 void ShowFpsEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
143 effects->paintWindow( w, mask, region, data );
145 // Take intersection of region and actual window's rect, minus the fps area
146 // (since we keep repainting it) and count the pixels.
147 QRegion r2 = region & QRect( w->x(), w->y(), w->width(), w->height() );
148 r2 -= fps_rect;
149 int winsize = 0;
150 foreach( const QRect& r, r2.rects())
151 winsize += r.width() * r.height();
152 paint_size[ paints_pos ] += winsize;
155 void ShowFpsEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
157 effects->paintScreen( mask, region, data );
158 int fps = 0;
159 for( int i = 0;
160 i < MAX_FPS;
161 ++i )
162 if( abs( t.minute() * 60000 + t.second() * 1000 + t.msec() - frames[ i ] ) < 1000 )
163 ++fps; // count all frames in the last second
164 if( fps > MAX_TIME )
165 fps = MAX_TIME; // keep it the same height
166 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
167 if( effects->compositingType() == OpenGLCompositing)
169 paintGL( fps );
170 glFinish(); // make sure all rendering is done
172 #endif
173 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
174 if( effects->compositingType() == XRenderCompositing)
176 paintXrender( fps );
177 XSync( display(), False ); // make sure all rendering is done
179 #endif
182 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
183 void ShowFpsEffect::paintGL( int fps )
185 int x = this->x;
186 int y = this->y;
187 glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT );
188 glEnable( GL_BLEND );
189 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
190 // TODO painting first the background white and then the contents
191 // means that the contents also blend with the background, I guess
192 glColor4f( 1, 1, 1, alpha ); // white
193 glBegin( GL_QUADS );
194 glVertex2i( x, y );
195 glVertex2i( x + 2*NUM_PAINTS + FPS_WIDTH, y );
196 glVertex2i( x + 2*NUM_PAINTS + FPS_WIDTH, y + MAX_TIME );
197 glVertex2i( x, y + MAX_TIME );
198 glEnd();
199 y += MAX_TIME; // paint up from the bottom
200 glBegin( GL_QUADS );
201 glColor4f( 0, 0, 1, alpha ); // blue
202 glVertex2i( x, y );
203 glVertex2i( x + FPS_WIDTH, y );
204 glVertex2i( x + FPS_WIDTH, y - fps );
205 glVertex2i( x, y - fps );
206 glEnd();
209 glColor4f( 0, 0, 0, alpha ); // black
210 glBegin( GL_LINES );
211 for( int i = 10;
212 i < MAX_TIME;
213 i += 10 )
215 glVertex2i( x, y - i );
216 glVertex2i( x + FPS_WIDTH, y - i );
218 glEnd();
219 x += FPS_WIDTH;
221 // Paint FPS graph
222 paintFPSGraph( x, y );
223 x += NUM_PAINTS;
225 // Paint amount of rendered pixels graph
226 paintDrawSizeGraph( x, y );
228 // Paint FPS numerical value
229 paintFPSText(fps);
231 // Paint paint sizes
232 glPopAttrib();
234 #endif
236 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
238 Differences between OpenGL and XRender:
239 - differently specified rectangles (X: width/height, O: x2,y2)
240 - XRender uses pre-multiplied alpha
242 void ShowFpsEffect::paintXrender( int fps )
244 Pixmap pixmap = XCreatePixmap( display(), rootWindow(), FPS_WIDTH, MAX_TIME, 32 );
245 XRenderPicture p( pixmap, 32 );
246 XFreePixmap( display(), pixmap );
247 XRenderColor col;
248 col.alpha = int( alpha * 0xffff );
249 col.red = int( alpha * 0xffff ); // white
250 col.green = int( alpha * 0xffff );
251 col.blue= int( alpha * 0xffff );
252 XRenderFillRectangle( display(), PictOpSrc, p, &col, 0, 0, FPS_WIDTH, MAX_TIME );
253 col.red = 0; // blue
254 col.green = 0;
255 col.blue = int( alpha * 0xffff );
256 XRenderFillRectangle( display(), PictOpSrc, p, &col, 0, MAX_TIME - fps, FPS_WIDTH, fps );
257 col.red = 0; // black
258 col.green = 0;
259 col.blue = 0;
260 for( int i = 10;
261 i < MAX_TIME;
262 i += 10 )
264 XRenderFillRectangle( display(), PictOpSrc, p, &col, 0, MAX_TIME - i, FPS_WIDTH, 1 );
266 XRenderComposite( display(), alpha != 1.0 ? PictOpOver : PictOpSrc, p, None,
267 effects->xrenderBufferPicture(), 0, 0, 0, 0, x, y, FPS_WIDTH, MAX_TIME );
269 // Paint FPS graph
270 paintFPSGraph( x + FPS_WIDTH, y );
272 // Paint amount of rendered pixels graph
273 paintDrawSizeGraph( x + FPS_WIDTH + MAX_TIME, y );
275 #endif
277 void ShowFpsEffect::paintFPSGraph(int x, int y)
279 // Paint FPS graph
280 QList<int> lines;
281 lines << 10 << 20 << 50;
282 QList<int> values;
283 for( int i = 0;
284 i < NUM_PAINTS;
285 ++i )
287 values.append( paints[ ( i + paints_pos ) % NUM_PAINTS ] );
289 paintGraph( x, y, values, lines, true );
292 void ShowFpsEffect::paintDrawSizeGraph(int x, int y)
294 int max_drawsize = 0;
295 for( int i = 0; i < NUM_PAINTS; i++)
296 max_drawsize = qMax(max_drawsize, paint_size[ i ] );
298 // Log of min/max values shown on graph
299 const float max_pixels_log = 7.2f;
300 const float min_pixels_log = 2.0f;
301 const int minh = 5; // Minimum height of the bar when value > 0
303 float drawscale = (MAX_TIME - minh) / (max_pixels_log - min_pixels_log);
304 QList<int> drawlines;
306 for( int logh = (int)min_pixels_log; logh <= max_pixels_log; logh++ )
307 drawlines.append( (int)(( logh - min_pixels_log ) * drawscale ) + minh );
309 QList<int> drawvalues;
310 for( int i = 0;
311 i < NUM_PAINTS;
312 ++i )
314 int value = paint_size[ ( i + paints_pos ) % NUM_PAINTS ];
315 int h = 0;
316 if( value > 0)
318 h = (int)(( log10( (double)value ) - min_pixels_log ) * drawscale );
319 h = qMin( qMax( 0, h ) + minh, MAX_TIME );
321 drawvalues.append( h );
323 paintGraph( x, y, drawvalues, drawlines, false );
326 void ShowFpsEffect::paintGraph( int x, int y, QList<int> values, QList<int> lines, bool colorize)
328 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
329 if( effects->compositingType() == OpenGLCompositing)
331 glColor4f( 0, 0, 0, alpha ); // black
332 glBegin( GL_LINES );
333 // First draw the lines
334 foreach( int h, lines)
336 glVertex2i( x, y - h );
337 glVertex2i( x + values.count(), y - h );
339 // Then the graph values
340 glColor4f( 0.5, 0.5, 0.5, alpha );
341 for( int i = 0; i < values.count(); i++ )
343 int value = values[ i ];
344 if( colorize )
346 if( value <= 10 )
347 glColor4f( 0, 1, 0, alpha ); // green
348 else if( value <= 20 )
349 glColor4f( 1, 1, 0, alpha ); // yellow
350 else if( value <= 50 )
351 glColor4f( 1, 0, 0, alpha ); // red
352 else
353 glColor4f( 0, 0, 0, alpha ); // black
355 glVertex2i( x + values.count() - i, y );
356 glVertex2i( x + values.count() - i, y - value );
358 glEnd();
360 #endif
361 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
362 if( effects->compositingType() == XRenderCompositing)
364 Pixmap pixmap = XCreatePixmap( display(), rootWindow(), values.count(), MAX_TIME, 32 );
365 XRenderPicture p( pixmap, 32 );
366 XFreePixmap( display(), pixmap );
367 XRenderColor col;
368 col.alpha = int( alpha * 0xffff );
370 // Draw background
371 col.red = col.green = col.blue = int( alpha * 0xffff ); // white
372 XRenderFillRectangle( display(), PictOpSrc, p, &col, 0, 0, values.count(), MAX_TIME );
374 // Then the values
375 col.red = col.green = col.blue = int( alpha * 0x8000 ); // grey
376 for( int i = 0; i < values.count(); i++ )
378 int value = values[ i ];
379 if( colorize )
381 if( value <= 10 )
382 { // green
383 col.red = 0;
384 col.green = int( alpha * 0xffff );
385 col.blue = 0;
387 else if( value <= 20 )
388 { // yellow
389 col.red = int( alpha * 0xffff );
390 col.green = int( alpha * 0xffff );
391 col.blue = 0;
393 else if( value <= 50 )
394 { // red
395 col.red = int( alpha * 0xffff );
396 col.green = 0;
397 col.blue = 0;
399 else
400 { // black
401 col.red = 0;
402 col.green = 0;
403 col.blue = 0;
406 XRenderFillRectangle( display(), PictOpSrc, p, &col,
407 values.count() - i, MAX_TIME - value, 1, value );
410 // Then the lines
411 col.red = col.green = col.blue = 0; // black
412 foreach( int h, lines)
413 XRenderFillRectangle( display(), PictOpSrc, p, &col, 0, MAX_TIME - h, values.count(), 1 );
415 // Finally render the pixmap onto screen
416 XRenderComposite( display(), alpha != 1.0 ? PictOpOver : PictOpSrc, p, None,
417 effects->xrenderBufferPicture(), 0, 0, 0, 0, x, y, values.count(), MAX_TIME );
419 #endif
422 void ShowFpsEffect::postPaintScreen()
424 effects->postPaintScreen();
425 paints[ paints_pos ] = t.elapsed();
426 if( ++paints_pos == NUM_PAINTS )
427 paints_pos = 0;
428 effects->addRepaint( fps_rect );
431 void ShowFpsEffect::paintFPSText(int fps)
433 if( !fpsTextRect.isValid())
434 return;
435 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
436 QImage im(100, 100, QImage::Format_ARGB32);
437 im.fill(0);
438 QPainter painter(&im);
439 painter.setFont(textFont);
440 painter.setPen(textColor);
441 painter.drawText(QRect(0, 0, 100, 100), textAlign, QString::number(fps));
442 if(fpsText)
443 delete fpsText;
444 fpsText = new GLTexture(im);
445 fpsText->bind();
446 fpsText->render(QRegion(fpsTextRect), fpsTextRect);
447 fpsText->unbind();
448 effects->addRepaint(fpsTextRect);
449 #endif
452 } // namespace