00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "compositingprefs.h"
00022
00023 #include "kwinglobals.h"
00024
00025 #include <kdebug.h>
00026 #include <kxerrorhandler.h>
00027 #include <klocale.h>
00028 #include <kdeversion.h>
00029
00030
00031 namespace KWin
00032 {
00033
00034 CompositingPrefs::CompositingPrefs()
00035 : mXgl( false )
00036 , mEnableCompositing( false )
00037 , mEnableVSync( true )
00038 , mEnableDirectRendering( true )
00039 , mStrictBinding( true )
00040 {
00041 }
00042
00043 CompositingPrefs::~CompositingPrefs()
00044 {
00045 }
00046
00047 bool CompositingPrefs::enableCompositing() const
00048 {
00049 return mEnableCompositing;
00050 }
00051
00052 bool CompositingPrefs::compositingPossible()
00053 {
00054 #ifdef KWIN_HAVE_COMPOSITING
00055 Extensions::init();
00056 if( !Extensions::compositeAvailable())
00057 {
00058 kDebug( 1212 ) << "No composite extension available";
00059 return false;
00060 }
00061 if( !Extensions::damageAvailable())
00062 {
00063 kDebug( 1212 ) << "No damage extension available";
00064 return false;
00065 }
00066 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00067 if( Extensions::glxAvailable())
00068 return true;
00069 #endif
00070 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00071 if( Extensions::renderAvailable() && Extensions::fixesAvailable())
00072 return true;
00073 #endif
00074 kDebug( 1212 ) << "No OpenGL or XRender/XFixes support";
00075 return false;
00076 #else
00077 return false;
00078 #endif
00079 }
00080
00081 QString CompositingPrefs::compositingNotPossibleReason()
00082 {
00083 #ifdef KWIN_HAVE_COMPOSITING
00084 Extensions::init();
00085 if( !Extensions::compositeAvailable() || !Extensions::damageAvailable())
00086 {
00087 return i18n("Required X extensions (XComposite and XDamage) are not available.");
00088 }
00089 #if defined( KWIN_HAVE_OPENGL_COMPOSITING ) && !defined( KWIN_HAVE_XRENDER_COMPOSITING )
00090 if( !Extensions::glxAvailable())
00091 return i18n( "GLX/OpenGL are not available and only OpenGL support is compiled." );
00092 #elif !defined( KWIN_HAVE_OPENGL_COMPOSITING ) && defined( KWIN_HAVE_XRENDER_COMPOSITING )
00093 if( !( Extensions::renderAvailable() && Extensions::fixesAvailable()))
00094 return i18n( "XRender/XFixes extensions are not available and only XRender support"
00095 " is compiled." );
00096 #else
00097 if( !( Extensions::glxAvailable()
00098 || ( Extensions::renderAvailable() && Extensions::fixesAvailable())))
00099 {
00100 return i18n( "GLX/OpenGL and XRender/XFixes are not available." );
00101 }
00102 #endif
00103 return QString();
00104 #else
00105 return i18n("Compositing was disabled at compile time.\n"
00106 "It is likely Xorg development headers were not installed.");
00107 #endif
00108 }
00109
00110
00111
00112
00113 bool CompositingPrefs::validateSetup( CompositingType compositingType ) const
00114 {
00115 switch( compositingType )
00116 {
00117 case NoCompositing:
00118 return false;
00119 case OpenGLCompositing:
00120 if( mDriver == "software" )
00121 {
00122 kDebug( 1212 ) << "Software GL renderer detected, forcing compositing off.";
00123 return false;
00124 }
00125 return true;
00126 case XRenderCompositing:
00127 return true;
00128 }
00129 abort();
00130 }
00131
00132 void CompositingPrefs::detect()
00133 {
00134 if( !compositingPossible())
00135 {
00136 return;
00137 }
00138
00139 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00140 if( !Extensions::glxAvailable())
00141 {
00142 kDebug( 1212 ) << "No GLX available";
00143 return;
00144 }
00145 int glxmajor, glxminor;
00146 glXQueryVersion( display(), &glxmajor, &glxminor );
00147 kDebug( 1212 ) << "glx version is " << glxmajor << "." << glxminor;
00148 bool hasglx13 = ( glxmajor > 1 || ( glxmajor == 1 && glxminor >= 3 ));
00149
00150
00151 GLXContext oldcontext = glXGetCurrentContext();
00152 GLXDrawable olddrawable = glXGetCurrentDrawable();
00153 GLXDrawable oldreaddrawable = None;
00154 if( hasglx13 )
00155 oldreaddrawable = glXGetCurrentReadDrawable();
00156
00157 if( initGLXContext() )
00158 {
00159 detectDriverAndVersion();
00160 applyDriverSpecificOptions();
00161 }
00162 if( hasglx13 )
00163 glXMakeContextCurrent( display(), olddrawable, oldreaddrawable, oldcontext );
00164 else
00165 glXMakeCurrent( display(), olddrawable, oldcontext );
00166 deleteGLXContext();
00167 #endif
00168 }
00169
00170 bool CompositingPrefs::initGLXContext()
00171 {
00172 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00173 mGLContext = NULL;
00174 KXErrorHandler handler;
00175
00176 QVector<int> attribs;
00177 attribs << GLX_RGBA;
00178 attribs << GLX_RED_SIZE << 1;
00179 attribs << GLX_GREEN_SIZE << 1;
00180 attribs << GLX_BLUE_SIZE << 1;
00181 attribs << None;
00182
00183 XVisualInfo* visinfo = glXChooseVisual( display(), DefaultScreen( display()), attribs.data() );
00184 if( !visinfo )
00185 {
00186 attribs.last() = GLX_DOUBLEBUFFER;
00187 attribs << None;
00188 visinfo = glXChooseVisual( display(), DefaultScreen( display()), attribs.data() );
00189 if (!visinfo)
00190 {
00191 kDebug( 1212 ) << "Error: couldn't find RGB GLX visual";
00192 return false;
00193 }
00194 }
00195
00196 mGLContext = glXCreateContext( display(), visinfo, NULL, True );
00197 if ( !mGLContext )
00198 {
00199 kDebug( 1212 ) << "glXCreateContext failed";
00200 XDestroyWindow( display(), mGLWindow );
00201 return false;
00202 }
00203
00204 XSetWindowAttributes attr;
00205 attr.background_pixel = 0;
00206 attr.border_pixel = 0;
00207 attr.colormap = XCreateColormap( display(), rootWindow(), visinfo->visual, AllocNone );
00208 attr.event_mask = StructureNotifyMask | ExposureMask;
00209 unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
00210 int width = 100, height = 100;
00211 mGLWindow = XCreateWindow( display(), rootWindow(), 0, 0, width, height,
00212 0, visinfo->depth, InputOutput,
00213 visinfo->visual, mask, &attr );
00214
00215 return glXMakeCurrent( display(), mGLWindow, mGLContext ) && !handler.error( true );
00216 #else
00217 return false;
00218 #endif
00219 }
00220
00221 void CompositingPrefs::deleteGLXContext()
00222 {
00223 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00224 if( mGLContext == NULL )
00225 return;
00226 glXDestroyContext( display(), mGLContext );
00227 XDestroyWindow( display(), mGLWindow );
00228 #endif
00229 }
00230
00231 void CompositingPrefs::detectDriverAndVersion()
00232 {
00233 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00234 mGLVendor = QString((const char*)glGetString( GL_VENDOR ));
00235 mGLRenderer = QString((const char*)glGetString( GL_RENDERER ));
00236 mGLVersion = QString((const char*)glGetString( GL_VERSION ));
00237 mXgl = detectXgl();
00238 kDebug( 1212 ) << "GL vendor is" << mGLVendor;
00239 kDebug( 1212 ) << "GL renderer is" << mGLRenderer;
00240 kDebug( 1212 ) << "GL version is" << mGLVersion;
00241 kDebug( 1212 ) << "XGL:" << ( mXgl ? "yes" : "no" );
00242
00243 if( mGLRenderer.startsWith( "Mesa DRI Intel" ))
00244 {
00245 mDriver = "intel";
00246 QStringList words = mGLRenderer.split(" ");
00247 mVersion = Version( words[ words.count() - 2 ] );
00248 }
00249 else if( mGLVendor == "NVIDIA Corporation" )
00250 {
00251 mDriver = "nvidia";
00252 QStringList words = mGLVersion.split(" ");
00253 mVersion = Version( words[ words.count() - 1 ] );
00254 }
00255 else if( mGLVendor == "ATI Technologies Inc." )
00256 {
00257 mDriver = "fglrx";
00258 mVersion = Version( mGLVersion.split(" ").first());
00259 }
00260 else if( mGLRenderer.startsWith( "Mesa DRI" ))
00261 {
00262 mDriver = "radeon";
00263 mVersion = Version( mGLRenderer.split(" ")[ 3 ] );
00264 }
00265 else if( mGLRenderer == "Software Rasterizer" )
00266 {
00267 mDriver = "software";
00268 QStringList words = mGLVersion.split(" ");
00269 mVersion = Version( words[ words.count() - 1 ] );
00270 }
00271 else
00272 {
00273 mDriver = "unknown";
00274 }
00275
00276 kDebug( 1212 ) << "Detected driver" << mDriver << ", version" << mVersion.join(".");
00277 #endif
00278 }
00279
00280
00281 void CompositingPrefs::applyDriverSpecificOptions()
00282 {
00283 if( mXgl )
00284 {
00285 kDebug( 1212 ) << "xgl, enabling";
00286 mEnableCompositing = true;
00287 mStrictBinding = false;
00288 }
00289 else if( mDriver == "intel" )
00290 {
00291 kDebug( 1212 ) << "intel driver, disabling vsync, enabling direct";
00292 mEnableVSync = false;
00293 mEnableDirectRendering = true;
00294 if( mVersion >= Version( "20061017" ))
00295 {
00296 if( mGLRenderer.contains( "Intel(R) 9" ))
00297 {
00298 kDebug( 1212 ) << "intel >= 20061017 and 900-series card, enabling compositing";
00299 mEnableCompositing = true;
00300 }
00301 if( mGLRenderer.contains( "Mesa DRI Intel(R) G" ))
00302 {
00303 kDebug( 1212 ) << "intel >= 20061017 and Gxx-series card, enabling compositing";
00304 mEnableCompositing = true;
00305 }
00306 }
00307 }
00308 else if( mDriver == "nvidia" )
00309 {
00310 mStrictBinding = false;
00311 if( mVersion >= Version( "173.14.12" ))
00312 {
00313 kDebug( 1212 ) << "nvidia >= 173.14.12, enabling compositing";
00314 mEnableCompositing = true;
00315 }
00316 }
00317 else if( mDriver == "radeon" )
00318 {
00319 if( mGLRenderer.startsWith( "Mesa DRI R200" ) && mVersion >= Version( "20060602" ))
00320 {
00321 kDebug( 1212 ) << "radeon r200 >= 20060602, enabling compositing";
00322 mEnableCompositing = true;
00323 }
00324 }
00325 else if( mDriver == "fglrx" )
00326 {
00327 if( mVersion >= Version( "2.1.7412" ))
00328 {
00329 kDebug( 1212 ) << "fglrx >= 2.1.7412, enabling compositing";
00330 mEnableCompositing = true;
00331 }
00332 }
00333 }
00334
00335
00336 bool CompositingPrefs::detectXgl()
00337 {
00338 return VendorRelease(display()) == 70000001;
00339 }
00340
00341 CompositingPrefs::Version::Version( const QString& str ) :
00342 QStringList()
00343 {
00344 QRegExp numrx( "(\\d+)|(\\D+)" );
00345 int pos = 0;
00346 while(( pos = numrx.indexIn( str, pos )) != -1 )
00347 {
00348 pos += numrx.matchedLength();
00349
00350 QString part = numrx.cap();
00351 if( part == "." )
00352 continue;
00353
00354 append( part );
00355 }
00356 }
00357
00358 int CompositingPrefs::Version::compare( const Version& v ) const
00359 {
00360 for( int i = 0; i < qMin( count(), v.count() ); i++ )
00361 {
00362 if( at( i )[ 0 ].isDigit() )
00363 {
00364
00365 int num = at( i ).toInt();
00366 int vnum = v.at( i ).toInt();
00367 if( num > vnum )
00368 return 1;
00369 else if( num < vnum )
00370 return -1;
00371 }
00372 else
00373 {
00374
00375 if( at( i ) > v.at( i ))
00376 return 1;
00377 else if( at( i ) < v.at( i ))
00378 return -1;
00379 }
00380 }
00381
00382 if( count() > v.count() )
00383 return 1;
00384 else if( count() < v.count() )
00385 return -1;
00386 else
00387 return 0;
00388 }
00389
00390 }
00391