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 );