From 59f21e39fecb0e71b8c7619b32639a8a90b1a0f6 Mon Sep 17 00:00:00 2001 From: Rivo Laks Date: Tue, 18 Sep 2007 13:59:06 +0000 Subject: [PATCH] Add automatic driver detection for compositing options. This is used to set sane defaults and work around possible driver bugs. Also, if you have a "whitelisted" driver (nvidia >= 96.39 or intel >= 20061017) then compositing will be enabled by default for you. svn path=/trunk/KDE/kdebase/workspace/; revision=714004 --- CMakeLists.txt | 1 + composite.cpp | 6 ++ compositingprefs.cpp | 216 +++++++++++++++++++++++++++++++++++++++++++ compositingprefs.h | 78 ++++++++++++++++ options.cpp | 44 +++++---- options.h | 2 + 6 files changed, 328 insertions(+), 19 deletions(-) create mode 100644 compositingprefs.cpp create mode 100644 compositingprefs.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 788b74c239..b511c6cd2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,7 @@ set(kwin_KDEINIT_SRCS scene_opengl.cpp deleted.cpp effects.cpp + compositingprefs.cpp ) qt4_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.KWin.xml workspace.h KWin::Workspace ) diff --git a/composite.cpp b/composite.cpp index b41c24a8e8..31fedebc0f 100644 --- a/composite.cpp +++ b/composite.cpp @@ -37,6 +37,7 @@ License. See the file "COPYING" for the exact licensing terms. #include "scene_basic.h" #include "scene_xrender.h" #include "scene_opengl.h" +#include "compositingprefs.h" #include @@ -65,6 +66,11 @@ namespace KWin void Workspace::setupCompositing() { #if defined( HAVE_XCOMPOSITE ) && defined( HAVE_XDAMAGE ) + // Driver-specific config detection + CompositingPrefs prefs; + prefs.detect(); + options->reloadCompositingSettings( prefs ); + if( !options->useCompositing ) { kDebug( 1212 ) << "Compositing is turned off in options"; diff --git a/compositingprefs.cpp b/compositingprefs.cpp new file mode 100644 index 0000000000..2393e5741b --- /dev/null +++ b/compositingprefs.cpp @@ -0,0 +1,216 @@ +/***************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2007 Rivo Laks + +You can Freely distribute this program under the GNU General Public +License. See the file "COPYING" for the exact licensing terms. +******************************************************************/ + +#include "compositingprefs.h" + +#include "options.h" +#include "utils.h" + +#include + + +namespace KWin +{ + +CompositingPrefs::CompositingPrefs() + { + mEnableCompositing = false; + mEnableVSync = true; + mEnableDirectRendering = true; + } +CompositingPrefs::~CompositingPrefs() + { + } + +void CompositingPrefs::detect() + { +#ifdef HAVE_OPENGL + if( createGLXContext() ) + { + detectDriverAndVersion(); + applyDriverSpecificOptions(); + + deleteGLXContext(); + } +#endif + } + +bool CompositingPrefs::createGLXContext() +{ +#ifdef HAVE_OPENGL + // Most of this code has been taken from glxinfo.c + QVector attribs; + attribs << GLX_RGBA; + attribs << GLX_RED_SIZE << 1; + attribs << GLX_GREEN_SIZE << 1; + attribs << GLX_BLUE_SIZE << 1; + attribs << None; + + int scrnum = 0; // correct? + XVisualInfo* visinfo = glXChooseVisual( display(), scrnum, attribs.data() ); + if( !visinfo ) + { + attribs.last() = GLX_DOUBLEBUFFER; + attribs << None; + visinfo = glXChooseVisual( display(), scrnum, attribs.data() ); + if (!visinfo) + { + kError() << "Error: couldn't find RGB GLX visual"; + return false; + } + } + + mGLContext = glXCreateContext( display(), visinfo, NULL, True ); + if ( !mGLContext ) + { + kError() << "glXCreateContext failed"; + XDestroyWindow( display(), mGLWindow ); + return false; + } + + XSetWindowAttributes attr; + attr.background_pixel = 0; + attr.border_pixel = 0; + attr.colormap = XCreateColormap( display(), rootWindow(), visinfo->visual, AllocNone ); + attr.event_mask = StructureNotifyMask | ExposureMask; + unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + int width = 100, height = 100; + mGLWindow = XCreateWindow( display(), rootWindow(), 0, 0, width, height, + 0, visinfo->depth, InputOutput, + visinfo->visual, mask, &attr ); + + return glXMakeCurrent( display(), mGLWindow, mGLContext ); +#else + return false; +#endif +} + +void CompositingPrefs::deleteGLXContext() +{ +#ifdef HAVE_OPENGL + glXDestroyContext( display(), mGLContext ); + XDestroyWindow( display(), mGLWindow ); +#endif +} + +void CompositingPrefs::detectDriverAndVersion() + { +#ifdef HAVE_OPENGL + QString glvendor = QString((const char*)glGetString( GL_VENDOR )); + QString glrenderer = QString((const char*)glGetString( GL_RENDERER )); + QString glversion = QString((const char*)glGetString( GL_VERSION )); + kDebug() << "GL vendor is" << glvendor; + kDebug() << "GL renderer is" << glrenderer; + kDebug() << "GL version is" << glversion; + + if( glrenderer.contains( "Intel" )) + { + mDriver = "intel"; + QStringList words = glrenderer.split(" "); + mVersion = Version( words[ words.count() - 2 ] ); + } + else if( glvendor.contains( "NVIDIA" )) + { + mDriver = "nvidia"; + QStringList words = glversion.split(" "); + mVersion = Version( words[ words.count() - 1 ] ); + } + else + { + mDriver = "unknown"; + } + + kDebug() << "Detected driver" << mDriver << ", version" << mVersion.join("."); +#endif + } + +void CompositingPrefs::applyDriverSpecificOptions() + { + if( mDriver == "intel") + { + if( mVersion <= Version( "20061017" )) + { + kDebug() << "intel <= 20061017, disabling vsync, enabling direct"; + mEnableVSync = false; + mEnableDirectRendering = true; + } + if( mVersion >= Version( "20061017" )) + { + kDebug() << "intel >= 20061017, enabling compositing"; + mEnableCompositing = true; + } + } + else if( mDriver == "nvidia" ) + { + if( mVersion <= Version( "100.14.11" )) + { + kDebug() << "nvidia <= 100.14.11, disabling vsync"; + mEnableVSync = false; + } + if( mVersion >= Version( "96.39" )) + { + kDebug() << "nvidia >= 96.39, enabling compositing"; + mEnableCompositing = true; + } + } + } + + +CompositingPrefs::Version::Version( const QString& str ) : + QStringList() + { + QRegExp numrx( "(\\d+)|(\\D+)" ); + int pos = 0; + while(( pos = numrx.indexIn( str, pos )) != -1 ) + { + pos += numrx.matchedLength(); + + QString part = numrx.cap(); + if( part == "." ) + continue; + + append( part ); + } + } + +int CompositingPrefs::Version::compare( const Version& v ) const + { + for( int i = 0; i < qMin( count(), v.count() ); i++ ) + { + if( at( i )[ 0 ].isDigit() ) + { + // This part of version string is numeric - compare numbers + int num = at( i ).toInt(); + int vnum = v.at( i ).toInt(); + if( num > vnum ) + return 1; + else if( num < vnum ) + return -1; + } + else + { + // This part is string + if( at( i ) > v.at( i )) + return 1; + else if( at( i ) < v.at( i )) + return -1; + } + } + + if( count() > v.count() ) + return 1; + else if( count() < v.count() ) + return -1; + else + return 0; + } + +} // namespace + diff --git a/compositingprefs.h b/compositingprefs.h new file mode 100644 index 0000000000..ff5631bfce --- /dev/null +++ b/compositingprefs.h @@ -0,0 +1,78 @@ +/***************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2007 Rivo Laks + +You can Freely distribute this program under the GNU General Public +License. See the file "COPYING" for the exact licensing terms. +******************************************************************/ + +#ifndef KWIN_COMPOSITINGPREFS_H +#define KWIN_COMPOSITINGPREFS_H + +#include +#include + +#include "kwinglutils.h" + + +namespace KWin +{ + +class CompositingPrefs +{ +public: + CompositingPrefs(); + ~CompositingPrefs(); + + class Version : public QStringList + { + public: + Version() : QStringList() {} + Version( const QString& str ); + + int compare( const Version& v ) const; + + bool operator<( const Version& v ) const { return ( compare( v ) == -1 ); } + bool operator<=( const Version& v ) const { return ( compare( v ) != 1 ); } + bool operator>( const Version& v ) const { return ( compare( v ) == 1 ); } + bool operator>=( const Version& v ) const { return ( compare( v ) != -1 ); } + }; + + bool enableCompositing() const { return mEnableCompositing; } + bool enableVSync() const { return mEnableVSync; } + bool enableDirectRendering() const { return mEnableDirectRendering; } + + void detect(); + + QString driver() const { return mDriver; } + Version version() const { return mVersion; } + + +protected: + + void detectDriverAndVersion(); + void applyDriverSpecificOptions(); + + bool createGLXContext(); + void deleteGLXContext(); + + +private: + QString mDriver; + Version mVersion; + + bool mEnableCompositing; + bool mEnableVSync; + bool mEnableDirectRendering; + + GLXContext mGLContext; + Window mGLWindow; +}; + +} + +#endif //KWIN_COMPOSITINGPREFS_H + + diff --git a/options.cpp b/options.cpp index 42b3326384..dca89a6a11 100644 --- a/options.cpp +++ b/options.cpp @@ -23,6 +23,7 @@ License. See the file "COPYING" for the exact licensing terms. #include #include "client.h" +#include "compositingprefs.h" #endif @@ -177,25 +178,6 @@ unsigned long Options::updateSettings() CmdAll3 = mouseCommand(config.readEntry("CommandAll3","Resize"), false ); CmdAllWheel = mouseWheelCommand(config.readEntry("CommandAllWheel","Nothing")); - // Compositing settings - config.changeGroup("Compositing"); - useCompositing = config.readEntry("Enabled", false); - QString compositingBackend = config.readEntry("Backend", "OpenGL"); - if( compositingBackend == "XRender" ) - compositingMode = XRenderCompositing; - else - compositingMode = OpenGLCompositing; - QString glmode = config.readEntry("GLMode", "TFP" ).toUpper(); - if( glmode == "TFP" ) - glMode = GLTFP; - else if( glmode == "SHM" ) - glMode = GLSHM; - else - glMode = GLFallback; - glDirect = config.readEntry("GLDirect", true ); - glVSync = config.readEntry("GLVSync", true ); - smoothScale = qBound( -1, config.readEntry( "GLTextureFilter", -1 ), 2 ); - config.changeGroup("Translucency"); refreshRate = config.readEntry( "RefreshRate", 0 ); glStrictBinding = config.readEntry( "GLStrictBinding", false ); @@ -222,6 +204,30 @@ unsigned long Options::updateSettings() return changed; } +void Options::reloadCompositingSettings(const CompositingPrefs& prefs) + { + KSharedConfig::Ptr _config = KGlobal::config(); + KConfigGroup config(_config, "Compositing"); + + // Compositing settings + useCompositing = config.readEntry("Enabled", prefs.enableCompositing()); + QString compositingBackend = config.readEntry("Backend", "OpenGL"); + if( compositingBackend == "XRender" ) + compositingMode = XRenderCompositing; + else + compositingMode = OpenGLCompositing; + QString glmode = config.readEntry("GLMode", "TFP" ).toUpper(); + if( glmode == "TFP" ) + glMode = GLTFP; + else if( glmode == "SHM" ) + glMode = GLSHM; + else + glMode = GLFallback; + glDirect = config.readEntry("GLDirect", prefs.enableDirectRendering() ); + glVSync = config.readEntry("GLVSync", prefs.enableVSync() ); + smoothScale = qBound( -1, config.readEntry( "GLTextureFilter", -1 ), 2 ); + } + // restricted should be true for operations that the user may not be able to repeat // if the window is moved out of the workspace (e.g. if the user moves a window diff --git a/options.h b/options.h index b80d4d83e5..39c0997d8c 100644 --- a/options.h +++ b/options.h @@ -24,6 +24,7 @@ namespace KWin { class Client; +class CompositingPrefs; class Options : public KDecorationOptions { @@ -33,6 +34,7 @@ class Options : public KDecorationOptions ~Options(); virtual unsigned long updateSettings(); + void reloadCompositingSettings(const CompositingPrefs& prefs); /*! Different focus policies: