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 *********************************************************************/
23 #include <kwinconfig.h>
25 #include <kconfiggroup.h>
27 #include <ksharedconfig.h>
29 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
32 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
34 #include <X11/extensions/Xrender.h>
37 #include <kwinxrenderutils.h>
45 KWIN_EFFECT( showfps
, ShowFpsEffect
)
47 const int FPS_WIDTH
= 10;
48 const int MAX_TIME
= 100;
50 ShowFpsEffect::ShowFpsEffect()
53 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
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
;
80 x
= displayWidth() - 2*NUM_PAINTS
- FPS_WIDTH
- x
;
82 y
= displayHeight() - MAX_TIME
;
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
);
100 fpsTextRect
= QRect(0, 0, 100, 100);
101 textAlign
= Qt::AlignTop
|Qt::AlignLeft
;
104 fpsTextRect
= QRect(displayWidth()-100, 0, 100, 100);
105 textAlign
= Qt::AlignTop
|Qt::AlignRight
;
108 fpsTextRect
= QRect(0, displayHeight()-100, 100, 100);
109 textAlign
= Qt::AlignBottom
|Qt::AlignLeft
;
112 fpsTextRect
= QRect(displayWidth()-100, displayHeight()-100, 100, 100);
113 textAlign
= Qt::AlignBottom
|Qt::AlignRight
;
116 fpsTextRect
= QRect();
120 fpsTextRect
= QRect(x
, y
, FPS_WIDTH
+ NUM_PAINTS
, MAX_TIME
);
121 textAlign
= Qt::AlignTop
|Qt::AlignRight
;
126 void ShowFpsEffect::prePaintScreen( ScreenPrePaintData
& data
, int time
)
129 // TODO optimized away
132 frames
[ frames_pos
] = t
.minute() * 60000 + t
.second() * 1000 + t
.msec();
133 if( ++frames_pos
== MAX_FPS
)
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() );
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
);
162 if( abs( t
.minute() * 60000 + t
.second() * 1000 + t
.msec() - frames
[ i
] ) < 1000 )
163 ++fps
; // count all frames in the last second
165 fps
= MAX_TIME
; // keep it the same height
166 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
167 if( effects
->compositingType() == OpenGLCompositing
)
170 glFinish(); // make sure all rendering is done
173 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
174 if( effects
->compositingType() == XRenderCompositing
)
177 XSync( display(), False
); // make sure all rendering is done
182 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
183 void ShowFpsEffect::paintGL( int fps
)
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
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
);
199 y
+= MAX_TIME
; // paint up from the bottom
201 glColor4f( 0, 0, 1, alpha
); // blue
203 glVertex2i( x
+ FPS_WIDTH
, y
);
204 glVertex2i( x
+ FPS_WIDTH
, y
- fps
);
205 glVertex2i( x
, y
- fps
);
209 glColor4f( 0, 0, 0, alpha
); // black
215 glVertex2i( x
, y
- i
);
216 glVertex2i( x
+ FPS_WIDTH
, y
- i
);
222 paintFPSGraph( x
, y
);
225 // Paint amount of rendered pixels graph
226 paintDrawSizeGraph( x
, y
);
228 // Paint FPS numerical value
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
);
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
);
255 col
.blue
= int( alpha
* 0xffff );
256 XRenderFillRectangle( display(), PictOpSrc
, p
, &col
, 0, MAX_TIME
- fps
, FPS_WIDTH
, fps
);
257 col
.red
= 0; // black
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
);
270 paintFPSGraph( x
+ FPS_WIDTH
, y
);
272 // Paint amount of rendered pixels graph
273 paintDrawSizeGraph( x
+ FPS_WIDTH
+ MAX_TIME
, y
);
277 void ShowFpsEffect::paintFPSGraph(int x
, int y
)
281 lines
<< 10 << 20 << 50;
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
;
314 int value
= paint_size
[ ( i
+ paints_pos
) % NUM_PAINTS
];
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
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
];
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
353 glColor4f( 0, 0, 0, alpha
); // black
355 glVertex2i( x
+ values
.count() - i
, y
);
356 glVertex2i( x
+ values
.count() - i
, y
- value
);
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
);
368 col
.alpha
= int( alpha
* 0xffff );
371 col
.red
= col
.green
= col
.blue
= int( alpha
* 0xffff ); // white
372 XRenderFillRectangle( display(), PictOpSrc
, p
, &col
, 0, 0, values
.count(), MAX_TIME
);
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
];
384 col
.green
= int( alpha
* 0xffff );
387 else if( value
<= 20 )
389 col
.red
= int( alpha
* 0xffff );
390 col
.green
= int( alpha
* 0xffff );
393 else if( value
<= 50 )
395 col
.red
= int( alpha
* 0xffff );
406 XRenderFillRectangle( display(), PictOpSrc
, p
, &col
,
407 values
.count() - i
, MAX_TIME
- value
, 1, value
);
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
);
422 void ShowFpsEffect::postPaintScreen()
424 effects
->postPaintScreen();
425 paints
[ paints_pos
] = t
.elapsed();
426 if( ++paints_pos
== NUM_PAINTS
)
428 effects
->addRepaint( fps_rect
);
431 void ShowFpsEffect::paintFPSText(int fps
)
433 if( !fpsTextRect
.isValid())
435 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
436 QImage
im(100, 100, QImage::Format_ARGB32
);
438 QPainter
painter(&im
);
439 painter
.setFont(textFont
);
440 painter
.setPen(textColor
);
441 painter
.drawText(QRect(0, 0, 100, 100), textAlign
, QString::number(fps
));
444 fpsText
= new GLTexture(im
);
446 fpsText
->render(QRegion(fpsTextRect
), fpsTextRect
);
448 effects
->addRepaint(fpsTextRect
);