From 004d781e32f14169f435f7483a6f83a64c485d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Sat, 14 Oct 2006 07:15:23 +0000 Subject: [PATCH] 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 --- COMPOSITE_TODO | 9 +++++---- scene_opengl.cpp | 47 +++++++++++++++++++++++++++++++++-------------- scene_opengl.h | 16 +++++++++++++++- 3 files changed, 53 insertions(+), 19 deletions(-) diff --git a/COMPOSITE_TODO b/COMPOSITE_TODO index 37c14a3026..9b56a88a52 100644 --- a/COMPOSITE_TODO +++ b/COMPOSITE_TODO @@ -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 diff --git a/scene_opengl.cpp b/scene_opengl.cpp index a1786f574b..315250f708 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -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(); diff --git a/scene_opengl.h b/scene_opengl.h index 257c8dd5b4..6cf9697dba 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -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 {