5faa397849
for use in effects (and not only). Now a list of window quads (=window areas) is created at the beginning of the paint pass, prepaint calls can modify the split itself (i.e. divide it into more parts). The actual paint calls can then modify these quads (i.e. transform their geometry). This will allow better control of how the split is done and also allow painting e.g. only the decoration differently. Still work in progress, but it works. Also pass data to prepaint functions in a struct, as there is already quite a number of them. svn path=/trunk/KDE/kdebase/workspace/; revision=684893
239 lines
7.1 KiB
C++
239 lines
7.1 KiB
C++
/*****************************************************************
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
Copyright (C) 2006 Lubos Lunak <l.lunak@kde.org>
|
|
|
|
You can Freely distribute this program under the GNU General Public
|
|
License. See the file "COPYING" for the exact licensing terms.
|
|
******************************************************************/
|
|
|
|
#include "showfps.h"
|
|
|
|
#include <config-X11.h>
|
|
|
|
#include <kconfig.h>
|
|
#include <ksharedconfig.h>
|
|
|
|
#ifdef HAVE_OPENGL
|
|
#include <GL/gl.h>
|
|
#endif
|
|
#ifdef HAVE_XRENDER
|
|
#include <X11/Xlib.h>
|
|
#include <X11/extensions/Xrender.h>
|
|
#endif
|
|
|
|
namespace KWin
|
|
{
|
|
|
|
KWIN_EFFECT( showfps, ShowFpsEffect )
|
|
|
|
const int FPS_WIDTH = 10;
|
|
const int MAX_TIME = 100;
|
|
|
|
ShowFpsEffect::ShowFpsEffect()
|
|
: paints_pos( 0 )
|
|
, frames_pos( 0 )
|
|
{
|
|
for( int i = 0;
|
|
i < NUM_PAINTS;
|
|
++i )
|
|
paints[ i ] = 0;
|
|
for( int i = 0;
|
|
i < MAX_FPS;
|
|
++i )
|
|
frames[ i ] = 0;
|
|
KConfigGroup config( KGlobal::config(), "EffectShowFps" );
|
|
alpha = config.readEntry( "Alpha", 0.5 );
|
|
x = config.readEntry( "X", -10000 );
|
|
y = config.readEntry( "Y", 0 );
|
|
if( x == -10000 ) // there's no -0 :(
|
|
x = displayWidth() - NUM_PAINTS - FPS_WIDTH;
|
|
else if ( x < 0 )
|
|
x = displayWidth() - NUM_PAINTS - FPS_WIDTH - x;
|
|
if( y == -10000 )
|
|
y = displayHeight() - MAX_TIME;
|
|
else if ( y < 0 )
|
|
y = displayHeight() - MAX_TIME - y;
|
|
}
|
|
|
|
void ShowFpsEffect::prePaintScreen( ScreenPrePaintData& data, int time )
|
|
{
|
|
if( time == 0 ) {
|
|
// TODO optimized away
|
|
}
|
|
t.start();
|
|
frames[ frames_pos ] = t.minute() * 60000 + t.second() * 1000 + t.msec();
|
|
if( ++frames_pos == MAX_FPS )
|
|
frames_pos = 0;
|
|
effects->prePaintScreen( data, time );
|
|
data.paint += QRect( x, y, FPS_WIDTH + NUM_PAINTS, MAX_TIME );
|
|
}
|
|
|
|
void ShowFpsEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
|
|
{
|
|
effects->paintScreen( mask, region, data );
|
|
int fps = 0;
|
|
for( int i = 0;
|
|
i < MAX_FPS;
|
|
++i )
|
|
if( abs( t.minute() * 60000 + t.second() * 1000 + t.msec() - frames[ i ] ) < 1000 )
|
|
++fps; // count all frames in the last second
|
|
if( fps > MAX_TIME )
|
|
fps = MAX_TIME; // keep it the same height
|
|
#ifdef HAVE_OPENGL
|
|
if( effects->compositingType() == OpenGLCompositing)
|
|
{
|
|
paintGL( fps );
|
|
glFinish(); // make sure all rendering is done
|
|
}
|
|
#endif
|
|
#ifdef HAVE_XRENDER
|
|
if( effects->compositingType() == XRenderCompositing)
|
|
{
|
|
paintXrender( fps );
|
|
XSync( display(), False ); // make sure all rendering is done
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void ShowFpsEffect::paintGL( int fps )
|
|
{
|
|
#ifdef HAVE_OPENGL
|
|
int x = this->x;
|
|
int y = this->y;
|
|
glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT );
|
|
glEnable( GL_BLEND );
|
|
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
|
// TODO painting first the background white and then the contents
|
|
// means that the contents also blend with the background, I guess
|
|
glColor4f( 1, 1, 1, alpha ); // white
|
|
glBegin( GL_QUADS );
|
|
glVertex2i( x, y );
|
|
glVertex2i( x + NUM_PAINTS + FPS_WIDTH, y );
|
|
glVertex2i( x + NUM_PAINTS + FPS_WIDTH, y + MAX_TIME );
|
|
glVertex2i( x, y + MAX_TIME );
|
|
glEnd();
|
|
y += MAX_TIME; // paint up from the bottom
|
|
glBegin( GL_QUADS );
|
|
glColor4f( 0, 0, 1, alpha ); // blue
|
|
glVertex2i( x, y );
|
|
glVertex2i( x + FPS_WIDTH, y );
|
|
glVertex2i( x + FPS_WIDTH, y - fps );
|
|
glVertex2i( x, y - fps );
|
|
glEnd();
|
|
glColor4f( 0, 0, 0, alpha ); // black
|
|
glBegin( GL_LINES );
|
|
for( int i = 10;
|
|
i < MAX_TIME;
|
|
i += 10 )
|
|
{
|
|
glVertex2i( x, y - i );
|
|
glVertex2i( x + FPS_WIDTH, y - i );
|
|
}
|
|
glEnd();
|
|
x += FPS_WIDTH;
|
|
glBegin( GL_LINES );
|
|
for( int i = 0;
|
|
i < NUM_PAINTS;
|
|
++i )
|
|
{
|
|
int value = paints[ ( i + paints_pos ) % NUM_PAINTS ];
|
|
if( value > MAX_TIME )
|
|
value = MAX_TIME; // limit
|
|
if( value <= 10 )
|
|
glColor4f( 0, 1, 0, alpha ); // green
|
|
else if( value <= 20 )
|
|
glColor4f( 1, 1, 0, alpha ); // yellow
|
|
else if( value <= 50 )
|
|
glColor4f( 1, 0, 0, alpha ); // red
|
|
else
|
|
glColor4f( 0, 0, 0, alpha ); // black
|
|
glVertex2i( x + NUM_PAINTS - i, y );
|
|
glVertex2i( x + NUM_PAINTS - i, y - value );
|
|
}
|
|
glEnd();
|
|
glPopAttrib();
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
Differences between OpenGL and XRender:
|
|
- differently specified rectangles (X: width/height, O: x2,y2)
|
|
- XRender uses pre-multiplied alpha
|
|
*/
|
|
void ShowFpsEffect::paintXrender( int fps )
|
|
{
|
|
#ifdef HAVE_XRENDER
|
|
Pixmap pixmap = XCreatePixmap( display(), rootWindow(), NUM_PAINTS + FPS_WIDTH, MAX_TIME, 32 );
|
|
XRenderPictFormat* format = XRenderFindStandardFormat( display(), PictStandardARGB32 );
|
|
Picture p = XRenderCreatePicture( display(), pixmap, format, 0, NULL );
|
|
XFreePixmap( display(), pixmap );
|
|
XRenderColor col;
|
|
col.alpha = int( alpha * 0xffff );
|
|
col.red = int( alpha * 0xffff ); // white
|
|
col.green = int( alpha * 0xffff );
|
|
col.blue= int( alpha * 0xffff );
|
|
XRenderFillRectangle( display(), PictOpSrc, p, &col, 0, 0, NUM_PAINTS + FPS_WIDTH, MAX_TIME );
|
|
col.red = 0; // blue
|
|
col.green = 0;
|
|
col.blue = int( alpha * 0xffff );
|
|
XRenderFillRectangle( display(), PictOpSrc, p, &col, 0, MAX_TIME - fps, FPS_WIDTH, fps );
|
|
col.red = 0; // black
|
|
col.green = 0;
|
|
col.blue = 0;
|
|
for( int i = 10;
|
|
i < MAX_TIME;
|
|
i += 10 )
|
|
{
|
|
XRenderFillRectangle( display(), PictOpSrc, p, &col, 0, MAX_TIME - i, FPS_WIDTH, 1 );
|
|
}
|
|
for( int i = 0;
|
|
i < NUM_PAINTS;
|
|
++i )
|
|
{
|
|
int value = paints[ ( i + paints_pos ) % NUM_PAINTS ];
|
|
if( value > MAX_TIME )
|
|
value = MAX_TIME; // limit
|
|
if( value <= 10 )
|
|
{ // green
|
|
col.red = 0;
|
|
col.green = int( alpha * 0xffff );
|
|
col.blue = 0;
|
|
}
|
|
else if( value <= 20 )
|
|
{ // yellow
|
|
col.red = int( alpha * 0xffff );
|
|
col.green = int( alpha * 0xffff );
|
|
col.blue = 0;
|
|
}
|
|
else if( value <= 50 )
|
|
{ // red
|
|
col.red = int( alpha * 0xffff );
|
|
col.green = 0;
|
|
col.blue = 0;
|
|
}
|
|
else
|
|
{ // black
|
|
col.red = 0;
|
|
col.green = 0;
|
|
col.blue = 0;
|
|
}
|
|
XRenderFillRectangle( display(), PictOpSrc, p, &col, FPS_WIDTH + NUM_PAINTS - i, MAX_TIME - value, 1, value );
|
|
}
|
|
XRenderComposite( display(), alpha != 1.0 ? PictOpOver : PictOpSrc, p, None,
|
|
effects->xrenderBufferPicture(), 0, 0, 0, 0, x, y, FPS_WIDTH + NUM_PAINTS, MAX_TIME );
|
|
XRenderFreePicture( display(), p );
|
|
#endif
|
|
}
|
|
|
|
void ShowFpsEffect::postPaintScreen()
|
|
{
|
|
effects->postPaintScreen();
|
|
paints[ paints_pos ] = t.elapsed();
|
|
if( ++paints_pos == NUM_PAINTS )
|
|
paints_pos = 0;
|
|
effects->addRepaint( x, y, FPS_WIDTH + NUM_PAINTS, MAX_TIME );
|
|
}
|
|
|
|
} // namespace
|