For simple paint, clip by above windows. A missing todo is to still

update only changed areas instead of doing full glXSwapBuffers()
when possible.


svn path=/branches/work/kwin_composite/; revision=595357
This commit is contained in:
Luboš Luňák 2006-10-14 07:15:23 +00:00
parent b60b847e25
commit 004d781e32
3 changed files with 53 additions and 19 deletions

View file

@ -73,7 +73,8 @@ TODO:
/ design framework for graphical effects
- modelling it after compiz seems to make a lot of sense
* make paintSimpleScreen() clip non-visible parts
- clip parts of lower windows by parts of windows above them, so that those parts
don't need to be painted
- similarly like in scene_xrender.cpp
* update only those parts of the screen that have been changed
- for paintSimpleScreen() - it currently sets region to the whole screen
- instead of using glXSwapBuffers() or XCopyArea() that update the whole screen,
there should be glCopyPixels() used
- compiz has such code in evenLoop() in the if() block for COMP_SCREEN_DAMAGE_REGION_MASK

View file

@ -267,7 +267,7 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList windows )
glClear( GL_COLOR_BUFFER_BIT );
glScalef( 1, -1, 1 );
glTranslatef( 0, -displayHeight(), 0 );
if( /*generic case*/true )
if( /*generic case*/false )
paintGenericScreen( windows );
else
paintSimpleScreen( damage, windows );
@ -285,7 +285,7 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList windows )
checkGLError( "PostPaint" );
}
// the generic drawing code that should eventually handle even
// the generic painting code that should eventually handle even
// transformations
void SceneOpenGL::paintGenericScreen( ToplevelList windows )
{
@ -301,15 +301,18 @@ void SceneOpenGL::paintGenericScreen( ToplevelList windows )
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}
w.draw();
w.paint( infiniteRegion());
glDisable( GL_BLEND );
}
}
// the optimized case without any transformations at all
void SceneOpenGL::paintSimpleScreen( QRegion, ToplevelList windows )
void SceneOpenGL::paintSimpleScreen( QRegion damage, ToplevelList windows )
{
QList< Window* > phase2;
QList< Phase2Data > phase2;
QRegion region = damage;
// TODO repaint only damaged areas (means also don't do glXSwapBuffers and similar)
region = QRegion( 0, 0, displayWidth(), displayHeight());
for( int i = windows.count() - 1; // top to bottom
i >= 0;
--i )
@ -319,25 +322,35 @@ void SceneOpenGL::paintSimpleScreen( QRegion, ToplevelList windows )
Window& w = this->windows[ c ];
if( !w.isVisible())
continue;
if( region.isEmpty()) // completely clipped
continue;
if( !w.isOpaque())
{
phase2.prepend( &w );
phase2.prepend( Phase2Data( &w, region ));
continue;
}
w.bindTexture();
w.draw();
w.paint( region );
// window is opaque, clip windows below
region -= w.shape().translated( w.x(), w.y());
}
foreach( Window* w2, phase2 )
paintBackground( region );
foreach( Phase2Data d, phase2 )
{
Window& w = *w2;
Window& w = *d.window;
w.bindTexture();
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
w.draw();
w.paint( d.region );
glDisable( GL_BLEND );
}
}
void SceneOpenGL::paintBackground( QRegion )
{
// TODO?
}
void SceneOpenGL::windowAdded( Toplevel* c )
{
assert( !windows.contains( c ));
@ -562,7 +575,7 @@ QRegion SceneOpenGL::Window::shape() const
return shape_region;
}
static void quadDraw( int x1, int y1, int x2, int y2, bool invert_y )
static void quadPaint( int x1, int y1, int x2, int y2, bool invert_y )
{
glTexCoord2i( x1, invert_y ? y2 : y1 );
glVertex2i( x1, y1 );
@ -574,8 +587,14 @@ static void quadDraw( int x1, int y1, int x2, int y2, bool invert_y )
glVertex2i( x1, y2 );
}
void SceneOpenGL::Window::draw()
void SceneOpenGL::Window::paint( QRegion region )
{
// paint only requested areas
if( region != infiniteRegion()) // avoid integer overflow
region.translate( -x(), -y());
region &= shape();
if( region.isEmpty())
return;
// TODO for double-buffered root glDrawBuffer( GL_BACK );
glXMakeContextCurrent( display(), glxroot, glxroot, context );
glPushMatrix();
@ -602,9 +621,9 @@ void SceneOpenGL::Window::draw()
}
glEnable( GL_TEXTURE_RECTANGLE_ARB );
glBegin( GL_QUADS );
foreach( QRect r, shape().rects())
foreach( QRect r, region.rects())
{
quadDraw( r.x(), r.y(), r.x() + r.width(), r.y() + r.height(),
quadPaint( r.x(), r.y(), r.x() + r.width(), r.y() + r.height(),
texture_y_inverted );
}
glEnd();

View file

@ -36,6 +36,8 @@ class SceneOpenGL
bool findConfig( const int* attrs, GLXFBConfig& config, VisualID visual = None );
void paintGenericScreen( ToplevelList windows );
void paintSimpleScreen( QRegion damage, ToplevelList windows );
void paintBackground( QRegion damage );
static QRegion infiniteRegion();
typedef GLuint Texture;
GC gcroot;
Drawable buffer;
@ -47,6 +49,12 @@ class SceneOpenGL
static bool tfp_mode;
class Window;
QMap< Toplevel*, Window > windows;
struct Phase2Data
{
Phase2Data( Window* w, QRegion r ) : window( w ), region( r ) {}
Window* window;
QRegion region;
};
};
class SceneOpenGL::Window
@ -59,7 +67,7 @@ class SceneOpenGL::Window
int y() const;
int width() const;
int height() const;
void draw();
void paint( QRegion region );
bool isVisible() const;
bool isOpaque() const;
void bindTexture();
@ -77,6 +85,12 @@ class SceneOpenGL::Window
mutable bool shape_valid;
};
inline
QRegion SceneOpenGL::infiniteRegion()
{ // INT_MIN / 2 because it's width/height (INT_MIN+INT_MAX==-1)
return QRegion( INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX );
}
inline
int SceneOpenGL::Window::x() const
{