From f060c3bfbbefd278735a38ab84ab057268dec9c8 Mon Sep 17 00:00:00 2001 From: Philip Falkner Date: Fri, 2 Feb 2007 19:58:35 +0000 Subject: [PATCH] Improved filtering algorithm. Now fast filtering is used by default, while (depending on SmoothScale in kwinrc) bilinear filtering is used on transformed windows and screens. Optionally, if SmoothScale is set to 2, trilinear filtering will be attempted instead of bilinear. This requires GL_ARB_texture_non_power_of_two, GL_EXT_framebuffer_object, and valid mipmaps. svn path=/branches/work/kwin_composite/; revision=629453 --- options.cpp | 2 +- options.h | 4 +++- scene.cpp | 1 + scene.h | 3 +++ scene_opengl.cpp | 44 ++++++++++++++++++++++++++++++++++++++------ scene_opengl.h | 1 + scene_xrender.cpp | 16 ++++++++++++++-- 7 files changed, 61 insertions(+), 10 deletions(-) diff --git a/options.cpp b/options.cpp index c9d9456559..3a2f55e725 100644 --- a/options.cpp +++ b/options.cpp @@ -195,7 +195,7 @@ unsigned long Options::updateSettings() onlyDecoTranslucent = config->readEntry("OnlyDecoTranslucent", QVariant(false)).toBool(); refreshRate = config->readEntry( "RefreshRate", 0 ); - smoothScale = qBound( -1, config->readEntry( "SmoothScale", -1 ), 1 ); + smoothScale = qBound( -1, config->readEntry( "SmoothScale", -1 ), 2 ); QString glmode = config->readEntry("GLMode", "TFP" ).upper(); if( glmode == "TFP" ) diff --git a/options.h b/options.h index f86e249cd1..1f82a87fec 100644 --- a/options.h +++ b/options.h @@ -301,7 +301,9 @@ class Options : public KDecorationOptions bool onlyDecoTranslucent; uint refreshRate; - int smoothScale; // 0 = no, 1 = yes, -1 = auto + int smoothScale; // 0 = no, 1 = yes when transformed, + // 2 = try trilinear when transformed; else 1, + // -1 = auto enum GLMode { GLTFP, GLSHM, GLFallback }; GLMode glMode; diff --git a/scene.cpp b/scene.cpp index 0ce1b8a86e..e8f64ea779 100644 --- a/scene.cpp +++ b/scene.cpp @@ -242,6 +242,7 @@ void Scene::finalPaintWindow( EffectWindow* w, int mask, QRegion region, WindowP Scene::Window::Window( Toplevel * c ) : toplevel( c ) + , filter( ImageFilterFast ) , shape_valid( false ) { } diff --git a/scene.h b/scene.h index 88b3bdda91..1f3eb01b3b 100644 --- a/scene.h +++ b/scene.h @@ -69,6 +69,8 @@ class Scene // Clear whole background as the very first step, without optimizing it PAINT_SCREEN_BACKGROUND_FIRST = 1 << 6, }; + // types of filtering available + enum ImageFilterType { ImageFilterFast, ImageFilterGood }; // there's nothing to paint (adjust time_diff later) void idle(); bool waitSyncAvailable() { return has_waitSync; } @@ -139,6 +141,7 @@ class Scene::Window Window() {} // QMap sucks even in Qt4 protected: Toplevel* toplevel; + ImageFilterType filter; private: mutable QRegion shape_region; mutable bool shape_valid; diff --git a/scene_opengl.cpp b/scene_opengl.cpp index ee1faedbe5..99b18d0245 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -717,6 +717,7 @@ SceneOpenGL::Window::Window( Toplevel* c ) , texture_y_inverted( false ) , texture_can_use_mipmaps( false ) , texture_has_valid_mipmaps( false ) + , texture_filter_trilinear( false ) , bound_glxpixmap( None ) , currentXResolution( -1 ) , currentYResolution( -1 ) @@ -1044,16 +1045,29 @@ void SceneOpenGL::Window::enableTexture() assert( bound_glxpixmap != None ); glXBindTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT, NULL ); } - if( options->smoothScale != 0 ) // default to yes - { - glTexParameteri( texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameteri( texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - } - else + if( filter == ImageFilterFast ) { glTexParameteri( texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); } + else if( filter == ImageFilterGood ) + { + if( texture_filter_trilinear ) + { + glTexParameteri( texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); + glTexParameteri( texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + if( !texture_has_valid_mipmaps ) + { + glGenerateMipmap( texture_target ); + texture_has_valid_mipmaps = true; + } + } + else + { + glTexParameteri( texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + } + } } void SceneOpenGL::Window::disableTexture() @@ -1117,6 +1131,24 @@ void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintDat return; bindTexture(); glPushMatrix(); + // set texture filter + if( options->smoothScale != 0 ) // default to yes + { + if( mask & PAINT_WINDOW_TRANSFORMED ) + filter = ImageFilterGood; + else if( mask & PAINT_SCREEN_TRANSFORMED ) + filter = ImageFilterGood; + else + filter = ImageFilterFast; + } + else + filter = ImageFilterFast; + // avoid unneeded mipmap generation by only using trilinear filtering + // when it actually makes a difference, that is with minification or + // changed vertices + texture_filter_trilinear = options->smoothScale == 2 + && supports_npot_textures && supports_fbo && texture_can_use_mipmaps + && ( verticesDirty || data.xScale < 1 || data.yScale < 1 ); // do required transformations int x = toplevel->x(); int y = toplevel->y(); diff --git a/scene_opengl.h b/scene_opengl.h index 34ec995eec..4315c37a9b 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -139,6 +139,7 @@ class SceneOpenGL::Window bool texture_y_inverted; // texture has y inverted bool texture_can_use_mipmaps; bool texture_has_valid_mipmaps; + bool texture_filter_trilinear; GLXPixmap bound_glxpixmap; // the glx pixmap the texture is bound to, only for tfp_mode QVector verticeslist; diff --git a/scene_xrender.cpp b/scene_xrender.cpp index 707bfef4d4..fecd8f43c7 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -438,6 +438,18 @@ void SceneXrender::Window::performPaint( int mask, QRegion region, WindowPaintDa Picture pic = picture(); // get XRender picture if( pic == None ) // The render format can be null for GL and/or Xv visuals return; + // set picture filter + if( options->smoothScale > 0 ) // only when forced, it's slow + { + if( mask & PAINT_WINDOW_TRANSFORMED ) + filter = ImageFilterGood; + else if( mask & PAINT_SCREEN_TRANSFORMED ) + filter = ImageFilterGood; + else + filter = ImageFilterFast; + } + else + filter = ImageFilterFast; // do required transformations int x = toplevel->x(); int y = toplevel->y(); @@ -472,7 +484,7 @@ void SceneXrender::Window::performPaint( int mask, QRegion region, WindowPaintDa XRenderSetPictureTransform( display(), pic, &xform ); width = (int)(width * xscale); height = (int)(height * yscale); - if( options->smoothScale == 1 ) // only when forced, it's slow + if( filter == ImageFilterGood ) XRenderSetPictureFilter( display(), pic, const_cast< char* >( "good" ), NULL, 0 ); // transform the shape for clipping in paintTransformedScreen() QVector< QRect > rects = transformed_shape.rects(); @@ -508,7 +520,7 @@ void SceneXrender::Window::performPaint( int mask, QRegion region, WindowPaintDa { XDoubleToFixed( 0 ), XDoubleToFixed( 0 ), XDoubleToFixed( 1 ) } }}; XRenderSetPictureTransform( display(), pic, &xform ); - if( options->smoothScale == 1 ) + if( filter == ImageFilterGood ) XRenderSetPictureFilter( display(), pic, const_cast< char* >( "fast" ), NULL, 0 ); } XFixesSetPictureClipRegion( display(), buffer, 0, 0, None );