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>
43 KWIN_EFFECT( showfps
, ShowFpsEffect
)
45 const int FPS_WIDTH
= 10;
46 const int MAX_TIME
= 100;
48 ShowFpsEffect::ShowFpsEffect()
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
;
71 x
= displayWidth() - 2*NUM_PAINTS
- FPS_WIDTH
- x
;
73 y
= displayHeight() - MAX_TIME
;
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
);
91 fpsTextRect
= QRect(0, 0, 100, 100);
92 textAlign
= Qt::AlignTop
|Qt::AlignLeft
;
95 fpsTextRect
= QRect(displayWidth()-100, 0, 100, 100);
96 textAlign
= Qt::AlignTop
|Qt::AlignRight
;
99 fpsTextRect
= QRect(0, displayHeight()-100, 100, 100);
100 textAlign
= Qt::AlignBottom
|Qt::AlignLeft
;
103 fpsTextRect
= QRect(displayWidth()-100, displayHeight()-100, 100, 100);
104 textAlign
= Qt::AlignBottom
|Qt::AlignRight
;
107 fpsTextRect
= QRect();
111 fpsTextRect
= QRect(x
, y
, FPS_WIDTH
+ NUM_PAINTS
, MAX_TIME
);
112 textAlign
= Qt::AlignTop
|Qt::AlignRight
;
117 void ShowFpsEffect::prePaintScreen( ScreenPrePaintData
& data
, int time
)
120 // TODO optimized away
123 frames
[ frames_pos
] = t
.minute() * 60000 + t
.second() * 1000 + t
.msec();
124 if( ++frames_pos
== MAX_FPS
)
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() );
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
);
153 if( abs( t
.minute() * 60000 + t
.second() * 1000 + t
.msec() - frames
[ i
] ) < 1000 )
154 ++fps
; // count all frames in the last second
156 fps
= MAX_TIME
; // keep it the same height
157 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
158 if( effects
->compositingType() == OpenGLCompositing
)
161 glFinish(); // make sure all rendering is done
164 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
165 if( effects
->compositingType() == XRenderCompositing
)
168 XSync( display(), False
); // make sure all rendering is done
173 void ShowFpsEffect::paintGL( int fps
)
175 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
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
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
);
190 y
+= MAX_TIME
; // paint up from the bottom
192 glColor4f( 0, 0, 1, alpha
); // blue
194 glVertex2i( x
+ FPS_WIDTH
, y
);
195 glVertex2i( x
+ FPS_WIDTH
, y
- fps
);
196 glVertex2i( x
, y
- fps
);
200 glColor4f( 0, 0, 0, alpha
); // black
206 glVertex2i( x
, y
- i
);
207 glVertex2i( x
+ FPS_WIDTH
, y
- i
);
213 paintFPSGraph( x
, y
);
216 // Paint amount of rendered pixels graph
217 paintDrawSizeGraph( x
, y
);
219 // Paint FPS numerical value
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
);
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
);
247 col
.blue
= int( alpha
* 0xffff );
248 XRenderFillRectangle( display(), PictOpSrc
, p
, &col
, 0, MAX_TIME
- fps
, FPS_WIDTH
, fps
);
249 col
.red
= 0; // black
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
);
263 paintFPSGraph( x
+ FPS_WIDTH
, y
);
265 // Paint amount of rendered pixels graph
266 paintDrawSizeGraph( x
+ FPS_WIDTH
+ MAX_TIME
, y
);
271 void ShowFpsEffect::paintFPSGraph(int x
, int y
)
275 lines
<< 10 << 20 << 50;
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
;
308 int value
= paint_size
[ ( i
+ paints_pos
) % NUM_PAINTS
];
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
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
];
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
347 glColor4f( 0, 0, 0, alpha
); // black
349 glVertex2i( x
+ values
.count() - i
, y
);
350 glVertex2i( x
+ values
.count() - i
, y
- value
);
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
);
363 col
.alpha
= int( alpha
* 0xffff );
366 col
.red
= col
.green
= col
.blue
= int( alpha
* 0xffff ); // white
367 XRenderFillRectangle( display(), PictOpSrc
, p
, &col
, 0, 0, values
.count(), MAX_TIME
);
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
];
379 col
.green
= int( alpha
* 0xffff );
382 else if( value
<= 20 )
384 col
.red
= int( alpha
* 0xffff );
385 col
.green
= int( alpha
* 0xffff );
388 else if( value
<= 50 )
390 col
.red
= int( alpha
* 0xffff );
401 XRenderFillRectangle( display(), PictOpSrc
, p
, &col
,
402 values
.count() - i
, MAX_TIME
- value
, 1, value
);
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
);
418 void ShowFpsEffect::postPaintScreen()
420 effects
->postPaintScreen();
421 paints
[ paints_pos
] = t
.elapsed();
422 if( ++paints_pos
== NUM_PAINTS
)
424 effects
->addRepaint( fps_rect
);
427 void ShowFpsEffect::paintFPSText(int fps
)
429 if( !fpsTextRect
.isValid())
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
));
440 fpsText
= new GLTexture(im
);
442 fpsText
->render(QRegion(fpsTextRect
), fpsTextRect
);
444 effects
->addRepaint(fpsTextRect
);